[
  {
    "path": ".github/workflows/c-cpp.yml",
    "content": "name: C/C++ CI\n\non:\n  push:\n    branches: [ master, development ]\n  pull_request:\n    branches: [ master, development ]\n\njobs:\n  build_ubuntu-amd64_latest:\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v2\n    - name: prerequisites\n    # pre-installed on ubuntu-1804: build-essential, git 2.28.0, cmake 3.10/3.17, make\n    # pre-installed: clang 6.0 / 8 / 9, gcc/++ 7.5.0/8.4.0/9.3.0\n      run: sudo apt -qq update && sudo apt -yqq install libusb-1.0-0-dev\n    - name: cmake_make\n      run: mkdir build && cmake -S . -B build && cd build && make\n    - name: compress\n      run: tar zcvf librtlsdr_build_ubuntu-amd64_latest.tar.gz --directory=build/src --exclude=CMakeFiles --exclude=*.cmake --exclude=Makefile --exclude=rtl_app_ver.h .\n    - name: 'Upload Artifact'\n      uses: actions/upload-artifact@v2\n      with:\n        name: ubuntu_latest_build\n        path: librtlsdr_build_ubuntu-amd64_latest.tar.gz\n\n  build_macos_latest:\n    runs-on: macos-latest\n\n    steps:\n    - uses: actions/checkout@v2\n    #- name: prerequisites\n    # pre-installed on macos-10.15: git 2.28.0, cmake 3.18.2, libusb 1.0.23\n    # pre-installed: clang/LLVM 10.0.1, gcc/++ 8.4.0/9.3.0\n    #  run: brew install libusb\n    - name: cmake_make\n      run: mkdir build && cmake -S . -B build && cd build && make\n    - name: compress\n      run: tar zcvf librtlsdr_build_macos-latest.tar.gz --directory=build/src --exclude=CMakeFiles --exclude=*.cmake --exclude=Makefile --exclude=rtl_app_ver.h .\n    - name: 'Upload Artifact'\n      uses: actions/upload-artifact@v2\n      with:\n        name: macos_latest_build\n        path: librtlsdr_build_macos-latest.tar.gz\n\n  cross_build_win32_win64_latest:\n    runs-on: ubuntu-20.04\n\n    steps:\n    - uses: actions/checkout@v2\n    - name: prerequisites\n      run: sudo apt -qq update && sudo apt -yqq install gcc-mingw-w64\n    - name: build_w32_static\n      run: bash ./cross_build_mingw32.sh static -DLINK_RTLTOOLS_AGAINST_STATIC_LIB=ON\n    - name: build_w32_static_udpsrv\n      run: bash ./cross_build_mingw32.sh static_udpsrv -DLINK_RTLTOOLS_AGAINST_STATIC_LIB=ON -DPROVIDE_UDP_SERVER=ON\n    - name: build_w32_dlldep\n      run: bash ./cross_build_mingw32.sh dlldep\n    - name: build_w32_dlldep_udpsrv\n      run: bash ./cross_build_mingw32.sh dlldep_udpsrv -DPROVIDE_UDP_SERVER=ON\n\n    - name: build_w64_static\n      run: bash ./cross_build_mingw64.sh static -DLINK_RTLTOOLS_AGAINST_STATIC_LIB=ON\n    - name: build_w64_static_udpsrv\n      run: bash ./cross_build_mingw64.sh static_udpsrv -DLINK_RTLTOOLS_AGAINST_STATIC_LIB=ON -DPROVIDE_UDP_SERVER=ON\n    - name: build_w64_dlldep\n      run: bash ./cross_build_mingw64.sh dlldep\n    - name: build_w64_dlldep_udpsrv\n      run: bash ./cross_build_mingw64.sh dlldep_udpsrv -DPROVIDE_UDP_SERVER=ON\n\n    - name: 'upload w32 static artifact'\n      uses: actions/upload-artifact@v2\n      with:\n        name: rtlsdr-bin-w32_static\n        path: rtlsdr-bin-w32_static/bin/\n    - name: 'upload w32 static_udpsrv artifact'\n      uses: actions/upload-artifact@v2\n      with:\n        name: rtlsdr-bin-w32_static_udpsrv\n        path: rtlsdr-bin-w32_static_udpsrv/bin/\n    - name: 'upload w32 dlldep artifact'\n      uses: actions/upload-artifact@v2\n      with:\n        name: rtlsdr-bin-w32_dlldep\n        path: rtlsdr-bin-w32_dlldep/bin/\n    - name: 'upload w32 dlldep_udpsrv artifact'\n      uses: actions/upload-artifact@v2\n      with:\n        name: rtlsdr-bin-w32_dlldep_udpsrv\n        path: rtlsdr-bin-w32_dlldep_udpsrv/bin/\n\n    - name: 'upload w64 static artifact'\n      uses: actions/upload-artifact@v2\n      with:\n        name: rtlsdr-bin-w64_static\n        path: rtlsdr-bin-w64_static/bin/\n    - name: 'upload w64 static_udpsrv artifact'\n      uses: actions/upload-artifact@v2\n      with:\n        name: rtlsdr-bin-w64_static_udpsrv\n        path: rtlsdr-bin-w64_static_udpsrv/bin/\n    - name: 'upload w64 dlldep artifact'\n      uses: actions/upload-artifact@v2\n      with:\n        name: rtlsdr-bin-w64_dlldep\n        path: rtlsdr-bin-w64_dlldep/bin/\n    - name: 'upload w64 dlldep_udpsrv artifact'\n      uses: actions/upload-artifact@v2\n      with:\n        name: rtlsdr-bin-w64_dlldep_udpsrv\n        path: rtlsdr-bin-w64_dlldep_udpsrv/bin/\n\n"
  },
  {
    "path": ".gitignore",
    "content": "Makefile\nMakefile.in\n.deps\n.libs\n*.o\n*.lo\n*.la\n*.pc\naclocal.m4\nacinclude.m4\naminclude.am\nm4/*.m4\nautom4te.cache\nconfig.h*\nconfig.sub\nconfig.log\nconfig.status\nconfig.guess\nconfigure\ndepcomp\nmissing\nltmain.sh\ninstall-sh\nstamp-h1\nlibtool\nDoxyfile\n\n.tarball-version\n.version\n\n.*.swp\n\ndoc/\n\nsrc/rtl_sdr\nsrc/rtl_tcp\n\nCMakeCache.txt\n*/CMakeFiles\nCMakeFiles\nbuild\n\n**/*.o\n**/*.so*\n**/*.a\nsrc/rtl_adsb\nsrc/rtl_eeprom\nsrc/rtl_fm\nsrc/rtl_ir\nsrc/rtl_power\nsrc/rtl_rpcd\nsrc/rtl_test\n\ndebianize/*.deb\n.cproject\n.project\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: c\ncompiler:\n  - gcc\n  - clang\n\nbefore_install:\n - sudo apt-get update -qq\n - sudo apt-get install -qq libusb-1.0-0-dev\n\nscript: cmake . && make && sudo make install\n"
  },
  {
    "path": "AUTHORS",
    "content": "Steve Markgraf <steve@steve-m.de>\nDimitri Stolnikov <horiz0n@gmx.net>\nHoernchen <la@tfc-server.de>\nKyle Keen <keenerd@gmail.com>\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "# Copyright 2012 OSMOCOM Project\n#\n# This file is part of rtl-sdr\n#\n# GNU Radio is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation; either version 3, or (at your option)\n# any later version.\n#\n# GNU Radio is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with GNU Radio; see the file COPYING.  If not, write to\n# the Free Software Foundation, Inc., 51 Franklin Street,\n# Boston, MA 02110-1301, USA.\n\n\n########################################################################\n# Project setup\n########################################################################\ncmake_minimum_required(VERSION 2.6...3.19)\nproject(rtlsdr C)\n\n# quite old cmake version - probably for compatibility with old OS versions?\n# see https://cmake.org/cmake/help/cmake2.6docs.html\n\n\n#select the release build type by default to get optimization flags\nif(NOT CMAKE_BUILD_TYPE)\n   set(CMAKE_BUILD_TYPE \"Release\")\n   message(STATUS \"Build type not specified: defaulting to release.\")\nendif(NOT CMAKE_BUILD_TYPE)\nset(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING \"\")\n\nlist(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules)\n\nif(NOT LIB_INSTALL_DIR)\n   set(LIB_INSTALL_DIR lib)\nendif()\n\nOPTION(LINK_RTLTOOLS_AGAINST_STATIC_LIB \"Link rtl-tools statically against librtlsdr\" OFF)\n\nOPTION(PROVIDE_UDP_SERVER \"Provide UDP server for tests\" OFF)\n\nOPTION(WITH_RPC \"RPC for non-Windows\" OFF)\n\n# Set the version information here\nset(VERSION_INFO_MAJOR_VERSION 0) # increment major on api compatibility changes\nset(VERSION_INFO_MINOR_VERSION 9) # increment minor on feature-level changes\nset(VERSION_INFO_PATCH_VERSION git) # increment patch for bug fixes and docs\ninclude(Version) # setup version info\n\n########################################################################\n# Version defines to include in library and tools\n########################################################################\n\nconfigure_file(\n    ${CMAKE_CURRENT_SOURCE_DIR}/src/rtl_app_ver.h.in\n    ${CMAKE_CURRENT_BINARY_DIR}/src/rtl_app_ver.h\n    @ONLY )\n\n\nif(PROVIDE_UDP_SERVER)\n    add_definitions(-DWITH_UDP_SERVER)\nendif()\n\n########################################################################\n# Compiler specific setup\n########################################################################\nif(CMAKE_COMPILER_IS_GNUCC AND NOT WIN32)\n    ADD_DEFINITIONS(-Wall)\n    ADD_DEFINITIONS(-Wextra)\n    ADD_DEFINITIONS(-Wno-unused-parameter)\n    ADD_DEFINITIONS(-Wno-unused)\n    ADD_DEFINITIONS(-Wsign-compare)\n    ADD_DEFINITIONS(-Wdeclaration-after-statement)\n    #http://gcc.gnu.org/wiki/Visibility\n    add_definitions(-fvisibility=hidden)\nelseif(MSVC14 OR MSVC14)\n#pthread-w32 issue, timespec is now part of time.h\n    ADD_DEFINITIONS(-D_TIMESPEC_DEFINED)\nendif()\nif (APPLE)\n  set(CMAKE_MACOSX_RPATH ON)\nendif (APPLE)\n\nOPTION(RTL_STATIC_BUILD \"Build rtl-tools static (except RTLSDR.DLL) on MinGW/Win32\" ON)\nif(RTL_STATIC_BUILD)\n    if (WIN32)\n        if(MINGW)\n            # Special MINGW stuff here\n            # see https://cmake.org/pipermail/cmake/2012-September/051970.html\n            # see http://stackoverflow.com/questions/13768515/how-to-do-static-linking-of-libwinpthread-1-dll-in-mingw\n            set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} -static-libgcc -static\")\n            set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++\")\n            set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS \"${CMAKE_SHARED_LIBRARY_LINK_C_FLAGS} -static-libgcc -s\")\n            set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS \"${CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS} -static-libgcc -static-libstdc++ -s\")\n        endif()\n    endif()\nendif()\n\n\n#########################################################################\n# Bug Fix\n#########################################################################\nOPTION(NEED_PTHREADS_WORKARROUND \"PThreads Workarround for timespec\")\nIF (NEED_PTHREADS_WORKARROUND)\n    ADD_DEFINITIONS(-DNEED_PTHREADS_WORKARROUND)\nENDIF()\n\n########################################################################\n# Find build dependencies\n########################################################################\nfind_package(PkgConfig)\nfind_package(LibUSB)\ncmake_policy(SET CMP0075 NEW)\nif(WIN32 AND NOT MINGW)\n    set(THREADS_USE_PTHREADS_WIN32 true)\nendif()\nfind_package(Threads)\n\nif(NOT LIBUSB_FOUND)\n    message(FATAL_ERROR \"LibUSB 1.0 required to compile rtl-sdr\")\nendif()\nif(NOT THREADS_FOUND)\n    message(FATAL_ERROR \"pthreads(-win32) required to compile rtl-sdr\")\nendif()\n########################################################################\n# Setup the include and linker paths\n########################################################################\ninclude_directories(\n    ${PROJECT_SOURCE_DIR}/include\n    ${LIBUSB_INCLUDE_DIR}\n    ${CMAKE_CURRENT_BINARY_DIR}/src\n    ${THREADS_PTHREADS_INCLUDE_DIR}\n)\n\n#link_directories(\n#    ...\n#)\n\n# Set component parameters\n#set(INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include CACHE INTERNAL \"\" FORCE)\n\n########################################################################\n# Create uninstall target\n########################################################################\nif(NOT TARGET uninstall)\n    configure_file(\n        ${PROJECT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in\n        ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake\n        @ONLY\n    )\n\n    add_custom_target(uninstall\n        ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake\n    )\nendif()\n\n########################################################################\n# Install udev rules\n########################################################################\noption(INSTALL_UDEV_RULES \"Install udev rules for RTL-SDR\" OFF)\nif (INSTALL_UDEV_RULES)\n    install (\n        FILES rtl-sdr.rules\n        DESTINATION \"/etc/udev/rules.d\"\n        COMPONENT \"udev\"\n        )\nelse (INSTALL_UDEV_RULES)\n    message (STATUS \"Udev rules not being installed, install them with -DINSTALL_UDEV_RULES=ON\")\nendif (INSTALL_UDEV_RULES)\n\noption(DETACH_KERNEL_DRIVER \"Detach kernel driver if loaded\" OFF)\nif (DETACH_KERNEL_DRIVER)\n    message (STATUS \"Building with kernel driver detaching enabled\")\n    add_definitions(-DDETACH_KERNEL_DRIVER=1)\nelse (DETACH_KERNEL_DRIVER)\n    message (STATUS \"Building with kernel driver detaching disabled, use -DDETACH_KERNEL_DRIVER=ON to enable\")\nendif (DETACH_KERNEL_DRIVER)\n\n########################################################################\n# Add subdirectories\n########################################################################\nadd_subdirectory(include)\nadd_subdirectory(src)\n\n########################################################################\n# Create Pkg Config File\n########################################################################\nFOREACH(inc ${LIBUSB_INCLUDE_DIR})\n    LIST(APPEND RTLSDR_PC_CFLAGS \"-I${inc}\")\nENDFOREACH(inc)\n\nFOREACH(lib ${LIBUSB_LIBRARY_DIRS})\n    LIST(APPEND RTLSDR_PC_LIBS \"-L${lib}\")\nENDFOREACH(lib)\n\n# use space-separation format for the pc file\nSTRING(REPLACE \";\" \" \" RTLSDR_PC_CFLAGS \"${RTLSDR_PC_CFLAGS}\")\nSTRING(REPLACE \";\" \" \" RTLSDR_PC_LIBS \"${RTLSDR_PC_LIBS}\")\n\n# unset these vars to avoid hard-coded paths to cross environment\nIF(CMAKE_CROSSCOMPILING)\n    UNSET(RTLSDR_PC_CFLAGS)\n    UNSET(RTLSDR_PC_LIBS)\nENDIF(CMAKE_CROSSCOMPILING)\n\nset(prefix ${CMAKE_INSTALL_PREFIX})\nset(exec_prefix \\${prefix})\nset(libdir \\${exec_prefix}/${LIB_INSTALL_DIR})\nset(includedir \\${prefix}/include)\n\nCONFIGURE_FILE(\n    ${CMAKE_CURRENT_SOURCE_DIR}/librtlsdr.pc.in\n    ${CMAKE_CURRENT_BINARY_DIR}/librtlsdr.pc\n@ONLY)\n\nINSTALL(\n    FILES ${CMAKE_CURRENT_BINARY_DIR}/librtlsdr.pc\n    DESTINATION ${LIB_INSTALL_DIR}/pkgconfig\n)\n\n########################################################################\n# Print Summary\n########################################################################\nMESSAGE(STATUS \"Building for version: ${VERSION} / ${LIBVER}\")\nMESSAGE(STATUS \"Using install prefix: ${CMAKE_INSTALL_PREFIX}\")\n"
  },
  {
    "path": "COPYING",
    "content": "\t\t    GNU GENERAL PUBLIC LICENSE\n\t\t       Version 2, June 1991\n\n Copyright (C) 1989, 1991 Free Software Foundation, Inc.,\n 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n\t\t\t    Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicense is intended to guarantee your freedom to share and change free\nsoftware--to make sure the software is free for all its users.  This\nGeneral Public License applies to most of the Free Software\nFoundation's software and to any other program whose authors commit to\nusing it.  (Some other Free Software Foundation software is covered by\nthe GNU Lesser General Public License instead.)  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthis service if you wish), that you receive source code or can get it\nif you want it, that you can change the software or use pieces of it\nin new free programs; and that you know you can do these things.\n\n  To protect your rights, we need to make restrictions that forbid\nanyone to deny you these rights or to ask you to surrender the rights.\nThese restrictions translate to certain responsibilities for you if you\ndistribute copies of the software, or if you modify it.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must give the recipients all the rights that\nyou have.  You must make sure that they, too, receive or can get the\nsource code.  And you must show them these terms so they know their\nrights.\n\n  We protect your rights with two steps: (1) copyright the software, and\n(2) offer you this license which gives you legal permission to copy,\ndistribute and/or modify the software.\n\n  Also, for each author's protection and ours, we want to make certain\nthat everyone understands that there is no warranty for this free\nsoftware.  If the software is modified by someone else and passed on, we\nwant its recipients to know that what they have is not the original, so\nthat any problems introduced by others will not reflect on the original\nauthors' reputations.\n\n  Finally, any free program is threatened constantly by software\npatents.  We wish to avoid the danger that redistributors of a free\nprogram will individually obtain patent licenses, in effect making the\nprogram proprietary.  To prevent this, we have made it clear that any\npatent must be licensed for everyone's free use or not licensed at all.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n\t\t    GNU GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License applies to any program or other work which contains\na notice placed by the copyright holder saying it may be distributed\nunder the terms of this General Public License.  The \"Program\", below,\nrefers to any such program or work, and a \"work based on the Program\"\nmeans either the Program or any derivative work under copyright law:\nthat is to say, a work containing the Program or a portion of it,\neither verbatim or with modifications and/or translated into another\nlanguage.  (Hereinafter, translation is included without limitation in\nthe term \"modification\".)  Each licensee is addressed as \"you\".\n\nActivities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning the Program is not restricted, and the output from the Program\nis covered only if its contents constitute a work based on the\nProgram (independent of having been made by running the Program).\nWhether that is true depends on what the Program does.\n\n  1. You may copy and distribute verbatim copies of the Program's\nsource code as you receive it, in any medium, provided that you\nconspicuously and appropriately publish on each copy an appropriate\ncopyright notice and disclaimer of warranty; keep intact all the\nnotices that refer to this License and to the absence of any warranty;\nand give any other recipients of the Program a copy of this License\nalong with the Program.\n\nYou may charge a fee for the physical act of transferring a copy, and\nyou may at your option offer warranty protection in exchange for a fee.\n\n  2. You may modify your copy or copies of the Program or any portion\nof it, thus forming a work based on the Program, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) You must cause the modified files to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    b) You must cause any work that you distribute or publish, that in\n    whole or in part contains or is derived from the Program or any\n    part thereof, to be licensed as a whole at no charge to all third\n    parties under the terms of this License.\n\n    c) If the modified program normally reads commands interactively\n    when run, you must cause it, when started running for such\n    interactive use in the most ordinary way, to print or display an\n    announcement including an appropriate copyright notice and a\n    notice that there is no warranty (or else, saying that you provide\n    a warranty) and that users may redistribute the program under\n    these conditions, and telling the user how to view a copy of this\n    License.  (Exception: if the Program itself is interactive but\n    does not normally print such an announcement, your work based on\n    the Program is not required to print an announcement.)\n\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Program,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Program, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote it.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Program.\n\nIn addition, mere aggregation of another work not based on the Program\nwith the Program (or with a work based on the Program) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may copy and distribute the Program (or a work based on it,\nunder Section 2) in object code or executable form under the terms of\nSections 1 and 2 above provided that you also do one of the following:\n\n    a) Accompany it with the complete corresponding machine-readable\n    source code, which must be distributed under the terms of Sections\n    1 and 2 above on a medium customarily used for software interchange; or,\n\n    b) Accompany it with a written offer, valid for at least three\n    years, to give any third party, for a charge no more than your\n    cost of physically performing source distribution, a complete\n    machine-readable copy of the corresponding source code, to be\n    distributed under the terms of Sections 1 and 2 above on a medium\n    customarily used for software interchange; or,\n\n    c) Accompany it with the information you received as to the offer\n    to distribute corresponding source code.  (This alternative is\n    allowed only for noncommercial distribution and only if you\n    received the program in object code or executable form with such\n    an offer, in accord with Subsection b above.)\n\nThe source code for a work means the preferred form of the work for\nmaking modifications to it.  For an executable work, complete source\ncode means all the source code for all modules it contains, plus any\nassociated interface definition files, plus the scripts used to\ncontrol compilation and installation of the executable.  However, as a\nspecial exception, the source code distributed need not include\nanything that is normally distributed (in either source or binary\nform) with the major components (compiler, kernel, and so on) of the\noperating system on which the executable runs, unless that component\nitself accompanies the executable.\n\nIf distribution of executable or object code is made by offering\naccess to copy from a designated place, then offering equivalent\naccess to copy the source code from the same place counts as\ndistribution of the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\n  4. You may not copy, modify, sublicense, or distribute the Program\nexcept as expressly provided under this License.  Any attempt\notherwise to copy, modify, sublicense or distribute the Program is\nvoid, and will automatically terminate your rights under this License.\nHowever, parties who have received copies, or rights, from you under\nthis License will not have their licenses terminated so long as such\nparties remain in full compliance.\n\n  5. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Program or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Program (or any work based on the\nProgram), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Program or works based on it.\n\n  6. Each time you redistribute the Program (or any work based on the\nProgram), the recipient automatically receives a license from the\noriginal licensor to copy, distribute or modify the Program subject to\nthese terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties to\nthis License.\n\n  7. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Program at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Program by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Program.\n\nIf any portion of this section is held invalid or unenforceable under\nany particular circumstance, the balance of the section is intended to\napply and the section as a whole is intended to apply in other\ncircumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system, which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\n  8. If the distribution and/or use of the Program is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Program under this License\nmay add an explicit geographical distribution limitation excluding\nthose countries, so that distribution is permitted only in or among\ncountries not thus excluded.  In such case, this License incorporates\nthe limitation as if written in the body of this License.\n\n  9. The Free Software Foundation may publish revised and/or new versions\nof the General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Program\nspecifies a version number of this License which applies to it and \"any\nlater version\", you have the option of following the terms and conditions\neither of that version or of any later version published by the Free\nSoftware Foundation.  If the Program does not specify a version number of\nthis License, you may choose any version ever published by the Free Software\nFoundation.\n\n  10. If you wish to incorporate parts of the Program into other free\nprograms whose distribution conditions are different, write to the author\nto ask for permission.  For software which is copyrighted by the Free\nSoftware Foundation, write to the Free Software Foundation; we sometimes\nmake exceptions for this.  Our decision will be guided by the two goals\nof preserving the free status of all derivatives of our free software and\nof promoting the sharing and reuse of software generally.\n\n\t\t\t    NO WARRANTY\n\n  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\nFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\nOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\nPROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\nOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\nTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\nPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\nREPAIR OR CORRECTION.\n\n  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\nREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\nINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\nOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\nTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\nYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\nPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGES.\n\n\t\t     END OF TERMS AND CONDITIONS\n\n\t    How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nAlso add information on how to contact you by electronic and paper mail.\n\nIf the program is interactive, make it output a short notice like this\nwhen it starts in an interactive mode:\n\n    Gnomovision version 69, Copyright (C) year name of author\n    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, the commands you use may\nbe called something other than `show w' and `show c'; they could even be\nmouse-clicks or menu items--whatever suits your program.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the program, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n  `Gnomovision' (which makes passes at compilers) written by James Hacker.\n\n  <signature of Ty Coon>, 1 April 1989\n  Ty Coon, President of Vice\n\nThis General Public License does not permit incorporating your program into\nproprietary programs.  If your program is a subroutine library, you may\nconsider it more useful to permit linking proprietary applications with the\nlibrary.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.\n"
  },
  {
    "path": "Doxyfile.in",
    "content": "# Doxyfile 1.7.4\n\n# This file describes the settings to be used by the documentation system\n# doxygen (www.doxygen.org) for a project.\n#\n# All text after a hash (#) is considered a comment and will be ignored.\n# The format is:\n#       TAG = value [value, ...]\n# For lists items can also be appended using:\n#       TAG += value [value, ...]\n# Values that contain spaces should be placed between quotes (\" \").\n\n#---------------------------------------------------------------------------\n# Project related configuration options\n#---------------------------------------------------------------------------\n\n# This tag specifies the encoding used for all characters in the config file\n# that follow. The default is UTF-8 which is also the encoding used for all\n# text before the first occurrence of this tag. Doxygen uses libiconv (or the\n# iconv built into libc) for the transcoding. See\n# http://www.gnu.org/software/libiconv for the list of possible encodings.\n\nDOXYFILE_ENCODING      = UTF-8\n\n# The PROJECT_NAME tag is a single word (or a sequence of words surrounded\n# by quotes) that should identify the project.\n\nPROJECT_NAME           = librtlsdr\n\n# The PROJECT_NUMBER tag can be used to enter a project or revision number.\n# This could be handy for archiving the generated documentation or\n# if some version control system is used.\n\nPROJECT_NUMBER         = @VERSION@\n\n# Using the PROJECT_BRIEF tag one can provide an optional one line description\n# for a project that appears at the top of each page and should give viewer\n# a quick idea about the purpose of the project. Keep the description short.\n\nPROJECT_BRIEF          = \"RTL-SDR library\"\n\n# With the PROJECT_LOGO tag one can specify an logo or icon that is\n# included in the documentation. The maximum height of the logo should not\n# exceed 55 pixels and the maximum width should not exceed 200 pixels.\n# Doxygen will copy the logo to the output directory.\n\nPROJECT_LOGO           =\n\n# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)\n# base path where the generated documentation will be put.\n# If a relative path is entered, it will be relative to the location\n# where doxygen was started. If left blank the current directory will be used.\n\nOUTPUT_DIRECTORY       = doc\n\n# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create\n# 4096 sub-directories (in 2 levels) under the output directory of each output\n# format and will distribute the generated files over these directories.\n# Enabling this option can be useful when feeding doxygen a huge amount of\n# source files, where putting all generated files in the same directory would\n# otherwise cause performance problems for the file system.\n\nCREATE_SUBDIRS         = NO\n\n# The OUTPUT_LANGUAGE tag is used to specify the language in which all\n# documentation generated by doxygen is written. Doxygen will use this\n# information to generate all constant output in the proper language.\n# The default language is English, other supported languages are:\n# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,\n# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,\n# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English\n# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,\n# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,\n# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.\n\nOUTPUT_LANGUAGE        = English\n\n# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will\n# include brief member descriptions after the members that are listed in\n# the file and class documentation (similar to JavaDoc).\n# Set to NO to disable this.\n\nBRIEF_MEMBER_DESC      = YES\n\n# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend\n# the brief description of a member or function before the detailed description.\n# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the\n# brief descriptions will be completely suppressed.\n\nREPEAT_BRIEF           = YES\n\n# This tag implements a quasi-intelligent brief description abbreviator\n# that is used to form the text in various listings. Each string\n# in this list, if found as the leading text of the brief description, will be\n# stripped from the text and the result after processing the whole list, is\n# used as the annotated text. Otherwise, the brief description is used as-is.\n# If left blank, the following values are used (\"$name\" is automatically\n# replaced with the name of the entity): \"The $name class\" \"The $name widget\"\n# \"The $name file\" \"is\" \"provides\" \"specifies\" \"contains\"\n# \"represents\" \"a\" \"an\" \"the\"\n\nABBREVIATE_BRIEF       =\n\n# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then\n# Doxygen will generate a detailed section even if there is only a brief\n# description.\n\nALWAYS_DETAILED_SEC    = NO\n\n# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all\n# inherited members of a class in the documentation of that class as if those\n# members were ordinary class members. Constructors, destructors and assignment\n# operators of the base classes will not be shown.\n\nINLINE_INHERITED_MEMB  = NO\n\n# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full\n# path before files name in the file list and in the header files. If set\n# to NO the shortest path that makes the file name unique will be used.\n\nFULL_PATH_NAMES        = YES\n\n# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag\n# can be used to strip a user-defined part of the path. Stripping is\n# only done if one of the specified strings matches the left-hand part of\n# the path. The tag can be used to show relative paths in the file list.\n# If left blank the directory from which doxygen is run is used as the\n# path to strip.\n\nSTRIP_FROM_PATH        =\n\n# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of\n# the path mentioned in the documentation of a class, which tells\n# the reader which header file to include in order to use a class.\n# If left blank only the name of the header file containing the class\n# definition is used. Otherwise one should specify the include paths that\n# are normally passed to the compiler using the -I flag.\n\nSTRIP_FROM_INC_PATH    =\n\n# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter\n# (but less readable) file names. This can be useful if your file system\n# doesn't support long names like on DOS, Mac, or CD-ROM.\n\nSHORT_NAMES            = NO\n\n# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen\n# will interpret the first line (until the first dot) of a JavaDoc-style\n# comment as the brief description. If set to NO, the JavaDoc\n# comments will behave just like regular Qt-style comments\n# (thus requiring an explicit @brief command for a brief description.)\n\nJAVADOC_AUTOBRIEF      = NO\n\n# If the QT_AUTOBRIEF tag is set to YES then Doxygen will\n# interpret the first line (until the first dot) of a Qt-style\n# comment as the brief description. If set to NO, the comments\n# will behave just like regular Qt-style comments (thus requiring\n# an explicit \\brief command for a brief description.)\n\nQT_AUTOBRIEF           = NO\n\n# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen\n# treat a multi-line C++ special comment block (i.e. a block of //! or ///\n# comments) as a brief description. This used to be the default behaviour.\n# The new default is to treat a multi-line C++ comment block as a detailed\n# description. Set this tag to YES if you prefer the old behaviour instead.\n\nMULTILINE_CPP_IS_BRIEF = NO\n\n# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented\n# member inherits the documentation from any documented member that it\n# re-implements.\n\nINHERIT_DOCS           = YES\n\n# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce\n# a new page for each member. If set to NO, the documentation of a member will\n# be part of the file/class/namespace that contains it.\n\nSEPARATE_MEMBER_PAGES  = NO\n\n# The TAB_SIZE tag can be used to set the number of spaces in a tab.\n# Doxygen uses this value to replace tabs by spaces in code fragments.\n\nTAB_SIZE               = 8\n\n# This tag can be used to specify a number of aliases that acts\n# as commands in the documentation. An alias has the form \"name=value\".\n# For example adding \"sideeffect=\\par Side Effects:\\n\" will allow you to\n# put the command \\sideeffect (or @sideeffect) in the documentation, which\n# will result in a user-defined paragraph with heading \"Side Effects:\".\n# You can put \\n's in the value part of an alias to insert newlines.\n\nALIASES                =\n\n# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C\n# sources only. Doxygen will then generate output that is more tailored for C.\n# For instance, some of the names that are used will be different. The list\n# of all members will be omitted, etc.\n\nOPTIMIZE_OUTPUT_FOR_C  = YES\n\n# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java\n# sources only. Doxygen will then generate output that is more tailored for\n# Java. For instance, namespaces will be presented as packages, qualified\n# scopes will look different, etc.\n\nOPTIMIZE_OUTPUT_JAVA   = NO\n\n# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran\n# sources only. Doxygen will then generate output that is more tailored for\n# Fortran.\n\nOPTIMIZE_FOR_FORTRAN   = NO\n\n# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL\n# sources. Doxygen will then generate output that is tailored for\n# VHDL.\n\nOPTIMIZE_OUTPUT_VHDL   = NO\n\n# Doxygen selects the parser to use depending on the extension of the files it\n# parses. With this tag you can assign which parser to use for a given extension.\n# Doxygen has a built-in mapping, but you can override or extend it using this\n# tag. The format is ext=language, where ext is a file extension, and language\n# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,\n# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make\n# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C\n# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions\n# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.\n\nEXTENSION_MAPPING      =\n\n# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want\n# to include (a tag file for) the STL sources as input, then you should\n# set this tag to YES in order to let doxygen match functions declarations and\n# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.\n# func(std::string) {}). This also makes the inheritance and collaboration\n# diagrams that involve STL classes more complete and accurate.\n\nBUILTIN_STL_SUPPORT    = NO\n\n# If you use Microsoft's C++/CLI language, you should set this option to YES to\n# enable parsing support.\n\nCPP_CLI_SUPPORT        = NO\n\n# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.\n# Doxygen will parse them like normal C++ but will assume all classes use public\n# instead of private inheritance when no explicit protection keyword is present.\n\nSIP_SUPPORT            = NO\n\n# For Microsoft's IDL there are propget and propput attributes to indicate getter\n# and setter methods for a property. Setting this option to YES (the default)\n# will make doxygen replace the get and set methods by a property in the\n# documentation. This will only work if the methods are indeed getting or\n# setting a simple type. If this is not the case, or you want to show the\n# methods anyway, you should set this option to NO.\n\nIDL_PROPERTY_SUPPORT   = YES\n\n# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC\n# tag is set to YES, then doxygen will reuse the documentation of the first\n# member in the group (if any) for the other members of the group. By default\n# all members of a group must be documented explicitly.\n\nDISTRIBUTE_GROUP_DOC   = NO\n\n# Set the SUBGROUPING tag to YES (the default) to allow class member groups of\n# the same type (for instance a group of public functions) to be put as a\n# subgroup of that type (e.g. under the Public Functions section). Set it to\n# NO to prevent subgrouping. Alternatively, this can be done per class using\n# the \\nosubgrouping command.\n\nSUBGROUPING            = YES\n\n# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and\n# unions are shown inside the group in which they are included (e.g. using\n# @ingroup) instead of on a separate page (for HTML and Man pages) or\n# section (for LaTeX and RTF).\n\nINLINE_GROUPED_CLASSES = NO\n\n# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum\n# is documented as struct, union, or enum with the name of the typedef. So\n# typedef struct TypeS {} TypeT, will appear in the documentation as a struct\n# with name TypeT. When disabled the typedef will appear as a member of a file,\n# namespace, or class. And the struct will be named TypeS. This can typically\n# be useful for C code in case the coding convention dictates that all compound\n# types are typedef'ed and only the typedef is referenced, never the tag name.\n\nTYPEDEF_HIDES_STRUCT   = NO\n\n# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to\n# determine which symbols to keep in memory and which to flush to disk.\n# When the cache is full, less often used symbols will be written to disk.\n# For small to medium size projects (<1000 input files) the default value is\n# probably good enough. For larger projects a too small cache size can cause\n# doxygen to be busy swapping symbols to and from disk most of the time\n# causing a significant performance penalty.\n# If the system has enough physical memory increasing the cache will improve the\n# performance by keeping more symbols in memory. Note that the value works on\n# a logarithmic scale so increasing the size by one will roughly double the\n# memory usage. The cache size is given by this formula:\n# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,\n# corresponding to a cache size of 2^16 = 65536 symbols\n\nSYMBOL_CACHE_SIZE      = 0\n\n#---------------------------------------------------------------------------\n# Build related configuration options\n#---------------------------------------------------------------------------\n\n# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in\n# documentation are documented, even if no documentation was available.\n# Private class members and static file members will be hidden unless\n# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES\n\nEXTRACT_ALL            = NO\n\n# If the EXTRACT_PRIVATE tag is set to YES all private members of a class\n# will be included in the documentation.\n\nEXTRACT_PRIVATE        = NO\n\n# If the EXTRACT_STATIC tag is set to YES all static members of a file\n# will be included in the documentation.\n\nEXTRACT_STATIC         = YES\n\n# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)\n# defined locally in source files will be included in the documentation.\n# If set to NO only classes defined in header files are included.\n\nEXTRACT_LOCAL_CLASSES  = YES\n\n# This flag is only useful for Objective-C code. When set to YES local\n# methods, which are defined in the implementation section but not in\n# the interface are included in the documentation.\n# If set to NO (the default) only methods in the interface are included.\n\nEXTRACT_LOCAL_METHODS  = NO\n\n# If this flag is set to YES, the members of anonymous namespaces will be\n# extracted and appear in the documentation as a namespace called\n# 'anonymous_namespace{file}', where file will be replaced with the base\n# name of the file that contains the anonymous namespace. By default\n# anonymous namespaces are hidden.\n\nEXTRACT_ANON_NSPACES   = NO\n\n# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all\n# undocumented members of documented classes, files or namespaces.\n# If set to NO (the default) these members will be included in the\n# various overviews, but no documentation section is generated.\n# This option has no effect if EXTRACT_ALL is enabled.\n\nHIDE_UNDOC_MEMBERS     = NO\n\n# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all\n# undocumented classes that are normally visible in the class hierarchy.\n# If set to NO (the default) these classes will be included in the various\n# overviews. This option has no effect if EXTRACT_ALL is enabled.\n\nHIDE_UNDOC_CLASSES     = NO\n\n# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all\n# friend (class|struct|union) declarations.\n# If set to NO (the default) these declarations will be included in the\n# documentation.\n\nHIDE_FRIEND_COMPOUNDS  = NO\n\n# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any\n# documentation blocks found inside the body of a function.\n# If set to NO (the default) these blocks will be appended to the\n# function's detailed documentation block.\n\nHIDE_IN_BODY_DOCS      = NO\n\n# The INTERNAL_DOCS tag determines if documentation\n# that is typed after a \\internal command is included. If the tag is set\n# to NO (the default) then the documentation will be excluded.\n# Set it to YES to include the internal documentation.\n\nINTERNAL_DOCS          = NO\n\n# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate\n# file names in lower-case letters. If set to YES upper-case letters are also\n# allowed. This is useful if you have classes or files whose names only differ\n# in case and if your file system supports case sensitive file names. Windows\n# and Mac users are advised to set this option to NO.\n\nCASE_SENSE_NAMES       = YES\n\n# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen\n# will show members with their full class and namespace scopes in the\n# documentation. If set to YES the scope will be hidden.\n\nHIDE_SCOPE_NAMES       = NO\n\n# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen\n# will put a list of the files that are included by a file in the documentation\n# of that file.\n\nSHOW_INCLUDE_FILES     = YES\n\n# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen\n# will list include files with double quotes in the documentation\n# rather than with sharp brackets.\n\nFORCE_LOCAL_INCLUDES   = NO\n\n# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]\n# is inserted in the documentation for inline members.\n\nINLINE_INFO            = YES\n\n# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen\n# will sort the (detailed) documentation of file and class members\n# alphabetically by member name. If set to NO the members will appear in\n# declaration order.\n\nSORT_MEMBER_DOCS       = YES\n\n# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the\n# brief documentation of file, namespace and class members alphabetically\n# by member name. If set to NO (the default) the members will appear in\n# declaration order.\n\nSORT_BRIEF_DOCS        = NO\n\n# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen\n# will sort the (brief and detailed) documentation of class members so that\n# constructors and destructors are listed first. If set to NO (the default)\n# the constructors will appear in the respective orders defined by\n# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.\n# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO\n# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.\n\nSORT_MEMBERS_CTORS_1ST = NO\n\n# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the\n# hierarchy of group names into alphabetical order. If set to NO (the default)\n# the group names will appear in their defined order.\n\nSORT_GROUP_NAMES       = NO\n\n# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be\n# sorted by fully-qualified names, including namespaces. If set to\n# NO (the default), the class list will be sorted only by class name,\n# not including the namespace part.\n# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.\n# Note: This option applies only to the class list, not to the\n# alphabetical list.\n\nSORT_BY_SCOPE_NAME     = NO\n\n# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to\n# do proper type resolution of all parameters of a function it will reject a\n# match between the prototype and the implementation of a member function even\n# if there is only one candidate or it is obvious which candidate to choose\n# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen\n# will still accept a match between prototype and implementation in such cases.\n\nSTRICT_PROTO_MATCHING  = NO\n\n# The GENERATE_TODOLIST tag can be used to enable (YES) or\n# disable (NO) the todo list. This list is created by putting \\todo\n# commands in the documentation.\n\nGENERATE_TODOLIST      = YES\n\n# The GENERATE_TESTLIST tag can be used to enable (YES) or\n# disable (NO) the test list. This list is created by putting \\test\n# commands in the documentation.\n\nGENERATE_TESTLIST      = YES\n\n# The GENERATE_BUGLIST tag can be used to enable (YES) or\n# disable (NO) the bug list. This list is created by putting \\bug\n# commands in the documentation.\n\nGENERATE_BUGLIST       = YES\n\n# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or\n# disable (NO) the deprecated list. This list is created by putting\n# \\deprecated commands in the documentation.\n\nGENERATE_DEPRECATEDLIST= YES\n\n# The ENABLED_SECTIONS tag can be used to enable conditional\n# documentation sections, marked by \\if sectionname ... \\endif.\n\nENABLED_SECTIONS       =\n\n# The MAX_INITIALIZER_LINES tag determines the maximum number of lines\n# the initial value of a variable or macro consists of for it to appear in\n# the documentation. If the initializer consists of more lines than specified\n# here it will be hidden. Use a value of 0 to hide initializers completely.\n# The appearance of the initializer of individual variables and macros in the\n# documentation can be controlled using \\showinitializer or \\hideinitializer\n# command in the documentation regardless of this setting.\n\nMAX_INITIALIZER_LINES  = 30\n\n# Set the SHOW_USED_FILES tag to NO to disable the list of files generated\n# at the bottom of the documentation of classes and structs. If set to YES the\n# list will mention the files that were used to generate the documentation.\n\nSHOW_USED_FILES        = YES\n\n# If the sources in your project are distributed over multiple directories\n# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy\n# in the documentation. The default is NO.\n\nSHOW_DIRECTORIES       = NO\n\n# Set the SHOW_FILES tag to NO to disable the generation of the Files page.\n# This will remove the Files entry from the Quick Index and from the\n# Folder Tree View (if specified). The default is YES.\n\nSHOW_FILES             = YES\n\n# Set the SHOW_NAMESPACES tag to NO to disable the generation of the\n# Namespaces page.\n# This will remove the Namespaces entry from the Quick Index\n# and from the Folder Tree View (if specified). The default is YES.\n\nSHOW_NAMESPACES        = YES\n\n# The FILE_VERSION_FILTER tag can be used to specify a program or script that\n# doxygen should invoke to get the current version for each file (typically from\n# the version control system). Doxygen will invoke the program by executing (via\n# popen()) the command <command> <input-file>, where <command> is the value of\n# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file\n# provided by doxygen. Whatever the program writes to standard output\n# is used as the file version. See the manual for examples.\n\nFILE_VERSION_FILTER    =\n\n# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed\n# by doxygen. The layout file controls the global structure of the generated\n# output files in an output format independent way. The create the layout file\n# that represents doxygen's defaults, run doxygen with the -l option.\n# You can optionally specify a file name after the option, if omitted\n# DoxygenLayout.xml will be used as the name of the layout file.\n\nLAYOUT_FILE            =\n\n#---------------------------------------------------------------------------\n# configuration options related to warning and progress messages\n#---------------------------------------------------------------------------\n\n# The QUIET tag can be used to turn on/off the messages that are generated\n# by doxygen. Possible values are YES and NO. If left blank NO is used.\n\nQUIET                  = NO\n\n# The WARNINGS tag can be used to turn on/off the warning messages that are\n# generated by doxygen. Possible values are YES and NO. If left blank\n# NO is used.\n\nWARNINGS               = YES\n\n# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings\n# for undocumented members. If EXTRACT_ALL is set to YES then this flag will\n# automatically be disabled.\n\nWARN_IF_UNDOCUMENTED   = YES\n\n# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for\n# potential errors in the documentation, such as not documenting some\n# parameters in a documented function, or documenting parameters that\n# don't exist or using markup commands wrongly.\n\nWARN_IF_DOC_ERROR      = YES\n\n# The WARN_NO_PARAMDOC option can be enabled to get warnings for\n# functions that are documented, but have no documentation for their parameters\n# or return value. If set to NO (the default) doxygen will only warn about\n# wrong or incomplete parameter documentation, but not about the absence of\n# documentation.\n\nWARN_NO_PARAMDOC       = NO\n\n# The WARN_FORMAT tag determines the format of the warning messages that\n# doxygen can produce. The string should contain the $file, $line, and $text\n# tags, which will be replaced by the file and line number from which the\n# warning originated and the warning text. Optionally the format may contain\n# $version, which will be replaced by the version of the file (if it could\n# be obtained via FILE_VERSION_FILTER)\n\nWARN_FORMAT            = \"$file:$line: $text\"\n\n# The WARN_LOGFILE tag can be used to specify a file to which warning\n# and error messages should be written. If left blank the output is written\n# to stderr.\n\nWARN_LOGFILE           =\n\n#---------------------------------------------------------------------------\n# configuration options related to the input files\n#---------------------------------------------------------------------------\n\n# The INPUT tag can be used to specify the files and/or directories that contain\n# documented source files. You may enter file names like \"myfile.cpp\" or\n# directories like \"/usr/src/myproject\". Separate the files or directories\n# with spaces.\n\nINPUT                  = include src\n\n# This tag can be used to specify the character encoding of the source files\n# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is\n# also the default input encoding. Doxygen uses libiconv (or the iconv built\n# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for\n# the list of possible encodings.\n\nINPUT_ENCODING         = UTF-8\n\n# If the value of the INPUT tag contains directories, you can use the\n# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp\n# and *.h) to filter out the source-files in the directories. If left\n# blank the following patterns are tested:\n# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh\n# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py\n# *.f90 *.f *.for *.vhd *.vhdl\n\nFILE_PATTERNS          =\n\n# The RECURSIVE tag can be used to turn specify whether or not subdirectories\n# should be searched for input files as well. Possible values are YES and NO.\n# If left blank NO is used.\n\nRECURSIVE              = YES\n\n# The EXCLUDE tag can be used to specify files and/or directories that should\n# excluded from the INPUT source files. This way you can easily exclude a\n# subdirectory from a directory tree whose root is specified with the INPUT tag.\n\nEXCLUDE                =\n\n# The EXCLUDE_SYMLINKS tag can be used select whether or not files or\n# directories that are symbolic links (a Unix file system feature) are excluded\n# from the input.\n\nEXCLUDE_SYMLINKS       = NO\n\n# If the value of the INPUT tag contains directories, you can use the\n# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude\n# certain files from those directories. Note that the wildcards are matched\n# against the file with absolute path, so to exclude all test directories\n# for example use the pattern */test/*\n\nEXCLUDE_PATTERNS       =\n\n# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names\n# (namespaces, classes, functions, etc.) that should be excluded from the\n# output. The symbol name can be a fully qualified name, a word, or if the\n# wildcard * is used, a substring. Examples: ANamespace, AClass,\n# AClass::ANamespace, ANamespace::*Test\n\nEXCLUDE_SYMBOLS        =\n\n# The EXAMPLE_PATH tag can be used to specify one or more files or\n# directories that contain example code fragments that are included (see\n# the \\include command).\n\nEXAMPLE_PATH           =\n\n# If the value of the EXAMPLE_PATH tag contains directories, you can use the\n# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp\n# and *.h) to filter out the source-files in the directories. If left\n# blank all files are included.\n\nEXAMPLE_PATTERNS       =\n\n# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be\n# searched for input files to be used with the \\include or \\dontinclude\n# commands irrespective of the value of the RECURSIVE tag.\n# Possible values are YES and NO. If left blank NO is used.\n\nEXAMPLE_RECURSIVE      = NO\n\n# The IMAGE_PATH tag can be used to specify one or more files or\n# directories that contain image that are included in the documentation (see\n# the \\image command).\n\nIMAGE_PATH             = images/\n\n# The INPUT_FILTER tag can be used to specify a program that doxygen should\n# invoke to filter for each input file. Doxygen will invoke the filter program\n# by executing (via popen()) the command <filter> <input-file>, where <filter>\n# is the value of the INPUT_FILTER tag, and <input-file> is the name of an\n# input file. Doxygen will then use the output that the filter program writes\n# to standard output.\n# If FILTER_PATTERNS is specified, this tag will be\n# ignored.\n\nINPUT_FILTER           =\n\n# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern\n# basis.\n# Doxygen will compare the file name with each pattern and apply the\n# filter if there is a match.\n# The filters are a list of the form:\n# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further\n# info on how filters are used. If FILTER_PATTERNS is empty or if\n# non of the patterns match the file name, INPUT_FILTER is applied.\n\nFILTER_PATTERNS        =\n\n# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using\n# INPUT_FILTER) will be used to filter the input files when producing source\n# files to browse (i.e. when SOURCE_BROWSER is set to YES).\n\nFILTER_SOURCE_FILES    = NO\n\n# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file\n# pattern. A pattern will override the setting for FILTER_PATTERN (if any)\n# and it is also possible to disable source filtering for a specific pattern\n# using *.ext= (so without naming a filter). This option only has effect when\n# FILTER_SOURCE_FILES is enabled.\n\nFILTER_SOURCE_PATTERNS =\n\n#---------------------------------------------------------------------------\n# configuration options related to source browsing\n#---------------------------------------------------------------------------\n\n# If the SOURCE_BROWSER tag is set to YES then a list of source files will\n# be generated. Documented entities will be cross-referenced with these sources.\n# Note: To get rid of all source code in the generated output, make sure also\n# VERBATIM_HEADERS is set to NO.\n\nSOURCE_BROWSER         = NO\n\n# Setting the INLINE_SOURCES tag to YES will include the body\n# of functions and classes directly in the documentation.\n\nINLINE_SOURCES         = NO\n\n# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct\n# doxygen to hide any special comment blocks from generated source code\n# fragments. Normal C and C++ comments will always remain visible.\n\nSTRIP_CODE_COMMENTS    = YES\n\n# If the REFERENCED_BY_RELATION tag is set to YES\n# then for each documented function all documented\n# functions referencing it will be listed.\n\nREFERENCED_BY_RELATION = YES\n\n# If the REFERENCES_RELATION tag is set to YES\n# then for each documented function all documented entities\n# called/used by that function will be listed.\n\nREFERENCES_RELATION    = YES\n\n# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)\n# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from\n# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will\n# link to the source code.\n# Otherwise they will link to the documentation.\n\nREFERENCES_LINK_SOURCE = YES\n\n# If the USE_HTAGS tag is set to YES then the references to source code\n# will point to the HTML generated by the htags(1) tool instead of doxygen\n# built-in source browser. The htags tool is part of GNU's global source\n# tagging system (see http://www.gnu.org/software/global/global.html). You\n# will need version 4.8.6 or higher.\n\nUSE_HTAGS              = NO\n\n# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen\n# will generate a verbatim copy of the header file for each class for\n# which an include is specified. Set to NO to disable this.\n\nVERBATIM_HEADERS       = YES\n\n#---------------------------------------------------------------------------\n# configuration options related to the alphabetical class index\n#---------------------------------------------------------------------------\n\n# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index\n# of all compounds will be generated. Enable this if the project\n# contains a lot of classes, structs, unions or interfaces.\n\nALPHABETICAL_INDEX     = NO\n\n# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then\n# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns\n# in which this list will be split (can be a number in the range [1..20])\n\nCOLS_IN_ALPHA_INDEX    = 5\n\n# In case all classes in a project start with a common prefix, all\n# classes will be put under the same header in the alphabetical index.\n# The IGNORE_PREFIX tag can be used to specify one or more prefixes that\n# should be ignored while generating the index headers.\n\nIGNORE_PREFIX          =\n\n#---------------------------------------------------------------------------\n# configuration options related to the HTML output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_HTML tag is set to YES (the default) Doxygen will\n# generate HTML output.\n\nGENERATE_HTML          = YES\n\n# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.\n# If a relative path is entered the value of OUTPUT_DIRECTORY will be\n# put in front of it. If left blank `html' will be used as the default path.\n\nHTML_OUTPUT            = html\n\n# The HTML_FILE_EXTENSION tag can be used to specify the file extension for\n# each generated HTML page (for example: .htm,.php,.asp). If it is left blank\n# doxygen will generate files with .html extension.\n\nHTML_FILE_EXTENSION    = .html\n\n# The HTML_HEADER tag can be used to specify a personal HTML header for\n# each generated HTML page. If it is left blank doxygen will generate a\n# standard header. Note that when using a custom header you are responsible\n# for the proper inclusion of any scripts and style sheets that doxygen\n# needs, which is dependent on the configuration options used.\n# It is adviced to generate a default header using \"doxygen -w html\n# header.html footer.html stylesheet.css YourConfigFile\" and then modify\n# that header. Note that the header is subject to change so you typically\n# have to redo this when upgrading to a newer version of doxygen or when changing the value of configuration settings such as GENERATE_TREEVIEW!\n\nHTML_HEADER            =\n\n# The HTML_FOOTER tag can be used to specify a personal HTML footer for\n# each generated HTML page. If it is left blank doxygen will generate a\n# standard footer.\n\nHTML_FOOTER            =\n\n# The HTML_STYLESHEET tag can be used to specify a user-defined cascading\n# style sheet that is used by each HTML page. It can be used to\n# fine-tune the look of the HTML output. If the tag is left blank doxygen\n# will generate a default style sheet. Note that doxygen will try to copy\n# the style sheet file to the HTML output directory, so don't put your own\n# stylesheet in the HTML output directory as well, or it will be erased!\n\nHTML_STYLESHEET        =\n\n# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or\n# other source files which should be copied to the HTML output directory. Note\n# that these files will be copied to the base HTML output directory. Use the\n# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these\n# files. In the HTML_STYLESHEET file, use the file name only. Also note that\n# the files will be copied as-is; there are no commands or markers available.\n\nHTML_EXTRA_FILES       =\n\n# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.\n# Doxygen will adjust the colors in the stylesheet and background images\n# according to this color. Hue is specified as an angle on a colorwheel,\n# see http://en.wikipedia.org/wiki/Hue for more information.\n# For instance the value 0 represents red, 60 is yellow, 120 is green,\n# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.\n# The allowed range is 0 to 359.\n\nHTML_COLORSTYLE_HUE    = 220\n\n# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of\n# the colors in the HTML output. For a value of 0 the output will use\n# grayscales only. A value of 255 will produce the most vivid colors.\n\nHTML_COLORSTYLE_SAT    = 100\n\n# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to\n# the luminance component of the colors in the HTML output. Values below\n# 100 gradually make the output lighter, whereas values above 100 make\n# the output darker. The value divided by 100 is the actual gamma applied,\n# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,\n# and 100 does not change the gamma.\n\nHTML_COLORSTYLE_GAMMA  = 80\n\n# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML\n# page will contain the date and time when the page was generated. Setting\n# this to NO can help when comparing the output of multiple runs.\n\nHTML_TIMESTAMP         = YES\n\n# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,\n# files or namespaces will be aligned in HTML using tables. If set to\n# NO a bullet list will be used.\n\nHTML_ALIGN_MEMBERS     = YES\n\n# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML\n# documentation will contain sections that can be hidden and shown after the\n# page has loaded. For this to work a browser that supports\n# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox\n# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).\n\nHTML_DYNAMIC_SECTIONS  = NO\n\n# If the GENERATE_DOCSET tag is set to YES, additional index files\n# will be generated that can be used as input for Apple's Xcode 3\n# integrated development environment, introduced with OSX 10.5 (Leopard).\n# To create a documentation set, doxygen will generate a Makefile in the\n# HTML output directory. Running make will produce the docset in that\n# directory and running \"make install\" will install the docset in\n# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find\n# it at startup.\n# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html\n# for more information.\n\nGENERATE_DOCSET        = NO\n\n# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the\n# feed. A documentation feed provides an umbrella under which multiple\n# documentation sets from a single provider (such as a company or product suite)\n# can be grouped.\n\nDOCSET_FEEDNAME        = \"Doxygen generated docs\"\n\n# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that\n# should uniquely identify the documentation set bundle. This should be a\n# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen\n# will append .docset to the name.\n\nDOCSET_BUNDLE_ID       = org.doxygen.Project\n\n# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify\n# the documentation publisher. This should be a reverse domain-name style\n# string, e.g. com.mycompany.MyDocSet.documentation.\n\nDOCSET_PUBLISHER_ID    = org.doxygen.Publisher\n\n# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.\n\nDOCSET_PUBLISHER_NAME  = Publisher\n\n# If the GENERATE_HTMLHELP tag is set to YES, additional index files\n# will be generated that can be used as input for tools like the\n# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)\n# of the generated HTML documentation.\n\nGENERATE_HTMLHELP      = NO\n\n# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can\n# be used to specify the file name of the resulting .chm file. You\n# can add a path in front of the file if the result should not be\n# written to the html output directory.\n\nCHM_FILE               =\n\n# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can\n# be used to specify the location (absolute path including file name) of\n# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run\n# the HTML help compiler on the generated index.hhp.\n\nHHC_LOCATION           =\n\n# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag\n# controls if a separate .chi index file is generated (YES) or that\n# it should be included in the master .chm file (NO).\n\nGENERATE_CHI           = NO\n\n# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING\n# is used to encode HtmlHelp index (hhk), content (hhc) and project file\n# content.\n\nCHM_INDEX_ENCODING     =\n\n# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag\n# controls whether a binary table of contents is generated (YES) or a\n# normal table of contents (NO) in the .chm file.\n\nBINARY_TOC             = NO\n\n# The TOC_EXPAND flag can be set to YES to add extra items for group members\n# to the contents of the HTML help documentation and to the tree view.\n\nTOC_EXPAND             = NO\n\n# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and\n# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated\n# that can be used as input for Qt's qhelpgenerator to generate a\n# Qt Compressed Help (.qch) of the generated HTML documentation.\n\nGENERATE_QHP           = NO\n\n# If the QHG_LOCATION tag is specified, the QCH_FILE tag can\n# be used to specify the file name of the resulting .qch file.\n# The path specified is relative to the HTML output folder.\n\nQCH_FILE               =\n\n# The QHP_NAMESPACE tag specifies the namespace to use when generating\n# Qt Help Project output. For more information please see\n# http://doc.trolltech.com/qthelpproject.html#namespace\n\nQHP_NAMESPACE          = org.doxygen.Project\n\n# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating\n# Qt Help Project output. For more information please see\n# http://doc.trolltech.com/qthelpproject.html#virtual-folders\n\nQHP_VIRTUAL_FOLDER     = doc\n\n# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to\n# add. For more information please see\n# http://doc.trolltech.com/qthelpproject.html#custom-filters\n\nQHP_CUST_FILTER_NAME   =\n\n# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the\n# custom filter to add. For more information please see\n# <a href=\"http://doc.trolltech.com/qthelpproject.html#custom-filters\">\n# Qt Help Project / Custom Filters</a>.\n\nQHP_CUST_FILTER_ATTRS  =\n\n# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this\n# project's\n# filter section matches.\n# <a href=\"http://doc.trolltech.com/qthelpproject.html#filter-attributes\">\n# Qt Help Project / Filter Attributes</a>.\n\nQHP_SECT_FILTER_ATTRS  =\n\n# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can\n# be used to specify the location of Qt's qhelpgenerator.\n# If non-empty doxygen will try to run qhelpgenerator on the generated\n# .qhp file.\n\nQHG_LOCATION           =\n\n# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files\n#  will be generated, which together with the HTML files, form an Eclipse help\n# plugin. To install this plugin and make it available under the help contents\n# menu in Eclipse, the contents of the directory containing the HTML and XML\n# files needs to be copied into the plugins directory of eclipse. The name of\n# the directory within the plugins directory should be the same as\n# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before\n# the help appears.\n\nGENERATE_ECLIPSEHELP   = NO\n\n# A unique identifier for the eclipse help plugin. When installing the plugin\n# the directory name containing the HTML and XML files should also have\n# this name.\n\nECLIPSE_DOC_ID         = org.doxygen.Project\n\n# The DISABLE_INDEX tag can be used to turn on/off the condensed index at\n# top of each HTML page. The value NO (the default) enables the index and\n# the value YES disables it.\n\nDISABLE_INDEX          = NO\n\n# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values\n# (range [0,1..20]) that doxygen will group on one line in the generated HTML\n# documentation. Note that a value of 0 will completely suppress the enum\n# values from appearing in the overview section.\n\nENUM_VALUES_PER_LINE   = 4\n\n# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index\n# structure should be generated to display hierarchical information.\n# If the tag value is set to YES, a side panel will be generated\n# containing a tree-like index structure (just like the one that\n# is generated for HTML Help). For this to work a browser that supports\n# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).\n# Windows users are probably better off using the HTML help feature.\n\nGENERATE_TREEVIEW      = YES\n\n# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,\n# and Class Hierarchy pages using a tree view instead of an ordered list.\n\nUSE_INLINE_TREES       = NO\n\n# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be\n# used to set the initial width (in pixels) of the frame in which the tree\n# is shown.\n\nTREEVIEW_WIDTH         = 250\n\n# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open\n# links to external symbols imported via tag files in a separate window.\n\nEXT_LINKS_IN_WINDOW    = NO\n\n# Use this tag to change the font size of Latex formulas included\n# as images in the HTML documentation. The default is 10. Note that\n# when you change the font size after a successful doxygen run you need\n# to manually remove any form_*.png images from the HTML output directory\n# to force them to be regenerated.\n\nFORMULA_FONTSIZE       = 10\n\n# Use the FORMULA_TRANPARENT tag to determine whether or not the images\n# generated for formulas are transparent PNGs. Transparent PNGs are\n# not supported properly for IE 6.0, but are supported on all modern browsers.\n# Note that when changing this option you need to delete any form_*.png files\n# in the HTML output before the changes have effect.\n\nFORMULA_TRANSPARENT    = YES\n\n# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax\n# (see http://www.mathjax.org) which uses client side Javascript for the\n# rendering instead of using prerendered bitmaps. Use this if you do not\n# have LaTeX installed or if you want to formulas look prettier in the HTML\n# output. When enabled you also need to install MathJax separately and\n# configure the path to it using the MATHJAX_RELPATH option.\n\nUSE_MATHJAX            = NO\n\n# When MathJax is enabled you need to specify the location relative to the\n# HTML output directory using the MATHJAX_RELPATH option. The destination\n# directory should contain the MathJax.js script. For instance, if the mathjax\n# directory is located at the same level as the HTML output directory, then\n# MATHJAX_RELPATH should be ../mathjax. The default value points to the\n# mathjax.org site, so you can quickly see the result without installing\n# MathJax, but it is strongly recommended to install a local copy of MathJax\n# before deployment.\n\nMATHJAX_RELPATH        = http://www.mathjax.org/mathjax\n\n# When the SEARCHENGINE tag is enabled doxygen will generate a search box\n# for the HTML output. The underlying search engine uses javascript\n# and DHTML and should work on any modern browser. Note that when using\n# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets\n# (GENERATE_DOCSET) there is already a search function so this one should\n# typically be disabled. For large projects the javascript based search engine\n# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.\n\nSEARCHENGINE           = NO\n\n# When the SERVER_BASED_SEARCH tag is enabled the search engine will be\n# implemented using a PHP enabled web server instead of at the web client\n# using Javascript. Doxygen will generate the search PHP script and index\n# file to put on the web server. The advantage of the server\n# based approach is that it scales better to large projects and allows\n# full text search. The disadvantages are that it is more difficult to setup\n# and does not have live searching capabilities.\n\nSERVER_BASED_SEARCH    = NO\n\n#---------------------------------------------------------------------------\n# configuration options related to the LaTeX output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will\n# generate Latex output.\n\nGENERATE_LATEX         = YES\n\n# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.\n# If a relative path is entered the value of OUTPUT_DIRECTORY will be\n# put in front of it. If left blank `latex' will be used as the default path.\n\nLATEX_OUTPUT           = latex\n\n# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be\n# invoked. If left blank `latex' will be used as the default command name.\n# Note that when enabling USE_PDFLATEX this option is only used for\n# generating bitmaps for formulas in the HTML output, but not in the\n# Makefile that is written to the output directory.\n\nLATEX_CMD_NAME         = latex\n\n# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to\n# generate index for LaTeX. If left blank `makeindex' will be used as the\n# default command name.\n\nMAKEINDEX_CMD_NAME     = makeindex\n\n# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact\n# LaTeX documents. This may be useful for small projects and may help to\n# save some trees in general.\n\nCOMPACT_LATEX          = NO\n\n# The PAPER_TYPE tag can be used to set the paper type that is used\n# by the printer. Possible values are: a4, letter, legal and\n# executive. If left blank a4wide will be used.\n\nPAPER_TYPE             = a4wide\n\n# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX\n# packages that should be included in the LaTeX output.\n\nEXTRA_PACKAGES         =\n\n# The LATEX_HEADER tag can be used to specify a personal LaTeX header for\n# the generated latex document. The header should contain everything until\n# the first chapter. If it is left blank doxygen will generate a\n# standard header. Notice: only use this tag if you know what you are doing!\n\nLATEX_HEADER           =\n\n# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for\n# the generated latex document. The footer should contain everything after\n# the last chapter. If it is left blank doxygen will generate a\n# standard footer. Notice: only use this tag if you know what you are doing!\n\nLATEX_FOOTER           =\n\n# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated\n# is prepared for conversion to pdf (using ps2pdf). The pdf file will\n# contain links (just like the HTML output) instead of page references\n# This makes the output suitable for online browsing using a pdf viewer.\n\nPDF_HYPERLINKS         = NO\n\n# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of\n# plain latex in the generated Makefile. Set this option to YES to get a\n# higher quality PDF documentation.\n\nUSE_PDFLATEX           = NO\n\n# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\\\batchmode.\n# command to the generated LaTeX files. This will instruct LaTeX to keep\n# running if errors occur, instead of asking the user for help.\n# This option is also used when generating formulas in HTML.\n\nLATEX_BATCHMODE        = NO\n\n# If LATEX_HIDE_INDICES is set to YES then doxygen will not\n# include the index chapters (such as File Index, Compound Index, etc.)\n# in the output.\n\nLATEX_HIDE_INDICES     = NO\n\n# If LATEX_SOURCE_CODE is set to YES then doxygen will include\n# source code with syntax highlighting in the LaTeX output.\n# Note that which sources are shown also depends on other settings\n# such as SOURCE_BROWSER.\n\nLATEX_SOURCE_CODE      = NO\n\n#---------------------------------------------------------------------------\n# configuration options related to the RTF output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output\n# The RTF output is optimized for Word 97 and may not look very pretty with\n# other RTF readers or editors.\n\nGENERATE_RTF           = NO\n\n# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.\n# If a relative path is entered the value of OUTPUT_DIRECTORY will be\n# put in front of it. If left blank `rtf' will be used as the default path.\n\nRTF_OUTPUT             = rtf\n\n# If the COMPACT_RTF tag is set to YES Doxygen generates more compact\n# RTF documents. This may be useful for small projects and may help to\n# save some trees in general.\n\nCOMPACT_RTF            = NO\n\n# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated\n# will contain hyperlink fields. The RTF file will\n# contain links (just like the HTML output) instead of page references.\n# This makes the output suitable for online browsing using WORD or other\n# programs which support those fields.\n# Note: wordpad (write) and others do not support links.\n\nRTF_HYPERLINKS         = NO\n\n# Load stylesheet definitions from file. Syntax is similar to doxygen's\n# config file, i.e. a series of assignments. You only have to provide\n# replacements, missing definitions are set to their default value.\n\nRTF_STYLESHEET_FILE    =\n\n# Set optional variables used in the generation of an rtf document.\n# Syntax is similar to doxygen's config file.\n\nRTF_EXTENSIONS_FILE    =\n\n#---------------------------------------------------------------------------\n# configuration options related to the man page output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_MAN tag is set to YES (the default) Doxygen will\n# generate man pages\n\nGENERATE_MAN           = NO\n\n# The MAN_OUTPUT tag is used to specify where the man pages will be put.\n# If a relative path is entered the value of OUTPUT_DIRECTORY will be\n# put in front of it. If left blank `man' will be used as the default path.\n\nMAN_OUTPUT             = man\n\n# The MAN_EXTENSION tag determines the extension that is added to\n# the generated man pages (default is the subroutine's section .3)\n\nMAN_EXTENSION          = .3\n\n# If the MAN_LINKS tag is set to YES and Doxygen generates man output,\n# then it will generate one additional man file for each entity\n# documented in the real man page(s). These additional files\n# only source the real man page, but without them the man command\n# would be unable to find the correct page. The default is NO.\n\nMAN_LINKS              = NO\n\n#---------------------------------------------------------------------------\n# configuration options related to the XML output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_XML tag is set to YES Doxygen will\n# generate an XML file that captures the structure of\n# the code including all documentation.\n\nGENERATE_XML           = NO\n\n# The XML_OUTPUT tag is used to specify where the XML pages will be put.\n# If a relative path is entered the value of OUTPUT_DIRECTORY will be\n# put in front of it. If left blank `xml' will be used as the default path.\n\nXML_OUTPUT             = xml\n\n# The XML_SCHEMA tag can be used to specify an XML schema,\n# which can be used by a validating XML parser to check the\n# syntax of the XML files.\n\nXML_SCHEMA             =\n\n# The XML_DTD tag can be used to specify an XML DTD,\n# which can be used by a validating XML parser to check the\n# syntax of the XML files.\n\nXML_DTD                =\n\n# If the XML_PROGRAMLISTING tag is set to YES Doxygen will\n# dump the program listings (including syntax highlighting\n# and cross-referencing information) to the XML output. Note that\n# enabling this will significantly increase the size of the XML output.\n\nXML_PROGRAMLISTING     = YES\n\n#---------------------------------------------------------------------------\n# configuration options for the AutoGen Definitions output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will\n# generate an AutoGen Definitions (see autogen.sf.net) file\n# that captures the structure of the code including all\n# documentation. Note that this feature is still experimental\n# and incomplete at the moment.\n\nGENERATE_AUTOGEN_DEF   = NO\n\n#---------------------------------------------------------------------------\n# configuration options related to the Perl module output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_PERLMOD tag is set to YES Doxygen will\n# generate a Perl module file that captures the structure of\n# the code including all documentation. Note that this\n# feature is still experimental and incomplete at the\n# moment.\n\nGENERATE_PERLMOD       = NO\n\n# If the PERLMOD_LATEX tag is set to YES Doxygen will generate\n# the necessary Makefile rules, Perl scripts and LaTeX code to be able\n# to generate PDF and DVI output from the Perl module output.\n\nPERLMOD_LATEX          = NO\n\n# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be\n# nicely formatted so it can be parsed by a human reader.\n# This is useful\n# if you want to understand what is going on.\n# On the other hand, if this\n# tag is set to NO the size of the Perl module output will be much smaller\n# and Perl will parse it just the same.\n\nPERLMOD_PRETTY         = YES\n\n# The names of the make variables in the generated doxyrules.make file\n# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.\n# This is useful so different doxyrules.make files included by the same\n# Makefile don't overwrite each other's variables.\n\nPERLMOD_MAKEVAR_PREFIX =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the preprocessor\n#---------------------------------------------------------------------------\n\n# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will\n# evaluate all C-preprocessor directives found in the sources and include\n# files.\n\nENABLE_PREPROCESSING   = NO\n\n# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro\n# names in the source code. If set to NO (the default) only conditional\n# compilation will be performed. Macro expansion can be done in a controlled\n# way by setting EXPAND_ONLY_PREDEF to YES.\n\nMACRO_EXPANSION        = NO\n\n# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES\n# then the macro expansion is limited to the macros specified with the\n# PREDEFINED and EXPAND_AS_DEFINED tags.\n\nEXPAND_ONLY_PREDEF     = NO\n\n# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files\n# pointed to by INCLUDE_PATH will be searched when a #include is found.\n\nSEARCH_INCLUDES        = YES\n\n# The INCLUDE_PATH tag can be used to specify one or more directories that\n# contain include files that are not input files but should be processed by\n# the preprocessor.\n\nINCLUDE_PATH           =\n\n# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard\n# patterns (like *.h and *.hpp) to filter out the header-files in the\n# directories. If left blank, the patterns specified with FILE_PATTERNS will\n# be used.\n\nINCLUDE_FILE_PATTERNS  =\n\n# The PREDEFINED tag can be used to specify one or more macro names that\n# are defined before the preprocessor is started (similar to the -D option of\n# gcc). The argument of the tag is a list of macros of the form: name\n# or name=definition (no spaces). If the definition and the = are\n# omitted =1 is assumed. To prevent a macro definition from being\n# undefined via #undef or recursively expanded use the := operator\n# instead of the = operator.\n\nPREDEFINED             =\n\n# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then\n# this tag can be used to specify a list of macro names that should be expanded.\n# The macro definition that is found in the sources will be used.\n# Use the PREDEFINED tag if you want to use a different macro definition that\n# overrules the definition found in the source code.\n\nEXPAND_AS_DEFINED      =\n\n# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then\n# doxygen's preprocessor will remove all references to function-like macros\n# that are alone on a line, have an all uppercase name, and do not end with a\n# semicolon, because these will confuse the parser if not removed.\n\nSKIP_FUNCTION_MACROS   = YES\n\n#---------------------------------------------------------------------------\n# Configuration::additions related to external references\n#---------------------------------------------------------------------------\n\n# The TAGFILES option can be used to specify one or more tagfiles.\n# Optionally an initial location of the external documentation\n# can be added for each tagfile. The format of a tag file without\n# this location is as follows:\n#\n# TAGFILES = file1 file2 ...\n# Adding location for the tag files is done as follows:\n#\n# TAGFILES = file1=loc1 \"file2 = loc2\" ...\n# where \"loc1\" and \"loc2\" can be relative or absolute paths or\n# URLs. If a location is present for each tag, the installdox tool\n# does not have to be run to correct the links.\n# Note that each tag file must have a unique name\n# (where the name does NOT include the path)\n# If a tag file is not located in the directory in which doxygen\n# is run, you must also specify the path to the tagfile here.\n\nTAGFILES               =\n\n# When a file name is specified after GENERATE_TAGFILE, doxygen will create\n# a tag file that is based on the input files it reads.\n\nGENERATE_TAGFILE       =\n\n# If the ALLEXTERNALS tag is set to YES all external classes will be listed\n# in the class index. If set to NO only the inherited external classes\n# will be listed.\n\nALLEXTERNALS           = NO\n\n# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed\n# in the modules index. If set to NO, only the current project's groups will\n# be listed.\n\nEXTERNAL_GROUPS        = YES\n\n# The PERL_PATH should be the absolute path and name of the perl script\n# interpreter (i.e. the result of `which perl').\n\nPERL_PATH              = /usr/bin/perl\n\n#---------------------------------------------------------------------------\n# Configuration options related to the dot tool\n#---------------------------------------------------------------------------\n\n# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will\n# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base\n# or super classes. Setting the tag to NO turns the diagrams off. Note that\n# this option also works with HAVE_DOT disabled, but it is recommended to\n# install and use dot, since it yields more powerful graphs.\n\nCLASS_DIAGRAMS         = YES\n\n# You can define message sequence charts within doxygen comments using the \\msc\n# command. Doxygen will then run the mscgen tool (see\n# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the\n# documentation. The MSCGEN_PATH tag allows you to specify the directory where\n# the mscgen tool resides. If left empty the tool is assumed to be found in the\n# default search path.\n\nMSCGEN_PATH            =\n\n# If set to YES, the inheritance and collaboration graphs will hide\n# inheritance and usage relations if the target is undocumented\n# or is not a class.\n\nHIDE_UNDOC_RELATIONS   = YES\n\n# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is\n# available from the path. This tool is part of Graphviz, a graph visualization\n# toolkit from AT&T and Lucent Bell Labs. The other options in this section\n# have no effect if this option is set to NO (the default)\n\nHAVE_DOT               = NO\n\n# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is\n# allowed to run in parallel. When set to 0 (the default) doxygen will\n# base this on the number of processors available in the system. You can set it\n# explicitly to a value larger than 0 to get control over the balance\n# between CPU load and processing speed.\n\nDOT_NUM_THREADS        = 0\n\n# By default doxygen will write a font called Helvetica to the output\n# directory and reference it in all dot files that doxygen generates.\n# When you want a differently looking font you can specify the font name\n# using DOT_FONTNAME. You need to make sure dot is able to find the font,\n# which can be done by putting it in a standard location or by setting the\n# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory\n# containing the font.\n\nDOT_FONTNAME           = Helvetica\n\n# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.\n# The default size is 10pt.\n\nDOT_FONTSIZE           = 10\n\n# By default doxygen will tell dot to use the output directory to look for the\n# FreeSans.ttf font (which doxygen will put there itself). If you specify a\n# different font using DOT_FONTNAME you can set the path where dot\n# can find it using this tag.\n\nDOT_FONTPATH           =\n\n# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen\n# will generate a graph for each documented class showing the direct and\n# indirect inheritance relations. Setting this tag to YES will force the\n# the CLASS_DIAGRAMS tag to NO.\n\nCLASS_GRAPH            = YES\n\n# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen\n# will generate a graph for each documented class showing the direct and\n# indirect implementation dependencies (inheritance, containment, and\n# class references variables) of the class with other documented classes.\n\nCOLLABORATION_GRAPH    = YES\n\n# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen\n# will generate a graph for groups, showing the direct groups dependencies\n\nGROUP_GRAPHS           = YES\n\n# If the UML_LOOK tag is set to YES doxygen will generate inheritance and\n# collaboration diagrams in a style similar to the OMG's Unified Modeling\n# Language.\n\nUML_LOOK               = NO\n\n# If set to YES, the inheritance and collaboration graphs will show the\n# relations between templates and their instances.\n\nTEMPLATE_RELATIONS     = NO\n\n# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT\n# tags are set to YES then doxygen will generate a graph for each documented\n# file showing the direct and indirect include dependencies of the file with\n# other documented files.\n\nINCLUDE_GRAPH          = YES\n\n# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and\n# HAVE_DOT tags are set to YES then doxygen will generate a graph for each\n# documented header file showing the documented files that directly or\n# indirectly include this file.\n\nINCLUDED_BY_GRAPH      = YES\n\n# If the CALL_GRAPH and HAVE_DOT options are set to YES then\n# doxygen will generate a call dependency graph for every global function\n# or class method. Note that enabling this option will significantly increase\n# the time of a run. So in most cases it will be better to enable call graphs\n# for selected functions only using the \\callgraph command.\n\nCALL_GRAPH             = NO\n\n# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then\n# doxygen will generate a caller dependency graph for every global function\n# or class method. Note that enabling this option will significantly increase\n# the time of a run. So in most cases it will be better to enable caller\n# graphs for selected functions only using the \\callergraph command.\n\nCALLER_GRAPH           = NO\n\n# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen\n# will generate a graphical hierarchy of all classes instead of a textual one.\n\nGRAPHICAL_HIERARCHY    = YES\n\n# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES\n# then doxygen will show the dependencies a directory has on other directories\n# in a graphical way. The dependency relations are determined by the #include\n# relations between the files in the directories.\n\nDIRECTORY_GRAPH        = YES\n\n# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images\n# generated by dot. Possible values are svg, png, jpg, or gif.\n# If left blank png will be used.\n\nDOT_IMAGE_FORMAT       = png\n\n# The tag DOT_PATH can be used to specify the path where the dot tool can be\n# found. If left blank, it is assumed the dot tool can be found in the path.\n\nDOT_PATH               = /usr/bin/dot\n\n# The DOTFILE_DIRS tag can be used to specify one or more directories that\n# contain dot files that are included in the documentation (see the\n# \\dotfile command).\n\nDOTFILE_DIRS           =\n\n# The MSCFILE_DIRS tag can be used to specify one or more directories that\n# contain msc files that are included in the documentation (see the\n# \\mscfile command).\n\nMSCFILE_DIRS           =\n\n# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of\n# nodes that will be shown in the graph. If the number of nodes in a graph\n# becomes larger than this value, doxygen will truncate the graph, which is\n# visualized by representing a node as a red box. Note that doxygen if the\n# number of direct children of the root node in a graph is already larger than\n# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note\n# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.\n\nDOT_GRAPH_MAX_NODES    = 50\n\n# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the\n# graphs generated by dot. A depth value of 3 means that only nodes reachable\n# from the root by following a path via at most 3 edges will be shown. Nodes\n# that lay further from the root node will be omitted. Note that setting this\n# option to 1 or 2 may greatly reduce the computation time needed for large\n# code bases. Also note that the size of a graph can be further restricted by\n# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.\n\nMAX_DOT_GRAPH_DEPTH    = 0\n\n# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent\n# background. This is disabled by default, because dot on Windows does not\n# seem to support this out of the box. Warning: Depending on the platform used,\n# enabling this option may lead to badly anti-aliased labels on the edges of\n# a graph (i.e. they become hard to read).\n\nDOT_TRANSPARENT        = NO\n\n# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output\n# files in one run (i.e. multiple -o and -T options on the command line). This\n# makes dot run faster, but since only newer versions of dot (>1.8.10)\n# support this, this feature is disabled by default.\n\nDOT_MULTI_TARGETS      = NO\n\n# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will\n# generate a legend page explaining the meaning of the various boxes and\n# arrows in the dot generated graphs.\n\nGENERATE_LEGEND        = YES\n\n# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will\n# remove the intermediate dot files that are used to generate\n# the various graphs.\n\nDOT_CLEANUP            = YES\n"
  },
  {
    "path": "Makefile.am",
    "content": "AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6\nACLOCAL_AMFLAGS = -I m4\n\nINCLUDES = $(all_includes) -I$(top_srcdir)/include\nSUBDIRS = include src\n\npkgconfigdir = $(libdir)/pkgconfig\npkgconfig_DATA = librtlsdr.pc\n\nBUILT_SOURCES = $(top_srcdir)/.version\n$(top_srcdir)/.version:\n\techo $(VERSION) > $@-t && mv $@-t $@\ndist-hook:\n\techo $(VERSION) > $(distdir)/.tarball-version\n\ninstall-udev-rules:\n\t$(INSTALL_DATA) rtl-sdr.rules /etc/udev/rules.d\n\nuninstall-udev-rules:\n\trm -rf /etc/udev/rules.d/rtl-sdr.rules\n\nEXTRA_DIST = git-version-gen .version\n\nif HAVE_DOXYGEN\n\npkgdocdir=$(docdir)/$(PACKAGE)-$(VERSION)\ndoc_htmldir=$(pkgdocdir)/html\n\ndoc_html_DATA = $(top_builddir)/doc/html.tar\n\n$(doc_html_DATA): $(top_builddir)/doc/html/index.html\n\tcd $(top_builddir)/doc && tar cf html.tar html\n\n$(top_builddir)/doc/html/index.html: $(SOURCES) Doxyfile\n\t@rm -rf doc\n\tmkdir -p doc\n\t$(DOXYGEN) Doxyfile\n\ninstall-data-hook:\n\tcd $(DESTDIR)$(doc_htmldir) && tar xf html.tar --strip-components 1 && rm -f html.tar\n\nuninstall-hook:\n\trm -rf $(DESTDIR)/$(doc_htmldir)\n\nDX_CLEAN = doc/{html,latex}/* doc/html.tar\n\nendif\n\nMOSTLYCLEANFILES = $(DX_CLEAN)\n"
  },
  {
    "path": "README.md",
    "content": "[![librtlsdr version](https://img.shields.io/github/tag/librtlsdr/librtlsdr.svg?style=flat&label=librtlsdr)](https://github.com/librtlsdr/librtlsdr/releases)\n[![GPLv2 License](http://img.shields.io/badge/license-GPLv2-brightgreen.svg)](https://tldrlegal.com/license/gnu-general-public-license-v2)\n\n# Description\n\nrtl-sdr turns your Realtek RTL2832 based DVB dongle into a SDR receiver\n\n\n# New enhancements and features in this version\n\nMany different developments have been taken in this release. For an overview, see [improvements](README_improvements.md)\n\n# Build / Install (on debian/ubuntu)\n\n## prerequisites\ndevelopment tools have to be installed:\n```\nsudo apt-get install build-essential cmake git\n```\n\ninstall the libusb-1.0 development package::\n```\nsudo apt-get install libusb-dev libusb-1.0-0-dev\n```\n\n## retrieve the sources - right branch\n\n```\ngit clone https://github.com/librtlsdr/librtlsdr.git\n```\n\nin case you want the *development* branch, e.g. for testing or preparing patches:\n```\ncd librtlsdr\ngit checkout development\n```\n\nby default, you should have the *master* branch, in doubt:\n```\ncd librtlsdr\ngit status\ngit checkout master\n```\n\n## build\nrun cmake and start compilation. cmake will accept some options, e.g.\n* `-DINSTALL_UDEV_RULES=ON`, default is `OFF`\n* `-DDETACH_KERNEL_DRIVER=ON`, default is `OFF`\n* `-DPROVIDE_UDP_SERVER=ON`, default is `OFF`\n* `-DWITH_RPC=ON`, default is `OFF`\n* `-DLINK_RTLTOOLS_AGAINST_STATIC_LIB=ON`, default is `OFF`\n* `-DRTL_STATIC_BUILD=OFF`, default is `ON`: for MINGW on WIN32\n\nall cmake options are optional\n\n```\nmkdir build && cd build\ncmake ../ -DINSTALL_UDEV_RULES=ON\nmake\n```\n\n## install\nsetup into prefix, usually will require `sudo`:\n```\nsudo make install\nsudo ldconfig\n```\n\n# Development builds / binaries\n\n[GitHub Actions](https://github.com/librtlsdr/librtlsdr/actions) is used for development builds - for Linux (x86), MacOS and Windows x86 32/64.\nCross-builds for Windows from a Linux machine: see [cross_build_mingw32.sh](cross_build_mingw32.sh) or [cross_build_mingw64.sh](cross_build_mingw64.sh)\n\n# For more information see:\n\nhttp://superkuh.com/rtlsdr.html\n\nhttps://osmocom.org/projects/rtl-sdr/wiki/Rtl-sdr\n\n\n# Setup for SDR only use - without DVB compatibility:\n\n- a special USB vendor/product id got reserved at http://pid.codes/ : 0x1209/0x2832\n- for such devices the linux kernel's DVB modules are not loaded automatically,\n thus can be used without blacklisting *dvb_usb_rtl28xxu* below /etc/modprobe.d/\n- this allows to use a second RTL dongle for use with DVB in parallel\n- the IDs can be programmed with '`rtl_eeprom -n`' or '`rtl_eeprom -g realtek_sdr`'\n- for permanent blacklisting you might check/call following from the clone git directory\n    ```./install-blacklist.sh```\n\n\n# Contributing\n\nPull requests are always welcome but please make changes to, and pull request from, the development branch.\n\n## Initial setup:\n\n- fork the librtlsdr repo via GitHub\n- clone your fork locally and cd to the cloned repo's folder\n- add the upstream development repo:\n    * `git remote add upstream git@github.com:librtlsdr/librtlsdr.git`\n- track the development branch: \n    * `git branch --track development origin/development`\n\n## Normal workflow:\n\n- checkout the development branch and make your changes\n- commit your changes\n- sync your local development branch with the upstream development branch:\n    * `git fetch upstream`\n    * `git merge upstream/development`\n- push your commit/s to your forked repo\n- do a pull request via GitHub\n"
  },
  {
    "path": "README.rtlfm_cmdfile",
    "content": "\nrtl_fm now has option '-C' for a command file, from which a list of frequencies are read.\nSo it's similar to using a frequency range, as with \"-f 118M:137M:25k\"\nThe difference is, that you can parametrize one frequency per line together with\n- the tuner gain\n- condition for triggering\n- measurement duration\nand a command to execute.\nLines starting with '#' are skipped / interpreted as comments.\nParameters a seperated by comma.\n\nHere's an example:\n---\n# freq in Hz or special keyword, gain in dB, trig_crit (in/out/lt/gt), trig_level, trig_tolerance, #meas, #blocks, trigger_command\n# windows: rtl_fm -f 105.2m -E rdc -w 350k -s 200k -m 2.2m      -B 200000 -C cmdfile.csv -n -v\n#          rtl_fm -f 105.2m -E rdc -w 350k -s 200k -m 2.2m -W 4 -B 10000  -C cmdfile.csv -n -v\n# linux: ./rtl_fm -f 105.2m -E rdc -w 350k -s 200k -m 2.2m -B 200000 -C cmdfile.csv -n -v\n#\n# windows command examples:\n# cmd.exe, /C echo hello world\n# cmd.exe, /C start notepad\n# calc.exe\n#\n# linux examples:\n# ssmtp\n# sendxmpp\n## for piping some message to ssmtp or sendxmpp you'll need to write small scripts\n\n# 'adcmax' keyword in first column activates measurement of max adc value at capture rate to determine optimum gain and avoid oversteering\n# 'adcrms' keyword activates rms calculation at capture rate. for usual it's similar to adcmax. there are differences in case of oversteering\n#   activate verbose output (option '-v') to get the output. The maximum possible sample value is 128.\n#   You should have approx. 6 dB headroom to allow measuring stronger signals, that means measured baseline values should be below 64.\n#   An the other side you'll want to measure weaker signals, so the measured baseline value should be above a minimum of approx 8 or 16.\nadcmax,\nadcrms,\n100.7m, 30, in, 0, 1, 10, 100,\n33.0m, 20,out,60, 3, 10, 400, /home/odroid/test/simple.sh, frq !freq! gain !gain! measured !mlevel! tenth dB !crit! { !reflevel! +/- !reftol! tenth dB }\n# now check for optimal gain in some steps, which should be done per frequency!:\n100.7m, 0, gt, 400, 1, 1, 100,\n100.7m, 3, gt, 400, 1, 1, 100,\n100.7m, 6, gt, 400, 1, 1, 100,\n100.7m, 12, gt, 400, 1, 1, 100,\n100.7m, 18, gt, 400, 1, 1, 100,\n\n---\n\n* first frequency is 100.7 MHz, tuned with ~ 30 dB tuner gain;\ncondition is 'in' { 0 +/- 1 } dB,\nwith 10 measurements, averaging the rms level in dB.\nEach single measurement is processed after decimation of block/buffer-size many samples (see option -W).\n  The resulting number of decimated samples might get too small to allow a reliable measurement.\n  This number also depends on the capture rate: ensure minimum capture rate with option '-m'. This is also important for reducing aliases.\n  Check the output 'block length after decimation is ... samples'!\nIf condition for measured level is true, then a command can be triggered, which is executed in background.\nThen, a next trigger for this frequency is blocked for 100 measurements.\nThere is nothing triggered for 100.7 MHz.\n\n* 2nd frequency is 33.0 MHz, tuned with ~ 20 dB tuner gain;\ncondition is 'out' { 60 +/- 3 } dB,\nwith 10 measurements.\nThat means, the trigger is activated when averaged level is below 57 dB or above 63 dB.\nNext trigger for this frequency is blocked for 400 measurements.\nTriggered command is the shell script '/home/odroid/test/simple.sh',\nwith the arguments 'frq !freq! gain !gain! measured !mlevel! tenth dB !crit! { !reflevel! +/- !reftol! tenth dB }'.\nYou can use following keywords in the arguments, which need to be free standing!:\n- !freq!\ncurrent frequency in Hz\n\n- !gain!\ncurrent tuner gain in tenth dB to allow easier evaluation from scripts.\n\n- !mlevel!\naverage measured level in tenth dB\n\n- !crit!\none of \"in\", \"out\", \"<\" or \">\" for the tested condition\n\n- !reflevel!\ncondition's reference level in tenth dB\n\n- !reftol!\ncondition's reference tolerance in tenth dB\n\n\nApplication might be monitoring of some stations\nand triggering a notification, e.g. via ssmtp or sendxmpp,\nwhen a stations power level is below it's expected value.\n\nAnother application might be triggering a recording with a second RTL dongle.\n\n\nSend comments, suggestions or reports to\nHayati Ayguen <h_ayguen@web.de>\n\n"
  },
  {
    "path": "README.rtlsdr_rpc",
    "content": "This implementation of librtlsdr makes remote dongles\nappear to the local software as if they were on the\nsame computer. It works by forwarding librtlsdr calls\nto the remote computer over TCP.\n\nIt allows one to use existing tools without modifying\nthem. Also, it allows a developer to use the same API\nno matter weither the dongle is local or distant.\n\nTo use it, one must compile and install the library\nwith CMAKE the usual way. Note that you may need to\nuninstall the existing librtlsdr, as people reported\nruntime errors due to conflicting installs.\n\nThen, a server (called rtl_rpcd) must be run on the\nremote location.\n\nIn my case, the dongle is in a beagle bone black is\nat address 192.168.0.43:\nbeagleboneblack #> ./rtl_rpcd\n\nThen, the existing tool (for instance rtlizer) can be\nrun on the local computer using:\nRTLSDR_RPC_IS_ENABLED=1 RTLSDR_RPC_SERV_ADDR=192.168.0.43 \\\nrtlizer\n\nThis implementation still has some limitations, but\nworks well in most cases. Please report any bug to\ntexane@gmail.com\n\nAlso, note that the latest version of libusb should be\nused as librtlsdr crashed when used with older version\n(esp. the rtlsdr_read_async routine):\nhttps://github.com/libusb/libusb.git\n\nlist of known working software:\nrtl_fm\nrtl_power\nrtlsdr-waterfall\nrtlizer\ngnuradio-companion\ncubicsdr\ngqrx\nlinrad\n"
  },
  {
    "path": "README_improvements.md",
    "content": "\n# improvements, compared to the osmocom sources\n\n\n## versions\n\ncomparing osmocom's git git://git.osmocom.org/rtl-sdr.git dated from 2020-08-19\nagainst librtlsdr's development branch (initially same date, but updated 2020-10-04)\n\n\n## \"Driver\" Library Features\n\n* added support for special USB (vendor) VID 0x1209 (product) PID 0x2832: \"Generic RTL2832U\":\n  * A special USB vendor/product id got reserved at http://pid.codes/1209/2832/\n  * for such devices the linux kernel's DVB modules are not loaded automatically, thus can be used without blacklisting dvb_usb_rtl28xxu below /etc/modprobe.d/\n  * this allows to use a second RTL dongle for use with DVB in parallel\n  * the IDs can be programmed with '`rtl_eeprom -n`' or '`rtl_eeprom -g realtek_sdr`'\n  * see https://www.rtl-sdr.com/watching-dvb-t-tv-and-using-sdr-mode-at-the-same-time-with-two-rtl-sdrs/\n\n* added support for using RTLSDR-Dongle from remote - see rtl_rpcd and [README.rtlsdr_rpc](README.rtlsdr_rpc)\n\n* support for all GPIO pins of RTL2832 through API and rtl_biast\n\n  * functions were provided from Marko Cebokli at http://lea.hamradio.si/~s57uuu/mischam/rtlsdr/ports.html\n\n* improvements for R820T/2 tuner\n  also see https://codingspirit.de/librtlsdr-driver.pdf\n  several features from https://github.com/old-dab/rtlsdr/\n  \n  * added better bandwidth support\n    * added smaller bandwidths, improving selectivity:\n      290, 375, 420, 470, 600, 860, 950, 1100, 1200, 1300, 1500, 1600, 1750, 1800, 1950, 2200, 3000, 5000 kHz.\n      These are coarse measured values .. which might get adjusted in future.\n    * bandwidth filters utilize tuner's low- and highpass filters at IF\n  * added spectrum flipping (inside tuner) - and back in RTL2832\n    * the band edges (low/high-pass) have different steepness;\n      the steeper edge can be selected with the mixer sideband (`rtlsdr_set_tuner_sideband()`),\n      to achieve better attenuation depending on signal scenario\n  * added (automatic) control over VGA (variable gain amplifier)\n    * VGA gain (besides LNA and Mixer) can be utilized and set to automatic, letting it controlled from RTL2832U.\n      Having all automatic (AGC) including activation of digital AGC in RTL2832 (`rtlsdr_set_agc_mode()`), oversteering effects got reduced (a lot).\n    * total gain range now up to 100 dB\n  * deactivated \"Filter extension under weak signal\" for a stable filter characteristic\n  * added shifting of IF-center, to receive away from DC. see `rtlsdr_set_tuner_band_center()`\n\n* harmonic reception for R820T/2 tuner:\n\n  * allow reception for frequencies above ~ 1.76 GHz\n  * tested in lab conditions up to 6.0 GHz\n  * 5th harmonic is used automatically by default when direct reception is not possible (when tuner-PLL doesn't lock)\n  * 3rd harmonic looks also promising. harmonic factor is parametrizable with passthrough driver option '**harm=**' to set n-th harmonic\n  * reception in real world from antenna is very likely to require a suitable high pass or bandpass filter and an LNA in front of the RTLSDR dongle\n\n* passthrough driver options:\n\n  * all the rtlsdr tools below support option '**-O**' followed by a '**:**' separated string of specific options,\n    which are passed to the library by calling `rtlsdr_set_opt_string()`.\n\n  * process options from environment variable **LIBRTLSDR_OPT** for applications which don't support/use `rtlsdr_set_opt_string()` and don't support some of the features. \n\n  * there are many options, e.g.\n\n    * **bw=** set the tuner bandwidth in kHz\n    * **agc=** activate tuner AGC\n    * **gain=** set tuner's gain value manually in tenth dB\n    * **dagc=** set digital AGC of RTL2832\n    * **t=** set bias tee for RTL-SDR V3 or compatible, see https://www.rtl-sdr.com/rtl-sdr-blog-v-3-dongles-user-guide/\n    * **tp=** set pin for bias tee\n    * **ds=** set direct sampling (HF mode) for RTL-SDR V3 or compatible, see https://www.rtl-sdr.com/rtl-sdr-blog-v-3-dongles-user-guide/\n    * **dm=** set direct sampling mode\n\n  * many of the options are R820T/2-tuner specific:\n\n    * **bc=** set the the reception bands' center in Hz\n\n    * **sb=** set tuner sideband\n\n    * **ifm=** set IF mode (AGC, fixed gain, ..) for VGA (variable gain amplifier)\n\n    * **harm=** set n-th harmonic reception\n\n    * **vcocmin=** set minimum VCO current\n\n    * **vcocmax=** set maximum VCO current\n\n    * **vcoalgo=** set VCO algorithm\n\n      \n\n* probably some more: it's highly probable, that this list is incomplete\n\n\n## \"Driver\" Library API\n\n* added rtlsdr_set_and_get_tuner_bandwidth(), which also delivers the bandwidth.\n [ with rtlsdr_set_tuner_bandwidth() does not deliver the bandwidth ]\n* added rtlsdr_set_tuner_band_center(),  to set center of the filtered tuner band\n* added rtlsdr_set_tuner_sideband(), to set mixer sideband\n* added rtlsdr_set_tuner_gain_ext(), special for R820T/2 tuner\n* added rtlsdr_set_tuner_if_mode(), sets AGC modes in detail\n* added rtlsdr_set_dithering(), to allow disabling frequency dithering for R820T/2 tuner\n* added rtlsdr_set_ds_mode() including threshold frequency\n* added rtlsdr_ir_query()\n* added rtlsdr_set_opt_string() and rtlsdr_get_opt_help()\n for configuration of 'driver' - especially from command line.\nnew alternative: environment variable **LIBRTLSDR_OPT**\n* added rtlsdr_set_tuner_i2c_register(), rtlsdr_get_tuner_i2c_register()\n and rtlsdr_set_tuner_i2c_override()\n exposing hacking of tuner-specific I2C registers\n* added rtlsdr_get_ver_id(),\n to allow discrimination between osmocom library - or this fork\n* added rtlsdr_get_version()\n* added rtlsdr_set_gpio_output(), rtlsdr_set_gpio_input(), rtlsdr_set_gpio_bit(), rtlsdr_get_gpio_bit(), rtlsdr_set_gpio_byte(), rtlsdr_get_gpio_byte() and rtlsdr_set_gpio_status()\n* added rtlsdr_set_center_freq64(), to set frequencies above ~4.29 GHz, the 32-bit limit\n* added rtlsdr_get_center_freq64()\n* added rtlsdr_set_harmonic_rx() to activate/change harmonic reception\n\n\n## Added Tools\n\n* added rtl_ir:\n display received IR signals.\n  * requires the IR diode of an RTL-SDR - which might not exist!\n\n* added rtl_rpcd:\n a Remote Procedure Call server for RTL-SDR dongles.\n  * for use, set environment variable \"**RTLSDR_RPC_IS_ENABLED**\"\n  * optionally set environment varibales \"**RTLSDR_RPC_SERV_ADDR**\"\n    and \"**RTLSDR_RPC_SERV_PORT**\". These default to \"127.0.0.1\" and \"40000\".\n  * requires cmake option **WITH_RPC**\n\n* added rtl_raw2wav:\n save rtl_sdr or rtl_fm's output (pipe) into a wave file,\n including some meta information like timestamp and frequency\n\n* added rtl_udp:\n same as rtl_tcp - just using UDP instead of TCP\n\n* added rtl_wavestat:\n display wave file meta information\n\n* added rtl_wavestream:\n stream raw data (in specified format)\n\n\n## Improved Tools\n\n* rtl_fm:\n  * added command file option '-C', which can trigger actions depending on signal.\n    have a look at [README.rtlfm_cmdfile](README.rtlfm_cmdfile).\n  * added command line interface option '-E rdc', to enable dc blocking on raw I/Q data at capture rate\n  * added CLI option '-E rtlagc', to enable rtl2832's digital agc\n  * added CLI option '-E bclo', to use tuner bandwidths low  corner as band center\n  * added CLI option '-E bchi', to use tuner bandwidths high corner as band center\n  * added CLI option '-O', to set RTL driver options separated with ':', e.g. -O 'bc=30000:agc=0'\n  * added CLI option '-R', to specify number of seconds to run\n  * added CLI option '-H', to write wave Header to file, producing a wave file with meta information,\n    compatible with several SDR programs\n  * added CLI option '-o', to request oversampling (4 recommended) for processing gain\n* rtl_biast:\n   * several options for reading/writing other GPIOs\n* many tools have more options.\n compare all the details by starting with command line option '-h'.\n\n\n## \"Driver\" Library's UDP-Server\n\n* enabled by cmake option **PROVIDE_UDP_SERVER** for tests. OFF by default\n\n* activated by rtlsdr_set_opt_string(): \"**port=1**\" or \"**port=**<udp_port>\",\n default port number: 32323\n \n* purpose is to allow configuration at runtime with a simple text protocol, e.g. with netcat\n\n* for detailed protocol, see comment section in parse() of librtlsdr.c.\n or look for sections with '#ifdef WITH_UDP_SERVER'\n \n* this feature was copied and enhanced from https://sourceforge.net/projects/librtlsdr-wincontrol/ developed from [sourceforge user randaller](https://sourceforge.net/u/randaller/profile/), which in turn is an adaption of https://github.com/gat3way/r820tweak, which was developed by Milen Rangelov\n\n* simple usage from command line, e.g. to retrieve help\n\n   ```\n   echo \"h\" | timeout 1 netcat -u 127.0.0.1 32323\n   ```\n\n   without `timeout`, press Ctrl+C\n   the output is:\n\n   ```\n   g <register>                  # get content of I2C ..\n   s <register> <value> [<mask>] # set conten\n   S <register> <value> [<mask>] # set content - keeping value in future\n   i <IFfrequency>  # set IF frequency [0 .. 28'800'000]\n   f <RFfrequency>  # set center frequency\n   b <bandwidth>    # set tuner bandwidth\n   c <frequency>    # set tuner bw center in output [-1'600'000 .. 1'600'000]\n   v <sideband>     # set tuner sideband: 0 for LSB, 1 for USB\n   a <tunerIFmode>  # set VGA: 0 for auto; in tenth dB or 10000+idx\n   m <tuner gain>   # set tuner gain\n   M <gainMode>     # 0 .. 3: digital rtl agc (0..1) * 2 + tuner agc (0..1)\n   ```\n\n\n\n## RTL_TCP TCP-PROTOCOL\n\n* allows non-GPL programs to utilize the RTLSDR stuff in a license compliant way\n\n* added several control functions in rtl_tcp, not existing in osmocom release:\n UDP_ESTABLISH, UDP_TERMINATE, SET_I2C_TUNER_REGISTER, SET_I2C_TUNER_OVERRIDE,\n SET_TUNER_BW_IF_CENTER, SET_TUNER_IF_MODE, SET_SIDEBAND, REPORT_I2C_REGS, SET_FREQ_HI32\n\n* control functions documented in rtl_tcp.h\n\n* (by default) control port number 1234, configurable via command-line-interface (CLI)\n\n* response(s) at +1 of control port: 1235, configurable via CLI\n\n* protocol details in protocol_rtl_tcp.txt\n\n"
  },
  {
    "path": "cmake/Modules/FindLibUSB.cmake",
    "content": "if(NOT LIBUSB_FOUND)\n  pkg_check_modules (LIBUSB_PKG libusb-1.0)\n  find_path(LIBUSB_INCLUDE_DIR NAMES libusb.h\n    PATHS\n    ${LIBUSB_PKG_INCLUDE_DIRS}\n    /usr/include/libusb-1.0\n    /usr/include\n    /usr/local/include\n  )\n\n#standard library name for libusb-1.0\nset(libusb1_library_names usb-1.0 libusb-1.0)\n\n#libusb-1.0 compatible library on freebsd\nif((CMAKE_SYSTEM_NAME STREQUAL \"FreeBSD\") OR (CMAKE_SYSTEM_NAME STREQUAL \"kFreeBSD\"))\n    list(APPEND libusb1_library_names usb)\nendif()\n\n  find_library(LIBUSB_LIBRARIES\n    NAMES ${libusb1_library_names}\n    PATHS\n    ${LIBUSB_PKG_LIBRARY_DIRS}\n    /usr/lib\n    /usr/local/lib\n  )\n\ninclude(CheckFunctionExists)\nif(LIBUSB_INCLUDE_DIRS)\n    set(CMAKE_REQUIRED_INCLUDES ${LIBUSB_INCLUDE_DIRS})\nendif()\nif(LIBUSB_LIBRARIES)\n    set(CMAKE_REQUIRED_LIBRARIES ${LIBUSB_LIBRARIES})\nendif()\n\nCHECK_FUNCTION_EXISTS(\"libusb_handle_events_timeout_completed\" HAVE_LIBUSB_HANDLE_EVENTS_TIMEOUT_COMPLETED)\nif(HAVE_LIBUSB_HANDLE_EVENTS_TIMEOUT_COMPLETED)\n    add_definitions(-DHAVE_LIBUSB_HANDLE_EVENTS_TIMEOUT_COMPLETED=1)\nendif(HAVE_LIBUSB_HANDLE_EVENTS_TIMEOUT_COMPLETED)\n\nCHECK_FUNCTION_EXISTS(\"libusb_error_name\" HAVE_LIBUSB_ERROR_NAME)\nif(HAVE_LIBUSB_ERROR_NAME)\n    add_definitions(-DHAVE_LIBUSB_ERROR_NAME=1)\nendif(HAVE_LIBUSB_ERROR_NAME)\n\nif(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES)\n  set(LIBUSB_FOUND TRUE CACHE INTERNAL \"libusb-1.0 found\")\n  message(STATUS \"Found libusb-1.0: ${LIBUSB_INCLUDE_DIR}, ${LIBUSB_LIBRARIES}\")\nelse(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES)\n  set(LIBUSB_FOUND FALSE CACHE INTERNAL \"libusb-1.0 found\")\n  message(STATUS \"libusb-1.0 not found.\")\nendif(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES)\n\nmark_as_advanced(LIBUSB_INCLUDE_DIR LIBUSB_LIBRARIES)\n\nendif(NOT LIBUSB_FOUND)\n"
  },
  {
    "path": "cmake/Modules/FindThreads.cmake",
    "content": "# Updated FindThreads.cmake that supports pthread-win32\n# Downloaded from http://www.vtk.org/Bug/bug_view_advanced_page.php?bug_id=6399\n\n# - This module determines the thread library of the system.\n#\n# The following variables are set\n#  CMAKE_THREAD_LIBS_INIT     - the thread library\n#  CMAKE_USE_SPROC_INIT       - are we using sproc?\n#  CMAKE_USE_WIN32_THREADS_INIT - using WIN32 threads?\n#  CMAKE_USE_PTHREADS_INIT    - are we using pthreads\n#  CMAKE_HP_PTHREADS_INIT     - are we using hp pthreads\n#\n# If use of pthreads-win32 is desired, the following variables\n# can be set.\n#\n#  THREADS_USE_PTHREADS_WIN32 -\n#    Setting this to true searches for the pthreads-win32\n#    port (since CMake 2.8.0)\n#\n#  THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME\n#      C  = no exceptions (default)\n#         (NOTE: This is the default scheme on most POSIX thread\n#          implementations and what you should probably be using)\n#      CE = C++ Exception Handling\n#      SE = Structure Exception Handling (MSVC only)\n#      (NOTE: Changing this option from the default may affect\n#       the portability of your application.  See pthreads-win32\n#       documentation for more details.)\n#\n#======================================================\n# Example usage where threading library\n# is provided by the system:\n#\n#   find_package(Threads REQUIRED)\n#   add_executable(foo foo.cc)\n#   target_link_libraries(foo ${CMAKE_THREAD_LIBS_INIT})\n#\n# Example usage if pthreads-win32 is desired on Windows\n# or a system provided thread library:\n#\n#   set(THREADS_USE_PTHREADS_WIN32 true)\n#   find_package(Threads REQUIRED)\n#   include_directories(${THREADS_PTHREADS_INCLUDE_DIR})\n#\n#   add_executable(foo foo.cc)\n#   target_link_libraries(foo ${CMAKE_THREAD_LIBS_INIT})\n#\n\nINCLUDE (CheckIncludeFiles)\nINCLUDE (CheckLibraryExists)\nSET(Threads_FOUND FALSE)\n\nIF(WIN32 AND NOT CYGWIN AND THREADS_USE_PTHREADS_WIN32)\n  SET(_Threads_ptwin32 true)\nENDIF()\n\n# Do we have sproc?\nIF(CMAKE_SYSTEM MATCHES IRIX)\n  CHECK_INCLUDE_FILES(\"sys/types.h;sys/prctl.h\"  CMAKE_HAVE_SPROC_H)\nENDIF()\n\nIF(CMAKE_HAVE_SPROC_H)\n  # We have sproc\n  SET(CMAKE_USE_SPROC_INIT 1)\n\nELSEIF(_Threads_ptwin32)\n\n  IF(NOT DEFINED THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME)\n    # Assign the default scheme\n    SET(THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME \"C\")\n  ELSE()\n    # Validate the scheme specified by the user\n    IF(NOT THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME STREQUAL \"C\" AND\n       NOT THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME STREQUAL \"CE\" AND\n       NOT THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME STREQUAL \"SE\")\n         MESSAGE(FATAL_ERROR \"See documentation for FindPthreads.cmake, only C, CE, and SE modes are allowed\")\n    ENDIF()\n    IF(NOT MSVC AND THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME STREQUAL \"SE\")\n      MESSAGE(FATAL_ERROR \"Structured Exception Handling is only allowed for MSVC\")\n    ENDIF(NOT MSVC AND THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME STREQUAL \"SE\")\n  ENDIF()\n\n  FIND_PATH(THREADS_PTHREADS_INCLUDE_DIR pthread.h)\n\n  # Determine the library filename\n  IF(MSVC)\n    SET(_Threads_pthreads_libname\n        pthreadV${THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME}2)\n  ELSEIF(MINGW)\n    SET(_Threads_pthreads_libname\n        pthreadG${THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME}2)\n  ELSE()\n    MESSAGE(FATAL_ERROR \"This should never happen\")\n  ENDIF()\n\n  # Use the include path to help find the library if possible\n  SET(_Threads_lib_paths \"\")\n  IF(THREADS_PTHREADS_INCLUDE_DIR)\n     GET_FILENAME_COMPONENT(_Threads_root_dir\n                            ${THREADS_PTHREADS_INCLUDE_DIR} PATH)\n     SET(_Threads_lib_paths ${_Threads_root_dir}/lib)\n  ENDIF()\n  FIND_LIBRARY(THREADS_PTHREADS_WIN32_LIBRARY\n               NAMES ${_Threads_pthreads_libname}\n               PATHS ${_Threads_lib_paths}\n               DOC \"The Portable Threads Library for Win32\"\n               NO_SYSTEM_PATH\n               )\n\n  IF(THREADS_PTHREADS_INCLUDE_DIR AND THREADS_PTHREADS_WIN32_LIBRARY)\n    MARK_AS_ADVANCED(THREADS_PTHREADS_INCLUDE_DIR)\n    SET(CMAKE_THREAD_LIBS_INIT ${THREADS_PTHREADS_WIN32_LIBRARY})\n    SET(CMAKE_HAVE_THREADS_LIBRARY 1)\n    SET(Threads_FOUND TRUE)\n  ENDIF()\n\n  MARK_AS_ADVANCED(THREADS_PTHREADS_WIN32_LIBRARY)\n\nELSE()\n  # Do we have pthreads?\n  CHECK_INCLUDE_FILES(\"pthread.h\" CMAKE_HAVE_PTHREAD_H)\n  IF(CMAKE_HAVE_PTHREAD_H)\n\n    #\n    # We have pthread.h\n    # Let's check for the library now.\n    #\n    SET(CMAKE_HAVE_THREADS_LIBRARY)\n    IF(NOT THREADS_HAVE_PTHREAD_ARG)\n\n      # Do we have -lpthreads\n      CHECK_LIBRARY_EXISTS(pthreads pthread_create \"\" CMAKE_HAVE_PTHREADS_CREATE)\n      IF(CMAKE_HAVE_PTHREADS_CREATE)\n        SET(CMAKE_THREAD_LIBS_INIT \"-lpthreads\")\n        SET(CMAKE_HAVE_THREADS_LIBRARY 1)\n        SET(Threads_FOUND TRUE)\n      ENDIF()\n\n      # Ok, how about -lpthread\n      CHECK_LIBRARY_EXISTS(pthread pthread_create \"\" CMAKE_HAVE_PTHREAD_CREATE)\n      IF(CMAKE_HAVE_PTHREAD_CREATE)\n        SET(CMAKE_THREAD_LIBS_INIT \"-lpthread\")\n        SET(Threads_FOUND TRUE)\n        SET(CMAKE_HAVE_THREADS_LIBRARY 1)\n      ENDIF()\n\n      IF(CMAKE_SYSTEM MATCHES \"SunOS.*\")\n        # On sun also check for -lthread\n        CHECK_LIBRARY_EXISTS(thread thr_create \"\" CMAKE_HAVE_THR_CREATE)\n        IF(CMAKE_HAVE_THR_CREATE)\n          SET(CMAKE_THREAD_LIBS_INIT \"-lthread\")\n          SET(CMAKE_HAVE_THREADS_LIBRARY 1)\n          SET(Threads_FOUND TRUE)\n        ENDIF()\n      ENDIF(CMAKE_SYSTEM MATCHES \"SunOS.*\")\n\n    ENDIF(NOT THREADS_HAVE_PTHREAD_ARG)\n\n    IF(NOT CMAKE_HAVE_THREADS_LIBRARY)\n      # If we did not found -lpthread, -lpthread, or -lthread, look for -pthread\n      IF(\"THREADS_HAVE_PTHREAD_ARG\" MATCHES \"^THREADS_HAVE_PTHREAD_ARG\")\n        MESSAGE(STATUS \"Check if compiler accepts -pthread\")\n        TRY_RUN(THREADS_PTHREAD_ARG THREADS_HAVE_PTHREAD_ARG\n          ${CMAKE_BINARY_DIR}\n          ${CMAKE_ROOT}/Modules/CheckForPthreads.c\n          CMAKE_FLAGS -DLINK_LIBRARIES:STRING=-pthread\n          COMPILE_OUTPUT_VARIABLE OUTPUT)\n\n        IF(THREADS_HAVE_PTHREAD_ARG)\n          IF(THREADS_PTHREAD_ARG MATCHES \"^2$\")\n            SET(Threads_FOUND TRUE)\n            MESSAGE(STATUS \"Check if compiler accepts -pthread - yes\")\n          ELSE()\n            MESSAGE(STATUS \"Check if compiler accepts -pthread - no\")\n            FILE(APPEND\n              ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log\n              \"Determining if compiler accepts -pthread returned ${THREADS_PTHREAD_ARG} instead of 2. The compiler had the following output:\\n${OUTPUT}\\n\\n\")\n          ENDIF()\n        ELSE()\n          MESSAGE(STATUS \"Check if compiler accepts -pthread - no\")\n          FILE(APPEND\n            ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log\n            \"Determining if compiler accepts -pthread failed with the following output:\\n${OUTPUT}\\n\\n\")\n        ENDIF()\n\n      ENDIF(\"THREADS_HAVE_PTHREAD_ARG\" MATCHES \"^THREADS_HAVE_PTHREAD_ARG\")\n\n      IF(THREADS_HAVE_PTHREAD_ARG)\n        SET(Threads_FOUND TRUE)\n        SET(CMAKE_THREAD_LIBS_INIT \"-pthread\")\n      ENDIF()\n\n    ENDIF(NOT CMAKE_HAVE_THREADS_LIBRARY)\n  ENDIF(CMAKE_HAVE_PTHREAD_H)\nENDIF()\n\nIF(CMAKE_THREAD_LIBS_INIT)\n  SET(CMAKE_USE_PTHREADS_INIT 1)\n  SET(Threads_FOUND TRUE)\nENDIF()\n\nIF(CMAKE_SYSTEM MATCHES \"Windows\"\n   AND NOT THREADS_USE_PTHREADS_WIN32)\n  SET(CMAKE_USE_WIN32_THREADS_INIT 1)\n  SET(Threads_FOUND TRUE)\nENDIF()\n\nIF(CMAKE_USE_PTHREADS_INIT)\n  IF(CMAKE_SYSTEM MATCHES \"HP-UX-*\")\n    # Use libcma if it exists and can be used.  It provides more\n    # symbols than the plain pthread library.  CMA threads\n    # have actually been deprecated:\n    #   http://docs.hp.com/en/B3920-90091/ch12s03.html#d0e11395\n    #   http://docs.hp.com/en/947/d8.html\n    # but we need to maintain compatibility here.\n    # The CMAKE_HP_PTHREADS setting actually indicates whether CMA threads\n    # are available.\n    CHECK_LIBRARY_EXISTS(cma pthread_attr_create \"\" CMAKE_HAVE_HP_CMA)\n    IF(CMAKE_HAVE_HP_CMA)\n      SET(CMAKE_THREAD_LIBS_INIT \"-lcma\")\n      SET(CMAKE_HP_PTHREADS_INIT 1)\n      SET(Threads_FOUND TRUE)\n    ENDIF(CMAKE_HAVE_HP_CMA)\n    SET(CMAKE_USE_PTHREADS_INIT 1)\n  ENDIF()\n\n  IF(CMAKE_SYSTEM MATCHES \"OSF1-V*\")\n    SET(CMAKE_USE_PTHREADS_INIT 0)\n    SET(CMAKE_THREAD_LIBS_INIT )\n  ENDIF()\n\n  IF(CMAKE_SYSTEM MATCHES \"CYGWIN_NT*\")\n    SET(CMAKE_USE_PTHREADS_INIT 1)\n    SET(Threads_FOUND TRUE)\n    SET(CMAKE_THREAD_LIBS_INIT )\n    SET(CMAKE_USE_WIN32_THREADS_INIT 0)\n  ENDIF()\nENDIF(CMAKE_USE_PTHREADS_INIT)\n\nINCLUDE(FindPackageHandleStandardArgs)\nIF(_Threads_ptwin32)\n  FIND_PACKAGE_HANDLE_STANDARD_ARGS(Threads DEFAULT_MSG\n    THREADS_PTHREADS_WIN32_LIBRARY THREADS_PTHREADS_INCLUDE_DIR)\nELSE()\n  FIND_PACKAGE_HANDLE_STANDARD_ARGS(Threads DEFAULT_MSG Threads_FOUND)\nENDIF()\n"
  },
  {
    "path": "cmake/Modules/Version.cmake",
    "content": "# Copyright 2013 OSMOCOM Project\n#\n# This file is part of rtl-sdr\n#\n# rtl-sdr is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation; either version 3, or (at your option)\n# any later version.\n#\n# rtl-sdr is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with rtl-sdr; see the file COPYING.  If not, write to\n# the Free Software Foundation, Inc., 51 Franklin Street,\n# Boston, MA 02110-1301, USA.\n\nif(DEFINED __INCLUDED_VERSION_CMAKE)\n    return()\nendif()\nset(__INCLUDED_VERSION_CMAKE TRUE)\n\n# VERSION_INFO_* variables must be provided by user\nset(MAJOR_VERSION ${VERSION_INFO_MAJOR_VERSION})\nset(MINOR_VERSION ${VERSION_INFO_MINOR_VERSION})\nset(PATCH_VERSION ${VERSION_INFO_PATCH_VERSION})\n\n########################################################################\n# Extract the version string from git describe.\n########################################################################\nfind_package(Git QUIET)\n\nif(GIT_FOUND AND EXISTS ${PROJECT_SOURCE_DIR}/.git)\n    message(STATUS \"Extracting version information from git describe...\")\n    execute_process(\n        COMMAND ${GIT_EXECUTABLE} describe --always --abbrev=4 --long\n        OUTPUT_VARIABLE GIT_DESCRIBE OUTPUT_STRIP_TRAILING_WHITESPACE\n        WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}\n    )\nelse()\n    set(GIT_DESCRIBE \"v${MAJOR_VERSION}.${MINOR_VERSION}.x-xxx-xunknown\")\nendif()\n\n########################################################################\n# Use the logic below to set the version constants\n########################################################################\nif(\"${PATCH_VERSION}\" STREQUAL \"git\")\n    # VERSION: 3.6git-xxx-gxxxxxxxx\n    # LIBVER:  3.6git\n    set(VERSION \"${GIT_DESCRIBE}\")\n    set(LIBVER  \"${MAJOR_VERSION}.${MINOR_VERSION}${PATCH_VERSION}\")\nelse()\n    # This is a numbered release.\n    # VERSION: 3.6.1\n    # LIBVER:  3.6.1\n    set(VERSION \"${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}\")\n    set(LIBVER \"${VERSION}\")\nendif()\n"
  },
  {
    "path": "cmake/cmake_uninstall.cmake.in",
    "content": "# http://www.vtk.org/Wiki/CMake_FAQ#Can_I_do_.22make_uninstall.22_with_CMake.3F\n\nIF(NOT EXISTS \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\")\n  MESSAGE(FATAL_ERROR \"Cannot find install manifest: \\\"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\\\"\")\nENDIF(NOT EXISTS \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\")\n\nFILE(READ \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\" files)\nSTRING(REGEX REPLACE \"\\n\" \";\" files \"${files}\")\nFOREACH(file ${files})\n  MESSAGE(STATUS \"Uninstalling \\\"$ENV{DESTDIR}${file}\\\"\")\n  IF(EXISTS \"$ENV{DESTDIR}${file}\")\n    EXEC_PROGRAM(\n      \"@CMAKE_COMMAND@\" ARGS \"-E remove \\\"$ENV{DESTDIR}${file}\\\"\"\n      OUTPUT_VARIABLE rm_out\n      RETURN_VALUE rm_retval\n      )\n    IF(NOT \"${rm_retval}\" STREQUAL 0)\n      MESSAGE(FATAL_ERROR \"Problem when removing \\\"$ENV{DESTDIR}${file}\\\"\")\n    ENDIF(NOT \"${rm_retval}\" STREQUAL 0)\n  ELSEIF(IS_SYMLINK \"$ENV{DESTDIR}${file}\")\n    EXEC_PROGRAM(\n      \"@CMAKE_COMMAND@\" ARGS \"-E remove \\\"$ENV{DESTDIR}${file}\\\"\"\n      OUTPUT_VARIABLE rm_out\n      RETURN_VALUE rm_retval\n      )\n    IF(NOT \"${rm_retval}\" STREQUAL 0)\n      MESSAGE(FATAL_ERROR \"Problem when removing \\\"$ENV{DESTDIR}${file}\\\"\")\n    ENDIF(NOT \"${rm_retval}\" STREQUAL 0)\n  ELSE(EXISTS \"$ENV{DESTDIR}${file}\")\n    MESSAGE(STATUS \"File \\\"$ENV{DESTDIR}${file}\\\" does not exist.\")\n  ENDIF(EXISTS \"$ENV{DESTDIR}${file}\")\nENDFOREACH(file)\n"
  },
  {
    "path": "configure.ac",
    "content": "AC_INIT([librtlsdr],\n        m4_esyscmd([./git-version-gen .tarball-version]),\n        [osmocom-sdr@lists.osmocom.org])\n\nAM_INIT_AUTOMAKE([dist-bzip2])\n\ndnl kernel style compile messages\nm4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])\n\ndnl checks for programs\nAC_PROG_MAKE_SET\nAC_PROG_CC\nAC_PROG_INSTALL\nAM_PROG_CC_C_O\nLT_INIT\nAC_PROG_LIBTOOL\n\nPKG_CHECK_MODULES(LIBUSB, libusb-1.0 >= 1.0)\nLIBS=\"$LIBS $LIBUSB_LIBS\"\nCFLAGS=\"$CFLAGS $LIBUSB_CFLAGS\"\n\nAC_PATH_PROG(DOXYGEN,doxygen,false)\nAM_CONDITIONAL(HAVE_DOXYGEN, test $DOXYGEN != false)\n\nAC_CONFIG_MACRO_DIR([m4])\n\ndnl checks for header files\nAC_HEADER_STDC\nAC_CHECK_HEADERS(sys/types.h)\nAC_CHECK_HEADERS(pthread.h,, [AC_MSG_ERROR([pthread.h required])])\n\n# pc variables\nAC_SUBST(RTLSDR_PC_LIBS,[\"$LIBS\"])\nAC_SUBST(RTLSDR_PC_CFLAGS,[\"$CFLAGS\"])\n\ndnl checks for required libraries\ndnl pthreads\nAC_CHECK_LIB(pthread, pthread_create, [LIBS=\"$LIBS -lpthread\"])\n\ndnl libmath (for rtl_fm)\nAC_CHECK_LIB(m, atan2, [LIBS=\"$LIBS -lm\"])\n\ndnl libmath (for rtl_adsb)\nAC_CHECK_LIB(m, sqrt, [LIBS=\"$LIBS -lm\"])\n\ndnl libmath (for rtl_power)\nAC_CHECK_LIB(m, atan2, [LIBS=\"$LIBS -lm\"])\n\ndnl librealtime (for rtl_test)\nAC_CHECK_LIB(rt, clock_gettime, [LIBS=\"$LIBS -lrt\"])\n\nAC_ARG_ENABLE(sanitize,\n\t\t[AS_HELP_STRING([--enable-sanitize], [Compile with address sanitizer enabled], )],\n\t\t[sanitize=$enableval], [sanitize=\"no\"])\nif test x\"$sanitize\" = x\"yes\"\nthen\n\tCFLAGS=\"$CFLAGS -fsanitize=address -fsanitize=undefined\"\n\tCPPFLAGS=\"$CPPFLAGS -fsanitize=address -fsanitize=undefined\"\nfi\n\nAC_ARG_ENABLE(werror,\n\t[AS_HELP_STRING(\n\t\t[--enable-werror],\n\t\t[Turn all compiler warnings into errors, with exceptions:\n\t\t a) deprecation (allow upstream to mark deprecation without breaking builds);\n\t\t b) \"#warning\" pragmas (allow to remind ourselves of errors without breaking builds)\n\t\t]\n\t)],\n\t[werror=$enableval], [werror=\"no\"])\nif test x\"$werror\" = x\"yes\"\nthen\n\tWERROR_FLAGS=\"-Werror\"\n\tWERROR_FLAGS+=\" -Wno-error=deprecated -Wno-error=deprecated-declarations\"\n\tWERROR_FLAGS+=\" -Wno-error=cpp\" # \"#warning\"\n\tCFLAGS=\"$CFLAGS $WERROR_FLAGS\"\n\tCPPFLAGS=\"$CPPFLAGS $WERROR_FLAGS\"\nfi\n\n# The following test is taken from WebKit's webkit.m4\nsaved_CFLAGS=\"$CFLAGS\"\nCFLAGS=\"$CFLAGS -fvisibility=hidden \"\nAC_MSG_CHECKING([if ${CC} supports -fvisibility=hidden])\nAC_COMPILE_IFELSE([AC_LANG_SOURCE([char foo;])],\n    [ AC_MSG_RESULT([yes])\n      SYMBOL_VISIBILITY=\"-fvisibility=hidden\"],\n      AC_MSG_RESULT([no]))\nCFLAGS=\"$saved_CFLAGS\"\nAC_SUBST(SYMBOL_VISIBILITY)\n\nAC_MSG_CHECKING(whether compiler understands -Wall)\nold_CFLAGS=\"$CFLAGS\"\nCFLAGS=\"$CFLAGS -Wall -Wextra -Wno-unused-parameter -Wno-unused -Wsign-compare -Wdeclaration-after-statement\"\nAC_TRY_COMPILE([],[],\n  AC_MSG_RESULT(yes),\n  AC_MSG_RESULT(no)\n  CFLAGS=\"$old_CFLAGS\")\n\nAC_ARG_ENABLE(driver-detach,\n[  --enable-driver-detach          Enable detaching of kernel driver (disabled by default)],\n[if test x$enableval = xyes; then\n    CFLAGS=\"$CFLAGS -DDETACH_KERNEL_DRIVER\"\nfi])\n\ndnl Generate the output\nAC_CONFIG_HEADER(config.h)\n\nAC_OUTPUT(\n\tlibrtlsdr.pc\n\tinclude/Makefile\n\tsrc/Makefile\n\tMakefile\n\tDoxyfile\n)\n"
  },
  {
    "path": "contrib/jenkins.sh",
    "content": "#!/usr/bin/env bash\n# jenkins build helper script for openbsc.  This is how we build on jenkins.osmocom.org\n\nif ! [ -x \"$(command -v osmo-build-dep.sh)\" ]; then\n\techo \"Error: We need to have scripts/osmo-deps.sh from http://git.osmocom.org/osmo-ci/ in PATH !\"\n\texit 2\nfi\n\n\nset -ex\n\nbase=\"$PWD\"\ndeps=\"$base/deps\"\ninst=\"$deps/install\"\nexport deps inst\n\nosmo-clean-workspace.sh\n\nmkdir \"$deps\" || true\n\nset +x\necho\necho\necho\necho \" =============================== rtl-sdr ===============================\"\necho\nset -x\n\ncd \"$base\"\nautoreconf --install --force\n./configure --enable-sanitize --enable-werror\n$MAKE $PARALLEL_MAKE\nLD_LIBRARY_PATH=\"$inst/lib\" $MAKE check \\\n  || cat-testlogs.sh\nLD_LIBRARY_PATH=\"$inst/lib\" \\\n  DISTCHECK_CONFIGURE_FLAGS=\"--enable-werror\" \\\n  $MAKE distcheck \\\n  || cat-testlogs.sh\n\nosmo-clean-workspace.sh\n"
  },
  {
    "path": "cross_build_mingw32.sh",
    "content": "#!/bin/bash\n\n# requires debian/ubuntu packages: zip gcc-mingw-w64\n\nREPO_DIR=$(pwd)\n\nif [ -z \"$1\" ]; then\n  echo \"usage: $0 <zip-post> <any other cmake options>\"\n  exit 1\nfi\n\nZIP_POST=\"$1\"\nshift\n\nCROSS=\"i686-w64-mingw32\"\nWN=\"w32\"\nTOOLCHAIN=\"mingw-w32-i686.cmake\"\n\n# libusb\nif /bin/true; then\n  cd ${REPO_DIR} && rm -rf libusb_${WN}\n  cd ${REPO_DIR} && git clone --branch v1.0.23 https://github.com/libusb/libusb.git libusb_${WN}\n  echo -e \"\\n\\n********************************************************\"\n  echo \"start build of libusb_${WN}\"\n  cd ${REPO_DIR}/libusb_${WN} && ./bootstrap.sh && \\\n    CC=${CROSS}-gcc \\\n    AR=${CROSS}-ar \\\n    RANLIB=${CROSS}-ranlib \\\n    ./configure --prefix=${REPO_DIR}/mingw_libusb_${WN} --host=${CROSS} --disable-shared && \\\n    make && make install\n    echo -e \"\\n\\nlisting of ${REPO_DIR}/mingw_libusb_${WN}\"\n    ls -alh ${REPO_DIR}/mingw_libusb_${WN}\n    echo -e \"\\nlisting of ${REPO_DIR}/mingw_libusb_${WN}/include\"\n    ls -alh ${REPO_DIR}/mingw_libusb_${WN}/include\n    echo -e \"\\nlisting of ${REPO_DIR}/mingw_libusb_${WN}/lib\"\n    ls -alh ${REPO_DIR}/mingw_libusb_${WN}/lib\n    echo -e \"\\n\"\nfi\n\n# librtlsdr\nif /bin/true; then\n  cd ${REPO_DIR} && rm -rf build_${WN}\n  echo -e \"\\n\\n********************************************************\"\n  echo \"start build of librtlsdr_${WN}\"\n  mkdir ${REPO_DIR}/build_${WN} && cd ${REPO_DIR}/build_${WN} && \\\n    cmake -DCMAKE_TOOLCHAIN_FILE=${REPO_DIR}/${TOOLCHAIN} \\\n      -DCMAKE_INSTALL_PREFIX=${REPO_DIR}/rtlsdr-bin-${WN}_${ZIP_POST} \\\n      -DRTL_STATIC_BUILD=ON \"$@\"  \\\n      -DLIBUSB_INCLUDE_DIR=${REPO_DIR}/mingw_libusb_${WN}/include/libusb-1.0 \\\n      -DLIBUSB_LIBRARIES=${REPO_DIR}/mingw_libusb_${WN}/lib/libusb-1.0.a \\\n      ../  && \\\n    make && make install\n  md5sum  ${REPO_DIR}/rtlsdr-bin-${WN}_${ZIP_POST}/bin/* >${REPO_DIR}/rtlsdr-bin-${WN}_${ZIP_POST}/bin/md5sums.txt\n  sha1sum ${REPO_DIR}/rtlsdr-bin-${WN}_${ZIP_POST}/bin/* >${REPO_DIR}/rtlsdr-bin-${WN}_${ZIP_POST}/bin/sha1sums.txt\nfi\n\n"
  },
  {
    "path": "cross_build_mingw64.sh",
    "content": "#!/bin/bash\n\n# requires debian/ubuntu packages: zip gcc-mingw-w64\n\nREPO_DIR=$(pwd)\n\nif [ -z \"$1\" ]; then\n  echo \"usage: $0 <zip-post> <any other cmake options>\"\n  exit 1\nfi\n\nZIP_POST=\"$1\"\nshift\n\nCROSS=\"x86_64-w64-mingw32\"\nWN=\"w64\"\nTOOLCHAIN=\"mingw-w64-x64_64.cmake\"\n\n# libusb\nif /bin/true; then\n  cd ${REPO_DIR} && rm -rf libusb_${WN}\n  cd ${REPO_DIR} && git clone --branch v1.0.23 https://github.com/libusb/libusb.git libusb_${WN}\n  echo -e \"\\n\\n********************************************************\"\n  echo \"start build of libusb_${WN}\"\n  cd ${REPO_DIR}/libusb_${WN} && ./bootstrap.sh && \\\n    CC=${CROSS}-gcc \\\n    AR=${CROSS}-ar \\\n    RANLIB=${CROSS}-ranlib \\\n    ./configure --prefix=${REPO_DIR}/mingw_libusb_${WN} --host=${CROSS} --disable-shared && \\\n    make && make install\n    echo -e \"\\n\\nlisting of ${REPO_DIR}/mingw_libusb_${WN}\"\n    ls -alh ${REPO_DIR}/mingw_libusb_${WN}\n    echo -e \"\\nlisting of ${REPO_DIR}/mingw_libusb_${WN}/include\"\n    ls -alh ${REPO_DIR}/mingw_libusb_${WN}/include\n    echo -e \"\\nlisting of ${REPO_DIR}/mingw_libusb_${WN}/lib\"\n    ls -alh ${REPO_DIR}/mingw_libusb_${WN}/lib\n    echo -e \"\\n\"\nfi\n\n# librtlsdr\nif /bin/true; then\n  cd ${REPO_DIR} && rm -rf build_${WN}\n  echo -e \"\\n\\n********************************************************\"\n  echo \"start build of librtlsdr_${WN}\"\n  mkdir ${REPO_DIR}/build_${WN} && cd ${REPO_DIR}/build_${WN} && \\\n    cmake -DCMAKE_TOOLCHAIN_FILE=${REPO_DIR}/${TOOLCHAIN} \\\n      -DCMAKE_INSTALL_PREFIX=${REPO_DIR}/rtlsdr-bin-${WN}_${ZIP_POST} \\\n      -DRTL_STATIC_BUILD=ON \"$@\"  \\\n      -DLIBUSB_INCLUDE_DIR=${REPO_DIR}/mingw_libusb_${WN}/include/libusb-1.0 \\\n      -DLIBUSB_LIBRARIES=${REPO_DIR}/mingw_libusb_${WN}/lib/libusb-1.0.a \\\n      ../  && \\\n    make && make install\n  md5sum  ${REPO_DIR}/rtlsdr-bin-${WN}_${ZIP_POST}/bin/* >${REPO_DIR}/rtlsdr-bin-${WN}_${ZIP_POST}/bin/md5sums.txt\n  sha1sum ${REPO_DIR}/rtlsdr-bin-${WN}_${ZIP_POST}/bin/* >${REPO_DIR}/rtlsdr-bin-${WN}_${ZIP_POST}/bin/sha1sums.txt\nfi\n\n"
  },
  {
    "path": "debian/.gitignore",
    "content": "*.deb\n"
  },
  {
    "path": "debian/README.Debian",
    "content": "rtl-sdr for Debian\n-------------------\n\nIn the beginning Antti Palosaari noticed that some digital video\nreceiver tuners can be turned into a cheap software defined radio.\n\nSince there is also support in the Linux kernel to use these devices\nas digital video receivers, by default the hardware will be claimed\nby Linux keernel drivers for that purpose.\n\nHaving these rtl-sdr packages installed likely means that these\ndevices should be available for the alternate software defined\nradio use.\n\nThe librtlsdr0 package in Debian has configuration files to\nhelp manage the conflicting uses:\n\n1. Blacklists DVB-T kernel modules provided by the Linux kernel\n-------------------------------------------------------------------\n\nConfig file:\n/etc/modprobe.d/librtlsdr-blacklist.conf\n\ncontains lines to blacklist dvb_usb_rtl28xxu, e4000 and rtl2832\nkernel modules.\n\nShould you wish to use a device via the Linux video receiver software\nwhile still having the librtlsdr0 package installed you may edit\nthis file. (Placing a # at the beginning os a line makes it a comment.)\n\nThen unplug/plug the USB stick.\n\nNot that if rtl-sdr applications are then run, they will complain about\nfailing to open the device. In that case, restore the blacklist and\nunplug/plug the USB stick.\n\nIf librtlsdr-blacklist.conf does not exist, then rtl-sdr was built\nwith the DETACH_KERNEL_DRIVER option.\n\n2. Permissions\n--------------\n\nDevices are available to users in the plugdev group.\n\nThe librtlsdr0 package installs these default rules:\n/lib/udev/rules.d/60-librtlsdr0.rules\n\nIf you have permissions issues, you may override these values\nwith your own rules in /etc:\n\n/etc/udev/rules.d/60-librtlsdr0.rules\n\nAfter editing udev rules, run as root: \n udevadm control --reload-rules\n\n"
  },
  {
    "path": "debian/changelog",
    "content": "rtl-sdr (0.7git) unstable; urgency=medium\n\n  * Accumulated changes from librtlsdr community\n\n -- Karl Semich <0xloem@gmail.com>  Wed, 03 Oct 2018 15:09:44 +0000\n\nrtl-sdr (0.6git) unstable; urgency=medium\n\n  * New upstream release\n\n -- Harald Welte <laforge@gnumonks.org>  Sun, 06 Jun 2018 15:09:42 +0200\n\nrtl-sdr (0.5.4-1) unstable; urgency=medium\n\n  * New upstream release\n  * update to v0.5.4-3-ga854ae8\n    use USB zero-copy transfers if possible\n\n -- A. Maitland Bottoms <bottoms@debian.org>  Sat, 12 May 2018 16:49:43 -0400\n\nrtl-sdr (0.5.3-14) unstable; urgency=medium\n\n  * update to v0.5.3-20-g4520f00 (Closes: #892974)\n  * minimal ipv6 support (Closes: #870804)\n  * VCS to salsa\n  * AppStream metadata.xml\n\n -- A. Maitland Bottoms <bottoms@debian.org>  Mon, 16 Apr 2018 20:45:53 -0400\n\nrtl-sdr (0.5.3-13) unstable; urgency=medium\n\n  * build with libusb-1.0-0-dev stub on hurd-i386\n  * initial ipv6 support for rtl_tcp...\n\n -- A. Maitland Bottoms <bottoms@debian.org>  Thu, 23 Nov 2017 15:59:40 -0500\n\nrtl-sdr (0.5.3-12) unstable; urgency=medium\n\n  * add new HanfTek dongle\n  * Bias T support (Closes: #854378, #842249)\n\n -- A. Maitland Bottoms <bottoms@debian.org>  Wed, 23 Aug 2017 23:31:27 -0400\n\nrtl-sdr (0.5.3-11) unstable; urgency=medium\n\n  * correct invocation of rm_conffile (Thanks Chris!) (Closes: #838161)\n  * drop uploaders line on advice of MIA team. (Closes: #836590)\n\n -- A. Maitland Bottoms <bottoms@debian.org>  Sat, 08 Oct 2016 11:17:47 -0400\n\nrtl-sdr (0.5.3-10) unstable; urgency=medium\n\n  * remove rtl-sdr-blacklist.conf on upgrade. Thanks Bob! (Closes: #829517)\n\n -- A. Maitland Bottoms <bottoms@debian.org>  Sat, 09 Jul 2016 23:38:24 -0400\n\nrtl-sdr (0.5.3-9) unstable; urgency=medium\n\n  * Edit of debian/librtlsdr0.udev in 0.5.3-8 was a no-op. Real fix\n    done to debian/patches/use-udev-uaccess-rules. (Closes: #825073)\n\n -- A. Maitland Bottoms <bottoms@debian.org>  Wed, 25 May 2016 17:19:57 -0400\n\nrtl-sdr (0.5.3-8) unstable; urgency=high\n\n  * Fix syntax errors for systemd-udevd in udev rules (Closes: #825073)\n\n -- A. Maitland Bottoms <bottoms@debian.org>  Tue, 24 May 2016 21:08:50 -0400\n\nrtl-sdr (0.5.3-7) unstable; urgency=medium\n\n  * better udev rules (more like camera devices in libgphoto2-6)\n\n -- A. Maitland Bottoms <bottoms@debian.org>  Tue, 10 May 2016 19:20:27 -0400\n\nrtl-sdr (0.5.3-6) unstable; urgency=medium\n\n  * Use ENV{ID_SOFTWARE_RADIO}=1 in udev rules (Closes: #823089)\n  * Enable DETACH_KERNEL_DRIVER (Closes: 823022)\n  * Make myself maintainer so I get the bug reports\n\n -- A. Maitland Bottoms <bottoms@debian.org>  Sun, 08 May 2016 12:12:13 -0400\n\nrtl-sdr (0.5.3-5) unstable; urgency=medium\n\n  * Add watch fiule\n  * place rtl-sdr -n comm section (Closes: #758077)\n  * improve-librtlsdr-pc-file (Closes: #784912)\n  * improve-scanning-range-parsing (LP: #1469478)\n\n -- A. Maitland Bottoms <bottoms@debian.org>  Sun, 23 Aug 2015 10:35:42 -0400\n\nrtl-sdr (0.5.3-4) unstable; urgency=low\n\n  * Update to v0.5.3-12-ge3c03f7\n\n -- A. Maitland Bottoms <bottoms@debian.org>  Sat, 08 Aug 2015 23:43:54 -0400\n\nrtl-sdr (0.5.3-3) unstable; urgency=low\n\n  * Update to v0.5.3-5-g6ee5573\n    lib: handle events after canceling transfers\n    lib: change default number of transfers to 15\n    rtl_tcp: make all global variables static\n\n -- A. Maitland Bottoms <bottoms@debian.org>  Sun, 13 Apr 2014 10:48:49 -0400\n\nrtl-sdr (0.5.3-2) unstable; urgency=low\n\n  * Upstream: lib: only print to stderr in tuner_r82xx_set_pll()\n  * Update man pages (New -M (modulation) and -E (option) and ppm setting)\n  * Have librtlsdr0 also install a blacklist for linux video drivers\n\n -- A. Maitland Bottoms <bottoms@debian.org>  Sat, 08 Feb 2014 22:40:06 -0500\n\nrtl-sdr (0.5.3-1) unstable; urgency=low\n\n  * New upstream git tag release\n\n -- A. Maitland Bottoms <bottoms@debian.org>  Thu, 06 Feb 2014 20:45:38 -0500\n\nrtl-sdr (0.5.2.7.3ab6-1~bpo70+1) wheezy-backports; urgency=low\n\n  * Rebuild for wheezy-backports.\n\n -- A. Maitland Bottoms <bottoms@debian.org>  Tue, 21 Jan 2014 19:34:16 -0500\n\nrtl-sdr (0.5.2.7.3ab6-1) unstable; urgency=low\n\n  * New upstream snapshot\n\n -- A. Maitland Bottoms <bottoms@debian.org>  Sun, 29 Dec 2013 21:37:19 -0500\n\nrtl-sdr (0.5.1.14.360d-1~wheezy) stable; urgency=low\n\n  * New upstream snapshot\n  * GNU Radio LiveDVD 2013-1110\n\n -- A. Maitland Bottoms <bottoms@debian.org>  Mon, 11 Nov 2013 12:46:00 -0500\n\nrtl-sdr (0.5.0.4.4914-2) unstable; urgency=low\n\n  * Use kfreebsd libusb\n\n -- A. Maitland Bottoms <bottoms@debian.org>  Fri, 01 Nov 2013 17:16:42 -0400\n\nrtl-sdr (0.5.0.4.4914-1) stable; urgency=low\n\n  * New upstream snapshot (Closes: #701018).\n  * Match GNU Radio live distribution version\n  * Sponsored upload\n\n -- A. Maitland Bottoms <bottoms@debian.org>  Sat, 28 Sep 2013 16:55:08 -0400\n\nrtl-sdr (0.5.0+git20130715-1) unstable; urgency=low\n\n  * Initial release (Closes: #701018).\n\n -- Adam Cécile (Le_Vert) <gandalf@le-vert.net>  Mon, 15 Jul 2013 15:51:05 +0200\n\nlibrtlsdr (0.0git3198f14-1) unstable; urgency=low\n\n  * New upstream git\n\n -- A. Maitland Bottoms <bottoms@debian.org>  Mon, 14 May 2012 20:28:18 -0400\n"
  },
  {
    "path": "debian/compat",
    "content": "9\n"
  },
  {
    "path": "debian/control",
    "content": "Source: rtl-sdr\nSection: comm\nPriority: optional\nMaintainer: A. Maitland Bottoms <bottoms@debian.org>\nBuild-Depends: cmake,\n               debhelper (>= 9.0.0~),\n               libusb-1.0-0-dev [linux-any],\n               libusb-dev [hurd-i386],\n               libusb2-dev [kfreebsd-any]\nStandards-Version: 4.1.4\nHomepage: http://sdr.osmocom.org/trac/wiki/rtl-sdr\nVcs-Browser: https://salsa.debian.org/bottoms/pkg-rtl-sdr\nVcs-Git: https://salsa.debian.org/bottoms/pkg-rtl-sdr.git\n\nPackage: librtlsdr-dev\nSection: libdevel\nArchitecture: any\nPre-Depends: ${misc:Pre-Depends}\nDepends: librtlsdr0 (= ${binary:Version}),\n         libusb-1.0-0-dev [!kfreebsd-any],\n         libusb2-dev [kfreebsd-any],\n         ${misc:Depends}\nDescription: Software defined radio receiver for Realtek RTL2832U (development)\n rtl-sdr is a software defined radio (SDR) receiver software for certain\n low-cost DVB-T/DAB(+) USB dongles based on the Realtek RTL2832U chip.\n .\n This package contains development files.\n\nPackage: librtlsdr0\nSection: libs\nArchitecture: any\nPre-Depends: ${misc:Pre-Depends}\nDepends: ${misc:Depends}, ${shlibs:Depends}\nMulti-Arch: same\nDescription: Software defined radio receiver for Realtek RTL2832U (library)\n rtl-sdr is a software defined radio (SDR) receiver software for certain\n low-cost DVB-T/DAB(+) USB dongles based on the Realtek RTL2832U chip.\n .\n This package contains the shared library.\n\nPackage: rtl-sdr\nArchitecture: any\nDepends: librtlsdr0 (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends}\nDescription: Software defined radio receiver for Realtek RTL2832U (tools)\n rtl-sdr is a software defined radio (SDR) receiver software for certain\n low-cost DVB-T/DAB(+) USB dongles based on the Realtek RTL2832U chip.\n .\n This package contains a set of command line utilities:\n  * rtl_adsb: a simple ADS-B decoder for RTL2832 based DVB-T receivers\n  * rtl_eeprom: an EEPROM programming tool for RTL2832 based DVB-T receivers\n  * rtl_fm: a narrow band FM demodulator for RTL2832 based DVB-T receivers\n  * rtl_sdr: an I/Q recorder for RTL2832 based DVB-T receivers\n  * rtl_tcp: an I/Q spectrum server for RTL2832 based DVB-T receivers\n  * rtl_test: a benchmark tool for RTL2832 based DVB-T receivers\n"
  },
  {
    "path": "debian/copyright",
    "content": "Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/\nUpstream-Name: rtl-sdr\nUpstream-Contact: http://sdr.osmocom.org/trac/wiki/rtl-sdr\nSource:\n git clone git://git.osmocom.org/rtl-sdr.git\n The upstream package source tarball was generated from the tag:\n git archive --format=tar --prefix=rtl-sdr-0.5.2.7.3ab6/ 3ab6ff | gzip > ../rtl-sdr_0.5.2.7.3ab6.orig.tar.gz\nComment:\n Debian packages sponsored by A. Maitland Bottoms,\n based upon packaging work by Adam Cécile.\n .\n Upstream Authors:\n Steve Markgraf <steve@steve-m.de>\n Dimitri Stolnikov <horiz0n@gmx.net>\n Hoernchen <la@tfc-server.de>\n Kyle Keen <keenerd@gmail.com>\nCopyright: 2012,2013 OSMOCOM Project\nLicense: GPL-2.0+\n\nFiles: *\nCopyright: 2012, 2013, OSMOCOM Project\nLicense: GPL-3+\n\nFiles: debian/*\nCopyright: 2013 Adam Cécile (Le_Vert) <gandalf@le-vert.net>\n           2012,2013 A. Maitland Bottoms <bottoms@debian.org>\nLicense: GPL-2.0+\n\nFiles: debian/librtlsdr0.udev\nCopyright: 2012, 2013, Osmocom rtl-sdr project\nLicense: GPL-3+\n\nFiles: debian/rtl_adsb.1\nCopyright: Copyright (c) 2013, A. Maitland Bottoms <bottoms@debian.org>\nLicense: GPL-2.0+\n\nFiles: debian/rtl_eeprom.1\n  debian/rtl_test.1\nCopyright: Copyright (c) 2013, A. Maitland Bottoms <bottoms@debian.org>\nLicense: GPL-2+\n\nFiles: git-version-gen\nCopyright: 2007-2010, Free Software Foundation, Inc.\nLicense: GPL-3+\n\nFiles: include/*\nCopyright: 2012, Steve Markgraf <steve@steve-m.de>\n  2012, Hans-Frieder Vogt <hfvogt@gmx.net>\nLicense: GPL-2+\n\nFiles: include/CMakeLists.txt\nCopyright: 2012, 2013, OSMOCOM Project\nLicense: GPL-3+\n\nFiles: include/rtl-sdr.h\nCopyright: 2012, Dimitri Stolnikov <horiz0n@gmx.net>\n  2012, 2013, Steve Markgraf <steve@steve-m.de>\nLicense: GPL-2+\n\nFiles: include/rtl-sdr_export.h\nCopyright: 2012, Hoernchen <la@tfc-server.de>\nLicense: GPL-2+\n\nFiles: include/tuner_e4k.h\nCopyright: 2012, Sylvain Munaut <tnt@246tNt.com>\n  2012, Hoernchen <la@tfc-server.de>\n  2011, 2012, Harald Welte <laforge@gnumonks.org>\nLicense: GPL-2+\n\nFiles: include/tuner_fc2580.h\nCopyright: Steve Markgraf <steve@steve-m.de>\nLicense: GPL-2.0+\n\nFiles: include/tuner_r82xx.h\nCopyright: 2013, Steve Markgraf <steve@steve-m.de>\n  2013, Mauro Carvalho Chehab <mchehab@redhat.com>\nLicense: GPL-2+\n\nFiles: rtl-sdr.rules\nCopyright: 2012, 2013, Osmocom rtl-sdr project\nLicense: GPL-3+\n\nFiles: src/*\nCopyright: 2012, Steve Markgraf <steve@steve-m.de>\nLicense: GPL-2+\n\nFiles: src/CMakeLists.txt\nCopyright: 2012, 2013, OSMOCOM Project\nLicense: GPL-3+\n\nFiles: src/Makefile.am\nCopyright: 2012 Steve Markgraf <steve@steve-m.de>\n           2012 Dimitri Stolnikov <horiz0n@gmx.net>\nLicense: GPL-2.0+\n\nFiles: src/convenience/*\nCopyright: 2014, Kyle Keen <keenerd@gmail.com>\nLicense: GPL-2+\n\nFiles: src/getopt/*\nCopyright: 88-96, 98, 99, 1987, 2000, 2001\nLicense: LGPL-2.1+\n\nFiles: src/getopt/getopt.h\nCopyright: 1989-1994, 1996-1999, 2001, Free Software Foundation, Inc.\nLicense: LGPL-2.1+\n\nFiles: src/librtlsdr.c\nCopyright: 2012-2014, Steve Markgraf <steve@steve-m.de>\n  2012, Dimitri Stolnikov <horiz0n@gmx.net>\nLicense: GPL-2+\n\nFiles: src/rtl_adsb.c\nCopyright: 2012, Youssef Touil <youssef@sdrsharp.com>\n  2012, Steve Markgraf <steve@steve-m.de>\n  2012, Kyle Keen <keenerd@gmail.com>\n  2012, Ian Gilmour <ian@sdrsharp.com>\n  2012, Hoernchen <la@tfc-server.de>\nLicense: GPL-2+\n\nFiles: src/rtl_fm.c\nCopyright: 2013, Elias Oenal <EliasOenal@gmail.com>\n  2012, Steve Markgraf <steve@steve-m.de>\n  2012, Kyle Keen <keenerd@gmail.com>\n  2012, Hoernchen <la@tfc-server.de>\nLicense: GPL-2+\n\nFiles: src/rtl_power.c\nCopyright: 2012, Steve Markgraf <steve@steve-m.de>\n  2012, Kyle Keen <keenerd@gmail.com>\n  2012, Hoernchen <la@tfc-server.de>\nLicense: GPL-2+\n\nFiles: src/rtl_tcp.c\nCopyright: 2012, Steve Markgraf <steve@steve-m.de>\n  2012, 2013, Hoernchen <la@tfc-server.de>\nLicense: GPL-2+\n\nFiles: src/rtl_test.c\nCopyright: 2014, Michael Tatarinov <kukabu@gmail.com>\n  2012-2014, Steve Markgraf <steve@steve-m.de>\n  2012-2014, Kyle Keen <keenerd@gmail.com>\nLicense: GPL-2+\n\nFiles: src/tuner_e4k.c\nCopyright: 2012, Sylvain Munaut <tnt@246tNt.com>\n  2012, Hoernchen <la@tfc-server.de>\n  2011, 2012, Harald Welte <laforge@gnumonks.org>\nLicense: GPL-2+\n\nFiles: src/tuner_fc0012.c\nCopyright: 2012, Steve Markgraf <steve@steve-m.de>\n  2012, Hans-Frieder Vogt <hfvogt@gmx.net>\nLicense: GPL-2+\n\nFiles: src/tuner_fc0013.c\nCopyright: 2012, Steve Markgraf <steve@steve-m.de>\n  2012, Hans-Frieder Vogt <hfvogt@gmx.net>\n  2010, Fitipower Integrated Technology Inc\nLicense: GPL-2+\n\nFiles: src/tuner_fc2580.c\nCopyright: Steve Markgraf <steve@steve-m.de>\n    Dimitri Stolnikov <horiz0n@gmx.net>\nLicense: GPL-2.0+\n\nFiles: src/tuner_r82xx.c\nCopyright: 2013, Steve Markgraf <steve@steve-m.de>\n  2013, Mauro Carvalho Chehab <mchehab@redhat.com>\nLicense: GPL-2+\n\nLicense: GPL-2+\n This program is free software; you can redistribute it and/or modify\n it under the terms of the GNU General Public License as published by\n the Free Software Foundation; version 2 dated June, 1991, or (at\n your option) any later version.\n .\n On Debian systems, the complete text of version 2 of the GNU General\n Public License can be found in '/usr/share/common-licenses/GPL-2'.\n\nLicense: GPL-2.0+\n This package is free software; you can redistribute it and/or modify\n it under the terms of the GNU General Public License as published by\n the Free Software Foundation; either version 2 of the License, or\n (at your option) any later version.\n .\n This package is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n GNU General Public License for more details.\n .\n You should have received a copy of the GNU General Public License\n along with this program. If not, see <http://www.gnu.org/licenses/>\n .\n On Debian systems, the complete text of the GNU General\n Public License version 2 can be found in \"/usr/share/common-licenses/GPL-2\".\n\nLicense: GPL-3+\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n .\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n GNU General Public License for more details.\n .\n You should have received a copy of the GNU General Public License\n along with this program.  If not, see <http://www.gnu.org/licenses/>.\n .\n On Debian systems, the complete text of the GNU Lesser General\n Public License can be found in \"/usr/share/common-licenses/GPL-3\".\n\nLicense: LGPL-2.1+\n This package is free software; you can redistribute it and/or\n modify it under the terms of the GNU Lesser General Public\n License as published by the Free Software Foundation; either\n version 2.1 of the License, or (at your option) any later version.\n .\n This package is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n Lesser General Public License for more details.\n .\n You should have received a copy of the GNU General Public License\n along with this program. If not, see <http://www.gnu.org/licenses/>.\n .\n On Debian systems, the complete text of the GNU Lesser General\n Public License can be found in \"/usr/share/common-licenses/LGPL-2\".\n"
  },
  {
    "path": "debian/copyright-scan-patterns.yml",
    "content": "ignore :\n  suffixes :\n   - in\n"
  },
  {
    "path": "debian/debianize_armhf",
    "content": "#!/bin/bash\n\nREPO_DIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )/../\"\n\nG_REV=`git rev-parse --short=8 HEAD`\nDATE=`date +\"%Y%m%d%H%M%S\"`\n#VERSION=\"0.5.3-git+${DATE}.${G_REV}~$1\"\nVERSION=`git describe | cut -dv -f2`\n#\n# librtlsdr0\n#\n\nrm -fr /tmp/librtlsdr0/\nmkdir -p /tmp/librtlsdr0/\nmkdir -p /tmp/librtlsdr0/usr/lib/arm-linux-gnueabihf/\nmkdir -p /tmp/librtlsdr0/DEBIAN\n\ncat <<- EOF > /tmp/librtlsdr0/DEBIAN/control\nPackage: librtlsdr0\nSource: rtl-sdr\nVersion: ${VERSION}\nArchitecture: armhf\nMaintainer: Lucas Teske <lucas@teske.net.br>\nPre-Depends: multiarch-support\nDepends: libc6 (>= 2.14), libusb-1.0-0 (>= 2:1.0.9)\nSection: libs\nPriority: extra\nMulti-Arch: same\nHomepage: http://sdr.osmocom.org/trac/wiki/rtl-sdr\nDescription: Software defined radio receiver for Realtek RTL2832U (library)\n rtl-sdr is a software defined radio (SDR) receiver software for certain\n low-cost DVB-T/DAB(+) USB dongles based on the Realtek RTL2832U chip.\n .\n This package contains the shared library.\nEOF\n\nDEB_PKG=\"librtlsdr0_${VERSION}_armhf.deb\"\n\ncp -rf ${REPO_DIR}/build/src/lib*so* /tmp/librtlsdr0/usr/lib/arm-linux-gnueabihf/\ndpkg-deb -b /tmp/librtlsdr0/ ./${DEB_PKG}\n\necho ${DEB_PKG}\n\n#\n# rtl-sdr\n#\n\nrm -fr /tmp/rtl-sdr/\nmkdir -p /tmp/rtl-sdr/\nmkdir -p /tmp/rtl-sdr/usr/bin/\nmkdir -p /tmp/rtl-sdr/DEBIAN\n\ncat <<- EOF > /tmp/rtl-sdr/DEBIAN/control\nPackage: rtl-sdr\nVersion: ${VERSION}\nArchitecture: armhf\nMaintainer: Lucas Teske <lucas@teske.net.br>\nDepends: librtlsdr0 (= ${VERSION}), libc6 (>= 2.15)\nSection: libs\nPriority: extra\nHomepage: http://sdr.osmocom.org/trac/wiki/rtl-sdr\nDescription: Software defined radio receiver for Realtek RTL2832U (tools)\n rtl-sdr is a software defined radio (SDR) receiver software for certain\n low-cost DVB-T/DAB(+) USB dongles based on the Realtek RTL2832U chip.\n .\n This package contains a set of command line utilities:\n  * rtl_adsb: a simple ADS-B decoder for RTL2832 based DVB-T receivers\n  * rtl_eeprom: an EEPROM programming tool for RTL2832 based DVB-T receivers\n  * rtl_fm: a narrow band FM demodulator for RTL2832 based DVB-T receivers\n  * rtl_sdr: an I/Q recorder for RTL2832 based DVB-T receivers\n  * rtl_tcp: an I/Q spectrum server for RTL2832 based DVB-T receivers\n  * rtl_test: a benchmark tool for RTL2832 based DVB-T receivers\n\n\nEOF\n\nDEB_PKG=\"rtl-sdr_${VERSION}_armhf.deb\"\n\ncp -rf ${REPO_DIR}/build/src/rtl_* /tmp/rtl-sdr/usr/bin/\ndpkg-deb -b /tmp/rtl-sdr/ ./${DEB_PKG}\n\necho ${DEB_PKG}\n\n\n#\n# librtlsdr-dev\n#\n\nrm -fr /tmp/librtlsdr-dev/\nmkdir -p /tmp/librtlsdr-dev/\nmkdir -p /tmp/librtlsdr-dev/usr/include\nmkdir -p /tmp/librtlsdr-dev/usr/lib/pkgconfig\nmkdir -p /tmp/librtlsdr-dev/DEBIAN\n\ncat <<- EOF > /tmp/librtlsdr-dev/DEBIAN/control\nPackage: librtlsdr-dev\nSource: rtl-sdr\nVersion: ${VERSION}\nArchitecture: armhf\nMaintainer: Lucas Teske <lucas@teske.net.br>\nPre-Depends: multiarch-support\nDepends: librtlsdr0 (= ${VERSION})\nSection: libdevel\nPriority: extra\nHomepage: http://sdr.osmocom.org/trac/wiki/rtl-sdr\nDescription: Software defined radio receiver for Realtek RTL2832U (development files)\n rtl-sdr is a software defined radio (SDR) receiver software for certain\n low-cost DVB-T/DAB(+) USB dongles based on the Realtek RTL2832U chip.\n .\n This package contains development files.\n\nEOF\n\nDEB_PKG=\"librtlsdr-dev_${VERSION}_armhf.deb\"\n\ncp -rf ${REPO_DIR}/include/*.h /tmp/librtlsdr-dev/usr/include\ncp ${REPO_DIR}/build/librtlsdr.pc /tmp/librtlsdr-dev/usr/lib/pkgconfig/\ndpkg-deb -b /tmp/librtlsdr-dev/ ./${DEB_PKG}\n\necho ${DEB_PKG}"
  },
  {
    "path": "debian/debianize_x32",
    "content": "#!/bin/bash\n\nREPO_DIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )/../\"\n\nG_REV=`git rev-parse --short=8 HEAD`\nDATE=`date +\"%Y%m%d%H%M%S\"`\n#VERSION=\"0.5.3-git+${DATE}.${G_REV}~$1\"\nVERSION=`git describe | cut -dv -f2`\n#\n# librtlsdr0\n#\n\nrm -fr /tmp/librtlsdr0/\nmkdir -p /tmp/librtlsdr0/\nmkdir -p /tmp/librtlsdr0/usr/lib/i386-linux-gnu/\nmkdir -p /tmp/librtlsdr0/DEBIAN\n\ncat <<- EOF > /tmp/librtlsdr0/DEBIAN/control\nPackage: librtlsdr0\nSource: rtl-sdr\nVersion: ${VERSION}\nArchitecture: i386\nMaintainer: Lucas Teske <lucas@teske.net.br>\nPre-Depends: multiarch-support\nDepends: libc6 (>= 2.14), libusb-1.0-0 (>= 2:1.0.9)\nSection: libs\nPriority: extra\nMulti-Arch: same\nHomepage: http://sdr.osmocom.org/trac/wiki/rtl-sdr\nDescription: Software defined radio receiver for Realtek RTL2832U (library)\n rtl-sdr is a software defined radio (SDR) receiver software for certain\n low-cost DVB-T/DAB(+) USB dongles based on the Realtek RTL2832U chip.\n .\n This package contains the shared library.\nEOF\n\nDEB_PKG=\"librtlsdr0_${VERSION}_i386.deb\"\n\ncp -rf ${REPO_DIR}/build/src/lib*so* /tmp/librtlsdr0/usr/lib/i386-linux-gnu/\ndpkg-deb -b /tmp/librtlsdr0/ ./${DEB_PKG}\n\necho ${DEB_PKG}\n\n#\n# rtl-sdr\n#\n\nrm -fr /tmp/rtl-sdr/\nmkdir -p /tmp/rtl-sdr/\nmkdir -p /tmp/rtl-sdr/usr/bin/\nmkdir -p /tmp/rtl-sdr/DEBIAN\n\ncat <<- EOF > /tmp/rtl-sdr/DEBIAN/control\nPackage: rtl-sdr\nVersion: ${VERSION}\nArchitecture: i386\nMaintainer: Lucas Teske <lucas@teske.net.br>\nDepends: librtlsdr0 (= ${VERSION}), libc6 (>= 2.15)\nSection: libs\nPriority: extra\nHomepage: http://sdr.osmocom.org/trac/wiki/rtl-sdr\nDescription: Software defined radio receiver for Realtek RTL2832U (tools)\n rtl-sdr is a software defined radio (SDR) receiver software for certain\n low-cost DVB-T/DAB(+) USB dongles based on the Realtek RTL2832U chip.\n .\n This package contains a set of command line utilities:\n  * rtl_adsb: a simple ADS-B decoder for RTL2832 based DVB-T receivers\n  * rtl_eeprom: an EEPROM programming tool for RTL2832 based DVB-T receivers\n  * rtl_fm: a narrow band FM demodulator for RTL2832 based DVB-T receivers\n  * rtl_sdr: an I/Q recorder for RTL2832 based DVB-T receivers\n  * rtl_tcp: an I/Q spectrum server for RTL2832 based DVB-T receivers\n  * rtl_test: a benchmark tool for RTL2832 based DVB-T receivers\n\n\nEOF\n\nDEB_PKG=\"rtl-sdr_${VERSION}_i386.deb\"\n\ncp -rf ${REPO_DIR}/build/src/rtl_* /tmp/rtl-sdr/usr/bin/\ndpkg-deb -b /tmp/rtl-sdr/ ./${DEB_PKG}\n\necho ${DEB_PKG}\n\n\n#\n# librtlsdr-dev\n#\n\nrm -fr /tmp/librtlsdr-dev/\nmkdir -p /tmp/librtlsdr-dev/\nmkdir -p /tmp/librtlsdr-dev/usr/include\nmkdir -p /tmp/librtlsdr-dev/usr/lib/pkgconfig\nmkdir -p /tmp/librtlsdr-dev/DEBIAN\n\ncat <<- EOF > /tmp/librtlsdr-dev/DEBIAN/control\nPackage: librtlsdr-dev\nSource: rtl-sdr\nVersion: ${VERSION}\nArchitecture: i386\nMaintainer: Lucas Teske <lucas@teske.net.br>\nPre-Depends: multiarch-support\nDepends: librtlsdr0 (= ${VERSION})\nSection: libdevel\nPriority: extra\nHomepage: http://sdr.osmocom.org/trac/wiki/rtl-sdr\nDescription: Software defined radio receiver for Realtek RTL2832U (development files)\n rtl-sdr is a software defined radio (SDR) receiver software for certain\n low-cost DVB-T/DAB(+) USB dongles based on the Realtek RTL2832U chip.\n .\n This package contains development files.\n\nEOF\n\nDEB_PKG=\"librtlsdr-dev_${VERSION}_i386.deb\"\n\ncp -rf ${REPO_DIR}/include/*.h /tmp/librtlsdr-dev/usr/include\ncp ${REPO_DIR}/build/librtlsdr.pc /tmp/librtlsdr-dev/usr/lib/pkgconfig/\ndpkg-deb -b /tmp/librtlsdr-dev/ ./${DEB_PKG}\n\necho ${DEB_PKG}"
  },
  {
    "path": "debian/debianize_x64",
    "content": "#!/bin/bash\n\nREPO_DIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )/../\"\n\nG_REV=`git rev-parse --short=8 HEAD`\nDATE=`date +\"%Y%m%d%H%M%S\"`\n#VERSION=\"0.5.3-git+${DATE}.${G_REV}~$1\"\nVERSION=`git describe | cut -dv -f2`\n#\n# librtlsdr0\n#\n\nrm -fr /tmp/librtlsdr0/\nmkdir -p /tmp/librtlsdr0/\nmkdir -p /tmp/librtlsdr0/usr/lib/x86_64-linux-gnu/\nmkdir -p /tmp/librtlsdr0/DEBIAN\n\ncat <<- EOF > /tmp/librtlsdr0/DEBIAN/control\nPackage: librtlsdr0\nSource: rtl-sdr\nVersion: ${VERSION}\nArchitecture: amd64\nMaintainer: Lucas Teske <lucas@teske.net.br>\nPre-Depends: multiarch-support\nDepends: libc6 (>= 2.14), libusb-1.0-0 (>= 2:1.0.9)\nSection: libs\nPriority: extra\nMulti-Arch: same\nHomepage: http://sdr.osmocom.org/trac/wiki/rtl-sdr\nDescription: Software defined radio receiver for Realtek RTL2832U (library)\n rtl-sdr is a software defined radio (SDR) receiver software for certain\n low-cost DVB-T/DAB(+) USB dongles based on the Realtek RTL2832U chip.\n .\n This package contains the shared library.\nEOF\n\nDEB_PKG=\"librtlsdr0_${VERSION}_amd64.deb\"\n\ncp -rf ${REPO_DIR}/build/src/lib*so* /tmp/librtlsdr0/usr/lib/x86_64-linux-gnu/\ndpkg-deb -b /tmp/librtlsdr0/ ./${DEB_PKG}\n\necho ${DEB_PKG}\n\n#\n# rtl-sdr\n#\n\nrm -fr /tmp/rtl-sdr/\nmkdir -p /tmp/rtl-sdr/\nmkdir -p /tmp/rtl-sdr/usr/bin/\nmkdir -p /tmp/rtl-sdr/DEBIAN\n\ncat <<- EOF > /tmp/rtl-sdr/DEBIAN/control\nPackage: rtl-sdr\nVersion: ${VERSION}\nArchitecture: amd64\nMaintainer: Lucas Teske <lucas@teske.net.br>\nDepends: librtlsdr0 (= ${VERSION}), libc6 (>= 2.15)\nSection: libs\nPriority: extra\nHomepage: http://sdr.osmocom.org/trac/wiki/rtl-sdr\nDescription: Software defined radio receiver for Realtek RTL2832U (tools)\n rtl-sdr is a software defined radio (SDR) receiver software for certain\n low-cost DVB-T/DAB(+) USB dongles based on the Realtek RTL2832U chip.\n .\n This package contains a set of command line utilities:\n  * rtl_adsb: a simple ADS-B decoder for RTL2832 based DVB-T receivers\n  * rtl_eeprom: an EEPROM programming tool for RTL2832 based DVB-T receivers\n  * rtl_fm: a narrow band FM demodulator for RTL2832 based DVB-T receivers\n  * rtl_sdr: an I/Q recorder for RTL2832 based DVB-T receivers\n  * rtl_tcp: an I/Q spectrum server for RTL2832 based DVB-T receivers\n  * rtl_test: a benchmark tool for RTL2832 based DVB-T receivers\n\n\nEOF\n\nDEB_PKG=\"rtl-sdr_${VERSION}_amd64.deb\"\n\ncp -rf ${REPO_DIR}/build/src/rtl_* /tmp/rtl-sdr/usr/bin/\ndpkg-deb -b /tmp/rtl-sdr/ ./${DEB_PKG}\n\necho ${DEB_PKG}\n\n\n#\n# librtlsdr-dev\n#\n\nrm -fr /tmp/librtlsdr-dev/\nmkdir -p /tmp/librtlsdr-dev/\nmkdir -p /tmp/librtlsdr-dev/usr/include\nmkdir -p /tmp/librtlsdr-dev/usr/lib/pkgconfig\nmkdir -p /tmp/librtlsdr-dev/DEBIAN\n\ncat <<- EOF > /tmp/librtlsdr-dev/DEBIAN/control\nPackage: librtlsdr-dev\nSource: rtl-sdr\nVersion: ${VERSION}\nArchitecture: amd64\nMaintainer: Lucas Teske <lucas@teske.net.br>\nPre-Depends: multiarch-support\nDepends: librtlsdr0 (= ${VERSION})\nSection: libdevel\nPriority: extra\nHomepage: http://sdr.osmocom.org/trac/wiki/rtl-sdr\nDescription: Software defined radio receiver for Realtek RTL2832U (development files)\n rtl-sdr is a software defined radio (SDR) receiver software for certain\n low-cost DVB-T/DAB(+) USB dongles based on the Realtek RTL2832U chip.\n .\n This package contains development files.\n\nEOF\n\nDEB_PKG=\"librtlsdr-dev_${VERSION}_amd64.deb\"\n\ncp -rf ${REPO_DIR}/include/*.h /tmp/librtlsdr-dev/usr/include\ncp ${REPO_DIR}/build/librtlsdr.pc /tmp/librtlsdr-dev/usr/lib/pkgconfig/\ndpkg-deb -b /tmp/librtlsdr-dev/ ./${DEB_PKG}\n\necho ${DEB_PKG}"
  },
  {
    "path": "debian/heatmap.py",
    "content": "#! /usr/bin/env python2\n\nfrom PIL import Image, ImageDraw, ImageFont\nimport sys, gzip, math, colorsys, datetime\nfrom collections import defaultdict\nfrom itertools import *\n\n# todo: matplotlib powered --interactive\n# arbitrary freq marker spacing\n\npath = sys.argv[1]\noutput = sys.argv[2]\n\nraw_data = lambda: open(path)\nif path.endswith('.gz'):\n    raw_data = lambda: gzip.open(path, 'rb')\n\ndef frange(start, stop, step):\n    i = 0\n    while (i*step + start <= stop):\n        yield i*step + start\n        i += 1\n\nprint(\"loading\")\n\nfreqs = set()\nf_cache = set()\ntimes = set()\nlabels = set()\nmin_z = 0\nmax_z = -100\nstart, stop = None, None\nfor line in raw_data():\n    line = [s.strip() for s in line.strip().split(',')]\n    line = [line[0], line[1]] + [float(s) for s in line[2:] if s]\n\n    low = line[2]\n    high = line[3]\n    step = line[4]\n    f_key = (int(low), int(high), step)\n    if f_key not in f_cache:\n        freqs.update(list(frange(int(low), int(high), step)))\n        freqs.add(high)\n        labels.add(low)\n        f_cache.add(f_key)\n\n    t = line[0] + ' ' + line[1]\n    times.add(t)\n\n    zs = line[6:]\n    min_z = min(min_z, min(z for z in zs if not math.isinf(z)))\n    max_z = max(max_z, max(zs))\n\n    if start is None:\n        start = datetime.datetime.strptime(line[0] + ' ' + line[1], '%Y-%m-%d %H:%M:%S')\n    stop = datetime.datetime.strptime(line[0] + ' ' + line[1], '%Y-%m-%d %H:%M:%S')\n\nfreqs = list(sorted(list(freqs)))\ntimes = list(sorted(list(times)))\nlabels = list(sorted(list(labels)))\n\nif len(labels) == 1:\n    delta = (max(freqs) - min(freqs)) / (len(freqs) / 500)\n    delta = round(delta / 10**int(math.log10(delta))) * 10**int(math.log10(delta))\n    delta = int(delta)\n    lower = int(math.ceil(min(freqs) / delta) * delta)\n    labels = list(range(lower, int(max(freqs)), delta))\n\nprint(\"x: %i, y: %i, z: (%f, %f)\" % (len(freqs), len(times), min_z, max_z))\n\ndef rgb2(z):\n    g = (z - min_z) / (max_z - min_z)\n    return (int(g*255), int(g*255), 50)\n\ndef rgb3(z):\n    g = (z - min_z) / (max_z - min_z)\n    c = colorsys.hsv_to_rgb(0.65-(g-0.08), 1, 0.2+g)\n    return (int(c[0]*256),int(c[1]*256),int(c[2]*256))\n\nprint(\"drawing\")\nimg = Image.new(\"RGB\", (len(freqs), len(times)))\npix = img.load()\nx_size = img.size[0]\nfor line in raw_data():\n    line = [s.strip() for s in line.strip().split(',')]\n    line = [line[0], line[1]] + [float(s) for s in line[2:] if s]\n    t = line[0] + ' ' + line[1]\n    if t not in times:\n        continue  # happens with live files\n    y = times.index(t)\n    low = line[2]\n    high = line[3]\n    step = line[4]\n    x_start = freqs.index(low)\n    for i in range(len(line[6:])):\n        x = x_start + i\n        if x >= x_size:\n            continue\n        z = line[6+i]\n        # fast check for nan/-inf\n        if not z >= min_z:\n            z = min_z\n        pix[x,y] = rgb2(z)\n\nprint(\"labeling\")\ndraw = ImageDraw.Draw(img)\nfont = ImageFont.load_default()\npixel_width = step\nfor label in labels:\n    y = 10\n    #x = freqs.index(label)\n    x = int((label-min(freqs)) / pixel_width)\n    s = '%.3fMHz' % (label/1000000.0)\n    draw.text((x, y), s, font=font, fill='white')\n\nduration = stop - start\nduration = duration.seconds\npixel_height = duration / len(times)\nhours = int(duration / 3600)\nminutes = int((duration - 3600*hours) / 60)\ndraw.text((2, img.size[1] - 45), 'Duration: %i:%02i' % (hours, minutes), font=font, fill='white')\ndraw.text((2, img.size[1] - 35), 'Range: %.2fMHz - %.2fMHz' % (min(freqs)/1e6, max(freqs)/1e6), font=font, fill='white')\ndraw.text((2, img.size[1] - 25), 'Pixel: %.2fHz x %is' % (pixel_width, int(round(pixel_height))), font=font, fill='white')\ndraw.text((2, img.size[1] - 15), 'Started: {0}'.format(start), font=font, fill='white')\n# bin size\n\nprint(\"saving\")\nimg.save(output)\n\n\n\n\n\n\n"
  },
  {
    "path": "debian/librtlsdr-dev.dirs",
    "content": "usr/lib\nusr/include\n"
  },
  {
    "path": "debian/librtlsdr-dev.install",
    "content": "usr/include/*\nusr/lib/*/lib*.a\nusr/lib/*/lib*.so\nusr/lib/*/pkgconfig/*\n"
  },
  {
    "path": "debian/librtlsdr0.dirs",
    "content": "etc/modprobe.d\nusr/lib\n"
  },
  {
    "path": "debian/librtlsdr0.install",
    "content": "usr/lib/*/lib*.so.*\ndebian/librtlsdr0.metainfo.xml usr/share/metainfo\n"
  },
  {
    "path": "debian/librtlsdr0.maintscript",
    "content": "rm_conffile /etc/modprobe.d/rtl-sdr-blacklist.conf 0.5.3-10~\n"
  },
  {
    "path": "debian/librtlsdr0.metainfo.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<component>\n  <id>librtlsdr0</id>\n  <metadata_license>GPL-2+</metadata_license>\n  <name>librtlsdr0</name>\n  <summary>Control of rtl-sdr radio receiver</summary>\n  <description>\n    <p>\nrtl-sdr is a software defined radio (SDR) receiver software for certain\nlow-cost DVB-T/DAB(+) USB dongles based on the Realtek RTL2832U chip.\n    </p>\n  </description>\n  <provides>\n    <modalias>usb:v0BDAp2832d*</modalias>\n    <modalias>usb:v0BDAp2838d*</modalias>\n    <modalias>usb:v0413p6680d*</modalias>\n    <modalias>usb:v0413p6F0Fd*</modalias>\n    <modalias>usb:v0458p707Fd*</modalias>\n    <modalias>usb:v0CCDp00A9d*</modalias>\n    <modalias>usb:v0CCDp00B3d*</modalias>\n    <modalias>usb:v0CCDp00B4d*</modalias>\n    <modalias>usb:v0CCDp00B5d*</modalias>\n    <modalias>usb:v0CCDp00B7d*</modalias>\n    <modalias>usb:v0CCDp00B8d*</modalias>\n    <modalias>usb:v0CCDp00B9d*</modalias>\n    <modalias>usb:v0CCDp00C0d*</modalias>\n    <modalias>usb:v0CCDp00C6d*</modalias>\n    <modalias>usb:v0CCDp00D3d*</modalias>\n    <modalias>usb:v0CCDp00D7d*</modalias>\n    <modalias>usb:v0CCDp00E0d*</modalias>\n    <modalias>usb:v1554p5020d*</modalias>\n    <modalias>usb:v15F4p0131d*</modalias>\n    <modalias>usb:v15F4p0133d*</modalias>\n    <modalias>usb:v185Bp0620d*</modalias>\n    <modalias>usb:v185Bp0650d*</modalias>\n    <modalias>usb:v185Bp0680d*</modalias>\n    <modalias>usb:v1B80pD393d*</modalias>\n    <modalias>usb:v1B80pD394d*</modalias>\n    <modalias>usb:v1B80pD395d*</modalias>\n    <modalias>usb:v1B80pD397d*</modalias>\n    <modalias>usb:v1B80pD398d*</modalias>\n    <modalias>usb:v1B80pD39Dd*</modalias>\n    <modalias>usb:v1B80pD3A4d*</modalias>\n    <modalias>usb:v1B80pD3A8d*</modalias>\n    <modalias>usb:v1B80pD3AFd*</modalias>\n    <modalias>usb:v1B80pD3B0d*</modalias>\n    <modalias>usb:v1D19p1101d*</modalias>\n    <modalias>usb:v1D19p1102d*</modalias>\n    <modalias>usb:v1D19p1103d*</modalias>\n    <modalias>usb:v1D19p1104d*</modalias>\n    <modalias>usb:v1F4DpA803d*</modalias>\n    <modalias>usb:v1F4DpB803d*</modalias>\n    <modalias>usb:v1F4DpC803d*</modalias>\n    <modalias>usb:v1F4DpD286d*</modalias>\n    <modalias>usb:v1F4DpD803d*</modalias>\n  </provides>\n</component>\n"
  },
  {
    "path": "debian/librtlsdr0.udev",
    "content": "#\n# Copyright 2012-2013 Osmocom rtl-sdr project\n#\n# This program is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#\n\n# original RTL2832U vid/pid (hama nano, for example)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0bda\", ATTRS{idProduct}==\"2832\", MODE:=\"0666\"\n\n# RTL2832U OEM vid/pid, e.g. ezcap EzTV668 (E4000), Newsky TV28T (E4000/R820T) etc.\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0bda\", ATTRS{idProduct}==\"2838\", MODE:=\"0666\"\n\n# DigitalNow Quad DVB-T PCI-E card (4x FC0012?)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0413\", ATTRS{idProduct}==\"6680\", MODE:=\"0666\"\n\n# Leadtek WinFast DTV Dongle mini D (FC0012)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0413\", ATTRS{idProduct}==\"6f0f\", MODE:=\"0666\"\n\n# Genius TVGo DVB-T03 USB dongle (Ver. B)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0458\", ATTRS{idProduct}==\"707f\", MODE:=\"0666\"\n\n# Terratec Cinergy T Stick Black (rev 1) (FC0012)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0ccd\", ATTRS{idProduct}==\"00a9\", MODE:=\"0666\"\n\n# Terratec NOXON rev 1 (FC0013)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0ccd\", ATTRS{idProduct}==\"00b3\", MODE:=\"0666\"\n\n# Terratec Deutschlandradio DAB Stick (FC0013)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0ccd\", ATTRS{idProduct}==\"00b4\", MODE:=\"0666\"\n\n# Terratec NOXON DAB Stick - Radio Energy (FC0013)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0ccd\", ATTRS{idProduct}==\"00b5\", MODE:=\"0666\"\n\n# Terratec Media Broadcast DAB Stick (FC0013)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0ccd\", ATTRS{idProduct}==\"00b7\", MODE:=\"0666\"\n\n# Terratec BR DAB Stick (FC0013)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0ccd\", ATTRS{idProduct}==\"00b8\", MODE:=\"0666\"\n\n# Terratec WDR DAB Stick (FC0013)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0ccd\", ATTRS{idProduct}==\"00b9\", MODE:=\"0666\"\n\n# Terratec MuellerVerlag DAB Stick (FC0013)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0ccd\", ATTRS{idProduct}==\"00c0\", MODE:=\"0666\"\n\n# Terratec Fraunhofer DAB Stick (FC0013)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0ccd\", ATTRS{idProduct}==\"00c6\", MODE:=\"0666\"\n\n# Terratec Cinergy T Stick RC (Rev.3) (E4000)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0ccd\", ATTRS{idProduct}==\"00d3\", MODE:=\"0666\"\n\n# Terratec T Stick PLUS (E4000)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0ccd\", ATTRS{idProduct}==\"00d7\", MODE:=\"0666\"\n\n# Terratec NOXON rev 2 (E4000)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0ccd\", ATTRS{idProduct}==\"00e0\", MODE:=\"0666\"\n\n# PixelView PV-DT235U(RN) (FC0012)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1554\", ATTRS{idProduct}==\"5020\", MODE:=\"0666\"\n\n# Astrometa DVB-T/DVB-T2 (R828D)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"15f4\", ATTRS{idProduct}==\"0131\", MODE:=\"0666\"\n\n# HanfTek DAB+FM+DVB-T\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"15f4\", ATTRS{idProduct}==\"0133\", MODE:=\"0666\"\n\n# Compro Videomate U620F (E4000)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"185b\", ATTRS{idProduct}==\"0620\", MODE:=\"0666\"\n\n# Compro Videomate U650F (E4000)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"185b\", ATTRS{idProduct}==\"0650\", MODE:=\"0666\"\n\n# Compro Videomate U680F (E4000)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"185b\", ATTRS{idProduct}==\"0680\", MODE:=\"0666\"\n\n# GIGABYTE GT-U7300 (FC0012)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1b80\", ATTRS{idProduct}==\"d393\", MODE:=\"0666\"\n\n# DIKOM USB-DVBT HD\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1b80\", ATTRS{idProduct}==\"d394\", MODE:=\"0666\"\n\n# Peak 102569AGPK (FC0012)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1b80\", ATTRS{idProduct}==\"d395\", MODE:=\"0666\"\n\n# KWorld KW-UB450-T USB DVB-T Pico TV (TUA9001)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1b80\", ATTRS{idProduct}==\"d397\", MODE:=\"0666\"\n\n# Zaapa ZT-MINDVBZP (FC0012)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1b80\", ATTRS{idProduct}==\"d398\", MODE:=\"0666\"\n\n# SVEON STV20 DVB-T USB & FM (FC0012)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1b80\", ATTRS{idProduct}==\"d39d\", MODE:=\"0666\"\n\n# Twintech UT-40 (FC0013)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1b80\", ATTRS{idProduct}==\"d3a4\", MODE:=\"0666\"\n\n# ASUS U3100MINI_PLUS_V2 (FC0013)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1b80\", ATTRS{idProduct}==\"d3a8\", MODE:=\"0666\"\n\n# SVEON STV27 DVB-T USB & FM (FC0013)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1b80\", ATTRS{idProduct}==\"d3af\", MODE:=\"0666\"\n\n# SVEON STV21 DVB-T USB & FM\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1b80\", ATTRS{idProduct}==\"d3b0\", MODE:=\"0666\"\n\n# Dexatek DK DVB-T Dongle (Logilink VG0002A) (FC2580)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1d19\", ATTRS{idProduct}==\"1101\", MODE:=\"0666\"\n\n# Dexatek DK DVB-T Dongle (MSI DigiVox mini II V3.0)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1d19\", ATTRS{idProduct}==\"1102\", MODE:=\"0666\"\n\n# Dexatek DK 5217 DVB-T Dongle (FC2580)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1d19\", ATTRS{idProduct}==\"1103\", MODE:=\"0666\"\n\n# MSI DigiVox Micro HD (FC2580)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1d19\", ATTRS{idProduct}==\"1104\", MODE:=\"0666\"\n\n# Sweex DVB-T USB (FC0012)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1f4d\", ATTRS{idProduct}==\"a803\", MODE:=\"0666\"\n\n# GTek T803 (FC0012)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1f4d\", ATTRS{idProduct}==\"b803\", MODE:=\"0666\"\n\n# Lifeview LV5TDeluxe (FC0012)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1f4d\", ATTRS{idProduct}==\"c803\", MODE:=\"0666\"\n\n# MyGica TD312 (FC0012)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1f4d\", ATTRS{idProduct}==\"d286\", MODE:=\"0666\"\n\n# PROlectrix DV107669 (FC0012)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1f4d\", ATTRS{idProduct}==\"d803\", MODE:=\"0666\"\n"
  },
  {
    "path": "debian/rtl-sdr-blacklist.conf",
    "content": "# This system has librtlsdr0 installed in order to\n# use digital video broadcast receivers as generic\n# software defined radios.\nblacklist dvb_usb_rtl28xxu\nblacklist e4000\nblacklist rtl2832\n"
  },
  {
    "path": "debian/rtl-sdr.dirs",
    "content": "usr/bin\n"
  },
  {
    "path": "debian/rtl-sdr.examples",
    "content": "debian/heatmap.py\n"
  },
  {
    "path": "debian/rtl-sdr.install",
    "content": "usr/bin/*\n"
  },
  {
    "path": "debian/rtl-sdr.manpages",
    "content": "debian/rtl_adsb.1\ndebian/rtl_eeprom.1\ndebian/rtl_fm.1\ndebian/rtl_power.1\ndebian/rtl_sdr.1\ndebian/rtl_tcp.1\ndebian/rtl_test.1\n"
  },
  {
    "path": "debian/rtl_adsb.1",
    "content": ".TH \"rtl_adsb\" 1 \"0.5.0\" RTL-SDR \"User Commands\"\n.SH NAME\nrtl_adsb \\- a simple ADS-B decoder\n.SH DESCRIPTION\nUses a re-purposed DVB-T receiver as a software defined\nradio to receive and decode ADS-B data.\tWritten by Kyle Keen\nand incorporated in the osmocom rtl-sdr project.\n.LP\nAutomatic dependent surveillance-broadcast, ADS-B, consists\nof position and other status data transmitted by aircraft\nin support of air traffic control in order to improve safety\nof flight.\n.LP\nMuch software is available for the RTL2832. Most of the user-level\npackages rely on the librtlsdr library which comes as part of the\nrtl-sdr codebase. This codebase contains both the library itself and\nalso a number of command line tools such as rtl_test, rtl_sdr,\nrtl_tcp, and rtl_fm. These command line tools use the library to test\nfor the existence of RTL2832 devices and to perform basic data\ntransfer functions to and from the device.\n.LP\nBecause most of the RTL2832 devices are connected using USB, the\nlibrtlsdr library depends on the libusb library to communicate with\nthe device.\n.SH USAGE\nWith a suitable antenna for receiving the 1090 MHz signal attached\nto the rtl-sdr supported device, this program will output the\ndata decoded from that signal.\n.SH SYNOPSIS\n.B  rtl_adsb [-R] [-g gain] [-p ppm] [output file]\n.SH OPTIONS\n.IP \"-d device_index (default: 0)\"\n.IP \"-V verbove output (default: off)\"\n.IP \"-S show short frames (default: off)\"\n.IP \"-Q quality (0: no sanity checks, 0.5: half bit, 1: one bit (default), 2: two bits)\"\n.IP \"-e allowed_errors (default: 5)\"\n.IP \"-g tuner_gain (default: automatic)\"\n.IP \"-p ppm_error (default: 0)\"\n.IP tfilename\n (a '-' dumps samples to stdout)\n (omitting the filename also uses stdout)\n.SH EXAMPLES\n.IP \"Streaming with netcat:\"\n  rtl_adsb | netcat -lp 8080\n\n  while true; do rtl_adsb | nc -lp 8080; done\n.IP \"Streaming with socat:\"\n  rtl_adsb | socat -u - TCP4:sdrsharp.com:47806\n.SH SEE ALSO\nRTL-SDR wiki documentation:\n.B http://sdr.osmocom.org/trac/wiki/rtl-sdr\n.LP\nOther rtl-sdr programs:\n.sp\nrtl_eeprom(1), rtl_fm(1), rtl_sdr(1), rtl_tcp(1), rtl_test(1)\n.SH AUTHOR\nThis manual page was written by Maitland Bottoms\nfor the Debian project (but may be used by others).\n.SH COPYRIGHT\nCopyright (c) 2013 A. Maitland Bottoms <bottoms@debian.org>\n.LP\nThis program is free software: you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 2 of the License, or\n(at your option) any later version.\n.LP\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n"
  },
  {
    "path": "debian/rtl_eeprom.1",
    "content": ".TH \"rtl_eeprom\" 1 \"0.5.0\" RTL-SDR \"User Commands\"\n.SH NAME\nrtl-eeprom \\- EEPROM programming tool for RTL2832 based DVB-T receivers\n.SH DESCRIPTION\nDumps configuration and also writes EEPROM configuration.\nWritten by Steve Markgraf and incorporated in the osmocom rtl-sdr project.\n.LP\nUse at your own risk, especially -w!\n.LP\nMuch software is available for the RTL2832. Most of the user-level\npackages rely on the librtlsdr library which comes as part of the\nrtl-sdr codebase. This codebase contains both the library itself and\nalso a number of command line tools such as rtl_test, rtl_sdr,\nrtl_tcp, and rtl_fm. These command line tools use the library to test\nfor the existence of RTL2832 devices and to perform basic data\ntransfer functions to and from the device.\n.LP\nBecause most of the RTL2832 devices are connected using USB, the\nlibrtlsdr library depends on the libusb library to communicate with\nthe device.\n.SH USAGE\nWriting bad information to the EEPROM will make your\ndevice useless. \n.SH SYNOPSIS\n.B  rtl_eeprom [OPTIONS]\n.SH OPTIONS\n.IP \"-d device_index (default: 0)\"\n.IP \"-m <str> set manufacturer string\"\n.IP \"-p <str> set product string\"\n.IP \"-s <str> set serial number string\"\n.IP \"-i <0,1> disable/enable IR-endpoint\"\n.IP \"-g <conf> generate default config and write to device\"\n   <conf> can be one of:\n   realtek  Realtek default (as without EEPROM)\n   realtek_oem  Realtek default OEM with EEPROM\n   noxon  Terratec NOXON DAB Stick\n   terratec_black  Terratec T Stick Black\n   terratec_plus  Terratec T Stick+ (DVB-T/DAB)\n.IP \"-w <filename> write dumped file to device\"\n.IP \"-r <filename> dump EEPROM to file\"\n.IP \"-h display this help text\"\n.LP\nUse on your own risk, especially -w!\n.SH SEE ALSO\nRTL-SDR wiki documentation:\n.B http://sdr.osmocom.org/trac/wiki/rtl-sdr\n.LP\nOther rtl-sdr programs:\n.sp\nrtl_adsb(1), rtl_fm(1), rtl_sdr(1), rtl_tcp(1), rtl_test(1)\n.SH AUTHOR\nThis manual page was written by Maitland Bottoms\nfor the Debian project (but may be used by others).\n.SH COPYRIGHT\nCopyright (c) 2013 A. Maitland Bottoms <bottoms@debian.org>\n.LP\nThis program is free software: you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 2 of the License, or\n(at your option) any later version.\n.LP\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n"
  },
  {
    "path": "debian/rtl_fm.1",
    "content": ".TH \"rtl_adsb\" 1 \"0.5.0\" RTL-SDR \"User Commands\"\n.SH NAME\nrtl_fm \\- a simple FM demodulator for RTL2832 based DVB-T receivers\n.SH DESCRIPTION\nUses a re-purposed DVB-T receiver as a software defined\nradio to receive narrow band FM signals and demodulate\nto audio. Written for and incorporated in the osmocom rtl-sdr project.\n.LP\nNarrowband FM is commonly used by public service agencies and\ncommercial dispatch operations in the VHF and UHF bands.\nAlso can demodulate Wideband FM, as found in the 88-108 MHz FM\nbroadcast band.\nExperimental options include AM, LSB, USB and DSB demodulation.\n.LP\nMuch software is available for the RTL2832. Most of the user-level\npackages rely on the librtlsdr library which comes as part of the\nrtl-sdr codebase. This codebase contains both the library itself and\nalso a number of command line tools such as rtl_test, rtl_sdr,\nrtl_tcp, and rtl_fm. These command line tools use the library to test\nfor the existence of RTL2832 devices and to perform basic data\ntransfer functions to and from the device.\n.LP\nBecause most of the RTL2832 devices are connected using USB, the\nlibrtlsdr library depends on the libusb library to communicate with\nthe device.\n.SH USAGE\nWith a suitable antenna for receiving the signal attached\nto the rtl-sdr supported device, this program will output the\ndigital audio data decoded from that signal. The data can be\nlistened to by piping to Sox or aplay applications to play the\nstream on the computer sound card.\n.SH SYNOPSIS\n.B  rtl_fm [-f freq] [-options] [filename]\n.SH OPTIONS\n.IP \"-f frequency_to_tune_to [Hz]\"\n use multiple -f for scanning, (requires squelch)\n ranges supported, -f 118M:137M:25k\n.IP \"[-M modulation (default: fm)]\"\n fm, wbfm, raw, am, usb, lsb\n wbfm == -M fm -s 170k -o 4 -A fast -r 32k -l 0 -E deemp\n raw mode outputs 2x16 bit IQ pairs\n.IP \"-s sample_rate (default: 24k)\"\n.IP \"-d device_index (default: 0)\"\n.IP \"-g tuner_gain (default: automatic)\"\n.IP \"-l squelch_level (default: 0/off)\"\n.IP \"-o oversampling (default: 1, 4 recommended)\"\n for fm squelch is inverted\n.IP \"[-o oversampling (default: 1, 4 recommended)]\"\n.IP \"-p ppm_error (default: 0)\"\n.IP \"[-E enable_option (default: none)]\"\n use multiple -E to enable multiple options\n    edge:   enable lower edge tuning\n    dc:     enable dc blocking filter\n    deemp:  enable de-emphasis filter\n    direct: enable direct sampling\n    offset: enable offset tuning\n.IP \"filename ('-' means stdout)\"\n omitting the filename also uses stdout\n.SH Experimental options\n.IP \"[-r resample_rate (default: none / same as -s)]\"\n.IP \"[-t squelch_delay (default: 10)]\"\n  +values will mute/scan, -values will exit\n.IP \"[-F fir_size (default: off)]\"\n    enables low-leakage downsample filter\n    size can be 0 or 9.  0 has bad roll off\n.IP \"-A std/fast/lut choose atan math (default: std)\"\n.IP filename\n (a '-' dumps samples to stdout)\n (omitting the filename also uses stdout)\n.SH EXAMPLES\nProduces signed 16 bit ints, use Sox or aplay to hear them.\n.IP \"rtl_fm ... - | play -t raw -r 24k -es -b 16 -c 1 -V1 -\"\n                  | aplay -r 24k -f S16_LE -t raw -c 1\n         -M wbfm  | play -r 32k ...\n.IP \"rtl_fm ...  -s 22050 - | multimon -t raw /dev/stdin\"\n.SH SEE ALSO\nRTL-SDR wiki documentation:\n.B http://sdr.osmocom.org/trac/wiki/rtl-sdr\n.LP\nRtl_fm Guide:\n.B http://kmkeen.com/rtl-demod-guide/\n.LP\n.sp\nsox(1), play(1), aplay(1)\n.LP\nOther rtl-sdr programs:\n.sp\nrtl_adsb(1), rtl_eeprom(1), rtl_sdr(1), rtl_tcp(1), rtl_test(1)\n.SH AUTHOR\nThis manual page was written by Maitland Bottoms\nfor the Debian project (but may be used by others).\n.SH COPYRIGHT\nCopyright (c) 2013 A. Maitland Bottoms <bottoms@debian.org>\n.LP\nThis program is free software: you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 2 of the License, or\n(at your option) any later version.\n.LP\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n"
  },
  {
    "path": "debian/rtl_power.1",
    "content": ".TH rtl_power: \"1\" \"0.5.1\" RTL_SDR \"User Commands\"\n.SH NAME\nrtl_power: \\- wideband spectrum monitor utility\n.SH DESCRIPTION\nUses a re-purposed DVB-T receiver as a software defined\nradio to receive signals in I/Q data form. Written for\nand incorporated in the osmocom rtl-sdr project.\n.SH USAGE\nrtl_power, a simple FFT logger for RTL2832 based DVB\\-T receivers\n.PP\nThis tool gathers signal data over a very wide area of the frequency spectrum,\nand then that data can be used to find active areas of the spectrum.\n.PP\nUse:    rtl_power \\fB\\-f\\fR freq_range [\\-options] [filename]\n.HP\n\\fB\\-f\\fR lower:upper:bin_size [Hz]\n.IP\n(bin size is a maximum, smaller more convenient bins\n.TP\nwill be used.\nvalid range 1Hz \\- 2.8MHz)\n.IP\n[\\-i integration_interval (default: 10 seconds)]\n.IP\n(buggy if a full sweep takes longer than the interval)\n.IP\n[\\-1 enables single\\-shot mode (default: off)]\n[\\-e exit_timer (default: off/0)]\n[\\-d device_index (default: 0)]\n[\\-g tuner_gain (default: automatic)]\n[\\-p ppm_error (default: 0)]\nfilename (a '\\-' dumps samples to stdout)\n.IP\n(omitting the filename also uses stdout)\n.SS \"Experimental options:\"\n.IP\n[\\-w window (default: rectangle)]\n.IP\n(hamming, blackman, blackman\\-harris, hann\\-poisson, bartlett, youssef)\n.IP\n[\\-c crop_percent (default: 0%, recommended: 20%\\-50%)]\n.IP\n(discards data at the edges, 100% discards everything)\n(has no effect for bins larger than 1MHz)\n.IP\n[\\-F fir_size (default: disabled)]\n.IP\n(enables low\\-leakage downsample filter,\n.TP\nfir_size can be 0 or 9.\n0 has bad roll off,\n.IP\ntry with '\\-c 50%')\n.IP\n[\\-P enables peak hold (default: off)]\n[\\-D enable direct sampling (default: off)]\n[\\-O enable offset tuning (default: off)]\n.SS \"CSV FFT output columns:\"\n.IP\ndate, time, Hz low, Hz high, Hz step, samples, dbm, dbm, ...\n.SH EXAMPLES\n.IP\nrtl_power \\fB\\-f\\fR 88M:108M:125k fm_stations.csv\n.IP\n(creates 160 bins across the FM band,\n.IP\nindividual stations should be visible)\n.IP\nrtl_power \\fB\\-f\\fR 100M:1G:1M \\fB\\-i\\fR 5m \\fB\\-1\\fR survey.csv\n.IP\n(a five minute low res scan of nearly everything)\n.IP\nrtl_power \\fB\\-f\\fR ... \\fB\\-i\\fR 15m \\fB\\-1\\fR log.csv\n.IP\n(integrate for 15 minutes and exit afterwards)\n.IP\nrtl_power \\fB\\-f\\fR ... \\fB\\-e\\fR 1h | gzip > log.csv.gz\n.IP\n(collect data for one hour and compress it on the fly)\n.SS \"Convert CSV to a waterfall graphic with:\"\n.IP\nhttp://kmkeen.com/tmp/heatmap.py.txt\n.PP\nrtl_power, a simple FFT logger for RTL2832 based DVB\\-T receivers\n.PP\nUse:    rtl_power \\fB\\-f\\fR freq_range [\\-options] [filename]\n.HP\n\\fB\\-f\\fR lower:upper:bin_size [Hz]\n.IP\n(bin size is a maximum, smaller more convenient bins\n.TP\nwill be used.\nvalid range 1Hz \\- 2.8MHz)\n.IP\n[\\-i integration_interval (default: 10 seconds)]\n.IP\n(buggy if a full sweep takes longer than the interval)\n.IP\n[\\-1 enables single\\-shot mode (default: off)]\n[\\-e exit_timer (default: off/0)]\n[\\-d device_index (default: 0)]\n[\\-g tuner_gain (default: automatic)]\n[\\-p ppm_error (default: 0)]\nfilename (a '\\-' dumps samples to stdout)\n.IP\n(omitting the filename also uses stdout)\n.SS \"Experimental options:\"\n.IP\n[\\-w window (default: rectangle)]\n.IP\n(hamming, blackman, blackman\\-harris, hann\\-poisson, bartlett, youssef)\n.IP\n[\\-c crop_percent (default: 0%, recommended: 20%\\-50%)]\n.IP\n(discards data at the edges, 100% discards everything)\n(has no effect for bins larger than 1MHz)\n.IP\n[\\-F fir_size (default: disabled)]\n.IP\n(enables low\\-leakage downsample filter,\n.TP\nfir_size can be 0 or 9.\n0 has bad roll off,\n.IP\ntry with '\\-c 50%')\n.IP\n[\\-P enables peak hold (default: off)]\n[\\-D enable direct sampling (default: off)]\n[\\-O enable offset tuning (default: off)]\n.SS \"CSV FFT output columns:\"\n.IP\ndate, time, Hz low, Hz high, Hz step, samples, dbm, dbm, ...\n.IP\nrtl_power \\fB\\-f\\fR 88M:108M:125k fm_stations.csv\n.IP\n(creates 160 bins across the FM band,\n.IP\nindividual stations should be visible)\n.IP\nrtl_power \\fB\\-f\\fR 100M:1G:1M \\fB\\-i\\fR 5m \\fB\\-1\\fR survey.csv\n.IP\n(a five minute low res scan of nearly everything)\n.IP\nrtl_power \\fB\\-f\\fR ... \\fB\\-i\\fR 15m \\fB\\-1\\fR log.csv\n.IP\n(integrate for 15 minutes and exit afterwards)\n.IP\nrtl_power \\fB\\-f\\fR ... \\fB\\-e\\fR 1h | gzip > log.csv.gz\n.IP\n(collect data for one hour and compress it on the fly)\n.SS \"Convert CSV to a waterfall graphic with:\"\n.IP\nhttp://kmkeen.com/tmp/heatmap.py.txt\n.SH \"SEE ALSO\"\n.LP\nRTL-SDR wiki documentation:\n.B http://sdr.osmocom.org/trac/wiki/rtl-sdr\n.LP\nOther rtl-sdr programs:\n.sp\nrtl_adsb(1), rtl_eeprom(1), rtl_fm(1), rtl_sdr(1), rtl_tcp(1), rtl_test(1)\n.SH AUTHOR\nThis manual page was written by Maitland Bottoms\nfor the Debian project (but may be used by others).\n.SH COPYRIGHT\nCopyright (c) 2013 A. Maitland Bottoms <bottoms@debian.org>\n.LP\nThis program is free software: you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 2 of the License, or\n(at your option) any later version.\n.LP\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n"
  },
  {
    "path": "debian/rtl_sdr.1",
    "content": ".TH \"rtl_sdr\" 1 \"0.5.0\" RTL-SDR \"User Commands\"\n.SH NAME\nrtl-sdr \\- an I/Q recorder for RTL2832 based DVB-T receivers\n.SH DESCRIPTION\nUses a re-purposed DVB-T receiver as a software defined\nradio to receive signals in I/Q data form. Written for\nand incorporated in the osmocom rtl-sdr project.\n.LP\nIn-Phase and Quadrature Phase data can faithfully represent\nall of the information in a band of frequencies centered\non a carrier signal frequency.\n.LP\nMuch software is available for the RTL2832. Most of the user-level\npackages rely on the librtlsdr library which comes as part of the\nrtl-sdr codebase. This codebase contains both the library itself and\nalso a number of command line tools such as rtl_test, rtl_sdr,\nrtl_tcp, and rtl_fm. These command line tools use the library to test\nfor the existence of RTL2832 devices and to perform basic data\ntransfer functions to and from the device.\n.LP\nBecause most of the RTL2832 devices are connected using USB, the\nlibrtlsdr library depends on the libusb library to communicate with\nthe device.\n.SH USAGE\nThis program captures information from a band of frequencies\nand outputs the data in a form useful to other software radio\nprograms.\n.SH SYNOPSIS\n.B  rtl_adsb [-f freq] [OPTIONS] [output file]\n.SH OPTIONS\n.IP \"-f frequency_to_tune_to [Hz]\"\n.IP \"-s samplerate (default: 2048000 Hz)\"\n.IP \"-d device_index (default: 0)\"\n.IP \"-g gain (default: 0 for auto)\"\n.IP \"-p ppm_error (default: 0)\"\n.IP \"-b output_block_size (default: 16 * 16384)\"\n.IP \"-n number of samples to read (default: 0, infinite)\"\n.IP \"-S force sync output (default: async)\"\n.IP tfilename\n (a '-' dumps samples to stdout)\n.SH EXAMPLES\n.IP \"Example: To tune to 392.0 MHz, and set the sample-rate to 1.8 MS/s, use:\"\n ./rtl_sdr /tmp/capture.bin -s 1.8e6 -f 392e6\n.LP\nto record samples to a file or to forward the data to a fifo.\n.LP\nIf the device can't be opened, make sure you have the appropriate\nrights to access the device (install udev-rules from the repository,\nor run it as root).\n.SH SEE ALSO\ngnuradio(1)\n.LP\nRTL-SDR wiki documentation:\n.B http://sdr.osmocom.org/trac/wiki/rtl-sdr\n.LP\nOther rtl-sdr programs:\n.sp\nrtl_adsb(1), rtl_eeprom(1), rtl_fm(1), rtl_power(1), rtl_tcp(1), rtl_test(1)\n.SH AUTHOR\nThis manual page was written by Maitland Bottoms\nfor the Debian project (but may be used by others).\n.SH COPYRIGHT\nCopyright (c) 2013 A. Maitland Bottoms <bottoms@debian.org>\n.LP\nThis program is free software: you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 2 of the License, or\n(at your option) any later version.\n.LP\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n"
  },
  {
    "path": "debian/rtl_tcp.1",
    "content": ".TH \"rtl_tcp\" 1 \"0.5.0\" RTL-SDR \"User Commands\"\n.SH NAME\nrtl_tcp \\- an I/Q spectrum server for RTL2832 based DVB-T receivers\n.SH DESCRIPTION\nUses a re-purposed DVB-T receiver as a software defined\nradio to receive and send I/Q data via TCP network to another\ndemodulation, decoding or logging apllication. Written for\nand incorporated into the osmocom rtl-sdr project.\n.LP\nMuch software is available for the RTL2832. Most of the user-level\npackages rely on the librtlsdr library which comes as part of the\nrtl-sdr codebase. This codebase contains both the library itself and\nalso a number of command line tools such as rtl_test, rtl_sdr,\nrtl_tcp, and rtl_fm. These command line tools use the library to test\nfor the existence of RTL2832 devices and to perform basic data\ntransfer functions to and from the device.\n.LP\nBecause most of the RTL2832 devices are connected using USB, the\nlibrtlsdr library depends on the libusb library to communicate with\nthe device.\n.SH USAGE\nRun this program on a machine with an rtl-sdr supported\ndevice connected and it will provide I/Q data to other applications\nvia TCP/IP.\n.SH SYNOPSIS\n.B  rtl_tcp [OPTIONS]\n.SH OPTIONS\n.IP \"-a listen address\"\n.IP \"-p listen port (default: 1234)\"\n.IP \"-f frequency to tune to [Hz]\"\n.IP \"-g gain (default: 0 for auto)\"\n.IP \"-s samplerate in Hz (default: 2048000 Hz)\"\n.IP \"-b number of buffers (default: 32, set by library)\"\n.IP \"-n max number of linked list buffers to keep (default: 500)\"\n.IP \"-d device_index (default: 0)\"\n.IP \"-P ppm_error (default: 0)\"\n.SH  Example:\n.IP \"rtl_tcp -a 10.0.0.2 [-p listen port (default: 1234)]\"\n Found 1 device(s).\n Found Elonics E4000 tuner\n Using Generic RTL2832U (e.g. hama nano)\n Tuned to 100000000 Hz.\n listening...\n.LP\nUse the device argument 'rtl_tcp=10.0.0.2:1234' in OsmoSDR (gr-osmosdr) source\nto receive samples in GRC and control rtl_tcp parameters (frequency, gain, ...).\n.LP\nuse the rtl_tcp=... device argument in gr-osmosdr source to receive\nthe samples in GRC and control the rtl settings remotely.\n.LP\nThis application has been successfully crosscompiled for ARM and MIPS\ndevices and is providing IQ data in a networked ADS-B setup at a rate\nof 2.4MSps. The gr-osmosdr source is being used together with an\noptimized gr-air-modes version (see Known Apps below). It is also\navailable as a package in OpenWRT.\n.LP\nA use case is described ​https://sites.google.com/site/embrtlsdr/\n.SH SEE ALSO\ngnuradio(1)\n.LP\nRTL-SDR wiki documentation:\n.B http://sdr.osmocom.org/trac/wiki/rtl-sdr\n.LP\nOther rtl-sdr programs:\n.sp\nrtl_adsb(1), rtl_eeprom(1), rtl_fm(1), rtl_sdr(1), rtl_test(1)\n.SH AUTHOR\nThis manual page was written by Maitland Bottoms\nfor the Debian project (but may be used by others).\n.SH COPYRIGHT\nCopyright (c) 2013 A. Maitland Bottoms <bottoms@debian.org>\n.LP\nThis program is free software: you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 2 of the License, or\n(at your option) any later version.\n.LP\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n"
  },
  {
    "path": "debian/rtl_test.1",
    "content": ".TH \"rtl_test\" 1 \"0.5.0\" RTL-SDR \"User Commands\"\n.SH NAME\nrtl_test \\- a benchmark tool for RTL2832 based DVB-T receivers\n.SH DESCRIPTION\nTest tuning range and functional sample rates of your device\non your system.\nUses a re-purposed DVB-T receiver as a software defined\nradio. Written for and incorporated into the osmocom rtl-sdr project.\n.LP\nMuch software is available for the RTL2832. Most of the user-level\npackages rely on the librtlsdr library which comes as part of the\nrtl-sdr codebase. This codebase contains both the library itself and\nalso a number of command line tools such as rtl_test, rtl_sdr,\nrtl_tcp, and rtl_fm. These command line tools use the library to test\nfor the existence of RTL2832 devices and to perform basic data\ntransfer functions to and from the device.\n.LP\nBecause most of the RTL2832 devices are connected using USB, the\nlibrtlsdr library depends on the libusb library to communicate with\nthe device.\n.SH SYNOPSIS\n.B  rtl_test [OPTIONS]\n.SH OPTIONS\n.IP \"-s samplerate (default: 2048000 Hz)\"\n.IP \"-d device_index (default: 0)\"\n.IP \"-t enable Elonics E4000 tuner benchmark]\"\n.IP \"-p enable PPM error measurement\"\n.IP \"-b output_block_size (default: 16 * 16384)\"\n.IP \"-S force sync output (default: async)\"\n.SH EXAMPLES\n.IP \"To check the possible tuning range (may heavily vary by some MHz depending on device and temperature), call\"\n rtl_test -t\n.IP \"To check the maximum samplerate possible on your machine, type (change the rate down until no sample loss occurs):\"\n rtl_test -s 3.2e6\n.LP\nA samplerate of 2.4e6 is known to work even over tcp connections (see\nrtl_tcp above). A sample rate of 2.88e6 may work without lost samples\nbut this may depend on your PC/Laptop's host interface.\n.SH SEE ALSO\nRTL-SDR wiki documentation:\n.B http://sdr.osmocom.org/trac/wiki/rtl-sdr\n.LP\nOther rtl-sdr programs:\n.sp\nrtl_adsb(1), rtl_eeprom(1), rtl_fm(1), rtl_sdr(1), rtl_tcp(1)\n.SH AUTHOR\nThis manual page was written by Maitland Bottoms\nfor the Debian project (but may be used by others).\n.SH COPYRIGHT\nCopyright (c) 2013 A. Maitland Bottoms <bottoms@debian.org>\n.LP\nThis program is free software: you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 2 of the License, or\n(at your option) any later version.\n.LP\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n"
  },
  {
    "path": "debian/rules",
    "content": "#!/usr/bin/make -f\nDEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH)\nexport DEB_HOST_MULTIARCH\n\n%:\n\tdh $@\n\noverride_dh_auto_configure: debian/librtlsdr0.udev\n\tdh_auto_configure -- -DLIB_INSTALL_DIR=lib/$(DEB_HOST_MULTIARCH) -DDETACH_KERNEL_DRIVER=ON\n\ndebian/librtlsdr0.udev: rtl-sdr.rules\n\tcp -p rtl-sdr.rules debian/librtlsdr0.udev\n"
  },
  {
    "path": "debian/source/format",
    "content": "3.0 (native)\n"
  },
  {
    "path": "debian/watch",
    "content": "version=4\nopts=\"mode=git, gitmode=full, pgpmode=none\" \\\n git://git.osmocom.org/rtl-sdr.git \\\n refs/tags/v([\\d\\.]+) debian uupdate\n"
  },
  {
    "path": "git-version-gen",
    "content": "#!/bin/sh\n# Print a version string.\nscriptversion=2010-01-28.01\n\n# Copyright (C) 2007-2010 Free Software Foundation, Inc.\n#\n# This program is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation; either version 3 of the License, or\n# (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n# This script is derived from GIT-VERSION-GEN from GIT: http://git.or.cz/.\n# It may be run two ways:\n# - from a git repository in which the \"git describe\" command below\n#   produces useful output (thus requiring at least one signed tag)\n# - from a non-git-repo directory containing a .tarball-version file, which\n#   presumes this script is invoked like \"./git-version-gen .tarball-version\".\n\n# In order to use intra-version strings in your project, you will need two\n# separate generated version string files:\n#\n# .tarball-version - present only in a distribution tarball, and not in\n#   a checked-out repository.  Created with contents that were learned at\n#   the last time autoconf was run, and used by git-version-gen.  Must not\n#   be present in either $(srcdir) or $(builddir) for git-version-gen to\n#   give accurate answers during normal development with a checked out tree,\n#   but must be present in a tarball when there is no version control system.\n#   Therefore, it cannot be used in any dependencies.  GNUmakefile has\n#   hooks to force a reconfigure at distribution time to get the value\n#   correct, without penalizing normal development with extra reconfigures.\n#\n# .version - present in a checked-out repository and in a distribution\n#   tarball.  Usable in dependencies, particularly for files that don't\n#   want to depend on config.h but do want to track version changes.\n#   Delete this file prior to any autoconf run where you want to rebuild\n#   files to pick up a version string change; and leave it stale to\n#   minimize rebuild time after unrelated changes to configure sources.\n#\n# It is probably wise to add these two files to .gitignore, so that you\n# don't accidentally commit either generated file.\n#\n# Use the following line in your configure.ac, so that $(VERSION) will\n# automatically be up-to-date each time configure is run (and note that\n# since configure.ac no longer includes a version string, Makefile rules\n# should not depend on configure.ac for version updates).\n#\n# AC_INIT([GNU project],\n#         m4_esyscmd([build-aux/git-version-gen .tarball-version]),\n#         [bug-project@example])\n#\n# Then use the following lines in your Makefile.am, so that .version\n# will be present for dependencies, and so that .tarball-version will\n# exist in distribution tarballs.\n#\n# BUILT_SOURCES = $(top_srcdir)/.version\n# $(top_srcdir)/.version:\n#\techo $(VERSION) > $@-t && mv $@-t $@\n# dist-hook:\n#\techo $(VERSION) > $(distdir)/.tarball-version\n\ncase $# in\n    1) ;;\n    *) echo 1>&2 \"Usage: $0 \\$srcdir/.tarball-version\"; exit 1;;\nesac\n\ntarball_version_file=$1\nnl='\n'\n\n# First see if there is a tarball-only version file.\n# then try \"git describe\", then default.\nif test -f $tarball_version_file\nthen\n    v=`cat $tarball_version_file` || exit 1\n    case $v in\n\t*$nl*) v= ;; # reject multi-line output\n\t[0-9]*) ;;\n\t*) v= ;;\n    esac\n    test -z \"$v\" \\\n\t&& echo \"$0: WARNING: $tarball_version_file seems to be damaged\" 1>&2\nfi\n\nif test -n \"$v\"\nthen\n    : # use $v\nelif\n       v=`git describe --abbrev=4 --match='v*' HEAD 2>/dev/null \\\n\t  || git describe --abbrev=4 HEAD 2>/dev/null` \\\n    && case $v in\n\t [0-9]*) ;;\n\t v[0-9]*) ;;\n\t *) (exit 1) ;;\n       esac\nthen\n    # Is this a new git that lists number of commits since the last\n    # tag or the previous older version that did not?\n    #   Newer: v6.10-77-g0f8faeb\n    #   Older: v6.10-g0f8faeb\n    case $v in\n\t*-*-*) : git describe is okay three part flavor ;;\n\t*-*)\n\t    : git describe is older two part flavor\n\t    # Recreate the number of commits and rewrite such that the\n\t    # result is the same as if we were using the newer version\n\t    # of git describe.\n\t    vtag=`echo \"$v\" | sed 's/-.*//'`\n\t    numcommits=`git rev-list \"$vtag\"..HEAD | wc -l`\n\t    v=`echo \"$v\" | sed \"s/\\(.*\\)-\\(.*\\)/\\1-$numcommits-\\2/\"`;\n\t    ;;\n    esac\n\n    # Change the first '-' to a '.', so version-comparing tools work properly.\n    # Remove the \"g\" in git describe's output string, to save a byte.\n    v=`echo \"$v\" | sed 's/-/./;s/\\(.*\\)-g/\\1-/'`;\nelse\n    v=UNKNOWN\nfi\n\nv=`echo \"$v\" |sed 's/^v//'`\n\n# Don't declare a version \"dirty\" merely because a time stamp has changed.\ngit status > /dev/null 2>&1\n\ndirty=`sh -c 'git diff-index --name-only HEAD' 2>/dev/null` || dirty=\ncase \"$dirty\" in\n    '') ;;\n    *) # Append the suffix only if there isn't one already.\n\tcase $v in\n\t  *-dirty) ;;\n\t  *) v=\"$v-dirty\" ;;\n\tesac ;;\nesac\n\n# Omit the trailing newline, so that m4_esyscmd can use the result directly.\necho \"$v\" | tr -d '\\012'\n\n# Local variables:\n# eval: (add-hook 'write-file-hooks 'time-stamp)\n# time-stamp-start: \"scriptversion=\"\n# time-stamp-format: \"%:y-%02m-%02d.%02H\"\n# time-stamp-end: \"$\"\n# End:\n"
  },
  {
    "path": "include/CMakeLists.txt",
    "content": "# Copyright 2012 OSMOCOM Project\n#\n# This file is part of rtl-sdr\n#\n# GNU Radio is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation; either version 3, or (at your option)\n# any later version.\n#\n# GNU Radio is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with GNU Radio; see the file COPYING.  If not, write to\n# the Free Software Foundation, Inc., 51 Franklin Street,\n# Boston, MA 02110-1301, USA.\n\n########################################################################\n# Install public header files\n########################################################################\ninstall(FILES\n    rtl-sdr.h\n    rtl_tcp.h\n    rtl-sdr_export.h\n    DESTINATION include\n)\n"
  },
  {
    "path": "include/Makefile.am",
    "content": "rtlsdr_HEADERS = rtl-sdr.h rtl-sdr_export.h\n\nnoinst_HEADERS = reg_field.h rtlsdr_i2c.h tuner_e4k.h tuner_fc0012.h tuner_fc0013.h tuner_fc2580.h tuner_r82xx.h\n\nrtlsdrdir = $(includedir)\n"
  },
  {
    "path": "include/controlThread.h",
    "content": "/*\n * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver\n * Copyright (C) 2019 <>\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef __RTL_CONTROL_THREAD_H\n#define __RTL_CONTROL_THREAD_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct\n{\n\trtlsdr_dev_t *dev;\n\tint port;\n\tint wait;\n\tint report_i2c;\n\tchar *addr;\n\tint* pDoExit;\n}\nctrl_thread_data_t;\nvoid *ctrl_thread_fn(void *arg);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n\n"
  },
  {
    "path": "include/reg_field.h",
    "content": "#ifndef _REG_FIELD_H\n#define _REG_FIELD_H\n\n#include <stdint.h>\n#include <stdarg.h>\n\nenum cmd_op {\n\tCMD_OP_GET\t= (1 << 0),\n\tCMD_OP_SET\t= (1 << 1),\n\tCMD_OP_EXEC\t= (1 << 2),\n};\n\nenum pstate {\n\tST_IN_CMD,\n\tST_IN_ARG,\n};\n\nstruct strbuf {\n\tuint8_t idx;\n\tchar buf[32];\n};\n\nstruct cmd_state {\n\tstruct strbuf cmd;\n\tstruct strbuf arg;\n\tenum pstate state;\n\tvoid (*out)(const char *format, va_list ap);\n};\n\nstruct cmd {\n\tconst char *cmd;\n\tuint32_t ops;\n\tint (*cb)(struct cmd_state *cs, enum cmd_op op, const char *cmd,\n\t\t  int argc, char **argv);\n\tconst char *help;\n};\n\n/* structure describing a field in a register */\nstruct reg_field {\n\tuint8_t reg;\n\tuint8_t shift;\n\tuint8_t width;\n};\n\nstruct reg_field_ops {\n\tconst struct reg_field *fields;\n\tconst char **field_names;\n\tuint32_t num_fields;\n\tvoid *data;\n\tint (*write_cb)(void *data, uint32_t reg, uint32_t val);\n\tuint32_t (*read_cb)(void *data, uint32_t reg);\n};\n\nuint32_t reg_field_read(struct reg_field_ops *ops, struct reg_field *field);\nint reg_field_write(struct reg_field_ops *ops, struct reg_field *field, uint32_t val);\nint reg_field_cmd(struct cmd_state *cs, enum cmd_op op,\n\t\t  const char *cmd, int argc, char **argv,\n\t\t  struct reg_field_ops *ops);\n\n#endif\n"
  },
  {
    "path": "include/rtl-sdr.h",
    "content": "/*\n * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver\n * Copyright (C) 2012-2013 by Steve Markgraf <steve@steve-m.de>\n * Copyright (C) 2012 by Dimitri Stolnikov <horiz0n@gmx.net>\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef __RTL_SDR_H\n#define __RTL_SDR_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n\n#include <stdint.h>\n#include <stddef.h>\n#include <rtl-sdr_export.h>\n\n\ntypedef struct rtlsdr_dev rtlsdr_dev_t;\n\nRTLSDR_API uint32_t rtlsdr_get_device_count(void);\n\nRTLSDR_API const char* rtlsdr_get_device_name(uint32_t index);\n\n/*!\n * Get USB device strings.\n *\n * NOTE: The string arguments must provide space for up to 256 bytes.\n *\n * \\param index the device index\n * \\param manufact manufacturer name, may be NULL\n * \\param product product name, may be NULL\n * \\param serial serial number, may be NULL\n * \\return 0 on success\n */\nRTLSDR_API int rtlsdr_get_device_usb_strings(uint32_t index,\n\t\t\t\t\t     char *manufact,\n\t\t\t\t\t     char *product,\n\t\t\t\t\t     char *serial);\n\n/*!\n * Get device index by USB serial string descriptor.\n *\n * \\param serial serial string of the device\n * \\return device index of first device where the name matched\n * \\return -1 if name is NULL\n * \\return -2 if no devices were found at all\n * \\return -3 if devices were found, but none with matching name\n */\nRTLSDR_API int rtlsdr_get_index_by_serial(const char *serial);\n\n/*!\n * Open device index by index.\n *\n * \\param pointer where to save the device handle, which again is a pointer\n * \\param serial serial string of the device\n * \\return device index to be opened\n * \\return -1 if device or libusb is inaccessible\n * \\return -3 if device permissions don't fit:\n *              check, if udev rules file rtl-sdr.rules needs to be installed\n * \\return negative, for a libusb error code or some other initialization error\n */\nRTLSDR_API int rtlsdr_open(rtlsdr_dev_t **dev, uint32_t index);\n\n/*!\n * Close device.\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\return -1 if device handle was already close - or never opened\n */\nRTLSDR_API int rtlsdr_close(rtlsdr_dev_t *dev);\n\n/* configuration functions */\n\n/*!\n * Set crystal oscillator frequencies used for the RTL2832 and the tuner IC.\n *\n * Usually both ICs use the same clock. Changing the clock may make sense if\n * you are applying an external clock to the tuner or to compensate the\n * frequency (and samplerate) error caused by the original (cheap) crystal.\n *\n * NOTE: Call this function only if you fully understand the implications.\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param rtl_freq frequency value used to clock the RTL2832 in Hz\n * \\param tuner_freq frequency value used to clock the tuner IC in Hz\n * \\return 0 on success\n */\nRTLSDR_API int rtlsdr_set_xtal_freq(rtlsdr_dev_t *dev, uint32_t rtl_freq,\n\t\t\t\t    uint32_t tuner_freq);\n\n/*!\n * Get crystal oscillator frequencies used for the RTL2832 and the tuner IC.\n *\n * Usually both ICs use the same clock.\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param rtl_freq frequency value used to clock the RTL2832 in Hz\n * \\param tuner_freq frequency value used to clock the tuner IC in Hz\n * \\return 0 on success\n */\nRTLSDR_API int rtlsdr_get_xtal_freq(rtlsdr_dev_t *dev, uint32_t *rtl_freq,\n\t\t\t\t    uint32_t *tuner_freq);\n\n/*!\n * Get USB device strings.\n *\n * NOTE: The string arguments must provide space for up to 256 bytes.\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param manufact manufacturer name, may be NULL\n * \\param product product name, may be NULL\n * \\param serial serial number, may be NULL\n * \\return 0 on success\n */\nRTLSDR_API int rtlsdr_get_usb_strings(rtlsdr_dev_t *dev, char *manufact,\n\t\t\t\t      char *product, char *serial);\n\n/*!\n * Write the device EEPROM\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param data buffer of data to be written\n * \\param offset address where the data should be written\n * \\param len length of the data\n * \\return 0 on success\n * \\return -1 if device handle is invalid\n * \\return -2 if EEPROM size is exceeded\n * \\return -3 if no EEPROM was found\n */\n\nRTLSDR_API int rtlsdr_write_eeprom(rtlsdr_dev_t *dev, uint8_t *data,\n\t\t\t\t  uint8_t offset, uint16_t len);\n\n/*!\n * Read the device EEPROM\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param data buffer where the data should be written\n * \\param offset address where the data should be read from\n * \\param len length of the data\n * \\return 0 on success\n * \\return -1 if device handle is invalid\n * \\return -2 if EEPROM size is exceeded\n * \\return -3 if no EEPROM was found\n */\n\nRTLSDR_API int rtlsdr_read_eeprom(rtlsdr_dev_t *dev, uint8_t *data,\n\t\t\t\t  uint8_t offset, uint16_t len);\n\n/*!\n * Set the frequency the device is tuned to.\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param frequency in Hz\n * \\return 0 on success\n * \\return < 0 if device handle is invalid or some other error\n */\nRTLSDR_API int rtlsdr_set_center_freq(rtlsdr_dev_t *dev, uint32_t freq);\n\n/*!\n * Set the frequency the device is tuned to: allow frequency > 32 bit ~= 4.29 GHz\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param frequency in Hz in 64 bit\n * \\return 0 on success\n * \\return < 0 if device handle is invalid or some other error\n */\nRTLSDR_API int rtlsdr_set_center_freq64(rtlsdr_dev_t *dev, uint64_t freq);\n\n/*!\n * Set harmonic reception - for R820T/2 tuner\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param harmonic - receive n'th harmonic. 0 = default for disabling this\n * \\return 0 on success\n * \\return < 0 if device handle is invalid or some other error\n */\nRTLSDR_API int rtlsdr_set_harmonic_rx(rtlsdr_dev_t *dev, int harmonic);\n\n/*!\n * Check, if tuner PLL (frequency) is still locked.\n * Tuner/PLL might loose lock (at high frequencies),\n * e.g. for temperature reasons\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\return   1: PLL is NOT locked\n * \\return   0: PLL HAS lock\n * \\return < 0: if device handle is invalid or some other error\n * \\return -2: not supported for devices' tuner\n */\nRTLSDR_API int rtlsdr_is_tuner_PLL_locked(rtlsdr_dev_t *dev);\n\n\n/*!\n * Get actual frequency the device is tuned to.\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\return 0 on error, frequency in Hz otherwise\n */\nRTLSDR_API uint32_t rtlsdr_get_center_freq(rtlsdr_dev_t *dev);\n\n/*!\n * Get actual frequency the device is tuned to.\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\return 0 on error, frequency in Hz otherwise\n */\nRTLSDR_API uint64_t rtlsdr_get_center_freq64(rtlsdr_dev_t *dev);\n\n\n/*!\n * Set the frequency correction value for the device.\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param ppm correction value in parts per million (ppm)\n * \\return 0 on success\n */\nRTLSDR_API int rtlsdr_set_freq_correction(rtlsdr_dev_t *dev, int ppm);\n\n/*!\n * Get actual frequency correction value of the device.\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\return correction value in parts per million (ppm)\n *         if dev is valid, no error can occur\n */\nRTLSDR_API int rtlsdr_get_freq_correction(rtlsdr_dev_t *dev);\n\nenum rtlsdr_tuner {\n\tRTLSDR_TUNER_UNKNOWN = 0,\n\tRTLSDR_TUNER_E4000,\n\tRTLSDR_TUNER_FC0012,\n\tRTLSDR_TUNER_FC0013,\n\tRTLSDR_TUNER_FC2580,\n\tRTLSDR_TUNER_R820T,\t\t/* or R820T2 - R820T and R820T2 is not disdinguishable */\n\tRTLSDR_TUNER_R828D\n};\n\n/*!\n * Get the tuner type.\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\return RTLSDR_TUNER_UNKNOWN on error, tuner type otherwise\n */\nRTLSDR_API enum rtlsdr_tuner rtlsdr_get_tuner_type(rtlsdr_dev_t *dev);\n\n/*!\n * Get a list of gains supported by the tuner.\n *\n * NOTE: The gains argument must be preallocated by the caller. If NULL is\n * being given instead, the number of available gain values will be returned.\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param gains array of gain values. In tenths of a dB, 115 means 11.5 dB.\n * \\return <= 0 on error, number of available (returned) gain values otherwise\n */\nRTLSDR_API int rtlsdr_get_tuner_gains(rtlsdr_dev_t *dev, int *gains);\n\n/*!\n * Set the gain for the device.\n * Manual gain mode must be enabled for this to work.\n *\n * Valid gain values (in tenths of a dB) for the E4000 tuner:\n * -10, 15, 40, 65, 90, 115, 140, 165, 190,\n * 215, 240, 290, 340, 420, 430, 450, 470, 490\n *\n * Valid gain values may be queried with \\ref rtlsdr_get_tuner_gains function.\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param gain in tenths of a dB, 115 means 11.5 dB.\n * \\return 0 on success\n */\nRTLSDR_API int rtlsdr_set_tuner_gain(rtlsdr_dev_t *dev, int gain);\n\n/*!\n * Set (and retrieve) the bandwidth for the device.\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param bw bandwidth in Hz. Zero means automatic BW selection.\n * \\param applied_bw is applied bandwidth in Hz, or 0 if unknown\n * \\param apply_bw: 1 to really apply configure the tuner chip; 0 for just returning applied_bw\n * \\return 0 on success\n */\nRTLSDR_API int rtlsdr_set_and_get_tuner_bandwidth(rtlsdr_dev_t *dev, uint32_t bw, uint32_t *applied_bw, int apply_bw );\n\n/*!\n * Set the bandwidth for the device.\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param bw bandwidth in Hz. Zero means automatic BW selection.\n * \\return 0 on success\n */\nRTLSDR_API int rtlsdr_set_tuner_bandwidth(rtlsdr_dev_t *dev, uint32_t bw );\n\n/*!\n * Sets the center of the filtered tuner band(width)\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param if_band_center_freq in Hz. Zero means, that band center shall be at zero (=default).\n *    set if_band_center_freq = +samplerate/4 to have the filtered band centered at output's right half.\n * \\return 0 on success\n */\nRTLSDR_API int rtlsdr_set_tuner_band_center(rtlsdr_dev_t *dev, int32_t if_band_center_freq );\n\n/*!\n * Set the mixer sideband for the device.\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param sideband mixer sideband 0 means lower sideband, 1 means upper sideband.\n * \\return 0 on success\n */\nRTLSDR_API int rtlsdr_set_tuner_sideband(rtlsdr_dev_t *dev, int sideband);\n\n/*!\n * Get actual (RF / HF) gain the device is configured to - excluding the IF gain.\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\return 0 on error, gain in tenths of a dB, 115 means 11.5 dB.\n *         unfortunately it's impossible to distinguish error against 0 dB\n */\nRTLSDR_API int rtlsdr_get_tuner_gain(rtlsdr_dev_t *dev);\n\n/*!\n * Set LNA / Mixer / VGA Device Gain for R820T/2 device is configured to.\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param lna_gain index in 0 .. 15: 0 == min;   see tuner_r82xx.c table r82xx_lna_gain_steps[]\n * \\param mixer_gain index in 0 .. 15: 0 == min; see tuner_r82xx.c table r82xx_mixer_gain_steps[]\n * \\param vga_gain index in 0 .. 15: 0 == -12 dB; 15 == 40.5 dB; => 3.5 dB/step;\n *        vga_gain index 16 activates AGC for VGA controlled from RTL2832\n *     see tuner_r82xx.c table r82xx_vga_gain_steps[]\n * \\return 0 on success\n */\nRTLSDR_API int rtlsdr_set_tuner_gain_ext(rtlsdr_dev_t *dev, int lna_gain, int mixer_gain, int vga_gain);\n\n/*!\n * Set the intermediate frequency gain for the device.\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param stage intermediate frequency gain stage number (1 to 6 for E4000)\n * \\param gain in tenths of a dB, -30 means -3.0 dB.\n * \\return 0 on success\n */\nRTLSDR_API int rtlsdr_set_tuner_if_gain(rtlsdr_dev_t *dev, int stage, int gain);\n\n/*!\n * Set the gain mode (automatic/manual) for the device.\n * Manual gain mode must be enabled for the gain setter function to work.\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param manual gain mode, 1 means manual gain mode shall be enabled.\n * \\return 0 on success\n */\nRTLSDR_API int rtlsdr_set_tuner_gain_mode(rtlsdr_dev_t *dev, int manual);\n\n/*!\n * Set the agc_variant for automatic gain mode for the device (only R820T/2).\n * Automatic gain mode must be enabled for the gain setter function to work.\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param if_mode:\n *         0           set automatic VGA, which is controlled from RTL2832\n *     -2500 .. +2500: set fixed IF gain in tenths of a dB, 115 means 11.5 dB.\n *                     use -1 or +1 in case you neither want attenuation nor gain.\n *                     this equals the VGA gain for R820T/2 tuner.\n *                     exact values (R820T/2) are in range -47 .. 408 in tenth of a dB,\n *                       giving -4.7 .. +40.8 dB. these exact values may slightly change\n *                       with better measurements.\n *     10000 .. 10015: IF gain == VGA index from parameter if_mode\n *                     set if_mode by index: index := VGA_idx +10000\n *     10016 .. 10031: same as 10000 .. 10015, but additionally set automatic VGA\n *     10011:          for fixed VGA (=default) of -12 dB + 11 * 3.5 dB = 26.5 dB\n * \n * \\return 0 on success\n */\nRTLSDR_API int rtlsdr_set_tuner_if_mode(rtlsdr_dev_t *dev, int if_mode);\n\n/*!\n * Set the sample rate for the device, also selects the baseband filters\n * according to the requested sample rate for tuners where this is possible.\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param samp_rate the sample rate to be set, possible values are:\n * \t\t    225001 - 300000 Hz\n * \t\t    900001 - 3200000 Hz\n * \t\t    sample loss is to be expected for rates > 2400000\n * \\return 0 on success, -EINVAL on invalid rate\n */\nRTLSDR_API int rtlsdr_set_sample_rate(rtlsdr_dev_t *dev, uint32_t rate);\n\n/*!\n * Get actual sample rate the device is configured to.\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\return 0 on error, sample rate in Hz otherwise\n */\nRTLSDR_API uint32_t rtlsdr_get_sample_rate(rtlsdr_dev_t *dev);\n\n/*!\n * Enable test mode that returns an 8 bit counter instead of the samples.\n * The counter is generated inside the RTL2832.\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param test mode, 1 means enabled, 0 disabled\n * \\return 0 on success\n */\nRTLSDR_API int rtlsdr_set_testmode(rtlsdr_dev_t *dev, int on);\n\n/*!\n * Enable or disable the internal digital AGC of the RTL2832.\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param digital AGC mode, 1 means enabled, 0 disabled\n * \\return 0 on success\n */\nRTLSDR_API int rtlsdr_set_agc_mode(rtlsdr_dev_t *dev, int on);\n\n/*!\n * Enable or disable the direct sampling mode. When enabled, the IF mode\n * of the RTL2832 is activated, and rtlsdr_set_center_freq() will control\n * the IF-frequency of the DDC, which can be used to tune from 0 to 28.8 MHz\n * (xtal frequency of the RTL2832).\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param on 0 means disabled, 1 I-ADC input enabled, 2 Q-ADC input enabled\n * \\return 0 on success\n */\nRTLSDR_API int rtlsdr_set_direct_sampling(rtlsdr_dev_t *dev, int on);\n\n/*!\n * Get state of the direct sampling mode\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\return -1 on error, 0 means disabled, 1 I-ADC input enabled\n *\t    2 Q-ADC input enabled\n */\nRTLSDR_API int rtlsdr_get_direct_sampling(rtlsdr_dev_t *dev);\n\nenum rtlsdr_ds_mode {\n\tRTLSDR_DS_IQ = 0,\t/* I/Q quadrature sampling of tuner output */\n\tRTLSDR_DS_I,\t\t/* 1: direct sampling on I branch: usually not connected */\n\tRTLSDR_DS_Q,\t\t/* 2: direct sampling on Q branch: HF on rtl-sdr v3 dongle */\n\tRTLSDR_DS_I_BELOW,\t/* 3: direct sampling on I branch when frequency below 'DS threshold frequency' */\n\tRTLSDR_DS_Q_BELOW\t/* 4: direct sampling on Q branch when frequency below 'DS threshold frequency' */\n};\n\n/*!\n * Set direct sampling mode with threshold\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param mode static modes 0 .. 2 as in rtlsdr_set_direct_sampling(). other modes do automatic switching\n * \\param freq_threshold direct sampling is used below this frequency, else quadrature mode through tuner\n *   set 0 for using default setting per tuner - not fully implemented yet!\n * \\return negative on error, 0 on success\n */\nRTLSDR_API int rtlsdr_set_ds_mode(rtlsdr_dev_t *dev, enum rtlsdr_ds_mode mode, uint32_t freq_threshold);\n\n/*!\n * Enable or disable offset tuning for zero-IF tuners, which allows to avoid\n * problems caused by the DC offset of the ADCs and 1/f noise.\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param on 0 means disabled, 1 enabled\n * \\return 0 on success\n */\nRTLSDR_API int rtlsdr_set_offset_tuning(rtlsdr_dev_t *dev, int on);\n\n/*!\n * Get state of the offset tuning mode\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\return -1 on error, 0 means disabled, 1 enabled\n */\nRTLSDR_API int rtlsdr_get_offset_tuning(rtlsdr_dev_t *dev);\n\n/*!\n * Enable or disable frequency dithering for r820t tuners.\n * Must be performed before freq_set().\n * Fails for other tuners.\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param on 0 means disabled, 1 enabled\n * \\return 0 on success\n */\nRTLSDR_API int rtlsdr_set_dithering(rtlsdr_dev_t *dev, int dither);\n\n/* streaming functions */\n\n\n/*!\n * Reset buffer in RTL2832\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\return 0 on success\n * \\return -1 on error\n */\nRTLSDR_API int rtlsdr_reset_buffer(rtlsdr_dev_t *dev);\n\n/*!\n * Read data synchronously\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\return 0 on success\n * \\return -1 on error or error code from libusb\n */\nRTLSDR_API int rtlsdr_read_sync(rtlsdr_dev_t *dev, void *buf, int len, int *n_read);\n\ntypedef void(*rtlsdr_read_async_cb_t)(unsigned char *buf, uint32_t len, void *ctx);\n\n/*!\n * Read samples from the device asynchronously. This function will block until\n * it is being canceled using rtlsdr_cancel_async()\n *\n * NOTE: This function is deprecated and is subject for removal.\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param cb callback function to return received samples\n * \\param ctx user specific context to pass via the callback function\n * \\return 0 on success\n */\nRTLSDR_API int rtlsdr_wait_async(rtlsdr_dev_t *dev, rtlsdr_read_async_cb_t cb, void *ctx);\n\n/*!\n * Read samples from the device asynchronously. This function will block until\n * it is being canceled using rtlsdr_cancel_async()\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param cb callback function to return received samples\n * \\param ctx user specific context to pass via the callback function\n * \\param buf_num optional buffer count, buf_num * buf_len = overall buffer size\n *\t\t  set to 0 for default buffer count (15)\n * \\param buf_len optional buffer length, must be multiple of 512,\n *\t\t  should be a multiple of 16384 (URB size), set to 0\n *\t\t  for default buffer length (16 * 32 * 512)\n * \\return 0 on success\n */\nRTLSDR_API int rtlsdr_read_async(rtlsdr_dev_t *dev,\n\t\t\t\t rtlsdr_read_async_cb_t cb,\n\t\t\t\t void *ctx,\n\t\t\t\t uint32_t buf_num,\n\t\t\t\t uint32_t buf_len);\n\n/*!\n * Cancel all pending asynchronous operations on the device.\n * Due to incomplete concurrency implementation, this should\n * only be called from within the callback function, so it is\n * in the correct thread.\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\return 0 on success\n */\nRTLSDR_API int rtlsdr_cancel_async(rtlsdr_dev_t *dev);\n\n/*!\n * Read from the remote control (RC) infrared (IR) sensor\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param buf buffer to write IR signal (MSB=pulse/space, 7LSB=duration*20usec), recommended 128-bytes\n * \\param buf_len size of buf\n * \\return 0 if no signal, >0 number of bytes written into buf, <0 for error\n */\nRTLSDR_API int rtlsdr_ir_query(rtlsdr_dev_t *dev, uint8_t *buf, size_t buf_len);\n\n\n/*!\n * Enable or disable (the bias tee on) GPIO PIN 0 - if not reconfigured.\n * See rtlsdr_set_opt_string() option 'T'.\n * This works for rtl-sdr.com v3 dongles, see\n *   http://www.rtl-sdr.com/rtl-sdr-blog-v-3-dongles-user-guide/\n * Note: rtlsdr_close() does not clear GPIO lines,\n * so it leaves the (bias tee) line enabled if a client program\n * doesn't explictly disable it.\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param on  1 for Bias T on. 0 for Bias T off.\n * \\return -1 if device is not initialized. 0 otherwise.\n */\nRTLSDR_API int rtlsdr_set_bias_tee(rtlsdr_dev_t *dev, int on);\n\n/*!\n * Enable or disable (the bias tee on) the given GPIO pin.\n * Note: rtlsdr_close() does not clear GPIO lines,\n * so it leaves the (bias tee) lines enabled if a client program\n * doesn't explictly disable it.\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param gpio the gpio pin -- assuming this line is connected to Bias T.\n *        gpio needs to be in 0 .. 7. BUT pin 4 is connected to Tuner RESET.\n *        and for FC0012 is already connected/reserved pin 6 for switching V/U-HF.\n * \\param on  1 for Bias T on. 0 for Bias T off.\n * \\return -1 if device is not initialized. 0 otherwise.\n */\nRTLSDR_API int rtlsdr_set_bias_tee_gpio(rtlsdr_dev_t *dev, int gpio, int on);\n\n\n/*\n * GPIO 0 .. 7 correspond to RTL2832U's pins as follows:\n * Pin information from http://lea.hamradio.si/~s57uuu/mischam/rtlsdr/ports.html\n *\n *   GPIO0 (=pin 37): BiasT for RTL-SDR.com V3\n *   GPIO1 (=pin 32): usually free - on RTL-SDR.com V3's Expansion Ports\n *   GPIO2 (=pin 31): usually free - on RTL-SDR.com V3's Expansion Ports\n *   GPIO3 (=pin 36): usually free\n *   GPIO4 (=pin 30): RESET for Tuners FC2580 and FC0012 /  on RTL-SDR.com V3's Expansion Ports\n *   GPIO5 (=pin 29): usually free - on RTL-SDR.com V3's Expansion Ports\n *   GPIO6 (=pin 22): select V-band/U-band filter for FC0012-Tuner\n *   GPIO7 (=pin 21): usually free\n *\n * CAUTION: The port pins use 3.3V logic levels and are static sensitive!\n *\n * most of following functions are also copied from Marko Cebokli's site\n * http://lea.hamradio.si/~s57uuu/mischam/rtlsdr/ports.html\n * but added return of error/status.\n * GPIO numbers 'gpio' in range 0 .. 7 for the following gpio functions\n * all \\return negative values, on error\n */\nRTLSDR_API int rtlsdr_set_gpio_output(rtlsdr_dev_t *dev, uint8_t gpio);\nRTLSDR_API int rtlsdr_set_gpio_input(rtlsdr_dev_t *dev, uint8_t gpio);\n\nRTLSDR_API int rtlsdr_set_gpio_bit(rtlsdr_dev_t *dev, uint8_t gpio, int val);\nRTLSDR_API int rtlsdr_get_gpio_bit(rtlsdr_dev_t *dev, uint8_t gpio, int *val);\n\nRTLSDR_API int rtlsdr_set_gpio_byte(rtlsdr_dev_t *dev, int val);\nRTLSDR_API int rtlsdr_get_gpio_byte(rtlsdr_dev_t *dev, int *val);\n\nRTLSDR_API int rtlsdr_set_gpio_status(rtlsdr_dev_t *dev, int *status );\n\n\n/*!\n * Sets multiple options from a string encoded like \"bw=300:agc=0:gain=27.3:dagc=0:T=1\".\n * this is a helper function, that programs don't need to implement every single option\n *   at the command line interface.\n * Options are seperated by colon ':'.\n * There mustn't be extra spaces between option name and '='.\n * option 'f' set center frequency as in rtlsdr_set_center_freq()\n * option 'bw' sets tuner bandwidth as in rtlsdr_set_tuner_bandwidth()\n *   - but value is in kHz.\n * option 'agc' sets tuner gain mode as with rtlsdr_set_tuner_gain_mode():\n *   '1' means manual gain mode shall be enabled.\n * option 'gain' sets tuner gain as with rtlsdr_set_tuner_gain():\n *   values in tenth dB.\n * option 'dagc' or 'dgc' de/activates digital agc as with rtlsdr_set_agc_mode().\n *   value 1 to enable. 0 to disable.\n * option 'ds' set direct sampling as with rtlsdr_set_direct_sampling():\n *   '0' to deactivate, '1' or 'i' for I-ADC input, '2' or 'q' for Q-ADC input\n * option 't' or 'T' for enabling bias tee on GPIO PIN 0 as with rtlsdr_set_bias_tee():\n *   '1' for Bias T on. '0' for Bias T off.\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param opts described option string\n * \\param verbose print parsed options to stderr\n */\nRTLSDR_API int rtlsdr_set_opt_string(rtlsdr_dev_t *dev, const char *opts, int verbose);\n\nRTLSDR_API const char * rtlsdr_get_opt_help(int longInfo);\n\n\n/*!\n * Exposes/permits hacking of Tuner-specific I2C registers: set register once\n *\n * \\param dev           the device handle given by rtlsdr_open()\n * \\param i2c_register  register address\n * \\param mask          8-bit bitmask, indicating which bits shall be set\n * \\param data          8-bit data, which shall be set\n * \\return -1 if device is not initialized. 0 otherwise.\n */\nRTLSDR_API int rtlsdr_set_tuner_i2c_register(rtlsdr_dev_t *dev, unsigned i2c_register, unsigned mask, unsigned data);\n\n/* TODO: uint8_t */\nRTLSDR_API int rtlsdr_get_tuner_i2c_register(rtlsdr_dev_t *dev, unsigned char* data, int len);\n\n\n/*!\n * Exposes/permits hacking of Tuner-specific I2C registers: set and keep register for future\n *\n * \\param dev           the device handle given by rtlsdr_open()\n * \\param i2c_register  register address\n * \\param mask          8-bit bitmask, indicating which bits shall be set\n * \\param data          8-bit data, which shall be set; data in 0 .. 255 sets override; data > 255 clears override\n * \\return -1 if device is not initialized. 0 otherwise.\n */\nRTLSDR_API int rtlsdr_set_tuner_i2c_override(rtlsdr_dev_t *dev, unsigned i2c_register, unsigned mask, unsigned data);\n\n\n/*!\n * request version id string to identify source and date of library\n *\n * \\return pointer to C string, e.g. \"github.com/librtlsdr\" or \"github.com/hayguen\" or .. with build date (in parantheses)\n *   string keeps owned by library\n */\nRTLSDR_API const char * rtlsdr_get_ver_id();\n\n/*!\n * request version numbers of library\n *\n * \\return major version in upper 16 bit, minor revision in lower 16 bit\n */\nRTLSDR_API uint32_t rtlsdr_get_version();\n\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* __RTL_SDR_H */\n"
  },
  {
    "path": "include/rtl-sdr_export.h",
    "content": "/*\n * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver\n * Copyright (C) 2012 by Hoernchen <la@tfc-server.de>\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef RTLSDR_EXPORT_H\n#define RTLSDR_EXPORT_H\n\n#if defined __GNUC__\n#  if __GNUC__ >= 4\n#    define __SDR_EXPORT   __attribute__((visibility(\"default\")))\n#    define __SDR_IMPORT   __attribute__((visibility(\"default\")))\n#  else\n#    define __SDR_EXPORT\n#    define __SDR_IMPORT\n#  endif\n#elif _MSC_VER\n#  define __SDR_EXPORT     __declspec(dllexport)\n#  define __SDR_IMPORT     __declspec(dllimport)\n#else\n#  define __SDR_EXPORT\n#  define __SDR_IMPORT\n#endif\n\n#ifndef rtlsdr_STATIC\n#\tifdef rtlsdr_EXPORTS\n#\tdefine RTLSDR_API __SDR_EXPORT\n#\telse\n#\tdefine RTLSDR_API __SDR_IMPORT\n#\tendif\n#else\n#define RTLSDR_API\n#endif\n#endif /* RTLSDR_EXPORT_H */\n"
  },
  {
    "path": "include/rtl_tcp.h",
    "content": "/*\n * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver\n * Copyright (C) 2012-2013 by Steve Markgraf <steve@steve-m.de>\n * Copyright (C) 2012 by Dimitri Stolnikov <horiz0n@gmx.net>\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef __RTL_TCP_H\n#define __RTL_TCP_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*!\n * This enum defines the possible commands in rtl_tcp\n * commands 0x01..0x0E are compatible to osmocom's rtlsdr\n * see https://github.com/osmocom/rtl-sdr/blob/master/src/rtl_tcp.c\n * commands >= 0x40 are extensions\n */\nenum RTL_TCP_COMMANDS {\n    SET_FREQUENCY             = 0x01,   /* sets frequency - amending hi word of SET_FREQ_HI32 if present */\n    SET_FREQ_HI32             = 0x56,   /* in addition to SET_FREQUENCY */\n    SET_SAMPLE_RATE           = 0x02,\n    SET_GAIN_MODE             = 0x03,\n    SET_GAIN                  = 0x04,\n    SET_FREQUENCY_CORRECTION  = 0x05,\n    SET_IF_STAGE              = 0x06,\n    SET_TEST_MODE             = 0x07,\n    SET_AGC_MODE              = 0x08,\n    SET_DIRECT_SAMPLING       = 0x09,\n    SET_OFFSET_TUNING         = 0x0A,\n    SET_RTL_CRYSTAL           = 0x0B,\n    SET_TUNER_CRYSTAL         = 0x0C,\n    SET_TUNER_GAIN_BY_INDEX   = 0x0D,\n#if 1\n    /* development branch since 2018-10-03 */\n    SET_BIAS_TEE              = 0x0E,\n    SET_TUNER_BANDWIDTH       = 0x40,\n#else\n    /* prev code - used in ExtIO - to build compatible rtl_tcp.exe */\n    SET_TUNER_BANDWIDTH       = 0x0E,\n    SET_BIAS_TEE              = 0x0F\n#endif\n    UDP_ESTABLISH             = 0x41,\n    UDP_TERMINATE             = 0x42,\n    SET_I2C_TUNER_REGISTER    = 0x43,   /* for experiments: 32 bit data word:\n                                         * 31 .. 20: register (12 bits)\n                                         * 19 .. 12: mask (8 bits)\n                                         * 11 ..  0: data (12 bits) */\n    SET_I2C_TUNER_OVERRIDE    = 0x44,   /* encoding as with SET_I2C_TUNER_REGISTER\n                                         * data (bits 11 .. 0) > 255 removes override */\n    SET_TUNER_BW_IF_CENTER    = 0x45,   /* freq from SET_FREQUENCY stays in center;\n                                         * the bandwidth (from SET_TUNER_BANDWIDTH)\n                                         * is set to be centered at given IF frequency */\n    SET_TUNER_IF_MODE         = 0x46,   /* set tuner IF mode - or gain */\n    SET_SIDEBAND              = 0x47,   /* Mixer Sideband for R820T */\n    REPORT_I2C_REGS           = 0x48,   /* perodically report I2C registers\n                                         * - if reverse channel is enabled */\n\n    GPIO_SET_OUTPUT_MODE      = 0x49,   /* rtlsdr_set_gpio_output() */\n    GPIO_SET_INPUT_MODE       = 0x50,   /* rtlsdr_set_gpio_input() */\n    GPIO_GET_IO_STATUS        = 0x51,   /* rtlsdr_set_gpio_status() */\n    GPIO_WRITE_PIN            = 0x52,   /* rtlsdr_set_gpio_output() and rtlsdr_set_gpio_bit() */\n    GPIO_READ_PIN             = 0x53,   /* rtlsdr_get_gpio_bit() */\n    GPIO_GET_BYTE             = 0x54,   /* rtlsdr_get_gpio_byte() */\n    \n    IS_TUNER_PLL_LOCKED       = 0x55,   /* rtlsdr_is_tuner_PLL_locked() */\n\n    /* SET_FREQ_HI32          = 0x56,    * rtlsdr_set_center_freq64() */\n};\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "include/rtlsdr_i2c.h",
    "content": "#ifndef __I2C_H\n#define __I2C_H\n\nuint32_t rtlsdr_get_tuner_clock(void *dev);\nint rtlsdr_i2c_write_fn(void *dev, uint8_t addr, uint8_t *buf, int len);\nint rtlsdr_i2c_read_fn(void *dev, uint8_t addr, uint8_t *buf, int len);\n\n#endif\n"
  },
  {
    "path": "include/rtlsdr_rpc.h",
    "content": "#ifndef RTLSDR_RPC_H_INCLUDED\n#define RTLSDR_RPC_H_INCLUDED\n\n\n#include <stdint.h>\n\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef void (*rtlsdr_rpc_read_async_cb_t)\n(unsigned char*, uint32_t, void*);\n\nuint32_t rtlsdr_rpc_get_device_count(void);\n\nconst char* rtlsdr_rpc_get_device_name\n(uint32_t nidex);\n\nint rtlsdr_rpc_get_device_usb_strings\n(uint32_t index, char* manufact, char* product, char* serial);\n\nint rtlsdr_rpc_get_index_by_serial\n(const char* serial);\n\nint rtlsdr_rpc_open\n(void** dev, uint32_t index);\n\nint rtlsdr_rpc_close\n(void* dev);\n\nint rtlsdr_rpc_set_xtal_freq\n(void* dev, uint32_t rtl_freq, uint32_t tuner_freq);\n\nint rtlsdr_rpc_get_xtal_freq\n(void* dev, uint32_t* rtl_freq, uint32_t* tuner_freq);\n\nint rtlsdr_rpc_get_usb_strings\n(void* dev, char* manufact, char* product, char* serial);\n\nint rtlsdr_rpc_write_eeprom\n(void* dev, uint8_t* data, uint8_t offset, uint16_t len);\n\nint rtlsdr_rpc_read_eeprom\n(void* dev, uint8_t* data, uint8_t offset, uint16_t len);\n\nint rtlsdr_rpc_set_center_freq\n(void* dev, uint32_t freq);\n\nuint32_t rtlsdr_rpc_get_center_freq\n(void* dev);\n\nint rtlsdr_rpc_set_freq_correction\n(void* dev, int ppm);\n\nint rtlsdr_rpc_get_freq_correction\n(void *dev);\n\nint rtlsdr_rpc_get_tuner_type\n(void* dev);\n\nint rtlsdr_rpc_get_tuner_gains\n(void* dev, int* gainsp);\n\nint rtlsdr_rpc_set_tuner_gain\n(void *dev, int gain);\n\nint rtlsdr_rpc_get_tuner_gain\n(void* dev);\n\nint rtlsdr_rpc_set_tuner_if_gain\n(void* dev, int stage, int gain);\n\nint rtlsdr_rpc_set_tuner_gain_mode\n(void* dev, int manual);\n\nint rtlsdr_rpc_set_and_get_tuner_bandwidth\n(void* devp, uint32_t bw, uint32_t *applied_bw, int apply_bw);\n\nint rtlsdr_rpc_set_sample_rate\n(void* dev, uint32_t rate);\n\nuint32_t rtlsdr_rpc_get_sample_rate\n(void* dev);\n\nint rtlsdr_rpc_set_testmode\n(void* dev, int on);\n\nint rtlsdr_rpc_set_agc_mode\n(void* dev, int on);\n\nint rtlsdr_rpc_set_direct_sampling\n(void* dev, int on);\n\nint rtlsdr_rpc_get_direct_sampling\n(void* dev);\n\nint rtlsdr_rpc_set_offset_tuning\n(void* dev, int on);\n\nint rtlsdr_rpc_get_offset_tuning\n(void* dev);\n\nint rtlsdr_rpc_reset_buffer\n(void* dev);\n\nint rtlsdr_rpc_read_sync\n(void* dev, void* buf, int len, int* n_read);\n\nint rtlsdr_rpc_wait_async\n(void* dev, rtlsdr_rpc_read_async_cb_t cb, void* ctx);\n\nint rtlsdr_rpc_read_async\n(void* dev, rtlsdr_rpc_read_async_cb_t cb, void* ctx, uint32_t buf_num, uint32_t buf_len);\n\nint rtlsdr_rpc_cancel_async\n(void* dev);\n\nunsigned int rtlsdr_rpc_is_enabled(void);\n\n#ifdef __cplusplus\n}\n#endif\n\n\n#endif /* RTLSDR_RPC_H_INCLUDED */\n"
  },
  {
    "path": "include/rtlsdr_rpc_msg.h",
    "content": "#ifndef RTLSDR_RPC_MSG_H_INCLUDED\n#define RTLSDR_RPC_MSG_H_INCLUDED\n\n\n#include <stdint.h>\n#include <sys/types.h>\n\ntypedef enum\n{\n  RTLSDR_RPC_OP_GET_DEVICE_COUNT = 0,\n  RTLSDR_RPC_OP_GET_DEVICE_NAME,\n  RTLSDR_RPC_OP_GET_DEVICE_USB_STRINGS,\n  RTLSDR_RPC_OP_GET_INDEX_BY_SERIAL,\n  RTLSDR_RPC_OP_OPEN,\n  RTLSDR_RPC_OP_CLOSE,\n  RTLSDR_RPC_OP_SET_XTAL_FREQ,\n  RTLSDR_RPC_OP_GET_XTAL_FREQ,\n  RTLSDR_RPC_OP_GET_USB_STRINGS,\n  RTLSDR_RPC_OP_WRITE_EEPROM,\n  RTLSDR_RPC_OP_READ_EEPROM,\n  RTLSDR_RPC_OP_SET_CENTER_FREQ,\n  RTLSDR_RPC_OP_GET_CENTER_FREQ,\n  RTLSDR_RPC_OP_SET_FREQ_CORRECTION,\n  RTLSDR_RPC_OP_GET_FREQ_CORRECTION,\n  RTLSDR_RPC_OP_GET_TUNER_TYPE,\n  RTLSDR_RPC_OP_GET_TUNER_GAINS,\n  RTLSDR_RPC_OP_SET_TUNER_GAIN,\n  RTLSDR_RPC_OP_GET_TUNER_GAIN,\n  RTLSDR_RPC_OP_SET_TUNER_IF_GAIN,\n  RTLSDR_RPC_OP_SET_TUNER_GAIN_MODE,\n  RTLSDR_RPC_OP_SET_GET_TUNER_BW,\n  RTLSDR_RPC_OP_SET_SAMPLE_RATE,\n  RTLSDR_RPC_OP_GET_SAMPLE_RATE,\n  RTLSDR_RPC_OP_SET_TESTMODE,\n  RTLSDR_RPC_OP_SET_AGC_MODE,\n  RTLSDR_RPC_OP_SET_DIRECT_SAMPLING,\n  RTLSDR_RPC_OP_GET_DIRECT_SAMPLING,\n  RTLSDR_RPC_OP_SET_OFFSET_TUNING,\n  RTLSDR_RPC_OP_GET_OFFSET_TUNING,\n  RTLSDR_RPC_OP_RESET_BUFFER,\n  RTLSDR_RPC_OP_READ_SYNC,\n  RTLSDR_RPC_OP_WAIT_ASYNC,\n  RTLSDR_RPC_OP_READ_ASYNC,\n  RTLSDR_RPC_OP_CANCEL_ASYNC,\n\n  /* non api operations */\n  RTLSDR_RPC_OP_EVENT_STATE,\n \n  RTLSDR_RPC_OP_INVALID\n} rtlsdr_rpc_op_t;\n\ntypedef struct\n{\n  /* raw network format */\n  uint32_t size;\n  uint8_t op;\n  uint8_t id;\n  uint32_t err;\n  uint8_t data[1];\n} __attribute__((packed)) rtlsdr_rpc_fmt_t;\n\ntypedef struct\n{\n  size_t off;\n  size_t size;\n  uint8_t* fmt;\n} rtlsdr_rpc_msg_t;\n\nint rtlsdr_rpc_msg_init(rtlsdr_rpc_msg_t*, size_t);\nint rtlsdr_rpc_msg_fini(rtlsdr_rpc_msg_t*);\nvoid rtlsdr_rpc_msg_reset(rtlsdr_rpc_msg_t*);\nint rtlsdr_rpc_msg_realloc(rtlsdr_rpc_msg_t*, size_t);\n\nvoid rtlsdr_rpc_msg_set_size(rtlsdr_rpc_msg_t*, size_t);\nsize_t rtlsdr_rpc_msg_get_size(const rtlsdr_rpc_msg_t*);\nvoid rtlsdr_rpc_msg_set_op(rtlsdr_rpc_msg_t*, rtlsdr_rpc_op_t);\nrtlsdr_rpc_op_t rtlsdr_rpc_msg_get_op(const rtlsdr_rpc_msg_t*);\nvoid rtlsdr_rpc_msg_set_id(rtlsdr_rpc_msg_t*, uint8_t);\nuint8_t rtlsdr_rpc_msg_get_id(const rtlsdr_rpc_msg_t*);\nvoid rtlsdr_rpc_msg_set_err(rtlsdr_rpc_msg_t*, int);\nint rtlsdr_rpc_msg_get_err(const rtlsdr_rpc_msg_t*);\n\nint rtlsdr_rpc_msg_push_int32(rtlsdr_rpc_msg_t*, int32_t);\nint rtlsdr_rpc_msg_push_uint32(rtlsdr_rpc_msg_t*, uint32_t);\nvoid rtlsdr_rpc_msg_push_uint32_safe(rtlsdr_rpc_msg_t*, uint32_t);\nint rtlsdr_rpc_msg_push_str(rtlsdr_rpc_msg_t*, const char*);\nint rtlsdr_rpc_msg_push_buf(rtlsdr_rpc_msg_t*, const uint8_t*, size_t);\nvoid rtlsdr_rpc_msg_skip_safe(rtlsdr_rpc_msg_t*, size_t);\nint rtlsdr_rpc_msg_pop_int32(rtlsdr_rpc_msg_t*, int32_t*);\nint rtlsdr_rpc_msg_pop_uint32(rtlsdr_rpc_msg_t*, uint32_t*);\nint rtlsdr_rpc_msg_pop_str(rtlsdr_rpc_msg_t*, const char**);\nint rtlsdr_rpc_msg_pop_buf(rtlsdr_rpc_msg_t*, const uint8_t**, size_t*);\n\n\n#endif /* RTLSDR_RPC_MSG_H_INCLUDED */\n"
  },
  {
    "path": "include/tuner_e4k.h",
    "content": "#ifndef _E4K_TUNER_H\n#define _E4K_TUNER_H\n\n/*\n * Elonics E4000 tuner driver\n *\n * (C) 2011-2012 by Harald Welte <laforge@gnumonks.org>\n * (C) 2012 by Sylvain Munaut <tnt@246tNt.com>\n * (C) 2012 by Hoernchen <la@tfc-server.de>\n *\n * All Rights Reserved\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#define E4K_I2C_ADDR\t0xc8\n#define E4K_CHECK_ADDR\t0x02\n#define E4K_CHECK_VAL\t0x40\n\nenum e4k_reg {\n\tE4K_REG_MASTER1\t\t\t= 0x00,\n\tE4K_REG_MASTER2\t\t\t= 0x01,\n\tE4K_REG_MASTER3\t\t\t= 0x02,\n\tE4K_REG_MASTER4\t\t\t= 0x03,\n\tE4K_REG_MASTER5\t\t\t= 0x04,\n\tE4K_REG_CLK_INP\t\t\t= 0x05,\n\tE4K_REG_REF_CLK\t\t\t= 0x06,\n\tE4K_REG_SYNTH1\t\t\t= 0x07,\n\tE4K_REG_SYNTH2\t\t\t= 0x08,\n\tE4K_REG_SYNTH3\t\t\t= 0x09,\n\tE4K_REG_SYNTH4\t\t\t= 0x0a,\n\tE4K_REG_SYNTH5\t\t\t= 0x0b,\n\tE4K_REG_SYNTH6\t\t\t= 0x0c,\n\tE4K_REG_SYNTH7\t\t\t= 0x0d,\n\tE4K_REG_SYNTH8\t\t\t= 0x0e,\n\tE4K_REG_SYNTH9\t\t\t= 0x0f,\n\tE4K_REG_FILT1\t\t\t= 0x10,\n\tE4K_REG_FILT2\t\t\t= 0x11,\n\tE4K_REG_FILT3\t\t\t= 0x12,\n\t// gap\n\tE4K_REG_GAIN1\t\t\t= 0x14,\n\tE4K_REG_GAIN2\t\t\t= 0x15,\n\tE4K_REG_GAIN3\t\t\t= 0x16,\n\tE4K_REG_GAIN4\t\t\t= 0x17,\n\t// gap\n\tE4K_REG_AGC1\t\t\t= 0x1a,\n\tE4K_REG_AGC2\t\t\t= 0x1b,\n\tE4K_REG_AGC3\t\t\t= 0x1c,\n\tE4K_REG_AGC4\t\t\t= 0x1d,\n\tE4K_REG_AGC5\t\t\t= 0x1e,\n\tE4K_REG_AGC6\t\t\t= 0x1f,\n\tE4K_REG_AGC7\t\t\t= 0x20,\n\tE4K_REG_AGC8\t\t\t= 0x21,\n\t// gap\n\tE4K_REG_AGC11\t\t\t= 0x24,\n\tE4K_REG_AGC12\t\t\t= 0x25,\n\t// gap\n\tE4K_REG_DC1\t\t\t\t= 0x29,\n\tE4K_REG_DC2\t\t\t\t= 0x2a,\n\tE4K_REG_DC3\t\t\t\t= 0x2b,\n\tE4K_REG_DC4\t\t\t\t= 0x2c,\n\tE4K_REG_DC5\t\t\t\t= 0x2d,\n\tE4K_REG_DC6\t\t\t\t= 0x2e,\n\tE4K_REG_DC7\t\t\t\t= 0x2f,\n\tE4K_REG_DC8\t\t\t\t= 0x30,\n\t// gap\n\tE4K_REG_QLUT0\t\t\t= 0x50,\n\tE4K_REG_QLUT1\t\t\t= 0x51,\n\tE4K_REG_QLUT2\t\t\t= 0x52,\n\tE4K_REG_QLUT3\t\t\t= 0x53,\n\t// gap\n\tE4K_REG_ILUT0\t\t\t= 0x60,\n\tE4K_REG_ILUT1\t\t\t= 0x61,\n\tE4K_REG_ILUT2\t\t\t= 0x62,\n\tE4K_REG_ILUT3\t\t\t= 0x63,\n\t// gap\n\tE4K_REG_DCTIME1\t\t\t= 0x70,\n\tE4K_REG_DCTIME2\t\t\t= 0x71,\n\tE4K_REG_DCTIME3\t\t\t= 0x72,\n\tE4K_REG_DCTIME4\t\t\t= 0x73,\n\tE4K_REG_PWM1\t\t\t= 0x74,\n\tE4K_REG_PWM2\t\t\t= 0x75,\n\tE4K_REG_PWM3\t\t\t= 0x76,\n\tE4K_REG_PWM4\t\t\t= 0x77,\n\tE4K_REG_BIAS\t\t\t= 0x78,\n\tE4K_REG_CLKOUT_PWDN\t\t= 0x7a,\n\tE4K_REG_CHFILT_CALIB\t= 0x7b,\n\tE4K_REG_I2C_REG_ADDR\t= 0x7d,\n\t// FIXME\n};\n\n#define E4K_MASTER1_RESET\t\t(1 << 0)\n#define E4K_MASTER1_NORM_STBY\t(1 << 1)\n#define E4K_MASTER1_POR_DET\t\t(1 << 2)\n\n#define E4K_SYNTH1_PLL_LOCK\t\t(1 << 0)\n#define E4K_SYNTH1_BAND_SHIF\t1\n\n#define E4K_SYNTH7_3PHASE_EN\t(1 << 3)\n\n#define E4K_SYNTH8_VCOCAL_UPD\t(1 << 2)\n\n#define E4K_FILT3_DISABLE\t\t(1 << 5)\n\n#define E4K_AGC1_LIN_MODE\t\t(1 << 4)\n#define E4K_AGC1_LNA_UPDATE\t\t(1 << 5)\n#define E4K_AGC1_LNA_G_LOW\t\t(1 << 6)\n#define E4K_AGC1_LNA_G_HIGH\t\t(1 << 7)\n\n#define E4K_AGC6_LNA_CAL_REQ\t(1 << 4)\n\n#define E4K_AGC7_MIX_GAIN_AUTO\t(1 << 0)\n#define E4K_AGC7_GAIN_STEP_5dB\t(1 << 5)\n\n#define E4K_AGC8_SENS_LIN_AUTO\t(1 << 0)\n\n#define E4K_AGC11_LNA_GAIN_ENH\t(1 << 0)\n\n#define E4K_DC1_CAL_REQ\t\t\t(1 << 0)\n\n#define E4K_DC5_I_LUT_EN\t\t(1 << 0)\n#define E4K_DC5_Q_LUT_EN\t\t(1 << 1)\n#define E4K_DC5_RANGE_DET_EN\t(1 << 2)\n#define E4K_DC5_RANGE_EN\t\t(1 << 3)\n#define E4K_DC5_TIMEVAR_EN\t\t(1 << 4)\n\n#define E4K_CLKOUT_DISABLE\t\t0x96\n\n#define E4K_CHFCALIB_CMD\t\t(1 << 0)\n\n#define E4K_AGC1_MOD_MASK\t\t0xF\n\nenum e4k_agc_mode {\n\tE4K_AGC_MOD_SERIAL\t\t\t\t= 0x0,\n\tE4K_AGC_MOD_IF_PWM_LNA_SERIAL\t= 0x1,\n\tE4K_AGC_MOD_IF_PWM_LNA_AUTONL\t= 0x2,\n\tE4K_AGC_MOD_IF_PWM_LNA_SUPERV\t= 0x3,\n\tE4K_AGC_MOD_IF_SERIAL_LNA_PWM\t= 0x4,\n\tE4K_AGC_MOD_IF_PWM_LNA_PWM\t\t= 0x5,\n\tE4K_AGC_MOD_IF_DIG_LNA_SERIAL\t= 0x6,\n\tE4K_AGC_MOD_IF_DIG_LNA_AUTON\t= 0x7,\n\tE4K_AGC_MOD_IF_DIG_LNA_SUPERV\t= 0x8,\n\tE4K_AGC_MOD_IF_SERIAL_LNA_AUTON\t= 0x9,\n\tE4K_AGC_MOD_IF_SERIAL_LNA_SUPERV = 0xa,\n};\n\nenum e4k_band {\n\tE4K_BAND_VHF2\t= 0,\n\tE4K_BAND_VHF3\t= 1,\n\tE4K_BAND_UHF\t= 2,\n\tE4K_BAND_L\t\t= 3,\n};\n\nenum e4k_mixer_filter_bw {\n\tE4K_F_MIX_BW_27M\t= 0,\n\tE4K_F_MIX_BW_4M6\t= 8,\n\tE4K_F_MIX_BW_4M2\t= 9,\n\tE4K_F_MIX_BW_3M8\t= 10,\n\tE4K_F_MIX_BW_3M4\t= 11,\n\tE4K_F_MIX_BW_3M\t\t= 12,\n\tE4K_F_MIX_BW_2M7\t= 13,\n\tE4K_F_MIX_BW_2M3\t= 14,\n\tE4K_F_MIX_BW_1M9\t= 15,\n};\n\nenum e4k_if_filter {\n\tE4K_IF_FILTER_MIX,\n\tE4K_IF_FILTER_CHAN,\n\tE4K_IF_FILTER_RC\n};\nstruct e4k_pll_params {\n\tuint32_t fosc;\n\tuint32_t intended_flo;\n\tuint32_t flo;\n\tuint16_t x;\n\tuint8_t z;\n\tuint8_t r;\n\tuint8_t r_idx;\n\tuint8_t threephase;\n};\n\nstruct e4k_state {\n\tvoid *i2c_dev;\n\tuint8_t i2c_addr;\n\tenum e4k_band band;\n\tstruct e4k_pll_params vco;\n\tvoid *rtl_dev;\n};\n\nint e4k_init(struct e4k_state *e4k);\nint e4k_standby(struct e4k_state *e4k, int enable);\nint e4k_if_gain_set(struct e4k_state *e4k, uint8_t stage, int8_t value);\nint e4k_mixer_gain_set(struct e4k_state *e4k, int8_t value);\nint e4k_commonmode_set(struct e4k_state *e4k, int8_t value);\nint e4k_tune_freq(struct e4k_state *e4k, uint32_t freq);\nint e4k_tune_params(struct e4k_state *e4k, struct e4k_pll_params *p);\nuint32_t e4k_compute_pll_params(struct e4k_pll_params *oscp, uint32_t fosc, uint32_t intended_flo);\nint e4k_if_filter_bw_get(struct e4k_state *e4k, enum e4k_if_filter filter);\nint e4k_if_filter_bw_set(struct e4k_state *e4k, enum e4k_if_filter filter,\n\t\t         uint32_t bandwidth);\nint e4k_if_filter_chan_enable(struct e4k_state *e4k, int on);\nint e4k_rf_filter_set(struct e4k_state *e4k);\n\nint e4k_manual_dc_offset(struct e4k_state *e4k, int8_t iofs, int8_t irange, int8_t qofs, int8_t qrange);\nint e4k_dc_offset_calibrate(struct e4k_state *e4k);\nint e4k_dc_offset_gen_table(struct e4k_state *e4k);\n\nint e4k_set_lna_gain(struct e4k_state *e4k, int32_t gain);\nint e4k_enable_manual_gain(struct e4k_state *e4k, uint8_t manual);\nint e4k_set_enh_gain(struct e4k_state *e4k, int32_t gain);\n#endif /* _E4K_TUNER_H */\n"
  },
  {
    "path": "include/tuner_fc0012.h",
    "content": "/*\n * Fitipower FC0012 tuner driver\n *\n * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net>\n *\n * modified for use in librtlsdr\n * Copyright (C) 2012 Steve Markgraf <steve@steve-m.de>\n *\n *    This program is free software; you can redistribute it and/or modify\n *    it under the terms of the GNU General Public License as published by\n *    the Free Software Foundation; either version 2 of the License, or\n *    (at your option) any later version.\n *\n *    This program is distributed in the hope that it will be useful,\n *    but WITHOUT ANY WARRANTY; without even the implied warranty of\n *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *    GNU General Public License for more details.\n *\n *    You should have received a copy of the GNU General Public License\n *    along with this program; if not, write to the Free Software\n *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n */\n\n#ifndef _FC0012_H_\n#define _FC0012_H_\n\n#define FC0012_I2C_ADDR\t\t0xc6\n#define FC0012_CHECK_ADDR\t0x00\n#define FC0012_CHECK_VAL\t0xa1\n\nint fc0012_init(void *dev);\nint fc0012_set_params(void *dev, uint32_t freq, uint32_t bandwidth);\nint fc0012_set_gain(void *dev, int gain);\nint fc0012_set_i2c_register(void *dev, unsigned i2c_register, unsigned data);\nint fc0012_get_i2c_register(void *dev, unsigned char* data, int len);\n\n#endif\n"
  },
  {
    "path": "include/tuner_fc0013.h",
    "content": "/*\n * Fitipower FC0013 tuner driver\n *\n * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net>\n *\n * modified for use in librtlsdr\n * Copyright (C) 2012 Steve Markgraf <steve@steve-m.de>\n *\n *    This program is free software; you can redistribute it and/or modify\n *    it under the terms of the GNU General Public License as published by\n *    the Free Software Foundation; either version 2 of the License, or\n *    (at your option) any later version.\n *\n *    This program is distributed in the hope that it will be useful,\n *    but WITHOUT ANY WARRANTY; without even the implied warranty of\n *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *    GNU General Public License for more details.\n *\n *    You should have received a copy of the GNU General Public License\n *    along with this program; if not, write to the Free Software\n *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n */\n\n#ifndef _FC0013_H_\n#define _FC0013_H_\n\n#define FC0013_I2C_ADDR\t\t0xc6\n#define FC0013_CHECK_ADDR\t0x00\n#define FC0013_CHECK_VAL\t0xa3\n\nint fc0013_init(void *dev);\nint fc0013_set_params(void *dev, uint32_t freq, uint32_t bandwidth);\nint fc0013_set_gain_mode(void *dev, int manual);\nint fc0013_set_lna_gain(void *dev, int gain);\n\n#endif\n"
  },
  {
    "path": "include/tuner_fc2580.h",
    "content": "#ifndef __TUNER_FC2580_H\n#define __TUNER_FC2580_H\n\n#define\tBORDER_FREQ\t\t\t2600000\t/* 2.6GHz : The border frequency which determines whether Low VCO or High VCO is used */\n#define USE_EXT_CLK\t\t\t0\t\t/* 0 : Use internal XTAL Oscillator / 1 : Use External Clock input */\n#define OFS_RSSI \t\t\t57\n\n#define FC2580_I2C_ADDR\t\t0xac\n#define FC2580_CHECK_ADDR\t0x01\n#define FC2580_CHECK_VAL\t0x56\n\n/* 16.384 MHz (at least on the Logilink VG0002A) */\n#define FC2580_XTAL_FREQ\t16384000\n\ntypedef enum {\n\tFC2580_UHF_BAND,\n\tFC2580_L_BAND,\n\tFC2580_VHF_BAND,\n\tFC2580_NO_BAND\n} fc2580_band_type;\n\ntypedef enum {\n\tFC2580_FCI_FAIL,\n\tFC2580_FCI_SUCCESS\n} fc2580_fci_result_type;\n\nenum FUNCTION_STATUS\n{\n\tFUNCTION_SUCCESS,\n\tFUNCTION_ERROR,\n};\n\nextern void fc2580_wait_msec(void *pTuner, int a);\n\nfc2580_fci_result_type fc2580_i2c_write(void *pTuner, unsigned char reg, unsigned char val);\nfc2580_fci_result_type fc2580_i2c_read(void *pTuner, unsigned char reg, unsigned char *read_data);\n\n/*==============================================================================\n       fc2580 initial setting\n\n  This function is a generic function which gets called to initialize\n\n  fc2580 in DVB-H mode or L-Band TDMB mode\n\n  <input parameter>\n\n  ifagc_mode\n    type : integer\n\t1 : Internal AGC\n\t2 : Voltage Control Mode\n\n==============================================================================*/\nfc2580_fci_result_type fc2580_set_init(void *pTuner, int ifagc_mode, unsigned int freq_xtal );\n\n/*==============================================================================\n       fc2580 frequency setting\n\n  This function is a generic function which gets called to change LO Frequency\n\n  of fc2580 in DVB-H mode or L-Band TDMB mode\n\n  <input parameter>\n\n  f_lo\n\tValue of target LO Frequency in 'kHz' unit\n\tex) 2.6GHz = 2600000\n\n==============================================================================*/\nfc2580_fci_result_type fc2580_set_freq(void *pTuner, unsigned int f_lo, unsigned int freq_xtal );\n\n\n/*==============================================================================\n       fc2580 filter BW setting\n\n  This function is a generic function which gets called to change Bandwidth\n\n  frequency of fc2580's channel selection filter\n\n  <input parameter>\n\n  filter_bw\n    1 : 1.53MHz(TDMB)\n\t6 : 6MHz\n\t7 : 7MHz\n\t8 : 7.8MHz\n\n\n==============================================================================*/\nfc2580_fci_result_type fc2580_set_filter( void *pTuner, unsigned char filter_bw, unsigned int freq_xtal );\n\n// The following context is FC2580 tuner API source code\n// Definitions\n\n// AGC mode\nenum FC2580_AGC_MODE\n{\n\tFC2580_AGC_INTERNAL = 1,\n\tFC2580_AGC_EXTERNAL = 2,\n};\n\n\n// Bandwidth mode\nenum FC2580_BANDWIDTH_MODE\n{\n\tFC2580_BANDWIDTH_1530000HZ = 1,\n\tFC2580_BANDWIDTH_6000000HZ = 6,\n\tFC2580_BANDWIDTH_7000000HZ = 7,\n\tFC2580_BANDWIDTH_8000000HZ = 8,\n};\n\n// Manipulaing functions\nint\nfc2580_Initialize(\n\tvoid *pTuner\n\t);\n\nint\nfc2580_SetRfFreqHz(\n\tvoid *pTuner,\n\tunsigned long RfFreqHz\n\t);\n\n// Extra manipulaing functions\nint\nfc2580_SetBandwidthMode(\n\tvoid *pTuner,\n\tint BandwidthMode\n\t);\n\n#endif\n"
  },
  {
    "path": "include/tuner_r82xx.h",
    "content": "/*\n * Rafael Micro R820T/R828D driver\n *\n * Copyright (C) 2013 Mauro Carvalho Chehab <mchehab@redhat.com>\n * Copyright (C) 2013 Steve Markgraf <steve@steve-m.de>\n *\n * This driver is a heavily modified version of the driver found in the\n * Linux kernel:\n * http://git.linuxtv.org/linux-2.6.git/history/HEAD:/drivers/media/tuners/r820t.c\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef R82XX_H\n#define R82XX_H\n\n#define R820T_I2C_ADDR\t\t0x34\n#define R828D_I2C_ADDR\t\t0x74\n#define R828D_XTAL_FREQ\t\t16000000\n\n#define R82XX_CHECK_ADDR\t0x00\n#define R82XX_CHECK_VAL\t\t0x69\n\n#define R82XX_IF_FREQ\t\t3570000\n\n#define REG_SHADOW_START\t5\n#define NUM_REGS\t\t\t32\n#define NUM_IMR\t\t\t\t5\n#define IMR_TRIAL\t\t\t9\n\n#define VER_NUM\t\t\t\t49\n\n#define USE_R82XX_ENV_VARS\t0\n\nenum r82xx_chip {\n\tCHIP_R820T,\n\tCHIP_R620D,\n\tCHIP_R828D,\n\tCHIP_R828,\n\tCHIP_R828S,\n\tCHIP_R820C,\n};\n\nenum r82xx_tuner_type {\n\tTUNER_RADIO = 1,\n\tTUNER_ANALOG_TV,\n\tTUNER_DIGITAL_TV\n};\n\nenum r82xx_xtal_cap_value {\n\tXTAL_LOW_CAP_30P = 0,\n\tXTAL_LOW_CAP_20P,\n\tXTAL_LOW_CAP_10P,\n\tXTAL_LOW_CAP_0P,\n\tXTAL_HIGH_CAP_0P\n};\n\nstruct r82xx_config {\n\tuint8_t i2c_addr;\n\tuint8_t vco_curr_min;  /* VCO min/max current for R18/0x12 bits [7:5] in 0 .. 7. use 0xff for default */\n\tuint8_t vco_curr_max;  /* value is inverted: programmed is 7-value, that 0 is lowest current */\n\tuint8_t vco_algo;\n\tint harmonic;\n\tuint32_t xtal;\n\tenum r82xx_chip rafael_chip;\n\tunsigned int max_i2c_msg_len;\n\tint use_predetect;\n\tint verbose;\n};\n\nstruct r82xx_priv {\n\tstruct r82xx_config\t\t*cfg;\n\n\tuint8_t\t\t\t\t\t\tregs[NUM_REGS];\n\tuint8_t\t\t\t\t\t\tbuf[NUM_REGS + 1];\n\tuint8_t\t\t\t\t\t\toverride_data[NUM_REGS];\n\tuint8_t\t\t\t\t\t\toverride_mask[NUM_REGS];\n\tenum r82xx_xtal_cap_value\txtal_cap_sel;\n\tuint16_t\t\t\t\t\tpll;\t/* kHz */\n\tuint64_t\t\t\t\t\trf_freq;  /* frequency from r82xx_set_freq() */\n\tuint32_t\t\t\t\t\tint_freq; /* if frequency at which to deliver towards RTL2832U */\n\tint32_t\t\t\t\t\t\tif_band_center_freq;\t/* frequency relative to zero IF,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t * on which the band center shall be positioned */\n\tuint8_t\t\t\t\t\t\tfil_cal_code;\n\tuint8_t\t\t\t\t\t\tinput;\n\tuint8_t\t\t\t\t\t\tlast_vco_curr;\n\tint\t\t\t\t\t\t\thas_lock;\n\tint\t\t\t\t\t\t\ttuner_pll_set;\n\tint\t\t\t\t\t\t\ttuner_harmonic;\n\tint\t\t\t\t\t\t\tinit_done;\n\tint\t\t\t\t\t\t\tsideband;\n\tint\t\t\t\t\t\t\tdisable_dither;\n\n\t/* Store current mode */\n\tuint32_t\t\t\t\tdelsys;\n\tenum r82xx_tuner_type\ttype;\n\tuint32_t\t\t\t\tbw;\t/* in MHz */\n\tvoid \t\t\t\t\t*rtl_dev;\n\n\tint\t\t\t\tlast_if_mode;\n\tint\t\t\t\tlast_manual_gain;\n\tint\t\t\t\tlast_extended_mode;\n\tint\t\t\t\tlast_LNA_value;\n\tint\t\t\t\tlast_Mixer_value;\n\tint\t\t\t\tlast_VGA_value;\n\n#if USE_R82XX_ENV_VARS\n\t/* store some environment variables */\n\tint printI2C;\n\tunsigned int filterCenter;\n\tunsigned int haveR9, valR9;\n\tunsigned int haveR10L, valR10L;\n\tunsigned int haveR10H, valR10H;\n\tunsigned int haveR11L, valR11L;\n\tunsigned int haveR11H, valR11H;\n\tunsigned int haveR13L, valR13L;\n\tunsigned int haveR13H, valR13H;\n\tunsigned int haveR14L, valR14L;\n\tunsigned int haveR14H, valR14H;\n\tunsigned int haveR30H, valR30H;\n\tunsigned int haveR30L, valR30L;\n#endif\n};\n\nstruct r82xx_freq_range {\n\tuint32_t\tfreq;\n\tuint8_t\t\topen_d;\n\tuint8_t\t\trf_mux_ploy;\n\tuint8_t\t\ttf_c;\n\tuint8_t\t\txtal_cap20p;\n\tuint8_t\t\txtal_cap10p;\n\tuint8_t\t\txtal_cap0p;\n};\n\nenum r82xx_delivery_system {\n\tSYS_UNDEFINED,\n\tSYS_DVBT,\n\tSYS_DVBT2,\n\tSYS_ISDBT,\n};\n\nint r82xx_standby(struct r82xx_priv *priv);\nint r82xx_init(struct r82xx_priv *priv);\nint r82xx_set_freq(struct r82xx_priv *priv, uint32_t freq);\nint r82xx_set_freq64(struct r82xx_priv *priv, uint64_t freq);\nint r82xx_is_tuner_locked(struct r82xx_priv *priv);\nint r82xx_set_gain(struct r82xx_priv *priv, int set_manual_gain, int gain, int extended_mode, int lna_gain, int mixer_gain, int vga_gain, int *rtl_vga_control);\nint r82xx_get_rf_gain(struct r82xx_priv *priv);\nint r82xx_get_if_gain(struct r82xx_priv *priv);\n\nint r82xx_set_if_mode(struct r82xx_priv *priv, int if_mode, int *rtl_vga_control);\n\nint r82xx_set_i2c_register(struct r82xx_priv *priv, unsigned i2c_register, unsigned data, unsigned mask);\nint r82xx_get_i2c_register(struct r82xx_priv *priv, unsigned char* data, int len);\nint r82xx_set_i2c_override(struct r82xx_priv *priv, unsigned i2c_register, unsigned data, unsigned mask);\n\nint r82xx_set_bandwidth(struct r82xx_priv *priv, int bandwidth,  uint32_t rate, uint32_t * applied_bw, int apply);\nint r82xx_set_bw_center(struct r82xx_priv *priv, int32_t if_band_center_freq);\n/* Mixer Sideband:  0: lower, 1: upper */\nint r82xx_set_sideband(struct r82xx_priv *priv, int sideband);\nint r82xx_get_sideband(struct r82xx_priv *priv);\n/* should rtlsdr flip the spectrum? */\nint r82xx_flip_rtl_sideband(struct r82xx_priv *priv);\nint r82xx_set_dither(struct r82xx_priv *priv, int dither);\n\nint r82xx_read_cache_reg(struct r82xx_priv *priv, int reg);\nint r82xx_write_reg_mask(struct r82xx_priv *priv, uint8_t reg, uint8_t val,uint8_t bit_mask);\nint r82xx_write_reg_mask_ext(struct r82xx_priv *priv, uint8_t reg, uint8_t val, uint8_t bit_mask, const char * func_name);\n\nint rtlsdr_check_dongle_model(void *dev, char *manufact_check, char *product_check);\n\n#endif\n\n"
  },
  {
    "path": "install-blacklist.sh",
    "content": "#!/bin/bash\n\nBLACKLIST_FN=\"\"\nif [ -f /etc/modprobe.d/rtlsdr-blacklist.conf ]; then\n  BLACKLIST_FN=\"rtlsdr-blacklist.conf\"\n  echo \"found /etc/modprobe.d/${BLACKLIST_FN}\"\nelif [ -f /etc/modprobe.d/blacklist-rtl8xxxu.conf ]; then\n  BLACKLIST_FN=\"blacklist-rtl8xxxu.conf\"\n  echo \"found /etc/modprobe.d/${BLACKLIST_FN}\"\nelif [ -f /etc/modprobe.d/raspi-blacklist.conf ]; then\n  BLACKLIST_FN=\"raspi-blacklist.conf\"\n  echo \"found /etc/modprobe.d/${BLACKLIST_FN}\"\nelse\n  BLACKLIST_FN=\"rtlsdr-blacklist.conf\"\n  echo \"could not find existing blacklist. will use /etc/modprobe.d/${BLACKLIST_FN}\"\nfi\n\nif [ -f /etc/modprobe.d/${BLACKLIST_FN} ]; then\n  cat /etc/modprobe.d/${BLACKLIST_FN} rtlsdr-blacklist.conf | sort | uniq >/dev/shm/${BLACKLIST_FN}\n  cp /dev/shm/${BLACKLIST_FN} /etc/modprobe.d/${BLACKLIST_FN}\n  echo \"updated /etc/modprobe.d/${BLACKLIST_FN} ; reboot to apply\"\nelse\n  cp rtlsdr-blacklist.conf /etc/modprobe.d/${BLACKLIST_FN}\n  echo \"created /etc/modprobe.d/${BLACKLIST_FN} ; reboot to apply\"\nfi\n\n"
  },
  {
    "path": "librtlsdr.pc.in",
    "content": "prefix=@prefix@\nexec_prefix=@exec_prefix@\nlibdir=@libdir@\nincludedir=@includedir@\n\nName: RTL-SDR Library\nDescription: C Utility Library\nVersion: @VERSION@\nCflags: -I${includedir}/ @RTLSDR_PC_CFLAGS@\nLibs: -L${libdir} -lrtlsdr -lusb-1.0\nLibs.private: @RTLSDR_PC_LIBS@\n"
  },
  {
    "path": "m4/.gitignore",
    "content": "/libtool.m4\n/lt*.m4\n"
  },
  {
    "path": "mingw-w32-i686.cmake",
    "content": "# Sample toolchain file for building for Windows from an Ubuntu Linux system.\n#\n# Typical usage:\n#    *) install cross compiler: `sudo apt-get install mingw-w64`\n#    *) cd build\n#    *) cmake -DCMAKE_TOOLCHAIN_FILE=~/mingw-w32-i686.cmake ..\n#\n# build for Windows' 32 bit architecture\n\nset(CMAKE_SYSTEM_NAME Windows)\nset(TOOLCHAIN_PREFIX i686-w64-mingw32)\n\n# cross compilers to use for C, C++ and Fortran\nset(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc)\nset(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++)\nset(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres)\n\n# target environment on the build host system\nset(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})\n\n# modify default behavior of FIND_XXX() commands\nset(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)\nset(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)\nset(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)\n"
  },
  {
    "path": "mingw-w64-x64_64.cmake",
    "content": "# Sample toolchain file for building for Windows from an Ubuntu Linux system.\n#\n# Typical usage:\n#    *) install cross compiler: `sudo apt-get install mingw-w64`\n#    *) cd build\n#    *) cmake -DCMAKE_TOOLCHAIN_FILE=~/mingw-w64-x86_64.cmake ..\n#\n# build for Windows' 64 bit architecture\n\nset(CMAKE_SYSTEM_NAME Windows)\nset(TOOLCHAIN_PREFIX x86_64-w64-mingw32)\n\n# cross compilers to use for C, C++ and Fortran\nset(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc)\nset(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++)\nset(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres)\n\n# target environment on the build host system\nset(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})\n\n# modify default behavior of FIND_XXX() commands\nset(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)\nset(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)\nset(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)\n"
  },
  {
    "path": "protocol_rtl_tcp.txt",
    "content": "\nThe command protocol of rtl_tcp is on port 1234 (by default):\n=============================================================\n\nCommands are directed from a client application towards rtl_tcp.\n\nEach command consists of 2 fields:\n\n1- command_id: value of enum RTL_TCP_COMMANDS, defined in rtl_tcp.h.\n  This element is an unsigned character, starting at offset 0\n  with length: 1 byte.\n\n2- parameter: depends on the command id,\n  e.g. is a frequency for SET_FREQUENCY.\n  This element is a (signed or unsigned) 32 bit integer,\n  starting at offset 1 with length: 4 bytes.\n\nBoth fields are in Network Byte Order (Big Endian).\nSize of one command is 3 bytes, without padding.\n\n\nReverse direction on command connection:\n========================================\n\nWith accepting a connection, rtl_tcp initially transmits some dongle_info.\n\nThe dongle_info consists of 3 fields:\n\n1- magic string: identifies the rtl_tcp protocol. The value is \"RTL0\".\n  This element is a fixed size string, starting at offset 0\n  with length 4 bytes.\n\n2- tuner type: identifies the tuner chip built in the controlled RTL-SDR model,\n  e.g. E4000 or R820T or R820T2.\n  This element is an unsigned 32 bit integer, starting at offset 4\n  with length: 4 bytes.\n\n3- tuner gain count: reports the number of available gain values,\n  necessary for the command SET_TUNER_GAIN_BY_INDEX.\n  This element is an unsigned 32 bit integer, starting at offset 8\n  with length: 4 bytes.\n\nBoth fields are in Network Byte Order (Big Endian).\nSize of one dongle_info is 12 bytes, without padding.\n\n\nAfter that initial dongle_info, from offset 12 byte, just raw I/Q data is transferred.\nFor each I/Q frame, in the commanded samplerate, I and Q values are transferred,\neach as unsigned 8 bit sample. Thus one I/Q-frame is 2 bytes, each frame 1 byte.\n\n\n\nResponse channel:\n=================\nThe command channel does not allow specific response on commands.\nThis is why an additional response channel got necessary.\nrtl_tcp now offers an additional tcp server \"response\" channel,\nby default, on the next port as the command protocol.\nThus, by default on port 1235.\n\n\nEach response from rtl_tcp to the client consists of 3 fields:\n\n1- command_id: references the command, which generated this response.\n  It's value is also the enum RTL_TCP_COMMANDS, defined in rtl_tcp.h.\n  This element is an unsigned character, starting at offset 0\n  with length: 1 byte.\n\n2- length_of_content: defines the number of bytes following this field at offset 3.\n  The length is necessary to allow responses with different lengths.\n  This element is an unsigned 16 bit integer, starting at offset 1\n  with length: 2 bytes. 0 is interpreted as 65536!\n  It is strongly recommended to limit the response to 32768 bytes in total.\n\n3- content: the content is command specific and might contain up to 65536 bytes.\n  The content starts at offset 3.\n\n\nAll fields are in Network Byte Order (Big Endian).\nSize of one response is (3 + length_of_content), without padding.\n\n"
  },
  {
    "path": "rtl-sdr.rules",
    "content": "#\n# Copyright 2012-2013 Osmocom rtl-sdr project\n#\n# This program is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#\n\n# original RTL2832U vid/pid (hama nano, for example)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0bda\", ATTRS{idProduct}==\"2832\", MODE:=\"0666\"\n\n# modified RTL2832U vid/pid .. not known to dvb modules\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1209\", ATTRS{idProduct}==\"2832\", MODE:=\"0666\"\n\n# RTL2832U OEM vid/pid, e.g. ezcap EzTV668 (E4000), Newsky TV28T (E4000/R820T) etc.\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0bda\", ATTRS{idProduct}==\"2838\", MODE:=\"0666\"\n\n# DigitalNow Quad DVB-T PCI-E card (4x FC0012?)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0413\", ATTRS{idProduct}==\"6680\", MODE:=\"0666\"\n\n# Leadtek WinFast DTV Dongle mini D (FC0012)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0413\", ATTRS{idProduct}==\"6f0f\", MODE:=\"0666\"\n\n# Genius TVGo DVB-T03 USB dongle (Ver. B)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0458\", ATTRS{idProduct}==\"707f\", MODE:=\"0666\"\n\n# Terratec Cinergy T Stick Black (rev 1) (FC0012)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0ccd\", ATTRS{idProduct}==\"00a9\", MODE:=\"0666\"\n\n# Terratec NOXON rev 1 (FC0013)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0ccd\", ATTRS{idProduct}==\"00b3\", MODE:=\"0666\"\n\n# Terratec Deutschlandradio DAB Stick (FC0013)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0ccd\", ATTRS{idProduct}==\"00b4\", MODE:=\"0666\"\n\n# Terratec NOXON DAB Stick - Radio Energy (FC0013)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0ccd\", ATTRS{idProduct}==\"00b5\", MODE:=\"0666\"\n\n# Terratec Media Broadcast DAB Stick (FC0013)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0ccd\", ATTRS{idProduct}==\"00b7\", MODE:=\"0666\"\n\n# Terratec BR DAB Stick (FC0013)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0ccd\", ATTRS{idProduct}==\"00b8\", MODE:=\"0666\"\n\n# Terratec WDR DAB Stick (FC0013)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0ccd\", ATTRS{idProduct}==\"00b9\", MODE:=\"0666\"\n\n# Terratec MuellerVerlag DAB Stick (FC0013)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0ccd\", ATTRS{idProduct}==\"00c0\", MODE:=\"0666\"\n\n# Terratec Fraunhofer DAB Stick (FC0013)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0ccd\", ATTRS{idProduct}==\"00c6\", MODE:=\"0666\"\n\n# Terratec Cinergy T Stick RC (Rev.3) (E4000)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0ccd\", ATTRS{idProduct}==\"00d3\", MODE:=\"0666\"\n\n# Terratec T Stick PLUS (E4000)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0ccd\", ATTRS{idProduct}==\"00d7\", MODE:=\"0666\"\n\n# Terratec NOXON rev 2 (E4000)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0ccd\", ATTRS{idProduct}==\"00e0\", MODE:=\"0666\"\n\n# PixelView PV-DT235U(RN) (FC0012)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1554\", ATTRS{idProduct}==\"5020\", MODE:=\"0666\"\n\n# Astrometa DVB-T/DVB-T2 (R828D)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"15f4\", ATTRS{idProduct}==\"0131\", MODE:=\"0666\"\n\n# HanfTek DAB+FM+DVB-T\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"15f4\", ATTRS{idProduct}==\"0133\", MODE:=\"0666\"\n\n# Compro Videomate U620F (E4000)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"185b\", ATTRS{idProduct}==\"0620\", MODE:=\"0666\"\n\n# Compro Videomate U650F (E4000)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"185b\", ATTRS{idProduct}==\"0650\", MODE:=\"0666\"\n\n# Compro Videomate U680F (E4000)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"185b\", ATTRS{idProduct}==\"0680\", MODE:=\"0666\"\n\n# GIGABYTE GT-U7300 (FC0012)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1b80\", ATTRS{idProduct}==\"d393\", MODE:=\"0666\"\n\n# DIKOM USB-DVBT HD\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1b80\", ATTRS{idProduct}==\"d394\", MODE:=\"0666\"\n\n# Peak 102569AGPK (FC0012)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1b80\", ATTRS{idProduct}==\"d395\", MODE:=\"0666\"\n\n# KWorld KW-UB450-T USB DVB-T Pico TV (TUA9001)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1b80\", ATTRS{idProduct}==\"d397\", MODE:=\"0666\"\n\n# Zaapa ZT-MINDVBZP (FC0012)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1b80\", ATTRS{idProduct}==\"d398\", MODE:=\"0666\"\n\n# SVEON STV20 DVB-T USB & FM (FC0012)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1b80\", ATTRS{idProduct}==\"d39d\", MODE:=\"0666\"\n\n# Twintech UT-40 (FC0013)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1b80\", ATTRS{idProduct}==\"d3a4\", MODE:=\"0666\"\n\n# ASUS U3100MINI_PLUS_V2 (FC0013)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1b80\", ATTRS{idProduct}==\"d3a8\", MODE:=\"0666\"\n\n# SVEON STV27 DVB-T USB & FM (FC0013)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1b80\", ATTRS{idProduct}==\"d3af\", MODE:=\"0666\"\n\n# SVEON STV21 DVB-T USB & FM\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1b80\", ATTRS{idProduct}==\"d3b0\", MODE:=\"0666\"\n\n# Dexatek DK DVB-T Dongle (Logilink VG0002A) (FC2580)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1d19\", ATTRS{idProduct}==\"1101\", MODE:=\"0666\"\n\n# Dexatek DK DVB-T Dongle (MSI DigiVox mini II V3.0)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1d19\", ATTRS{idProduct}==\"1102\", MODE:=\"0666\"\n\n# Dexatek DK 5217 DVB-T Dongle (FC2580)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1d19\", ATTRS{idProduct}==\"1103\", MODE:=\"0666\"\n\n# MSI DigiVox Micro HD (FC2580)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1d19\", ATTRS{idProduct}==\"1104\", MODE:=\"0666\"\n\n# Sweex DVB-T USB (FC0012)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1f4d\", ATTRS{idProduct}==\"a803\", MODE:=\"0666\"\n\n# GTek T803 (FC0012)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1f4d\", ATTRS{idProduct}==\"b803\", MODE:=\"0666\"\n\n# Lifeview LV5TDeluxe (FC0012)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1f4d\", ATTRS{idProduct}==\"c803\", MODE:=\"0666\"\n\n# MyGica TD312 (FC0012)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1f4d\", ATTRS{idProduct}==\"d286\", MODE:=\"0666\"\n\n# PROlectrix DV107669 (FC0012)\nSUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1f4d\", ATTRS{idProduct}==\"d803\", MODE:=\"0666\"\n"
  },
  {
    "path": "rtlsdr-blacklist.conf",
    "content": "blacklist dvb_usb_rtl28xxu\nblacklist dvb_usb_v2\nblacklist rtl_2830\nblacklist rtl_2832\nblacklist r820t\nblacklist rtl8xxxu\n"
  },
  {
    "path": "src/CMakeLists.txt",
    "content": "# Copyright 2012 OSMOCOM Project\n#\n# This file is part of rtl-sdr\n#\n# GNU Radio is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation; either version 3, or (at your option)\n# any later version.\n#\n# GNU Radio is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with GNU Radio; see the file COPYING.  If not, write to\n# the Free Software Foundation, Inc., 51 Franklin Street,\n# Boston, MA 02110-1301, USA.\n\nMACRO(RTLSDR_APPEND_SRCS)\n    LIST(APPEND rtlsdr_srcs ${ARGV})\nENDMACRO(RTLSDR_APPEND_SRCS)\n\nRTLSDR_APPEND_SRCS(\n    librtlsdr.c\n    tuner_e4k.c\n    tuner_fc0012.c\n    tuner_fc0013.c\n    tuner_fc2580.c\n    tuner_r82xx.c\n)\nif(WITH_RPC)\n    RTLSDR_APPEND_SRCS(\n        rtlsdr_rpc.c\n        rtlsdr_rpc_msg.c\n    )\nendif()\n\n########################################################################\n# Set up Windows DLL resource files\n########################################################################\nIF(MSVC)\n    include(${PROJECT_SOURCE_DIR}/cmake/Modules/Version.cmake)\n\n    configure_file(\n        ${CMAKE_CURRENT_SOURCE_DIR}/rtlsdr.rc.in\n        ${CMAKE_CURRENT_BINARY_DIR}/rtlsdr.rc\n    @ONLY)\n\n    RTLSDR_APPEND_SRCS(${CMAKE_CURRENT_BINARY_DIR}/rtlsdr.rc)\nENDIF(MSVC)\n\n########################################################################\n# Setup shared library variant\n########################################################################\nadd_library(rtlsdr_shared SHARED ${rtlsdr_srcs})\nif(NOT WIN32)\n    target_link_libraries(rtlsdr_shared ${LIBUSB_LIBRARIES})\nelse()\n    target_link_libraries(rtlsdr_shared ws2_32 ${LIBUSB_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})\nendif()\nif (WITH_RPC)\n    target_compile_definitions(rtlsdr_shared PUBLIC _ENABLE_RPC)\nendif()\n\nset_target_properties(rtlsdr_shared PROPERTIES DEFINE_SYMBOL \"rtlsdr_EXPORTS\")\nset_target_properties(rtlsdr_shared PROPERTIES OUTPUT_NAME rtlsdr)\nset_target_properties(rtlsdr_shared PROPERTIES SOVERSION ${MAJOR_VERSION})\nset_target_properties(rtlsdr_shared PROPERTIES VERSION ${LIBVER})\n\n########################################################################\n# Setup static library variant\n########################################################################\nadd_library(rtlsdr_static STATIC ${rtlsdr_srcs})\nif(NOT WIN32)\n    target_link_libraries(rtlsdr_static ${LIBUSB_LIBRARIES})\nelse()\n    target_link_libraries(rtlsdr_static ws2_32 ${LIBUSB_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})\nendif()\n\nif (WITH_RPC)\n    target_compile_definitions(rtlsdr_static PUBLIC _ENABLE_RPC)\nendif()\n\nset_property(TARGET rtlsdr_static APPEND PROPERTY COMPILE_DEFINITIONS \"rtlsdr_STATIC\" )\nif(NOT WIN32)\n    # Force same library filename for static and shared variants of the library\n    set_target_properties(rtlsdr_static PROPERTIES OUTPUT_NAME rtlsdr)\nendif()\n\n\n########################################################################\n# Set link library\n########################################################################\n\nif(LINK_RTLTOOLS_AGAINST_STATIC_LIB)\n    set(RTLSDR_TOOL_LIB rtlsdr_static)\nelse()\n    set(RTLSDR_TOOL_LIB rtlsdr_shared)\nendif()\n\n########################################################################\n# Setup libraries used in executables\n########################################################################\nadd_library(convenience_static STATIC\n    convenience/rtl_convenience.c  convenience/convenience.c  convenience/wavewrite.c\n)\n\nif(WIN32)\nadd_library(libgetopt_static STATIC\n    getopt/getopt.c\n)\ntarget_link_libraries(convenience_static\n    ${RTLSDR_TOOL_LIB}\n)\nendif()\n\n########################################################################\n# Build utility\n########################################################################\nadd_executable(rtl_sdr rtl_sdr.c)\nadd_executable(rtl_tcp rtl_tcp.c controlThread.c)\nadd_executable(rtl_udp rtl_udp.c)\nadd_executable(rtl_test rtl_test.c)\nadd_executable(rtl_fm rtl_fm.c)\nadd_executable(rtl_ir rtl_ir.c)\nadd_executable(rtl_eeprom rtl_eeprom.c)\nadd_executable(rtl_adsb rtl_adsb.c)\nadd_executable(rtl_power rtl_power.c)\nadd_executable(rtl_biast rtl_biast.c)\nadd_executable(rtl_raw2wav    rtl_raw2wav.c     convenience/convenience.c  convenience/wavewrite.c)\nadd_executable(rtl_wavestat   rtl_wavestat.c    convenience/convenience.c  convenience/waveread.c)\nadd_executable(rtl_wavestream rtl_wavestream.c  convenience/convenience.c  convenience/waveread.c)\n\nif (WITH_RPC)\n    add_executable(rtl_rpcd rtl_rpcd.c rtlsdr_rpc_msg.c)\n    set(INSTALL_TARGETS rtlsdr_shared rtlsdr_static rtl_sdr rtl_tcp rtl_udp rtl_test rtl_fm rtl_ir rtl_eeprom rtl_adsb rtl_power rtl_biast rtl_raw2wav rtl_wavestat rtl_wavestream rtl_rpcd)\nelse()\n    set(INSTALL_TARGETS rtlsdr_shared rtlsdr_static rtl_sdr rtl_tcp rtl_udp rtl_test rtl_fm rtl_ir rtl_eeprom rtl_adsb rtl_power rtl_biast rtl_raw2wav rtl_wavestat rtl_wavestream)\nendif()\n\ntarget_link_libraries(rtl_sdr ${RTLSDR_TOOL_LIB} convenience_static\n    ${LIBUSB_LIBRARIES}\n    ${CMAKE_THREAD_LIBS_INIT}\n)\ntarget_link_libraries(rtl_tcp ${RTLSDR_TOOL_LIB} convenience_static\n    ${LIBUSB_LIBRARIES}\n    ${CMAKE_THREAD_LIBS_INIT}\n)\ntarget_link_libraries(rtl_test ${RTLSDR_TOOL_LIB} convenience_static\n    ${LIBUSB_LIBRARIES}\n    ${CMAKE_THREAD_LIBS_INIT}\n)\ntarget_link_libraries(rtl_fm ${RTLSDR_TOOL_LIB} convenience_static\n    ${LIBUSB_LIBRARIES}\n    ${CMAKE_THREAD_LIBS_INIT}\n)\ntarget_link_libraries(rtl_ir ${RTLSDR_TOOL_LIB} convenience_static\n    ${LIBUSB_LIBRARIES}\n    ${CMAKE_THREAD_LIBS_INIT}\n)\ntarget_link_libraries(rtl_eeprom ${RTLSDR_TOOL_LIB} convenience_static\n    ${LIBUSB_LIBRARIES}\n    ${CMAKE_THREAD_LIBS_INIT}\n)\ntarget_link_libraries(rtl_adsb ${RTLSDR_TOOL_LIB} convenience_static\n    ${LIBUSB_LIBRARIES}\n    ${CMAKE_THREAD_LIBS_INIT}\n)\ntarget_link_libraries(rtl_udp ${RTLSDR_TOOL_LIB} convenience_static\n    ${LIBUSB_LIBRARIES}\n    ${CMAKE_THREAD_LIBS_INIT}\n)\ntarget_link_libraries(rtl_power ${RTLSDR_TOOL_LIB} convenience_static\n    ${LIBUSB_LIBRARIES}\n    ${CMAKE_THREAD_LIBS_INIT}\n)\ntarget_link_libraries(rtl_biast ${RTLSDR_TOOL_LIB} convenience_static\n    ${LIBUSB_LIBRARIES}\n    ${CMAKE_THREAD_LIBS_INIT}\n)\nif(WITH_RPC)\n    target_link_libraries(rtl_rpcd ${RTLSDR_TOOL_LIB} convenience_static\n        ${LIBUSB_LIBRARIES}\n        ${CMAKE_THREAD_LIBS_INIT}\n    )\nendif()\n\nif(UNIX)\n    target_link_libraries(rtl_fm m)\n    target_link_libraries(rtl_ir m)\n    target_link_libraries(rtl_adsb m)\n    target_link_libraries(rtl_power m)\n    target_link_libraries(rtl_raw2wav m)\n    target_link_libraries(rtl_wavestat m)\n    target_link_libraries(rtl_wavestream m)\n    if(APPLE OR CMAKE_SYSTEM MATCHES \"OpenBSD\")\n        target_link_libraries(rtl_test m)\n    else()\n        target_link_libraries(rtl_test m rt)\n    endif()\nendif()\n\nif(WIN32)\n    target_link_libraries(rtl_sdr libgetopt_static)\n    target_link_libraries(rtl_tcp ws2_32 libgetopt_static)\n    target_link_libraries(rtl_udp ws2_32 libgetopt_static)\n    target_link_libraries(rtl_test libgetopt_static)\n    target_link_libraries(rtl_fm libgetopt_static)\n    target_link_libraries(rtl_ir libgetopt_static)\n    target_link_libraries(rtl_eeprom libgetopt_static)\n    target_link_libraries(rtl_adsb libgetopt_static)\n    target_link_libraries(rtl_power libgetopt_static)\n    target_link_libraries(rtl_biast libgetopt_static)\n    target_link_libraries(rtl_raw2wav libgetopt_static)\n    target_link_libraries(rtl_wavestat libgetopt_static)\n    target_link_libraries(rtl_wavestream libgetopt_static)\n    find_library(LIBM NAMES m)\n    if (LIBM)\n    target_link_libraries(rtl_raw2wav m)\n    target_link_libraries(rtl_wavestat m)\n    target_link_libraries(rtl_wavestream m)\n    endif (LIBM)\n    set_property(TARGET rtl_sdr APPEND PROPERTY COMPILE_DEFINITIONS \"rtlsdr_STATIC\" )\n    set_property(TARGET rtl_tcp APPEND PROPERTY COMPILE_DEFINITIONS \"rtlsdr_STATIC\" )\n    set_property(TARGET rtl_udp APPEND PROPERTY COMPILE_DEFINITIONS \"rtlsdr_STATIC\" )\n    set_property(TARGET rtl_test APPEND PROPERTY COMPILE_DEFINITIONS \"rtlsdr_STATIC\" )\n    set_property(TARGET rtl_fm APPEND PROPERTY COMPILE_DEFINITIONS \"rtlsdr_STATIC\" )\n    set_property(TARGET rtl_ir APPEND PROPERTY COMPILE_DEFINITIONS \"rtlsdr_STATIC\" )\n    set_property(TARGET rtl_eeprom APPEND PROPERTY COMPILE_DEFINITIONS \"rtlsdr_STATIC\" )\n    set_property(TARGET rtl_adsb APPEND PROPERTY COMPILE_DEFINITIONS \"rtlsdr_STATIC\" )\n    set_property(TARGET rtl_power APPEND PROPERTY COMPILE_DEFINITIONS \"rtlsdr_STATIC\" )\n    set_property(TARGET rtl_biast APPEND PROPERTY COMPILE_DEFINITIONS \"rtlsdr_STATIC\" )\n    set_property(TARGET rtl_raw2wav APPEND PROPERTY COMPILE_DEFINITIONS \"rtlsdr_STATIC\" )\n    set_property(TARGET rtl_wavestat APPEND PROPERTY COMPILE_DEFINITIONS \"rtlsdr_STATIC\" )\n    set_property(TARGET rtl_wavestream APPEND PROPERTY COMPILE_DEFINITIONS \"rtlsdr_STATIC\" )\n    if (WITH_RPC)\n        target_link_libraries(rtl_rpcd ws2_32 libgetopt_static)\n        set_property(TARGET rtl_rpcd APPEND PROPERTY COMPILE_DEFINITIONS \"rtlsdr_STATIC\" )\n    endif()\nendif()\n########################################################################\n# Install built library files & utilities\n########################################################################\ninstall(TARGETS ${INSTALL_TARGETS}\n    LIBRARY DESTINATION ${LIB_INSTALL_DIR} # .so/.dylib file\n    ARCHIVE DESTINATION ${LIB_INSTALL_DIR} # .lib file\n    RUNTIME DESTINATION bin              # .dll file\n)\n"
  },
  {
    "path": "src/Makefile.am",
    "content": "# This is _NOT_ the library release version, it's an API version.\n# Please read Chapter 6 \"Library interface versions\" of the libtool documentation before making any modification\nLIBVERSION=0:5:0\n\nAUTOMAKE_OPTIONS = subdir-objects\nINCLUDES = $(all_includes) -I$(top_srcdir)/include\nnoinst_HEADERS = convenience/convenience.h\nAM_CFLAGS = ${CFLAGS} -fPIC ${SYMBOL_VISIBILITY}\n\nlib_LTLIBRARIES = librtlsdr.la\n\nlibrtlsdr_la_SOURCES = librtlsdr.c tuner_e4k.c tuner_fc0012.c tuner_fc0013.c tuner_fc2580.c tuner_r82xx.c rtlsdr_rpc.c rtlsdr_rpc_msg.c\nlibrtlsdr_la_LDFLAGS = -version-info $(LIBVERSION)\n\nbin_PROGRAMS         = rtl_sdr rtl_tcp rtl_test rtl_fm rtl_ir rtl_eeprom rtl_adsb rtl_power rtl_rpcd\n\nrtl_sdr_SOURCES      = rtl_sdr.c convenience/convenience.c\nrtl_sdr_LDADD        = librtlsdr.la\n\nrtl_tcp_SOURCES      = rtl_tcp.c convenience/convenience.c\nrtl_tcp_LDADD        = librtlsdr.la\n\nrtl_test_SOURCES      = rtl_test.c convenience/convenience.c\nrtl_test_LDADD        = librtlsdr.la $(LIBM)\n\nrtl_fm_SOURCES      = rtl_fm.c convenience/convenience.c\nrtl_fm_LDADD        = librtlsdr.la $(LIBM)\n\nrtl_ir_SOURCES      = rtl_ir.c convenience/convenience.c\nrtl_ir_LDADD        = librtlsdr.la $(LIBM)\n\nrtl_eeprom_SOURCES      = rtl_eeprom.c convenience/convenience.c\nrtl_eeprom_LDADD        = librtlsdr.la $(LIBM)\n\nrtl_adsb_SOURCES      = rtl_adsb.c convenience/convenience.c\nrtl_adsb_LDADD        = librtlsdr.la $(LIBM)\n\nrtl_power_SOURCES     = rtl_power.c convenience/convenience.c\nrtl_power_LDADD       = librtlsdr.la $(LIBM)\n\nrtl_rpcd_SOURCES     = rtl_rpcd.c rtlsdr_rpc_msg.c convenience/convenience.c\nrtl_rpcd_LDADD       = librtlsdr.la\n"
  },
  {
    "path": "src/controlThread.c",
    "content": "/*\n * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver\n * Copyright (C) 2012 by Steve Markgraf <steve@steve-m.de>\n * Copyright (C) 2012-2013 by Hoernchen <la@tfc-server.de>\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <errno.h>\n#include <signal.h>\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#ifndef _WIN32\n#include <unistd.h>\n#include <arpa/inet.h>\n#include <sys/socket.h>\n#include <sys/types.h>\n#include <sys/socket.h>\n#include <sys/time.h>\n#include <netinet/in.h>\n#include <fcntl.h>\n#else\n#include <winsock2.h>\n#include \"getopt/getopt.h\"\n#define usleep(x) Sleep(x/1000)\n#endif\n\n#ifdef NEED_PTHREADS_WORKARROUND\n#define HAVE_STRUCT_TIMESPEC\n#endif\n#include <pthread.h>\n\n#include \"rtl-sdr.h\"\n#include \"rtl_tcp.h\"\n#include \"controlThread.h\"\n#include \"convenience/convenience.h\"\n#include \"convenience/rtl_convenience.h\"\n\n#include \"tuner_r82xx.h\"\n\n#ifdef _WIN32\n#pragma comment(lib, \"ws2_32.lib\")\n\ntypedef int socklen_t;\n\n#else\n#define closesocket close\n#define SOCKADDR struct sockaddr\n#define SOCKET int\n#define SOCKET_ERROR -1\n#endif\n\n/* we need a message id in the protocol: 1st 2 byte (little endian) == message id */\n#define USE_MSGID_IN_PROTOCOL\t\t1\n\n#define NUM_I2C_REGISTERS  32\n#define TX_BUF_LEN (NUM_I2C_REGISTERS +4) //2 len, 1 head, 1 tail\n\n\nctrl_thread_data_t ctrl_thread_data;\n\nvoid *ctrl_thread_fn(void *arg)\n{\n\tunsigned char reg_values [NUM_I2C_REGISTERS];\n#if USE_MSGID_IN_PROTOCOL\n\tunsigned char txbuf [2+2 +1+NUM_I2C_REGISTERS+1]; //2 type, 2 length, 1 head, 1 tail\n#else\n\tunsigned char txbuf [NUM_I2C_REGISTERS+4]; //2 length, 1 head, 1 tail\n#endif\n\tint r = 1;\n\tstruct timeval tv = { 1,0 };\n\tstruct linger ling = { 1,0 };\n\tSOCKET listensocket;\n\tSOCKET controlSocket;\n\tint haveControlSocket = 0;\n\tstruct sockaddr_in local, remote;\n\tsocklen_t rlen;\n\n\tint error = 0;\n\tint ret = 0, len, result;\n\tfd_set connfds;\n\tfd_set writefds;\n\tint bytesleft, bytessent, index;\n\n\tctrl_thread_data_t *data = (ctrl_thread_data_t *)arg;\n\n\trtlsdr_dev_t *dev = data->dev;\n\tint port = data->port;\n\tint wait = data->wait;\n\tint report_i2c = data->report_i2c;\n\tchar *addr = data->addr;\n\tint* do_exit = data->pDoExit;\n\tu_long blockmode = 1;\n\tint retval;\n\n\n\tmemset(reg_values, 0, NUM_I2C_REGISTERS);\n\n\tmemset(&local, 0, sizeof(local));\n\tlocal.sin_family = AF_INET;\n\tlocal.sin_port = htons(port);\n\tlocal.sin_addr.s_addr = inet_addr(addr);\n\n\tlistensocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);\n\n\tsetsockopt(listensocket, SOL_SOCKET, SO_REUSEADDR, (char *)&r, sizeof(int));\n\tsetsockopt(listensocket, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling));\n\tretval = bind(listensocket, (struct sockaddr *)&local, sizeof(local));\n\tif (retval == SOCKET_ERROR)\n\t\terror = 1;\n#ifdef _WIN32\n\tioctlsocket(listensocket, FIONBIO, &blockmode);\n#else\n\tr = fcntl(listensocket, F_GETFL, 0);\n\tr = fcntl(listensocket, F_SETFL, r | O_NONBLOCK);\n#endif\n\n\twhile (1) {\n\t\tprintf(\"listening on Control port %d...\\n\", port);\n\t\tretval = listen(listensocket, 1);\n\t\tif (retval == SOCKET_ERROR)\n\t\t\terror = 1;\n\t\twhile (1) {\n\t\t\tFD_ZERO(&connfds);\n\t\t\tFD_SET(listensocket, &connfds);\n\t\t\ttv.tv_sec = 1;\n\t\t\ttv.tv_usec = 0;\n\t\t\tr = select(listensocket + 1, &connfds, NULL, NULL, &tv);\n\t\t\tif (*do_exit) {\n\t\t\t\tgoto close;\n\t\t\t}\n\t\t\telse if (r) {\n\t\t\t\trlen = sizeof(remote);\n\t\t\t\tcontrolSocket = accept(listensocket, (struct sockaddr *)&remote, &rlen);\n\t\t\t\thaveControlSocket = 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tsetsockopt(controlSocket, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling));\n\n\t\tprintf(\"Control client accepted!\\n\");\n\t\tusleep(5000000);\n\n\t\twhile (1) {\n\n\t\t\t/* check if i2c reporting is to be (de)activated */\n\t\t\tif ( report_i2c && !data->report_i2c )\n\t\t\t\treport_i2c = 0;\n\t\t\telse if ( !report_i2c && data->report_i2c )\n\t\t\t\treport_i2c = 1;\n\n\t\t\t/* @TODO: check if something else has to be transmitted */\n\n\t\t\tif ( !report_i2c )\n\t\t\t\tgoto sleep;\n\n\t\t\tresult = rtlsdr_get_tuner_i2c_register(dev, reg_values, NUM_I2C_REGISTERS);\n\t\t\t/* printf(\"rtlsdr_get_tuner_i2c_register\\n\"); */\n\t\t\tmemset(txbuf, 0, TX_BUF_LEN);\n\t\t\tif (result)\n\t\t\t\tgoto sleep;\n\n\t\t\t/* Little Endian */\n\t\t\tlen = 0;\n\t\t\t/* we need some message id: use enum RTL_TCP_COMMANDS */\n#if USE_MSGID_IN_PROTOCOL\n\t\t\ttxbuf[len++] = REPORT_I2C_REGS & 0x0FF;\n\t\t\ttxbuf[len++] = (REPORT_I2C_REGS >> 8) & 0x0FF;\n\t\t\t/* following message length in Little Endian */\n\t\t\ttxbuf[len++] = TX_BUF_LEN - 2 - 2;\t/* sub message id and length field */\n#else\n\t\t\ttxbuf[len++] = TX_BUF_LEN - 2;\t/* sub message id and length field */\n#endif\n\t\t\ttxbuf[len++] = 0;\n\t\t\t\n\t\t\t/* now the message contents */\n\t\t\ttxbuf[len++] = 0x55;\t\t\t/* @CS: do we need this? */\n\t\t\tmemcpy(&txbuf[len], reg_values, NUM_I2C_REGISTERS);\n\t\t\ttxbuf[TX_BUF_LEN - 1] = 0xaa;\t/* @CS: do we need this? */\n\t\t\tlen = sizeof(txbuf);\n\n\t\t\t/* now start (possibly blocking) transmission */\n\t\t\tbytessent = 0;\n\t\t\tbytesleft = len;\n\t\t\tindex = 0;\n\n\t\t\twhile (bytesleft > 0) {\n\t\t\t\tFD_ZERO(&writefds);\n\t\t\t\tFD_SET(controlSocket, &writefds);\n\t\t\t\ttv.tv_sec = 1;\n\t\t\t\ttv.tv_usec = 0;\n\t\t\t\tr = select(controlSocket + 1, NULL, &writefds, NULL, &tv);\n\t\t\t\tif (r) {\n\t\t\t\t\tbytessent = send(controlSocket, &txbuf[index], bytesleft, 0);\n\t\t\t\t\tbytesleft -= bytessent;\n\t\t\t\t\tindex += bytessent;\n\t\t\t\t}\n\t\t\t\tif (bytessent == SOCKET_ERROR || *do_exit) {\n\t\t\t\t\tgoto close;\n\t\t\t\t}\n\t\t\t}\nsleep:\n\t\t\tusleep(wait);\n\t\t}\nclose:\n\t\tif (haveControlSocket)\n\t\t\tclosesocket(controlSocket);\n\t\tif (*do_exit)\n\t\t{\n\t\t\tclosesocket(listensocket);\n\t\t\tprintf(\"Control Thread terminates\\n\");\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn 0;\n}\n\n"
  },
  {
    "path": "src/convenience/convenience.c",
    "content": "/*\n * Copyright (C) 2014 by Kyle Keen <keenerd@gmail.com>\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/* a collection of user friendly tools\n * todo: use strtol for more flexible int parsing\n * */\n\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <ctype.h>\n#include <time.h>\n#include <assert.h>\n\n#ifndef _WIN32\n#include <unistd.h>\n#include <sys/time.h>\n#else\n#include <windows.h>\n#include <fcntl.h>\n#include <io.h>\n#include <process.h>\n#define _USE_MATH_DEFINES\n#endif\n\n#include <math.h>\n\n\ndouble atofs(char *s)\n/* standard suffixes */\n{\n\tchar last;\n\tint len;\n\tdouble suff = 1.0;\n\tlen = strlen(s);\n\t/* allow formatting spaces from .csv command file */\n\twhile ( len > 1 && isspace(s[len-1]) )\t--len;\n\tlast = s[len-1];\n\ts[len-1] = '\\0';\n\tswitch (last) {\n\t\tcase 'g':\n\t\tcase 'G':\n\t\t\tsuff *= 1e3;\n\t\t\t/* fall-through */\n\t\tcase 'm':\n\t\tcase 'M':\n\t\t\tsuff *= 1e3;\n\t\t\t/* fall-through */\n\t\tcase 'k':\n\t\tcase 'K':\n\t\t\tsuff *= 1e3;\n\t\t\tsuff *= atof(s);\n\t\t\ts[len-1] = last;\n\t\t\treturn suff;\n\t}\n\ts[len-1] = last;\n\treturn atof(s);\n}\n\ndouble atoft(char *s)\n/* time suffixes, returns seconds */\n{\n\tchar last;\n\tint len;\n\tdouble suff = 1.0;\n\tlen = strlen(s);\n\tlast = s[len-1];\n\ts[len-1] = '\\0';\n\tswitch (last) {\n\t\tcase 'h':\n\t\tcase 'H':\n\t\t\tsuff *= 60;\n\t\t\t/* fall-through */\n\t\tcase 'm':\n\t\tcase 'M':\n\t\t\tsuff *= 60;\n\t\t\t/* fall-through */\n\t\tcase 's':\n\t\tcase 'S':\n\t\t\tsuff *= atof(s);\n\t\t\ts[len-1] = last;\n\t\t\treturn suff;\n\t}\n\ts[len-1] = last;\n\treturn atof(s);\n}\n\ndouble atofp(char *s)\n/* percent suffixes */\n{\n\tchar last;\n\tint len;\n\tdouble suff = 1.0;\n\tlen = strlen(s);\n\tlast = s[len-1];\n\ts[len-1] = '\\0';\n\tswitch (last) {\n\t\tcase '%':\n\t\t\tsuff *= 0.01;\n\t\t\tsuff *= atof(s);\n\t\t\ts[len-1] = last;\n\t\t\treturn suff;\n\t}\n\ts[len-1] = last;\n\treturn atof(s);\n}\n\n\nstatic struct tm * str_to_tm( const char * str, struct tm * t, double * fraction ) {\n\tchar b[16];\n\tint k, v;\n\t/* 0         1         2   */\n\t/* 01234567890123456789012 */\n\t/* 2019-09-15T01:53:20.234 - mostly ISO 8601 */\n\n\t*fraction = 0.0;\n\tt->tm_sec\t= 0;\n\tt->tm_min\t= 0;\n\tt->tm_hour\t= 0;\n\tt->tm_mday\t= 1;\n\tt->tm_mon\t= 0;\n\tt->tm_year\t= 0;\n\tt->tm_wday\t= 0;\n\tt->tm_yday\t= 0;\n\tt->tm_isdst\t= -1;\n\n\t/* date */\n\tif ( (str[4] == '-' || str[4] == '/') && str[4] == str[7] ) {\n\t\t/* year */\n\t\tb[4] = 0;\tfor ( k = 0; k < 4; ++k )\tb[k] = str[k];\n\t\tv = atoi(b);\n\t\tt->tm_year = v - 1900;\n\t\t/* month */\n\t\tb[2] = 0;\tfor ( k = 0; k < 2; ++k )\tb[k] = str[5+k];\n\t\tv = atoi(b);\n\t\tif (v < 1 || v > 12)\n\t\t\treturn NULL;\n\t\tt->tm_mon = v - 1;\n\t\t/* day */\n\t\tb[2] = 0;\tfor ( k = 0; k < 2; ++k )\tb[k] = str[8+k];\n\t\tv = atoi(b);\n\t\tif (v < 1 || v > 31)\n\t\t\treturn NULL;\n\t\tt->tm_mday = v;\n\t} else\n\t\treturn NULL;\n\n\tif (str[10] == 0 )\n\t\treturn t;\n\n\t/* time */\n\tif ( str[10] != 'T' && str[10] != ' ' && str[10] != '_' )\n\t\treturn NULL;\n\tif ( (str[13] == ':' || str[13] == '/') && str[13] == str[16] ) {\n\t\t/* hour */\n\t\tb[2] = 0;\tfor ( k = 0; k < 2; ++k )\tb[k] = str[11+k];\n\t\tv = atoi(b);\n\t\tif (v < 0 || v > 23)\n\t\t\treturn NULL;\n\t\tt->tm_hour = v;\n\t\t/* minute */\n\t\tb[2] = 0;\tfor ( k = 0; k < 2; ++k )\tb[k] = str[14+k];\n\t\tv = atoi(b);\n\t\tif (v < 0 || v > 59)\n\t\t\treturn NULL;\n\t\tt->tm_min = v;\n\t\t/* second */\n\t\tb[2] = 0;\tfor ( k = 0; k < 2; ++k )\tb[k] = str[17+k];\n\t\tv = atoi(b);\n\t\tif (v < 0 || v > 61)\n\t\t\treturn NULL;\n\t\tt->tm_sec = v;\n\t} else\n\t\treturn NULL;\n\n\tif (str[19] == 0 )\n\t\treturn t;\n\n\t/* fraction */\n\tif ( str[19] == '.' || str[19] == ',' ) {\n\t\tfor ( k = 0; k < 16; ++k )\tb[k] = 0;\n\t\tstrcpy(b, \"0.\");\n\t\tstrncpy(&b[2], &str[20], 12);\n\t\t*fraction = atof(b);\n\t\treturn t;\n\t}\n\n\t/* return t anyway .. without fraction */\n\treturn t;\n}\n\n\ntime_t utctimestr_to_time(const char * str, double * fraction) {\n\tstruct tm t;\n\tstruct tm *p;\n#ifdef _WIN32\n\tstruct tm gtm;\n\tstruct tm ltm;\n\ttime_t nt;\n\ttime_t gt;\n\ttime_t lt;\n#endif\n\tp = str_to_tm( str, &t, fraction );\n\tif (!p)\n\t\treturn 0;\n\tp->tm_isdst = 0;\n#ifndef _WIN32\n\treturn timegm(p);\n#else\n\t#ifdef _MSC_VER\n\t\treturn _mkgmtime(p);\n\t#else\n\t\t/* workaround missing mkgmtime on mingw */\n\t\tnt = mktime(p);\n\t\tgtm = *gmtime(&nt);\n\t\tltm = *localtime(&nt);\n\t\tgt = mktime(&gtm);\n\t\tlt = mktime(&ltm);\n\t\tassert( nt == gt );\n\t\tnt += ( lt - gt );\n\t\treturn nt;\n\t#endif\n#endif\n}\n\n\ntime_t localtimestr_to_time(const char * str, double * fraction) {\n\tstruct tm t;\n\tstruct tm *p;\n\n\tp = str_to_tm( str, &t, fraction );\n\t\n\tif (!p)\n\t\treturn 0;\n#ifndef _WIN32\n\treturn timelocal(p);\n#else\n\treturn mktime(p);\n#endif\n}\n\n\n\n#ifndef _WIN32\n\nvoid executeInBackground( char * file, char * args, char * searchStr[], char * replaceStr[] )\n{\n\tpid_t pid;\n\tchar * argv[256] = { NULL };\n\tint k, argc = 0;\n\targv[argc++] = file;\n\tif (args) {\n\t\targv[argc] = strtok(args, \" \");\n\t\twhile (argc < 256 && argv[argc]) {\n\t\t\targv[++argc] = strtok(NULL, \" \");\n\t\t\tfor (k=0; argv[argc] && searchStr && replaceStr && searchStr[k] && replaceStr[k]; k++) {\n\t\t\t\tif (!strcmp(argv[argc], searchStr[k])) {\n\t\t\t\t\targv[argc] = replaceStr[k];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tpid = fork();\n\tswitch (pid)\n\t{\n\tcase -1:\n\t\t/* Fork() has failed */\n\t\tfprintf(stderr, \"error: fork for '%s' failed!\\n\", file);\n\t\tbreak;\n\tcase 0:\n\t\texecvp(file, argv);\n\t\tfprintf(stderr, \"error: execv of '%s' from within fork failed!\\n\", file);\n\t\texit(10);\n\t\tbreak;\n\tdefault:\n\t\t/* This is processed by the parent */\n\t\tbreak;\n\t}\n}\n\n#else\n\nvoid executeInBackground( char * file, char * args, char * searchStr[], char * replaceStr[] )\n{\n\tchar * argv[256] = { NULL };\n\tint k, argc = 0;\n\targv[argc++] = file;\n \tif (args) {\n\t\targv[argc] = strtok(args, \" \\t\");\n\t\twhile (argc < 256 && argv[argc]) {\n\t\t\targv[++argc] = strtok(NULL, \" \\t\");\n\t\t\tfor (k=0; argv[argc] && searchStr && replaceStr && searchStr[k] && replaceStr[k]; k++) {\n\t\t\t\tif (!strcmp(argv[argc], searchStr[k])) {\n\t\t\t\t\targv[argc] = replaceStr[k];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tspawnvp(P_NOWAIT, file, argv);\n}\n\n#endif\n\n\n// vim: tabstop=8:softtabstop=8:shiftwidth=8:noexpandtab\n"
  },
  {
    "path": "src/convenience/convenience.h",
    "content": "/*\n * Copyright (C) 2014 by Kyle Keen <keenerd@gmail.com>\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n#ifndef __CONVENIENCE_H\n#define __CONVENIENCE_H\n\n#include <stdint.h>\n#include <stdio.h>\n#include <time.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* a collection of user friendly tools */\n\n/*!\n * Convert standard suffixes (k, M, G) to double\n *\n * \\param s a string to be parsed\n * \\return double\n */\n\ndouble atofs(char *s);\n\n/*!\n * Convert time suffixes (s, m, h) to double\n *\n * \\param s a string to be parsed\n * \\return seconds as double\n */\n\ndouble atoft(char *s);\n\n/*!\n * Convert percent suffixe (%) to double\n *\n * \\param s a string to be parsed\n * \\return double\n */\n\ndouble atofp(char *s);\n\n\ntime_t utctimestr_to_time(const char * str, double * fraction);\ntime_t localtimestr_to_time(const char * str, double * fraction);\n\n\nvoid executeInBackground( char * file, char * args, char * searchStr[], char * replaceStr[] );\n\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /*__CONVENIENCE_H*/\n"
  },
  {
    "path": "src/convenience/rtl_convenience.c",
    "content": "/*\n * Copyright (C) 2014 by Kyle Keen <keenerd@gmail.com>\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n/* a collection of user friendly tools\n * todo: use strtol for more flexible int parsing\n * */\n\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <ctype.h>\n#include <time.h>\n#include <assert.h>\n\n#ifndef _WIN32\n#include <unistd.h>\n#include <sys/time.h>\n#else\n#include <windows.h>\n#include <fcntl.h>\n#include <io.h>\n#define _USE_MATH_DEFINES\n#endif\n\n#include <math.h>\n\n#include \"rtl-sdr.h\"\n\n\nint nearest_gain(rtlsdr_dev_t *dev, int target_gain)\n{\n\tint i, r, err1, err2, count, nearest;\n\tint* gains;\n\tr = rtlsdr_set_tuner_gain_mode(dev, 1);\n\tif (r < 0) {\n\t\tfprintf(stderr, \"WARNING: Failed to enable manual gain.\\n\");\n\t\treturn r;\n\t}\n\tcount = rtlsdr_get_tuner_gains(dev, NULL);\n\tif (count <= 0) {\n\t\treturn 0;\n\t}\n\tgains = malloc(sizeof(int) * count);\n\tcount = rtlsdr_get_tuner_gains(dev, gains);\n\tnearest = gains[0];\n\tfor (i=0; i<count; i++) {\n\t\terr1 = abs(target_gain - nearest);\n\t\terr2 = abs(target_gain - gains[i]);\n\t\tif (err2 < err1) {\n\t\t\tnearest = gains[i];\n\t\t}\n\t}\n\tfree(gains);\n\treturn nearest;\n}\n\nint verbose_set_frequency(rtlsdr_dev_t *dev, uint64_t frequency)\n{\n\tint r;\n\tr = rtlsdr_set_center_freq64(dev, frequency);\n\tif (r < 0) {\n\t\tfprintf(stderr, \"WARNING: Failed to set center freq.\\n\");\n\t} else {\n\t\tfprintf(stderr, \"Tuned to %f MHz.\\n\", frequency * 1E-6);\n\t}\n\treturn r;\n}\n\nint verbose_set_sample_rate(rtlsdr_dev_t *dev, uint32_t samp_rate)\n{\n\tint r;\n\tr = rtlsdr_set_sample_rate(dev, samp_rate);\n\tif (r < 0) {\n\t\tfprintf(stderr, \"WARNING: Failed to set sample rate.\\n\");\n\t} else {\n\t\tfprintf(stderr, \"Sampling at %u S/s.\\n\", samp_rate);\n\t}\n\treturn r;\n}\n\nint verbose_set_bandwidth(rtlsdr_dev_t *dev, uint32_t bandwidth)\n{\n\tint r;\n\tuint32_t applied_bw = 0;\n\t/* r = rtlsdr_set_tuner_bandwidth(dev, bandwidth); */\n\tr = rtlsdr_set_and_get_tuner_bandwidth(dev, bandwidth, &applied_bw, 1 /* =apply_bw */);\n\tif (r < 0) {\n\t\tfprintf(stderr, \"WARNING: Failed to set bandwidth.\\n\");\n\t} else if (bandwidth > 0) {\n\t\tif (applied_bw)\n\t\t\tfprintf(stderr, \"Bandwidth parameter %u Hz resulted in %u Hz.\\n\", bandwidth, applied_bw);\n\t\telse\n\t\t\tfprintf(stderr, \"Set bandwidth parameter %u Hz.\\n\", bandwidth);\n\t} else {\n\t\tfprintf(stderr, \"Bandwidth set to automatic resulted in %u Hz.\\n\", applied_bw);\n\t}\n\treturn r;\n}\n\nint verbose_direct_sampling(rtlsdr_dev_t *dev, int on)\n{\n\tint r;\n\tr = rtlsdr_set_direct_sampling(dev, on);\n\tif (r != 0) {\n\t\tfprintf(stderr, \"WARNING: Failed to set direct sampling mode.\\n\");\n\t\treturn r;\n\t}\n\tif (on == 0) {\n\t\tfprintf(stderr, \"Direct sampling mode disabled.\\n\");}\n\tif (on == 1) {\n\t\tfprintf(stderr, \"Enabled direct sampling mode, input 1/I.\\n\");}\n\tif (on == 2) {\n\t\tfprintf(stderr, \"Enabled direct sampling mode, input 2/Q.\\n\");}\n\treturn r;\n}\n\nint verbose_offset_tuning(rtlsdr_dev_t *dev)\n{\n\tint r;\n\tr = rtlsdr_set_offset_tuning(dev, 1);\n\tif (r != 0) {\n\t\tif ( r == -2 )\n\t\t\tfprintf(stderr, \"WARNING: Failed to set offset tuning: tuner doesn't support offset tuning!\\n\");\n\t\telse if ( r == -3 )\n\t\t\tfprintf(stderr, \"WARNING: Failed to set offset tuning: direct sampling not combinable with offset tuning!\\n\");\n\t\telse\n\t\t\tfprintf(stderr, \"WARNING: Failed to set offset tuning.\\n\");\n\t} else {\n\t\tfprintf(stderr, \"Offset tuning mode enabled.\\n\");\n\t}\n\treturn r;\n}\n\nint verbose_auto_gain(rtlsdr_dev_t *dev)\n{\n\tint r;\n\tr = rtlsdr_set_tuner_gain_mode(dev, 0);\n\tif (r != 0) {\n\t\tfprintf(stderr, \"WARNING: Failed to set tuner gain.\\n\");\n\t} else {\n\t\tfprintf(stderr, \"Tuner gain set to automatic.\\n\");\n\t}\n\treturn r;\n}\n\nint verbose_gain_set(rtlsdr_dev_t *dev, int gain)\n{\n\tint r;\n\tr = rtlsdr_set_tuner_gain_mode(dev, 1);\n\tif (r < 0) {\n\t\tfprintf(stderr, \"WARNING: Failed to enable manual gain.\\n\");\n\t\treturn r;\n\t}\n\tr = rtlsdr_set_tuner_gain(dev, gain);\n\tif (r != 0) {\n\t\tfprintf(stderr, \"WARNING: Failed to set tuner gain.\\n\");\n\t} else {\n\t\tfprintf(stderr, \"Tuner gain set to %0.2f dB.\\n\", gain/10.0);\n\t}\n\treturn r;\n}\n\nint verbose_ppm_set(rtlsdr_dev_t *dev, int ppm_error)\n{\n\tint r;\n\tif (ppm_error == 0) {\n\t\treturn 0;}\n\tr = rtlsdr_set_freq_correction(dev, ppm_error);\n\tif (r < 0) {\n\t\tfprintf(stderr, \"WARNING: Failed to set ppm error.\\n\");\n\t} else {\n\t\tfprintf(stderr, \"Tuner error set to %i ppm.\\n\", ppm_error);\n\t}\n\treturn r;\n}\n\nint verbose_reset_buffer(rtlsdr_dev_t *dev)\n{\n\tint r;\n\tr = rtlsdr_reset_buffer(dev);\n\tif (r < 0) {\n\t\tfprintf(stderr, \"WARNING: Failed to reset buffers.\\n\");}\n\treturn r;\n}\n\nint verbose_device_search(char *s)\n{\n\tint i, device_count, device, offset, rc;\n\tchar *s2;\n\tchar vendor[256] = {0}, product[256] = {0}, serial[256] = {0};\n\tdevice_count = rtlsdr_get_device_count();\n\tif (!device_count) {\n\t\tfprintf(stderr, \"No supported devices found.\\n\");\n\t\treturn -1;\n\t}\n\tfprintf(stderr, \"Found %d device(s):\\n\", device_count);\n\tfor (i = 0; i < device_count; i++) {\n\t\tmemset(&vendor[0],  0, 256 * sizeof(char));\n\t\tmemset(&product[0], 0, 256 * sizeof(char));\n\t\tmemset(&serial[0],  0, 256 * sizeof(char));\n\t\trc = rtlsdr_get_device_usb_strings(i, vendor, product, serial);\n\t\tif ( rc == 0 )\n\t\t\tfprintf(stderr, \"  %d:  %s, %s, SN: %s\\n\", i, vendor, product, serial);\n\t\telse\n\t\t\tfprintf(stderr, \"  %d:  %s\\n\", i, \"Failed to query data\");\n\t}\n\tfprintf(stderr, \"\\n\");\n\t/* does string look like raw id number */\n\tdevice = (int)strtol(s, &s2, 0);\n\tif (s2[0] == '\\0' && device >= 0 && device < device_count) {\n\t\tfprintf(stderr, \"Using device %d: %s\\n\",\n\t\t\tdevice, rtlsdr_get_device_name((uint32_t)device));\n\t\treturn device;\n\t}\n\t/* does string exact match a serial */\n\tfor (i = 0; i < device_count; i++) {\n\t\tmemset(&vendor[0],  0, 256 * sizeof(char));\n\t\tmemset(&product[0], 0, 256 * sizeof(char));\n\t\tmemset(&serial[0],  0, 256 * sizeof(char));\n\t\trc = rtlsdr_get_device_usb_strings(i, vendor, product, serial);\n\t\tif (rc)\n\t\t\tcontinue;\n\t\tif (strcmp(s, serial) != 0) {\n\t\t\tcontinue;}\n\t\tdevice = i;\n\t\tfprintf(stderr, \"Using device %d: %s\\n\",\n\t\t\tdevice, rtlsdr_get_device_name((uint32_t)device));\n\t\treturn device;\n\t}\n\t/* does string prefix match a serial */\n\tfor (i = 0; i < device_count; i++) {\n\t\tmemset(&vendor[0],  0, 256 * sizeof(char));\n\t\tmemset(&product[0], 0, 256 * sizeof(char));\n\t\tmemset(&serial[0],  0, 256 * sizeof(char));\n\t\trc = rtlsdr_get_device_usb_strings(i, vendor, product, serial);\n\t\tif (rc)\n\t\t\tcontinue;\n\t\tif (strncmp(s, serial, strlen(s)) != 0) {\n\t\t\tcontinue;}\n\t\tdevice = i;\n\t\tfprintf(stderr, \"Using device %d: %s\\n\",\n\t\t\tdevice, rtlsdr_get_device_name((uint32_t)device));\n\t\treturn device;\n\t}\n\t/* does string suffix match a serial */\n\tfor (i = 0; i < device_count; i++) {\n\t\tmemset(&vendor[0],  0, 256 * sizeof(char));\n\t\tmemset(&product[0], 0, 256 * sizeof(char));\n\t\tmemset(&serial[0],  0, 256 * sizeof(char));\n\t\trc = rtlsdr_get_device_usb_strings(i, vendor, product, serial);\n\t\tif (rc)\n\t\t\tcontinue;\n\t\toffset = strlen(serial) - strlen(s);\n\t\tif (offset < 0) {\n\t\t\tcontinue;}\n\t\tif (strncmp(s, serial+offset, strlen(s)) != 0) {\n\t\t\tcontinue;}\n\t\tdevice = i;\n\t\tfprintf(stderr, \"Using device %d: %s\\n\",\n\t\t\tdevice, rtlsdr_get_device_name((uint32_t)device));\n\t\treturn device;\n\t}\n\tfprintf(stderr, \"No matching devices found.\\n\");\n\treturn -1;\n}\n\n\n// vim: tabstop=8:softtabstop=8:shiftwidth=8:noexpandtab\n"
  },
  {
    "path": "src/convenience/rtl_convenience.h",
    "content": "/*\n * Copyright (C) 2014 by Kyle Keen <keenerd@gmail.com>\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n#ifndef __RTL_CONVENIENCE_H\n#define __RTL_CONVENIENCE_H\n\n#include <stdint.h>\n#include <stdio.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* a collection of user friendly tools */\n\n/*!\n * Find nearest supported gain\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param target_gain in tenths of a dB\n * \\return 0 on success\n */\n\nint nearest_gain(rtlsdr_dev_t *dev, int target_gain);\n\n/*!\n * Set device frequency and report status on stderr\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param frequency in Hz\n * \\return 0 on success\n */\n\nint verbose_set_frequency(rtlsdr_dev_t *dev, uint64_t frequency);\n\n/*!\n * Set device sample rate and report status on stderr\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param samp_rate in samples/second\n * \\return 0 on success\n */\n\nint verbose_set_sample_rate(rtlsdr_dev_t *dev, uint32_t samp_rate);\n\n/*!\n * Set device bandwidth and report status on stderr\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param frequency in Hz\n * \\return 0 on success\n */\n\nint verbose_set_bandwidth(rtlsdr_dev_t *dev, uint32_t bandwidth);\n\n\n/*!\n * Enable or disable the direct sampling mode and report status on stderr\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param on 0 means disabled, 1 I-ADC input enabled, 2 Q-ADC input enabled\n * \\return 0 on success\n */\n\nint verbose_direct_sampling(rtlsdr_dev_t *dev, int on);\n\n/*!\n * Enable offset tuning and report status on stderr\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\return 0 on success\n */\n\nint verbose_offset_tuning(rtlsdr_dev_t *dev);\n\n/*!\n * Enable auto gain and report status on stderr\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\return 0 on success\n */\n\nint verbose_auto_gain(rtlsdr_dev_t *dev);\n\n/*!\n * Set tuner gain and report status on stderr\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param gain in tenths of a dB\n * \\return 0 on success\n */\n\nint verbose_gain_set(rtlsdr_dev_t *dev, int gain);\n\n/*!\n * Set the frequency correction value for the device and report status on stderr.\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\param ppm_error correction value in parts per million (ppm)\n * \\return 0 on success\n */\n\nint verbose_ppm_set(rtlsdr_dev_t *dev, int ppm_error);\n\n/*!\n * Reset buffer\n *\n * \\param dev the device handle given by rtlsdr_open()\n * \\return 0 on success\n */\n\nint verbose_reset_buffer(rtlsdr_dev_t *dev);\n\n/*!\n * Find the closest matching device.\n *\n * \\param s a string to be parsed\n * \\return dev_index int, -1 on error\n */\n\nint verbose_device_search(char *s);\n\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /*__RTL_CONVENIENCE_H*/\n"
  },
  {
    "path": "src/convenience/wavehdr.h",
    "content": "/*\n * Copyright (C) 2019 by Hayati Ayguen <h_ayguen@web.de>\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef __WAVEHDR_H\n#define __WAVEHDR_H\n\n#include <stdint.h>\n#include <stdio.h>\n#include <time.h>\n\n#pragma pack(push)\n#pragma pack(1)\n\ntypedef struct\n{\n\tchar\t\tID[4];\n\tuint32_t\tsize;\n} chunk_hdr;\n\ntypedef struct\n{\n\tuint16_t\twYear;\t\t\t/* 1601 through 30827 */\n\tuint16_t\twMonth;\t\t\t/* 1..12 */\n\tuint16_t\twDayOfWeek;\t\t/* 0 .. 6: 0 == Sunday, .., 6 == Saturday */\n\tuint16_t\twDay;\t\t\t/* 1 .. 31 */\n\tuint16_t\twHour;\t\t\t/* 0 .. 23 */\n\tuint16_t\twMinute;\t\t/* 0 .. 59 */\n\tuint16_t\twSecond;\t\t/* 0 .. 59 */\n\tuint16_t\twMilliseconds;\t/* 0 .. 999 */\n} Wind_SystemTime;\n\n\ntypedef struct\n{\n\t/* RIFF header */\n\tchunk_hdr\thdr;\t\t/* ID == \"RIFF\" string, size == full filesize - 8 bytes (maybe with some byte missing...) */\n\tchar\t\twaveID[4];\t/* \"WAVE\" string */\n} riff_chunk;\n\ntypedef struct\n{\n\t/* FMT header */\n\tchunk_hdr\thdr;\t\t/* ID == \"fmt \" */\n\tint16_t\t\twFormatTag;\n\tint16_t\t\tnChannels;\n\tint32_t\t\tnSamplesPerSec;\n\tint32_t\t\tnAvgBytesPerSec;\n\tint16_t\t\tnBlockAlign;\n\tint16_t\t\tnBitsPerSample;\n} fmt_chunk;\n\ntypedef struct\n{\n\t/* auxi header - used by SpectraVue / rfspace / HDSDR / ELAD FDM .. */\n\tchunk_hdr\thdr;\t\t/* =\"auxi\" (chunk rfspace) */\n\tWind_SystemTime StartTime;\n\tWind_SystemTime StopTime;\n\tuint32_t\tcenterFreq;\t\t/* receiver center frequency */\n\tuint32_t\tADsamplerate;\t/* A/D sample frequency before downsampling */\n\tuint32_t\tIFFrequency;\t/* IF freq if an external down converter is used */\n\tuint32_t\tBandwidth;\t\t/* displayable BW if you want to limit the display to less than Nyquist band */\n\tint32_t\t\tIQOffset;\t\t/* DC offset of the I and Q channels in 1/1000's of a count */\n\tint32_t\t\tUnused2;\n\tint32_t\t\tUnused3;\n\tint32_t\t\tUnused4;\n\tint32_t\t\tUnused5;\n} auxi_chunk;\n\ntypedef struct\n{\n\t/* DATA header */\n\tchunk_hdr\thdr;\t\t/* =\"data\" */\n} data_chunk;\n\ntypedef struct\n{\n\triff_chunk r;\n\tfmt_chunk  f;\n\tauxi_chunk a;\n\tdata_chunk d;\n} waveFileHeader;\n\n#pragma pack(pop)\n\n#endif /* __WAVEHDR_H */\n\n// vim: tabstop=8:softtabstop=8:shiftwidth=8:noexpandtab\n\n"
  },
  {
    "path": "src/convenience/waveread.c",
    "content": "/*\n * Copyright (C) 2019 by Hayati Ayguen <h_ayguen@web.de>\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include \"waveread.h\"\n\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <time.h>\n#include <assert.h>\n\n#ifndef _WIN32\n#include <unistd.h>\n#include <sys/time.h>\n#else\n#include <windows.h>\n#include <fcntl.h>\n#include <io.h>\n#include <process.h>\n#define _USE_MATH_DEFINES\n#endif\n\n#include <math.h>\n\n#include \"wavehdr.h\"\n\n#define PRINT_DEBUG_OUTPUTS\t\t0\n\nstatic waveFileHeader waveHdr;\n\nstatic uint32_t\twaveDataSize = 0;\n\n\nstatic void waveGetTimeInt(const Wind_SystemTime *p, time_t *tim, double *fraction)\n{\n\tstruct tm t;\n#ifdef _WIN32\n\tstruct tm gtm, ltm;\n\ttime_t nt, gt, lt;\n#endif\n\t/* fprintf(stderr, \"waveGetTimeInt( Wind_SystemTime = %04d-%02d-%02d T %02d:%02d:%02d %f )\\n\"\n\t\t, (int)(p->wYear), (int)(p->wMonth), (int)(p->wDay)\n\t\t, (int)(p->wHour), (int)(p->wMinute), (int)(p->wSecond)\n\t\t, (float)(p->wMilliseconds / 1000.0) );\n\t*/\n\n\tt.tm_year = p->wYear - 1900;    /* 1601 through 30827 */\n\tt.tm_mon = p->wMonth -1; \t\t/* 1..12 */\n\tt.tm_wday = p->wDayOfWeek;      /* 0 .. 6: 0 == Sunday, .., 6 == Saturday */\n\tt.tm_mday = p->wDay;\t\t\t/* 1 .. 31 */\n\tt.tm_hour = p->wHour;\t\t\t/* 0 .. 23 */\n\tt.tm_min = p->wMinute;\t\t\t/* 0 .. 59 */\n\tt.tm_sec = p->wSecond;\t\t\t/* 0 .. 59 */\n\tt.tm_wday = 0;\n\tt.tm_yday = 0;\n\tt.tm_isdst = 0;\n\t*fraction = p->wMilliseconds / 1000.0;\n#ifndef _WIN32\n\t*tim = timegm( &t );\n\t/* fprintf(stderr, \"  using timegm()\\n\"); */\n#else\n\t#ifdef _MSC_VER\n\t\t*tim = _mkgmtime(&t);\n\t/* fprintf(stderr, \"  using _mkgmtime()\\n\"); */\n\t#else\n\t\t/* workaround missing mkgmtime on mingw */\n\t\tnt = mktime(&t);\n\t\tgtm = *gmtime(&nt);\n\t\tltm = *localtime(&nt);\n\t\tgt = mktime(&gtm);\n\t\tlt = mktime(&ltm);\n\t\tassert( nt == gt );\n\t\tnt += ( lt - gt );\n\t\t*tim = nt;\n\t\t/* fprintf(stderr, \"  using mktime(), gmtime() and localtime() difference\\n\"); */\n\t#endif\n#endif\n}\n\n\n\nvoid waveGetStartTime(time_t *tim, double *fraction)\n{\n\twaveGetTimeInt(&waveHdr.a.StartTime, tim, fraction);\n}\n\nvoid waveGetStopTime(time_t *tim, double *fraction)\n{\n\twaveGetTimeInt(&waveHdr.a.StopTime, tim, fraction);\n}\n\n\nint  waveReadHeader(FILE * f, uint32_t *srate, uint32_t *freq, int *bitsPerSample, int *numChannels\n\t, uint32_t *nFrames, int16_t *formatTag, int verbosity)\n{\n\tuint8_t buf[32768];\n\tsize_t rd, smpSize;\n\tint readAuxiHdr = 0;\n\tint readDataHdr = 0;\n\tint rv = 0;\n\n#if PRINT_DEBUG_OUTPUTS\n\tfprintf(stderr, \"waveReadHeader(.., verbosity = %d)\\n\", verbosity);\n#endif\n\n\trd = fread( &waveHdr.r, sizeof(riff_chunk), 1, f );\n\tif ( rd != 1 )\n\t\treturn 10;\n\tif ( memcmp(waveHdr.r.hdr.ID, \"RIFF\", 4) )\n\t\treturn 11;\n\tif ( memcmp(waveHdr.r.waveID, \"WAVE\", 4 ) )\n\t\treturn 12;\n\n\trd = fread( &waveHdr.f, sizeof(fmt_chunk), 1, f );\n#if PRINT_DEBUG_OUTPUTS\n\tfprintf(stderr, \"read %d chunk '%c%c%c%c' size %u = 0x%X\\n\", (int)rd\n\t\t, waveHdr.f.hdr.ID[0], waveHdr.f.hdr.ID[1], waveHdr.f.hdr.ID[2], waveHdr.f.hdr.ID[3]\n\t\t, (unsigned)waveHdr.f.hdr.size, (unsigned)waveHdr.f.hdr.size );\n#endif\n\tif ( rd != 1 )\n\t\treturn 20;\n\tif ( memcmp(waveHdr.f.hdr.ID, \"fmt \", 4 ) )\n\t\treturn 21;\n\tif ( waveHdr.f.hdr.size != 16 )\n\t\treturn 22;\n\t*bitsPerSample = waveHdr.f.nBitsPerSample;\n\t*numChannels = waveHdr.f.nChannels;\n\t*srate = waveHdr.f.nSamplesPerSec;\n\t*formatTag = waveHdr.f.wFormatTag;\n\n\n\trd = fread( &waveHdr.a.hdr, sizeof(chunk_hdr), 1, f );\n\twhile ( !readDataHdr )\n\t{\n\t\tif ( rd != 1 )\n\t\t\treturn 30;\n\t#if PRINT_DEBUG_OUTPUTS\n\t\tfprintf(stderr, \"read %d chunk '%c%c%c%c' size %u = 0x%X\\n\", (int)rd\n\t\t\t, waveHdr.a.hdr.ID[0], waveHdr.a.hdr.ID[1], waveHdr.a.hdr.ID[2], waveHdr.a.hdr.ID[3]\n\t\t\t, (unsigned)waveHdr.a.hdr.size, (unsigned)waveHdr.a.hdr.size );\n\t#endif\n\t\tif ( !memcmp(waveHdr.a.hdr.ID, \"auxi\", 4 ) )\n\t\t{\n\t\t\tif ( verbosity )\n\t\t\t\tfprintf(stderr, \"read chunk 'auxi' .. continue searching for 'data'-chunk ..\\n\");\n\t\t\tif ( waveHdr.a.hdr.size > sizeof(buf) )\n\t\t\t\treturn 32;\n\t\t\tif ( waveHdr.a.hdr.size < (sizeof(auxi_chunk) - sizeof(chunk_hdr)) )\n\t\t\t\treturn 33;\n\t\t\trd = fread( buf, waveHdr.a.hdr.size, 1, f );\n\t\t\tif ( rd != 1 )\n\t\t\t\treturn 34;\n\t\t\tmemcpy( &waveHdr.a.StartTime, buf, sizeof(auxi_chunk) - sizeof(chunk_hdr));\n\t\t\t*freq = waveHdr.a.centerFreq;\n\t\t\treadAuxiHdr = 1;\n\t\t}\n\t\telse if ( !memcmp(waveHdr.a.hdr.ID, \"data\", 4 ) )\n\t\t{\n\t\t\tif ( verbosity )\n\t\t\t\tfprintf(stderr, \"read chunk 'data' .. going to process - %s 'auxi'-chunk ..\\n\", readAuxiHdr ? \"with\" : \"without\" );\n\t\t\twaveHdr.d.hdr = waveHdr.a.hdr;\n\t\t\tif (!readAuxiHdr) {\n\t\t\t\tmemset(&waveHdr.a, 0, sizeof(auxi_chunk));\n\t\t\t\twaveHdr.a.StartTime.wYear = 1970;\n\t\t\t\twaveHdr.a.StartTime.wMonth = 1;\n\t\t\t\twaveHdr.a.StartTime.wDay = 1;\n\t\t\t\t*freq = 100UL * 1000 * 1000;\t/* set frequency to 100 MHz */\n\t\t\t}\n\t\t\treadDataHdr = 1;\n\t\t\tbreak;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ( verbosity )\n\t\t\t\tfprintf(stderr, \"read chunk '%c%c%c%c' while expecting 'auxi' or 'data'. going to next chunk ..\\n\"\n\t\t\t\t\t, waveHdr.a.hdr.ID[0], waveHdr.a.hdr.ID[1], waveHdr.a.hdr.ID[2], waveHdr.a.hdr.ID[3] );\n\t\t\tif ( waveHdr.a.hdr.size > sizeof(buf) )\n\t\t\t\treturn 32;\n\t\t\trd = fread( buf, waveHdr.a.hdr.size, 1, f );\n\t\t\tif ( rd != 1 )\n\t\t\t\treturn 34;\n\t\t}\n\n\t\t/* read next chunk's header */\n\t\trd = fread( &waveHdr.a.hdr, sizeof(chunk_hdr), 1, f );\n\t}\n\n\tif ( !readDataHdr )\n\t{\n\t\trd = fread( &waveHdr.d.hdr, sizeof(chunk_hdr), 1, f );\n\t#if PRINT_DEBUG_OUTPUTS\n\t\tfprintf(stderr, \"read %d chunk '%c%c%c%c' size %u = 0x%X\\n\", (int)rd\n\t\t\t, waveHdr.d.hdr.ID[0], waveHdr.d.hdr.ID[1], waveHdr.d.hdr.ID[2], waveHdr.d.hdr.ID[3]\n\t\t\t, (unsigned)waveHdr.d.hdr.size, (unsigned)waveHdr.d.hdr.size );\n\t#endif\n\t}\n\telse\n\t\trd = 1;\n\tif ( rd != 1 )\n\t\treturn 40;\n\tif ( memcmp(waveHdr.d.hdr.ID, \"data\", 4 ) )\n\t\treturn 41;\n\n\tsmpSize = (*bitsPerSample + 7) / 8;\t\t/* round up to next byte */\n\tsmpSize *= *numChannels;\n\t*nFrames = waveHdr.d.hdr.size / smpSize;\n\n\tif ( verbosity >= 2 )\n\t{\n\t\tfprintf(stderr, \"riffSize = %lu\\n\", (unsigned long)waveHdr.r.hdr.size );\n\t\tfprintf(stderr, \"dataSize = %lu\\n\", (unsigned long)waveHdr.d.hdr.size);\n\t\tfprintf(stderr, \"nBlockAlign = %d\\n\", (int)waveHdr.f.nBlockAlign);\n\t\tfprintf(stderr, \"smpSize = %d\\n\", (int)smpSize);\n\t\tfprintf(stderr, \"*nFrames = %lu\\n\", (unsigned long)(*nFrames) );\n\t}\n\n\treturn rv;\n}\n\n\nint  waveReadSamples(FILE* f,  void * vpData, size_t numSamples, int needCleanData, size_t *numRead)\n{\n\tsize_t nw;\n\tswitch (waveHdr.f.nBitsPerSample)\n\t{\n\tcase 0:\n\tdefault:\n\t\treturn 1;\n\tcase 8:\n\t\t/* no endian conversion needed for single bytes */\n\t\tnw = fread(vpData, sizeof(uint8_t), numSamples, f);\n\t\t*numRead = nw;\n\t\treturn (nw == numSamples) ? 0 : 1;\n\tcase 16:\n\t\t/* TODO: endian conversion needed */\n\t\tnw = fread(vpData, sizeof(int16_t), numSamples, f);\n\t\tif ( needCleanData )\n\t\t{\n\t\t\t/* TODO: convert back endianness */\n\t\t}\n\t\t*numRead = nw;\n\t\treturn (nw == numSamples) ? 0 : 1;\n\t}\n}\n\nint  waveReadFrames(FILE* f,  void * vpData, size_t numFrames, int needCleanData, size_t *numRead)\n{\n\tsize_t nw;\n\tswitch (waveHdr.f.nBitsPerSample)\n\t{\n\tcase 0:\n\tdefault:\n\t\treturn 1;\n\tcase 8:\n\t\t/* no endian conversion needed for single bytes */\n\t\tnw = fread(vpData, waveHdr.f.nChannels * sizeof(uint8_t), numFrames, f);\n\t\t*numRead = nw;\n\t\treturn (nw == numFrames) ? 0 : 1;\n\tcase 16:\n\t\t/* TODO: endian conversion needed */\n\t\tnw = fread(vpData, waveHdr.f.nChannels * sizeof(int16_t), numFrames, f);\n\t\tif ( needCleanData )\n\t\t{\n\t\t\t/* TODO: convert back endianness */\n\t\t}\n\t\t*numRead = nw;\n\t\treturn (nw == numFrames) ? 0 : 1;\n\t}\n}\n\n// vim: tabstop=8:softtabstop=8:shiftwidth=8:noexpandtab\n"
  },
  {
    "path": "src/convenience/waveread.h",
    "content": "/*\n * Copyright (C) 2019 by Hayati Ayguen <h_ayguen@web.de>\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n#ifndef __WAVEREAD_H\n#define __WAVEREAD_H\n\n#include <stdint.h>\n#include <stdio.h>\n#include <time.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n\nint  waveReadHeader(FILE * f, uint32_t *samplerate, uint32_t *freq, int *bitsPerSample, int *numChannels\n\t, uint32_t *nFrames, int16_t *formatTag, int verbosity);\nint  waveReadFrames(FILE* f,  void * vpData, size_t numFrames, int needCleanData, size_t *numRead);\nint  waveReadSamples(FILE* f,  void * vpData, size_t numSamples, int needCleanData, size_t *numRead);  /* returns 0, when no errors occured */\nvoid waveGetStartTime(time_t *tim, double *fraction);\nvoid waveGetStopTime(time_t *tim, double *fraction);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /*__WAVEREAD_H*/\n"
  },
  {
    "path": "src/convenience/wavewrite.c",
    "content": "/*\n * Copyright (C) 2019 by Hayati Ayguen <h_ayguen@web.de>\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include \"wavewrite.h\"\n\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <time.h>\n#include <assert.h>\n\n#ifndef _WIN32\n#include <unistd.h>\n#include <sys/time.h>\n#else\n#include <windows.h>\n#include <fcntl.h>\n#include <io.h>\n#include <process.h>\n#define _USE_MATH_DEFINES\n#endif\n\n#include <math.h>\n\n#include \"wavehdr.h\"\n\nstatic waveFileHeader waveHdr;\n\nstatic uint32_t\twaveDataSize = 0;\nint\twaveHdrStarted = 0;\n\n#ifdef _WIN32\nint gettimeofday(struct timeval *tv, void* ignored)\n{\n\tFILETIME ft;\n\tunsigned __int64 tmp = 0;\n\tif (NULL != tv) {\n\t\tGetSystemTimeAsFileTime(&ft);\n\t\ttmp |= ft.dwHighDateTime;\n\t\ttmp <<= 32;\n\t\ttmp |= ft.dwLowDateTime;\n\t\ttmp /= 10;\n#ifdef _MSC_VER\n\t\ttmp -= 11644473600000000Ui64;\n#else\n\t\ttmp -= 11644473600000000ULL;\n#endif\n\t\ttv->tv_sec = (long)(tmp / 1000000UL);\n\t\ttv->tv_usec = (long)(tmp % 1000000UL);\n\t}\n\treturn 0;\n}\n#endif\n\nstatic void waveSetCurrTime(Wind_SystemTime *p)\n{\n\tstruct timeval tv;\n\tstruct tm t;\n\n\tgettimeofday(&tv, NULL);\n\tp->wMilliseconds = tv.tv_usec / 1000;\n\n#ifdef _WIN32\n\tt = *gmtime(&tv.tv_sec);\n#else\n\tgmtime_r(&tv.tv_sec, &t);\n#endif\n\n\tp->wYear = t.tm_year + 1900;\t/* 1601 through 30827 */\n\tp->wMonth = t.tm_mon + 1;\t\t/* 1..12 */\n\tp->wDayOfWeek = t.tm_wday;\t\t/* 0 .. 6: 0 == Sunday, .., 6 == Saturday */\n\tp->wDay = t.tm_mday;\t\t\t/* 1 .. 31 */\n\tp->wHour = t.tm_hour;\t\t\t/* 0 .. 23 */\n\tp->wMinute = t.tm_min;\t\t\t/* 0 .. 59 */\n\tp->wSecond = t.tm_sec;\t\t\t/* 0 .. 59 */\n}\n\nstatic void waveSetStartTimeInt(time_t tim, double fraction, Wind_SystemTime *p)\n{\n\tstruct tm t = *gmtime( &tim );\n\tp->wYear = t.tm_year + 1900;\t/* 1601 through 30827 */\n\tp->wMonth = t.tm_mon + 1;\t\t/* 1..12 */\n\tp->wDayOfWeek = t.tm_wday;\t\t/* 0 .. 6: 0 == Sunday, .., 6 == Saturday */\n\tp->wDay = t.tm_mday;\t\t\t/* 1 .. 31 */\n\tp->wHour = t.tm_hour;\t\t\t/* 0 .. 23 */\n\tp->wMinute = t.tm_min;\t\t\t/* 0 .. 59 */\n\tp->wSecond = t.tm_sec;\t\t\t/* 0 .. 59 */\n\tp->wMilliseconds = (int)( fraction * 1000.0 );\n\tif (p->wMilliseconds >= 1000)\n\t\tp->wMilliseconds = 999;\n}\n\nvoid waveSetStartTime(time_t tim, double fraction)\n{\n\twaveSetStartTimeInt(tim, fraction, &waveHdr.a.StartTime );\n\twaveHdr.a.StopTime = waveHdr.a.StartTime;\t\t/* to fix */\n}\n\n\nvoid wavePrepareHeader(unsigned samplerate, unsigned freq, int bitsPerSample, int numChannels)\n{\n\tint\tbytesPerSample = bitsPerSample / 8;\n\tint bytesPerFrame = bytesPerSample * numChannels;\n\n\tmemcpy( waveHdr.r.hdr.ID, \"RIFF\", 4 );\n\twaveHdr.r.hdr.size = sizeof(waveFileHeader) - 8;\t\t/* to fix */\n\tmemcpy( waveHdr.r.waveID, \"WAVE\", 4 );\n\n\tmemcpy( waveHdr.f.hdr.ID, \"fmt \", 4 );\n\twaveHdr.f.hdr.size = 16;\n\twaveHdr.f.wFormatTag = 1;\t\t\t\t\t/* PCM */\n\twaveHdr.f.nChannels = numChannels;\t\t/* I and Q channels */\n\twaveHdr.f.nSamplesPerSec = samplerate;\n\twaveHdr.f.nAvgBytesPerSec = samplerate * bytesPerFrame;\n\twaveHdr.f.nBlockAlign = waveHdr.f.nChannels;\n\twaveHdr.f.nBitsPerSample = bitsPerSample;\n\n\tmemcpy( waveHdr.a.hdr.ID, \"auxi\", 4 );\n\twaveHdr.a.hdr.size = 2 * sizeof(Wind_SystemTime) + 9 * sizeof(int32_t);  /* = 2 * 16 + 9 * 4 = 68 */\n\twaveSetCurrTime( &waveHdr.a.StartTime );\n\twaveHdr.a.StopTime = waveHdr.a.StartTime;\t\t/* to fix */\n\twaveHdr.a.centerFreq = freq;\n\twaveHdr.a.ADsamplerate = samplerate;\n\twaveHdr.a.IFFrequency = 0;\n\twaveHdr.a.Bandwidth = 0;\n\twaveHdr.a.IQOffset = 0;\n\twaveHdr.a.Unused2 = 0;\n\twaveHdr.a.Unused3 = 0;\n\twaveHdr.a.Unused4 = 0;\n\twaveHdr.a.Unused5 = 0;\n\n\tmemcpy( waveHdr.d.hdr.ID, \"data\", 4 );\n\twaveHdr.d.hdr.size = 0;\t\t/* to fix later */\n\twaveDataSize = 0;\n}\n\nvoid waveWriteHeader(unsigned samplerate, unsigned freq, int bitsPerSample, int numChannels, FILE * f)\n{\n\tif (f != stdout) {\n\t\tassert( !waveHdrStarted );\n\t\twavePrepareHeader(samplerate, freq, bitsPerSample, numChannels);\n\t\tfwrite(&waveHdr, sizeof(waveFileHeader), 1, f);\n\t\twaveHdrStarted = 1;\n\t}\n}\n\nint  waveWriteSamples(FILE* f,  void * vpData, size_t numSamples, int needCleanData)\n{\n\tsize_t nw;\n\tswitch (waveHdr.f.nBitsPerSample)\n\t{\n\tcase 0:\n\tdefault:\n\t\treturn 1;\n\tcase 8:\n\t\t/* no endian conversion needed for single bytes */\n\t\tnw = fwrite(vpData, sizeof(uint8_t), numSamples, f);\n\t\twaveDataSize += sizeof(uint8_t) * numSamples;\n\t\treturn (nw == numSamples) ? 0 : 1;\n\tcase 16:\n\t\t/* TODO: endian conversion needed */\n\t\tnw = fwrite(vpData, sizeof(int16_t), numSamples, f);\n\t\twaveDataSize += sizeof(int16_t) * numSamples;\n\t\tif ( needCleanData )\n\t\t{\n\t\t\t/* TODO: convert back endianness */\n\t\t}\n\t\treturn (nw == numSamples) ? 0 : 1;\n\t}\n}\n\nint  waveWriteFrames(FILE* f,  void * vpData, size_t numFrames, int needCleanData)\n{\n\tsize_t nw;\n\tswitch (waveHdr.f.nBitsPerSample)\n\t{\n\tcase 0:\n\tdefault:\n\t\treturn 1;\n\tcase 8:\n\t\t/* no endian conversion needed for single bytes */\n\t\tnw = fwrite(vpData, waveHdr.f.nChannels * sizeof(uint8_t), numFrames, f);\n\t\twaveDataSize += waveHdr.f.nChannels * sizeof(uint8_t) * numFrames;\n\t\treturn (nw == numFrames) ? 0 : 1;\n\tcase 16:\n\t\t/* TODO: endian conversion needed */\n\t\tnw = fwrite(vpData, waveHdr.f.nChannels * sizeof(int16_t), numFrames, f);\n\t\twaveDataSize += waveHdr.f.nChannels * sizeof(int16_t) * numFrames;\n\t\tif ( needCleanData )\n\t\t{\n\t\t\t/* TODO: convert back endianness */\n\t\t}\n\t\treturn (nw == numFrames) ? 0 : 1;\n\t}\n}\n\n\nint  waveFinalizeHeader(FILE * f)\n{\n\tif (f != stdout) {\n\t\tassert( waveHdrStarted );\n\t\twaveSetCurrTime( &waveHdr.a.StopTime );\n\t\twaveHdr.d.hdr.size = waveDataSize;\n\t\twaveHdr.r.hdr.size += waveDataSize;\n\t\t/* fprintf(stderr, \"waveFinalizeHeader(): datasize = %d\\n\", waveHdr.dataSize); */\n\t\twaveHdrStarted = 0;\n\t\tif ( fseek(f, 0, SEEK_SET) )\n\t\t\treturn 1;\n\t\tif ( 1 != fwrite(&waveHdr, sizeof(waveFileHeader), 1, f) )\n\t\t\treturn 1;\n\t\t/* fprintf(stderr, \"waveFinalizeHeader(): success writing header\\n\"); */\n\t\treturn 0;\n\t}\n\treturn 1;\n}\n\n// vim: tabstop=8:softtabstop=8:shiftwidth=8:noexpandtab\n"
  },
  {
    "path": "src/convenience/wavewrite.h",
    "content": "/*\n * Copyright (C) 2019 by Hayati Ayguen <h_ayguen@web.de>\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n#ifndef __WAVEWRITE_H\n#define __WAVEWRITE_H\n\n#include <stdint.h>\n#include <stdio.h>\n#include <time.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nextern int\twaveHdrStarted;\n\n/*!\n * helper functions to write and finalize wave headers\n *   with compatibility to some SDR programs - showing frequency:\n * raw sample data still have to be written by caller to FILE*.\n * call waveWriteHeader() before writing anything to to file\n * and call waveFinalizeHeader() afterwards,\n * stdout/stderr can't be used, because seek to begin isn't possible.\n * \n */\n\nvoid waveWriteHeader(unsigned samplerate, unsigned freq, int bitsPerSample, int numChannels, FILE * f);\n\n/* waveWriteFrames() writes (numFrames * numChannels) samples\n * waveWriteSamples()\n * both return 0, when no errors occured\n */\nint  waveWriteFrames(FILE* f,  void * vpData, size_t numFrames, int needCleanData);\nint  waveWriteSamples(FILE* f,  void * vpData, size_t numSamples, int needCleanData);  /* returns 0, when no errors occured */\nvoid waveSetStartTime(time_t t, double fraction);\nint  waveFinalizeHeader(FILE * f);      /* returns 0, when no errors occured */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /*__WAVEWRITE_H*/\n"
  },
  {
    "path": "src/getopt/getopt.c",
    "content": "/* Getopt for GNU.\n   NOTE: getopt is now part of the C library, so if you don't know what\n   \"Keep this file name-space clean\" means, talk to drepper@gnu.org\n   before changing it!\n   Copyright (C) 1987,88,89,90,91,92,93,94,95,96,98,99,2000,2001\n   Free Software Foundation, Inc.\n   This file is part of the GNU C Library.\n\n   The GNU C Library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Lesser General Public\n   License as published by the Free Software Foundation; either\n   version 2.1 of the License, or (at your option) any later version.\n\n   The GNU C Library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public\n   License along with the GNU C Library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA\n   02111-1307 USA.  */\n/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.\n   Ditto for AIX 3.2 and <stdlib.h>.  */\n#ifndef _NO_PROTO\n# define _NO_PROTO\n#endif\n\n#ifdef HAVE_CONFIG_H\n# include <config.h>\n#endif\n\n#if !defined __STDC__ || !__STDC__\n/* This is a separate conditional since some stdc systems\n   reject `defined (const)'.  */\n# ifndef const\n#  define const\n# endif\n#endif\n\n#include <stdio.h>\n\n/* Comment out all this code if we are using the GNU C Library, and are not\n   actually compiling the library itself.  This code is part of the GNU C\n   Library, but also included in many other GNU distributions.  Compiling\n   and linking in this code is a waste when using the GNU C library\n   (especially if it is a shared library).  Rather than having every GNU\n   program understand `configure --with-gnu-libc' and omit the object files,\n   it is simpler to just do this in the source for each such file.  */\n\n#define GETOPT_INTERFACE_VERSION 2\n#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2\n# include <gnu-versions.h>\n# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION\n#  define ELIDE_CODE\n# endif\n#endif\n\n#ifndef ELIDE_CODE\n\n\n/* This needs to come after some library #include\n   to get __GNU_LIBRARY__ defined.  */\n#ifdef\t__GNU_LIBRARY__\n/* Don't include stdlib.h for non-GNU C libraries because some of them\n   contain conflicting prototypes for getopt.  */\n# include <stdlib.h>\n# include <unistd.h>\n#endif\t/* GNU C library.  */\n\n#ifdef VMS\n# include <unixlib.h>\n# if HAVE_STRING_H - 0\n#  include <string.h>\n# endif\n#endif\n\n#ifndef _\n/* This is for other GNU distributions with internationalized messages.  */\n# if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC\n#  include <libintl.h>\n#  ifndef _\n#   define _(msgid)\tgettext (msgid)\n#  endif\n# else\n#  define _(msgid)\t(msgid)\n# endif\n#endif\n\n/* This version of `getopt' appears to the caller like standard Unix `getopt'\n   but it behaves differently for the user, since it allows the user\n   to intersperse the options with the other arguments.\n\n   As `getopt' works, it permutes the elements of ARGV so that,\n   when it is done, all the options precede everything else.  Thus\n   all application programs are extended to handle flexible argument order.\n\n   Setting the environment variable POSIXLY_CORRECT disables permutation.\n   Then the behavior is completely standard.\n\n   GNU application programs can use a third alternative mode in which\n   they can distinguish the relative order of options and other arguments.  */\n\n#include \"getopt.h\"\n\n/* For communication from `getopt' to the caller.\n   When `getopt' finds an option that takes an argument,\n   the argument value is returned here.\n   Also, when `ordering' is RETURN_IN_ORDER,\n   each non-option ARGV-element is returned here.  */\n\nchar *optarg;\n\n/* Index in ARGV of the next element to be scanned.\n   This is used for communication to and from the caller\n   and for communication between successive calls to `getopt'.\n\n   On entry to `getopt', zero means this is the first call; initialize.\n\n   When `getopt' returns -1, this is the index of the first of the\n   non-option elements that the caller should itself scan.\n\n   Otherwise, `optind' communicates from one call to the next\n   how much of ARGV has been scanned so far.  */\n\n/* 1003.2 says this must be 1 before any call.  */\nint optind = 1;\n\n/* Formerly, initialization of getopt depended on optind==0, which\n   causes problems with re-calling getopt as programs generally don't\n   know that. */\n\nint __getopt_initialized;\n\n/* The next char to be scanned in the option-element\n   in which the last option character we returned was found.\n   This allows us to pick up the scan where we left off.\n\n   If this is zero, or a null string, it means resume the scan\n   by advancing to the next ARGV-element.  */\n\nstatic char *nextchar;\n\n/* Callers store zero here to inhibit the error message\n   for unrecognized options.  */\n\nint opterr = 1;\n\n/* Set to an option character which was unrecognized.\n   This must be initialized on some systems to avoid linking in the\n   system's own getopt implementation.  */\n\nint optopt = '?';\n\n/* Describe how to deal with options that follow non-option ARGV-elements.\n\n   If the caller did not specify anything,\n   the default is REQUIRE_ORDER if the environment variable\n   POSIXLY_CORRECT is defined, PERMUTE otherwise.\n\n   REQUIRE_ORDER means don't recognize them as options;\n   stop option processing when the first non-option is seen.\n   This is what Unix does.\n   This mode of operation is selected by either setting the environment\n   variable POSIXLY_CORRECT, or using `+' as the first character\n   of the list of option characters.\n\n   PERMUTE is the default.  We permute the contents of ARGV as we scan,\n   so that eventually all the non-options are at the end.  This allows options\n   to be given in any order, even with programs that were not written to\n   expect this.\n\n   RETURN_IN_ORDER is an option available to programs that were written\n   to expect options and other ARGV-elements in any order and that care about\n   the ordering of the two.  We describe each non-option ARGV-element\n   as if it were the argument of an option with character code 1.\n   Using `-' as the first character of the list of option characters\n   selects this mode of operation.\n\n   The special argument `--' forces an end of option-scanning regardless\n   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only\n   `--' can cause `getopt' to return -1 with `optind' != ARGC.  */\n\nstatic enum\n{\n  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER\n} ordering;\n\n/* Value of POSIXLY_CORRECT environment variable.  */\nstatic char *posixly_correct;\n\n#ifdef\t__GNU_LIBRARY__\n/* We want to avoid inclusion of string.h with non-GNU libraries\n   because there are many ways it can cause trouble.\n   On some systems, it contains special magic macros that don't work\n   in GCC.  */\n# include <string.h>\n# define my_index\tstrchr\n#else\n\n# if 1 //HAVE_STRING_H\n#  include <string.h>\n# else\n#  include <strings.h>\n# endif\n\n/* Avoid depending on library functions or files\n   whose names are inconsistent.  */\n\n#ifndef getenv\n#ifdef _MSC_VER\n// DDK will complain if you don't use the stdlib defined getenv\n#include <stdlib.h>\n#else\nextern char *getenv ();\n#endif\n#endif\n\nstatic char *\nmy_index (str, chr)\n     const char *str;\n     int chr;\n{\n  while (*str)\n    {\n      if (*str == chr)\n\treturn (char *) str;\n      str++;\n    }\n  return 0;\n}\n\n/* If using GCC, we can safely declare strlen this way.\n   If not using GCC, it is ok not to declare it.  */\n#ifdef __GNUC__\n/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.\n   That was relevant to code that was here before.  */\n# if (!defined __STDC__ || !__STDC__) && !defined strlen\n/* gcc with -traditional declares the built-in strlen to return int,\n   and has done so at least since version 2.4.5. -- rms.  */\nextern int strlen (const char *);\n# endif /* not __STDC__ */\n#endif /* __GNUC__ */\n\n#endif /* not __GNU_LIBRARY__ */\n\n/* Handle permutation of arguments.  */\n\n/* Describe the part of ARGV that contains non-options that have\n   been skipped.  `first_nonopt' is the index in ARGV of the first of them;\n   `last_nonopt' is the index after the last of them.  */\n\nstatic int first_nonopt;\nstatic int last_nonopt;\n\n#ifdef _LIBC\n/* Stored original parameters.\n   XXX This is no good solution.  We should rather copy the args so\n   that we can compare them later.  But we must not use malloc(3).  */\nextern int __libc_argc;\nextern char **__libc_argv;\n\n/* Bash 2.0 gives us an environment variable containing flags\n   indicating ARGV elements that should not be considered arguments.  */\n\n# ifdef USE_NONOPTION_FLAGS\n/* Defined in getopt_init.c  */\nextern char *__getopt_nonoption_flags;\n\nstatic int nonoption_flags_max_len;\nstatic int nonoption_flags_len;\n# endif\n\n# ifdef USE_NONOPTION_FLAGS\n#  define SWAP_FLAGS(ch1, ch2) \\\n  if (nonoption_flags_len > 0)\t\t\t\t\t\t      \\\n    {\t\t\t\t\t\t\t\t\t      \\\n      char __tmp = __getopt_nonoption_flags[ch1];\t\t\t      \\\n      __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2];\t      \\\n      __getopt_nonoption_flags[ch2] = __tmp;\t\t\t\t      \\\n    }\n# else\n#  define SWAP_FLAGS(ch1, ch2)\n# endif\n#else\t/* !_LIBC */\n# define SWAP_FLAGS(ch1, ch2)\n#endif\t/* _LIBC */\n\n/* Exchange two adjacent subsequences of ARGV.\n   One subsequence is elements [first_nonopt,last_nonopt)\n   which contains all the non-options that have been skipped so far.\n   The other is elements [last_nonopt,optind), which contains all\n   the options processed since those non-options were skipped.\n\n   `first_nonopt' and `last_nonopt' are relocated so that they describe\n   the new indices of the non-options in ARGV after they are moved.  */\n\n#if defined __STDC__ && __STDC__\nstatic void exchange (char **);\n#endif\n\nstatic void\nexchange (argv)\n     char **argv;\n{\n  int bottom = first_nonopt;\n  int middle = last_nonopt;\n  int top = optind;\n  char *tem;\n\n  /* Exchange the shorter segment with the far end of the longer segment.\n     That puts the shorter segment into the right place.\n     It leaves the longer segment in the right place overall,\n     but it consists of two parts that need to be swapped next.  */\n\n#if defined _LIBC && defined USE_NONOPTION_FLAGS\n  /* First make sure the handling of the `__getopt_nonoption_flags'\n     string can work normally.  Our top argument must be in the range\n     of the string.  */\n  if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len)\n    {\n      /* We must extend the array.  The user plays games with us and\n\t presents new arguments.  */\n      char *new_str = malloc (top + 1);\n      if (new_str == NULL)\n\tnonoption_flags_len = nonoption_flags_max_len = 0;\n      else\n\t{\n\t  memset (__mempcpy (new_str, __getopt_nonoption_flags,\n\t\t\t     nonoption_flags_max_len),\n\t\t  '\\0', top + 1 - nonoption_flags_max_len);\n\t  nonoption_flags_max_len = top + 1;\n\t  __getopt_nonoption_flags = new_str;\n\t}\n    }\n#endif\n\n  while (top > middle && middle > bottom)\n    {\n      if (top - middle > middle - bottom)\n\t{\n\t  /* Bottom segment is the short one.  */\n\t  int len = middle - bottom;\n\t  register int i;\n\n\t  /* Swap it with the top part of the top segment.  */\n\t  for (i = 0; i < len; i++)\n\t    {\n\t      tem = argv[bottom + i];\n\t      argv[bottom + i] = argv[top - (middle - bottom) + i];\n\t      argv[top - (middle - bottom) + i] = tem;\n\t      SWAP_FLAGS (bottom + i, top - (middle - bottom) + i);\n\t    }\n\t  /* Exclude the moved bottom segment from further swapping.  */\n\t  top -= len;\n\t}\n      else\n\t{\n\t  /* Top segment is the short one.  */\n\t  int len = top - middle;\n\t  register int i;\n\n\t  /* Swap it with the bottom part of the bottom segment.  */\n\t  for (i = 0; i < len; i++)\n\t    {\n\t      tem = argv[bottom + i];\n\t      argv[bottom + i] = argv[middle + i];\n\t      argv[middle + i] = tem;\n\t      SWAP_FLAGS (bottom + i, middle + i);\n\t    }\n\t  /* Exclude the moved top segment from further swapping.  */\n\t  bottom += len;\n\t}\n    }\n\n  /* Update records for the slots the non-options now occupy.  */\n\n  first_nonopt += (optind - last_nonopt);\n  last_nonopt = optind;\n}\n\n/* Initialize the internal data when the first call is made.  */\n\n#if defined __STDC__ && __STDC__\nstatic const char *_getopt_initialize (int, char *const *, const char *);\n#endif\nstatic const char *\n_getopt_initialize (argc, argv, optstring)\n     int argc;\n     char *const *argv;\n     const char *optstring;\n{\n  /* Start processing options with ARGV-element 1 (since ARGV-element 0\n     is the program name); the sequence of previously skipped\n     non-option ARGV-elements is empty.  */\n\n  first_nonopt = last_nonopt = optind;\n\n  nextchar = NULL;\n\n  posixly_correct = getenv (\"POSIXLY_CORRECT\");\n\n  /* Determine how to handle the ordering of options and nonoptions.  */\n\n  if (optstring[0] == '-')\n    {\n      ordering = RETURN_IN_ORDER;\n      ++optstring;\n    }\n  else if (optstring[0] == '+')\n    {\n      ordering = REQUIRE_ORDER;\n      ++optstring;\n    }\n  else if (posixly_correct != NULL)\n    ordering = REQUIRE_ORDER;\n  else\n    ordering = PERMUTE;\n\n#if defined _LIBC && defined USE_NONOPTION_FLAGS\n  if (posixly_correct == NULL\n      && argc == __libc_argc && argv == __libc_argv)\n    {\n      if (nonoption_flags_max_len == 0)\n\t{\n\t  if (__getopt_nonoption_flags == NULL\n\t      || __getopt_nonoption_flags[0] == '\\0')\n\t    nonoption_flags_max_len = -1;\n\t  else\n\t    {\n\t      const char *orig_str = __getopt_nonoption_flags;\n\t      int len = nonoption_flags_max_len = strlen (orig_str);\n\t      if (nonoption_flags_max_len < argc)\n\t\tnonoption_flags_max_len = argc;\n\t      __getopt_nonoption_flags =\n\t\t(char *) malloc (nonoption_flags_max_len);\n\t      if (__getopt_nonoption_flags == NULL)\n\t\tnonoption_flags_max_len = -1;\n\t      else\n\t\tmemset (__mempcpy (__getopt_nonoption_flags, orig_str, len),\n\t\t\t'\\0', nonoption_flags_max_len - len);\n\t    }\n\t}\n      nonoption_flags_len = nonoption_flags_max_len;\n    }\n  else\n    nonoption_flags_len = 0;\n#endif\n\n  return optstring;\n}\n\n/* Scan elements of ARGV (whose length is ARGC) for option characters\n   given in OPTSTRING.\n\n   If an element of ARGV starts with '-', and is not exactly \"-\" or \"--\",\n   then it is an option element.  The characters of this element\n   (aside from the initial '-') are option characters.  If `getopt'\n   is called repeatedly, it returns successively each of the option characters\n   from each of the option elements.\n\n   If `getopt' finds another option character, it returns that character,\n   updating `optind' and `nextchar' so that the next call to `getopt' can\n   resume the scan with the following option character or ARGV-element.\n\n   If there are no more option characters, `getopt' returns -1.\n   Then `optind' is the index in ARGV of the first ARGV-element\n   that is not an option.  (The ARGV-elements have been permuted\n   so that those that are not options now come last.)\n\n   OPTSTRING is a string containing the legitimate option characters.\n   If an option character is seen that is not listed in OPTSTRING,\n   return '?' after printing an error message.  If you set `opterr' to\n   zero, the error message is suppressed but we still return '?'.\n\n   If a char in OPTSTRING is followed by a colon, that means it wants an arg,\n   so the following text in the same ARGV-element, or the text of the following\n   ARGV-element, is returned in `optarg'.  Two colons mean an option that\n   wants an optional arg; if there is text in the current ARGV-element,\n   it is returned in `optarg', otherwise `optarg' is set to zero.\n\n   If OPTSTRING starts with `-' or `+', it requests different methods of\n   handling the non-option ARGV-elements.\n   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.\n\n   Long-named options begin with `--' instead of `-'.\n   Their names may be abbreviated as long as the abbreviation is unique\n   or is an exact match for some defined option.  If they have an\n   argument, it follows the option name in the same ARGV-element, separated\n   from the option name by a `=', or else the in next ARGV-element.\n   When `getopt' finds a long-named option, it returns 0 if that option's\n   `flag' field is nonzero, the value of the option's `val' field\n   if the `flag' field is zero.\n\n   The elements of ARGV aren't really const, because we permute them.\n   But we pretend they're const in the prototype to be compatible\n   with other systems.\n\n   LONGOPTS is a vector of `struct option' terminated by an\n   element containing a name which is zero.\n\n   LONGIND returns the index in LONGOPT of the long-named option found.\n   It is only valid when a long-named option has been found by the most\n   recent call.\n\n   If LONG_ONLY is nonzero, '-' as well as '--' can introduce\n   long-named options.  */\n\nint\n_getopt_internal (argc, argv, optstring, longopts, longind, long_only)\n     int argc;\n     char *const *argv;\n     const char *optstring;\n     const struct option *longopts;\n     int *longind;\n     int long_only;\n{\n  int print_errors = opterr;\n  if (optstring[0] == ':')\n    print_errors = 0;\n\n  if (argc < 1)\n    return -1;\n\n  optarg = NULL;\n\n  if (optind == 0 || !__getopt_initialized)\n    {\n      if (optind == 0)\n\toptind = 1;\t/* Don't scan ARGV[0], the program name.  */\n      optstring = _getopt_initialize (argc, argv, optstring);\n      __getopt_initialized = 1;\n    }\n\n  /* Test whether ARGV[optind] points to a non-option argument.\n     Either it does not have option syntax, or there is an environment flag\n     from the shell indicating it is not an option.  The later information\n     is only used when the used in the GNU libc.  */\n#if defined _LIBC && defined USE_NONOPTION_FLAGS\n# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\\0'\t      \\\n\t\t      || (optind < nonoption_flags_len\t\t\t      \\\n\t\t\t  && __getopt_nonoption_flags[optind] == '1'))\n#else\n# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\\0')\n#endif\n\n  if (nextchar == NULL || *nextchar == '\\0')\n    {\n      /* Advance to the next ARGV-element.  */\n\n      /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been\n\t moved back by the user (who may also have changed the arguments).  */\n      if (last_nonopt > optind)\n\tlast_nonopt = optind;\n      if (first_nonopt > optind)\n\tfirst_nonopt = optind;\n\n      if (ordering == PERMUTE)\n\t{\n\t  /* If we have just processed some options following some non-options,\n\t     exchange them so that the options come first.  */\n\n\t  if (first_nonopt != last_nonopt && last_nonopt != optind)\n\t    exchange ((char **) argv);\n\t  else if (last_nonopt != optind)\n\t    first_nonopt = optind;\n\n\t  /* Skip any additional non-options\n\t     and extend the range of non-options previously skipped.  */\n\n\t  while (optind < argc && NONOPTION_P)\n\t    optind++;\n\t  last_nonopt = optind;\n\t}\n\n      /* The special ARGV-element `--' means premature end of options.\n\t Skip it like a null option,\n\t then exchange with previous non-options as if it were an option,\n\t then skip everything else like a non-option.  */\n\n      if (optind != argc && !strcmp (argv[optind], \"--\"))\n\t{\n\t  optind++;\n\n\t  if (first_nonopt != last_nonopt && last_nonopt != optind)\n\t    exchange ((char **) argv);\n\t  else if (first_nonopt == last_nonopt)\n\t    first_nonopt = optind;\n\t  last_nonopt = argc;\n\n\t  optind = argc;\n\t}\n\n      /* If we have done all the ARGV-elements, stop the scan\n\t and back over any non-options that we skipped and permuted.  */\n\n      if (optind == argc)\n\t{\n\t  /* Set the next-arg-index to point at the non-options\n\t     that we previously skipped, so the caller will digest them.  */\n\t  if (first_nonopt != last_nonopt)\n\t    optind = first_nonopt;\n\t  return -1;\n\t}\n\n      /* If we have come to a non-option and did not permute it,\n\t either stop the scan or describe it to the caller and pass it by.  */\n\n      if (NONOPTION_P)\n\t{\n\t  if (ordering == REQUIRE_ORDER)\n\t    return -1;\n\t  optarg = argv[optind++];\n\t  return 1;\n\t}\n\n      /* We have found another option-ARGV-element.\n\t Skip the initial punctuation.  */\n\n      nextchar = (argv[optind] + 1\n\t\t  + (longopts != NULL && argv[optind][1] == '-'));\n    }\n\n  /* Decode the current option-ARGV-element.  */\n\n  /* Check whether the ARGV-element is a long option.\n\n     If long_only and the ARGV-element has the form \"-f\", where f is\n     a valid short option, don't consider it an abbreviated form of\n     a long option that starts with f.  Otherwise there would be no\n     way to give the -f short option.\n\n     On the other hand, if there's a long option \"fubar\" and\n     the ARGV-element is \"-fu\", do consider that an abbreviation of\n     the long option, just like \"--fu\", and not \"-f\" with arg \"u\".\n\n     This distinction seems to be the most useful approach.  */\n\n  if (longopts != NULL\n      && (argv[optind][1] == '-'\n\t  || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))\n    {\n      char *nameend;\n      const struct option *p;\n      const struct option *pfound = NULL;\n      int exact = 0;\n      int ambig = 0;\n      int indfound = -1;\n      int option_index;\n\n      for (nameend = nextchar; *nameend && *nameend != '='; nameend++)\n\t/* Do nothing.  */ ;\n\n      /* Test all long options for either exact match\n\t or abbreviated matches.  */\n      for (p = longopts, option_index = 0; p->name; p++, option_index++)\n\tif (!strncmp (p->name, nextchar, nameend - nextchar))\n\t  {\n\t    if ((unsigned int) (nameend - nextchar)\n\t\t== (unsigned int) strlen (p->name))\n\t      {\n\t\t/* Exact match found.  */\n\t\tpfound = p;\n\t\tindfound = option_index;\n\t\texact = 1;\n\t\tbreak;\n\t      }\n\t    else if (pfound == NULL)\n\t      {\n\t\t/* First nonexact match found.  */\n\t\tpfound = p;\n\t\tindfound = option_index;\n\t      }\n\t    else if (long_only\n\t\t     || pfound->has_arg != p->has_arg\n\t\t     || pfound->flag != p->flag\n\t\t     || pfound->val != p->val)\n\t      /* Second or later nonexact match found.  */\n\t      ambig = 1;\n\t  }\n\n      if (ambig && !exact)\n\t{\n\t  if (print_errors)\n\t    fprintf (stderr, _(\"%s: option `%s' is ambiguous\\n\"),\n\t\t     argv[0], argv[optind]);\n\t  nextchar += strlen (nextchar);\n\t  optind++;\n\t  optopt = 0;\n\t  return '?';\n\t}\n\n      if (pfound != NULL)\n\t{\n\t  option_index = indfound;\n\t  optind++;\n\t  if (*nameend)\n\t    {\n\t      /* Don't test has_arg with >, because some C compilers don't\n\t\t allow it to be used on enums.  */\n\t      if (pfound->has_arg)\n\t\toptarg = nameend + 1;\n\t      else\n\t\t{\n\t\t  if (print_errors)\n\t\t    {\n\t\t      if (argv[optind - 1][1] == '-')\n\t\t\t/* --option */\n\t\t\tfprintf (stderr,\n\t\t\t\t _(\"%s: option `--%s' doesn't allow an argument\\n\"),\n\t\t\t\t argv[0], pfound->name);\n\t\t      else\n\t\t\t/* +option or -option */\n\t\t\tfprintf (stderr,\n\t\t\t\t _(\"%s: option `%c%s' doesn't allow an argument\\n\"),\n\t\t\t\t argv[0], argv[optind - 1][0], pfound->name);\n\t\t    }\n\n\t\t  nextchar += strlen (nextchar);\n\n\t\t  optopt = pfound->val;\n\t\t  return '?';\n\t\t}\n\t    }\n\t  else if (pfound->has_arg == 1)\n\t    {\n\t      if (optind < argc)\n\t\toptarg = argv[optind++];\n\t      else\n\t\t{\n\t\t  if (print_errors)\n\t\t    fprintf (stderr,\n\t\t\t   _(\"%s: option `%s' requires an argument\\n\"),\n\t\t\t   argv[0], argv[optind - 1]);\n\t\t  nextchar += strlen (nextchar);\n\t\t  optopt = pfound->val;\n\t\t  return optstring[0] == ':' ? ':' : '?';\n\t\t}\n\t    }\n\t  nextchar += strlen (nextchar);\n\t  if (longind != NULL)\n\t    *longind = option_index;\n\t  if (pfound->flag)\n\t    {\n\t      *(pfound->flag) = pfound->val;\n\t      return 0;\n\t    }\n\t  return pfound->val;\n\t}\n\n      /* Can't find it as a long option.  If this is not getopt_long_only,\n\t or the option starts with '--' or is not a valid short\n\t option, then it's an error.\n\t Otherwise interpret it as a short option.  */\n      if (!long_only || argv[optind][1] == '-'\n\t  || my_index (optstring, *nextchar) == NULL)\n\t{\n\t  if (print_errors)\n\t    {\n\t      if (argv[optind][1] == '-')\n\t\t/* --option */\n\t\tfprintf (stderr, _(\"%s: unrecognized option `--%s'\\n\"),\n\t\t\t argv[0], nextchar);\n\t      else\n\t\t/* +option or -option */\n\t\tfprintf (stderr, _(\"%s: unrecognized option `%c%s'\\n\"),\n\t\t\t argv[0], argv[optind][0], nextchar);\n\t    }\n\t  nextchar = (char *) \"\";\n\t  optind++;\n\t  optopt = 0;\n\t  return '?';\n\t}\n    }\n\n  /* Look at and handle the next short option-character.  */\n\n  {\n    char c = *nextchar++;\n    char *temp = my_index (optstring, c);\n\n    /* Increment `optind' when we start to process its last character.  */\n    if (*nextchar == '\\0')\n      ++optind;\n\n    if (temp == NULL || c == ':')\n      {\n\tif (print_errors)\n\t  {\n\t    if (posixly_correct)\n\t      /* 1003.2 specifies the format of this message.  */\n\t      fprintf (stderr, _(\"%s: illegal option -- %c\\n\"),\n\t\t       argv[0], c);\n\t    else\n\t      fprintf (stderr, _(\"%s: invalid option -- %c\\n\"),\n\t\t       argv[0], c);\n\t  }\n\toptopt = c;\n\treturn '?';\n      }\n    /* Convenience. Treat POSIX -W foo same as long option --foo */\n    if (temp[0] == 'W' && temp[1] == ';')\n      {\n\tchar *nameend;\n\tconst struct option *p;\n\tconst struct option *pfound = NULL;\n\tint exact = 0;\n\tint ambig = 0;\n\tint indfound = 0;\n\tint option_index;\n\n\t/* This is an option that requires an argument.  */\n\tif (*nextchar != '\\0')\n\t  {\n\t    optarg = nextchar;\n\t    /* If we end this ARGV-element by taking the rest as an arg,\n\t       we must advance to the next element now.  */\n\t    optind++;\n\t  }\n\telse if (optind == argc)\n\t  {\n\t    if (print_errors)\n\t      {\n\t\t/* 1003.2 specifies the format of this message.  */\n\t\tfprintf (stderr, _(\"%s: option requires an argument -- %c\\n\"),\n\t\t\t argv[0], c);\n\t      }\n\t    optopt = c;\n\t    if (optstring[0] == ':')\n\t      c = ':';\n\t    else\n\t      c = '?';\n\t    return c;\n\t  }\n\telse\n\t  /* We already incremented `optind' once;\n\t     increment it again when taking next ARGV-elt as argument.  */\n\t  optarg = argv[optind++];\n\n\t/* optarg is now the argument, see if it's in the\n\t   table of longopts.  */\n\n\tfor (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++)\n\t  /* Do nothing.  */ ;\n\n\t/* Test all long options for either exact match\n\t   or abbreviated matches.  */\n\tfor (p = longopts, option_index = 0; p->name; p++, option_index++)\n\t  if (!strncmp (p->name, nextchar, nameend - nextchar))\n\t    {\n\t      if ((unsigned int) (nameend - nextchar) == strlen (p->name))\n\t\t{\n\t\t  /* Exact match found.  */\n\t\t  pfound = p;\n\t\t  indfound = option_index;\n\t\t  exact = 1;\n\t\t  break;\n\t\t}\n\t      else if (pfound == NULL)\n\t\t{\n\t\t  /* First nonexact match found.  */\n\t\t  pfound = p;\n\t\t  indfound = option_index;\n\t\t}\n\t      else\n\t\t/* Second or later nonexact match found.  */\n\t\tambig = 1;\n\t    }\n\tif (ambig && !exact)\n\t  {\n\t    if (print_errors)\n\t      fprintf (stderr, _(\"%s: option `-W %s' is ambiguous\\n\"),\n\t\t       argv[0], argv[optind]);\n\t    nextchar += strlen (nextchar);\n\t    optind++;\n\t    return '?';\n\t  }\n\tif (pfound != NULL)\n\t  {\n\t    option_index = indfound;\n\t    if (*nameend)\n\t      {\n\t\t/* Don't test has_arg with >, because some C compilers don't\n\t\t   allow it to be used on enums.  */\n\t\tif (pfound->has_arg)\n\t\t  optarg = nameend + 1;\n\t\telse\n\t\t  {\n\t\t    if (print_errors)\n\t\t      fprintf (stderr, _(\"\\\n\t\t\t%s: option `-W %s' doesn't allow an argument\\n\"),\n\t\t\t       argv[0], pfound->name);\n\n\t\t    nextchar += strlen (nextchar);\n\t\t    return '?';\n\t\t  }\n\t      }\n\t    else if (pfound->has_arg == 1)\n\t      {\n\t\tif (optind < argc)\n\t\t  optarg = argv[optind++];\n\t\telse\n\t\t  {\n\t\t    if (print_errors)\n\t\t      fprintf (stderr,\n\t\t\t       _(\"%s: option `%s' requires an argument\\n\"),\n\t\t\t       argv[0], argv[optind - 1]);\n\t\t    nextchar += strlen (nextchar);\n\t\t    return optstring[0] == ':' ? ':' : '?';\n\t\t  }\n\t      }\n\t    nextchar += strlen (nextchar);\n\t    if (longind != NULL)\n\t      *longind = option_index;\n\t    if (pfound->flag)\n\t      {\n\t\t*(pfound->flag) = pfound->val;\n\t\treturn 0;\n\t      }\n\t    return pfound->val;\n\t  }\n\t  nextchar = NULL;\n\t  return 'W';\t/* Let the application handle it.   */\n      }\n    if (temp[1] == ':')\n      {\n\tif (temp[2] == ':')\n\t  {\n\t    /* This is an option that accepts an argument optionally.  */\n\t    if (*nextchar != '\\0')\n\t      {\n\t\toptarg = nextchar;\n\t\toptind++;\n\t      }\n\t    else\n\t      optarg = NULL;\n\t    nextchar = NULL;\n\t  }\n\telse\n\t  {\n\t    /* This is an option that requires an argument.  */\n\t    if (*nextchar != '\\0')\n\t      {\n\t\toptarg = nextchar;\n\t\t/* If we end this ARGV-element by taking the rest as an arg,\n\t\t   we must advance to the next element now.  */\n\t\toptind++;\n\t      }\n\t    else if (optind == argc)\n\t      {\n\t\tif (print_errors)\n\t\t  {\n\t\t    /* 1003.2 specifies the format of this message.  */\n\t\t    fprintf (stderr,\n\t\t\t     _(\"%s: option requires an argument -- %c\\n\"),\n\t\t\t     argv[0], c);\n\t\t  }\n\t\toptopt = c;\n\t\tif (optstring[0] == ':')\n\t\t  c = ':';\n\t\telse\n\t\t  c = '?';\n\t      }\n\t    else\n\t      /* We already incremented `optind' once;\n\t\t increment it again when taking next ARGV-elt as argument.  */\n\t      optarg = argv[optind++];\n\t    nextchar = NULL;\n\t  }\n      }\n    return c;\n  }\n}\n\nint\ngetopt (argc, argv, optstring)\n     int argc;\n     char *const *argv;\n     const char *optstring;\n{\n  return _getopt_internal (argc, argv, optstring,\n\t\t\t   (const struct option *) 0,\n\t\t\t   (int *) 0,\n\t\t\t   0);\n}\n\n#endif\t/* Not ELIDE_CODE.  */\n\n#ifdef TEST\n\n/* Compile with -DTEST to make an executable for use in testing\n   the above definition of `getopt'.  */\n\nint\nmain (argc, argv)\n     int argc;\n     char **argv;\n{\n  int c;\n  int digit_optind = 0;\n\n  while (1)\n    {\n      int this_option_optind = optind ? optind : 1;\n\n      c = getopt (argc, argv, \"abc:d:0123456789\");\n      if (c == -1)\n\tbreak;\n\n      switch (c)\n\t{\n\tcase '0':\n\tcase '1':\n\tcase '2':\n\tcase '3':\n\tcase '4':\n\tcase '5':\n\tcase '6':\n\tcase '7':\n\tcase '8':\n\tcase '9':\n\t  if (digit_optind != 0 && digit_optind != this_option_optind)\n\t    printf (\"digits occur in two different argv-elements.\\n\");\n\t  digit_optind = this_option_optind;\n\t  printf (\"option %c\\n\", c);\n\t  break;\n\n\tcase 'a':\n\t  printf (\"option a\\n\");\n\t  break;\n\n\tcase 'b':\n\t  printf (\"option b\\n\");\n\t  break;\n\n\tcase 'c':\n\t  printf (\"option c with value `%s'\\n\", optarg);\n\t  break;\n\n\tcase '?':\n\t  break;\n\n\tdefault:\n\t  printf (\"?? getopt returned character code 0%o ??\\n\", c);\n\t}\n    }\n\n  if (optind < argc)\n    {\n      printf (\"non-option ARGV-elements: \");\n      while (optind < argc)\n\tprintf (\"%s \", argv[optind++]);\n      printf (\"\\n\");\n    }\n\n  exit (0);\n}\n\n#endif /* TEST */\n"
  },
  {
    "path": "src/getopt/getopt.h",
    "content": "/* Declarations for getopt.\n   Copyright (C) 1989-1994, 1996-1999, 2001 Free Software Foundation, Inc.\n   This file is part of the GNU C Library.\n\n   The GNU C Library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Lesser General Public\n   License as published by the Free Software Foundation; either\n   version 2.1 of the License, or (at your option) any later version.\n\n   The GNU C Library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public\n   License along with the GNU C Library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA\n   02111-1307 USA.  */\n\n#ifndef _GETOPT_H\n\n#ifndef __need_getopt\n# define _GETOPT_H 1\n#endif\n\n/* If __GNU_LIBRARY__ is not already defined, either we are being used\n   standalone, or this is the first header included in the source file.\n   If we are being used with glibc, we need to include <features.h>, but\n   that does not exist if we are standalone.  So: if __GNU_LIBRARY__ is\n   not defined, include <ctype.h>, which will pull in <features.h> for us\n   if it's from glibc.  (Why ctype.h?  It's guaranteed to exist and it\n   doesn't flood the namespace with stuff the way some other headers do.)  */\n#if !defined __GNU_LIBRARY__\n# include <ctype.h>\n#endif\n\n#ifdef\t__cplusplus\nextern \"C\" {\n#endif\n\n/* For communication from `getopt' to the caller.\n   When `getopt' finds an option that takes an argument,\n   the argument value is returned here.\n   Also, when `ordering' is RETURN_IN_ORDER,\n   each non-option ARGV-element is returned here.  */\n\nextern char *optarg;\n\n/* Index in ARGV of the next element to be scanned.\n   This is used for communication to and from the caller\n   and for communication between successive calls to `getopt'.\n\n   On entry to `getopt', zero means this is the first call; initialize.\n\n   When `getopt' returns -1, this is the index of the first of the\n   non-option elements that the caller should itself scan.\n\n   Otherwise, `optind' communicates from one call to the next\n   how much of ARGV has been scanned so far.  */\n\nextern int optind;\n\n/* Callers store zero here to inhibit the error message `getopt' prints\n   for unrecognized options.  */\n\nextern int opterr;\n\n/* Set to an option character which was unrecognized.  */\n\nextern int optopt;\n\n#ifndef __need_getopt\n/* Describe the long-named options requested by the application.\n   The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector\n   of `struct option' terminated by an element containing a name which is\n   zero.\n\n   The field `has_arg' is:\n   no_argument\t\t(or 0) if the option does not take an argument,\n   required_argument\t(or 1) if the option requires an argument,\n   optional_argument \t(or 2) if the option takes an optional argument.\n\n   If the field `flag' is not NULL, it points to a variable that is set\n   to the value given in the field `val' when the option is found, but\n   left unchanged if the option is not found.\n\n   To have a long-named option do something other than set an `int' to\n   a compiled-in constant, such as set a value from `optarg', set the\n   option's `flag' field to zero and its `val' field to a nonzero\n   value (the equivalent single-letter option character, if there is\n   one).  For long options that have a zero `flag' field, `getopt'\n   returns the contents of the `val' field.  */\n\nstruct option\n{\n# if (defined __STDC__ && __STDC__) || defined __cplusplus\n  const char *name;\n# else\n  char *name;\n# endif\n  /* has_arg can't be an enum because some compilers complain about\n     type mismatches in all the code that assumes it is an int.  */\n  int has_arg;\n  int *flag;\n  int val;\n};\n\n/* Names for the values of the `has_arg' field of `struct option'.  */\n\n# define no_argument\t\t0\n# define required_argument\t1\n# define optional_argument\t2\n#endif\t/* need getopt */\n\n\n/* Get definitions and prototypes for functions to process the\n   arguments in ARGV (ARGC of them, minus the program name) for\n   options given in OPTS.\n\n   Return the option character from OPTS just read.  Return -1 when\n   there are no more options.  For unrecognized options, or options\n   missing arguments, `optopt' is set to the option letter, and '?' is\n   returned.\n\n   The OPTS string is a list of characters which are recognized option\n   letters, optionally followed by colons, specifying that that letter\n   takes an argument, to be placed in `optarg'.\n\n   If a letter in OPTS is followed by two colons, its argument is\n   optional.  This behavior is specific to the GNU `getopt'.\n\n   The argument `--' causes premature termination of argument\n   scanning, explicitly telling `getopt' that there are no more\n   options.\n\n   If OPTS begins with `--', then non-option arguments are treated as\n   arguments to the option '\\0'.  This behavior is specific to the GNU\n   `getopt'.  */\n\n#if (defined __STDC__ && __STDC__) || defined __cplusplus\n# ifdef __GNU_LIBRARY__\n/* Many other libraries have conflicting prototypes for getopt, with\n   differences in the consts, in stdlib.h.  To avoid compilation\n   errors, only prototype getopt for the GNU C library.  */\nextern int getopt (int __argc, char *const *__argv, const char *__shortopts);\n# else /* not __GNU_LIBRARY__ */\nextern int getopt ();\n# endif /* __GNU_LIBRARY__ */\n\n# ifndef __need_getopt\nextern int getopt_long (int __argc, char *const *__argv, const char *__shortopts,\n\t\t        const struct option *__longopts, int *__longind);\nextern int getopt_long_only (int __argc, char *const *__argv,\n\t\t\t     const char *__shortopts,\n\t\t             const struct option *__longopts, int *__longind);\n\n/* Internal only.  Users should not call this directly.  */\nextern int _getopt_internal (int __argc, char *const *__argv,\n\t\t\t     const char *__shortopts,\n\t\t             const struct option *__longopts, int *__longind,\n\t\t\t     int __long_only);\n# endif\n#else /* not __STDC__ */\nextern int getopt ();\n# ifndef __need_getopt\nextern int getopt_long ();\nextern int getopt_long_only ();\n\nextern int _getopt_internal ();\n# endif\n#endif /* __STDC__ */\n\n#ifdef\t__cplusplus\n}\n#endif\n\n/* Make sure we later can get all the definitions and declarations.  */\n#undef __need_getopt\n\n#endif /* getopt.h */\n"
  },
  {
    "path": "src/librtlsdr.c",
    "content": "/*\n * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver\n * Copyright (C) 2012-2014 by Steve Markgraf <steve@steve-m.de>\n * Copyright (C) 2012 by Dimitri Stolnikov <horiz0n@gmx.net>\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef _WIN32\n#include <unistd.h>\n#include <arpa/inet.h>\n#include <sys/socket.h>\n#include <sys/types.h>\n#include <netinet/in.h>\n#define LAST_SOCK_ERROR() errno\n#define closesocket close\n#define SOCKADDR struct sockaddr\n#define SOCKET int\n#define SOCKET_ERROR -1\n#define INVALID_SOCKET -1\n#else\n#include <winsock2.h>\n#define LAST_SOCK_ERROR() WSAGetLastError()\n#define usleep(x) Sleep(x/1000)\ntypedef int socklen_t;\n\n#pragma comment(lib, \"ws2_32.lib\")\n#endif\n\n#include <errno.h>\n#include <signal.h>\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <ctype.h>\n\n#ifndef _WIN32\n#define min(a, b) (((a) < (b)) ? (a) : (b))\n#endif\n\n#include <libusb.h>\n#ifndef WIN32\n#include \"rtlsdr_rpc.h\"\n#endif\n\n#include <pthread.h>\n\n/* cond dumbness */\n#define safe_cond_signal(n, m) pthread_mutex_lock(m); pthread_cond_signal(n); pthread_mutex_unlock(m)\n#define safe_cond_wait(n, m) pthread_mutex_lock(m); pthread_cond_wait(n, m); pthread_mutex_unlock(m)\n\n\n/*\n * All libusb callback functions should be marked with the LIBUSB_CALL macro\n * to ensure that they are compiled with the same calling convention as libusb.\n *\n * If the macro isn't available in older libusb versions, we simply define it.\n */\n#ifndef LIBUSB_CALL\n#define LIBUSB_CALL\n#endif\n\n/* libusb < 1.0.9 doesn't have libusb_handle_events_timeout_completed */\n#ifndef HAVE_LIBUSB_HANDLE_EVENTS_TIMEOUT_COMPLETED\n#define libusb_handle_events_timeout_completed(ctx, tv, c) \\\n\tlibusb_handle_events_timeout(ctx, tv)\n#endif\n\n/* two raised to the power of n */\n#define TWO_POW(n)\t\t((double)(1ULL<<(n)))\n\n#include <rtl-sdr.h>\n#include <rtl_app_ver.h>\n#include \"tuner_e4k.h\"\n#include \"tuner_fc0012.h\"\n#include \"tuner_fc0013.h\"\n#include \"tuner_fc2580.h\"\n#include \"tuner_r82xx.h\"\n\n#include <errno.h>\n#include <string.h>\n#include <sys/types.h>\n#ifndef _WIN32\n\t#include <sys/socket.h>\n\t#include <sys/un.h>\n#endif\n#include <signal.h>\n\n#define LOG_API_CALLS\t\t\t0\n#define LOG_API_SET_FREQ\t\t0\n#define PRINT_UDP_SRV_MSGS\t\t0\n\n#define INIT_R820T_TUNER_GAIN\t0\n#define ENBALE_R820T_HARM_OPT\t1\n#define ENABLE_VCO_OPTIONS\t\t1\n\n\n/* activate/use RTL's IF AGC control .. from  https://github.com/old-dab/rtlsdr\n * purpose: make AGC more smooth .. and NOT freeze\n * most of it is in switch case on tuner_type in rtlsdr_open() */\n#define USE_OLD_DAB_IF_GAIN\t\t1\n\n\ntypedef struct rtlsdr_tuner_iface {\n\t/* tuner interface */\n\tint (*init)(void *);\n\tint (*exit)(void *);\n\tint (*set_freq)(void *, uint32_t freq /* Hz */);\n\tint (*set_freq64)(void *, uint64_t freq /* Hz */);\n\tint (*set_bw)(void *, int bw /* Hz */, uint32_t *applied_bw /* configured bw in Hz */, int apply /* 1 == configure it!, 0 == deliver applied_bw */);\n\tint (*set_bw_center)(void *, int32_t if_band_center_freq);\n\tint (*set_gain)(void *, int gain /* tenth dB */);\n\tint (*set_if_gain)(void *, int stage, int gain /* tenth dB */);\n\tint (*set_gain_mode)(void *, int manual);\n\tint (*set_i2c_register)(void *, unsigned i2c_register, unsigned data /* byte */, unsigned mask /* byte */ );\n\tint (*set_i2c_override)(void *, unsigned i2c_register, unsigned data /* byte */, unsigned mask /* byte */ );\n\tunsigned (*get_i2c_register)(void *, int i2c_register);  /* read single register */\n\tint (*get_i2c_reg_array)(void *, unsigned char* data, int len);  /* -cs- */\n\tint (*set_sideband)(void *, int sideband);\n} rtlsdr_tuner_iface_t;\n\nenum rtlsdr_async_status {\n\tRTLSDR_INACTIVE = 0,\n\tRTLSDR_CANCELING,\n\tRTLSDR_RUNNING\n};\n\n#define FIR_LEN 16\n\n/*\n * FIR coefficients.\n *\n * The filter is running at XTal frequency. It is symmetric filter with 32\n * coefficients. Only first 16 coefficients are specified, the other 16\n * use the same values but in reversed order. The first coefficient in\n * the array is the outer one, the last, the last is the inner one.\n * First 8 coefficients are 8 bit signed integers, the next 8 coefficients\n * are 12 bit signed integers. All coefficients have the same weight.\n *\n * Default FIR coefficients used for DAB/FM by the Windows driver,\n * the DVB driver uses different ones\n */\nstatic const int fir_default[FIR_LEN] = {\n\t-54, -36, -41, -40, -32, -14, 14, 53,\t/* 8 bit signed */\n\t101, 156, 215, 273, 327, 372, 404, 421\t/* 12 bit signed */\n};\n\n\nenum softagc_mode {\n\tSOFTAGC_OFF = 0,\t/* off */\n\tSOFTAGC_ON_CHANGE,\t/* activate on initial start and on relevant changes .. and deactivate afterwards */\n\tSOFTAGC_AUTO_ATTEN,\t/* operate full time - but do only attenuate after initial control (ON_CHANGE) */\n\tSOFTAGC_AUTO\t\t/* operate full time - attenuate and gain */\n};\n\nenum softagc_stateT {\n\tSOFTSTATE_OFF = 0,\n\tSOFTSTATE_ON,\n\tSOFTSTATE_RESET_CONT,\n\tSOFTSTATE_RESET,\n\tSOFTSTATE_INIT\n};\n\nstruct softagc_state {\n\tpthread_t\t\tcommand_thread;\n\tpthread_mutex_t\tmutex;\n\tpthread_cond_t\tcond;\n\tvolatile int\texit_command_thread;\n\tvolatile int\tcommand_newGain;\n\tvolatile int\tcommand_changeGain;\n\n\tenum softagc_stateT\tagcState;\t/* active: don't forward samples while active for initial measurement */\n\tenum softagc_mode\tsoftAgcMode;\n\tint verbose;\n\n\tfloat\tscanTimeMs;         /* scan duration per gain level - to look for maximum */\n\tfloat\tdeadTimeMs;         /* dead time in ms - after changing tuner gain */\n\tint\t\tscanTimeSps;        /* scan duration in samples */\n\tint\t\tdeadTimeSps;        /* dead time in samples */\n\tvolatile int\tremainingDeadSps;   /* dead time in samples */\n\tint\t\tremainingScanSps;   /* scan duration in samples */\n\tint\t\tnumInHisto;         /* number of values in histogram */\n\tint\t\thisto[16];          /* count histogram over high 4 bits */\n\n\tint\t\tgainIdx;            /* currently tested gain idx */\n\tint\t\tsoftAgcBiasT;\n\n\tint\t\trpcNumGains;\t\t/* local copy for RPC speedup */\n\tint *\trpcGainValues;\n};\n\nstruct rtlsdr_dev {\n\tlibusb_context *ctx;\n\tstruct libusb_device_handle *devh;\n\tuint32_t xfer_buf_num;\n\tuint32_t xfer_buf_len;\n\tstruct libusb_transfer **xfer;\n\tunsigned char **xfer_buf;\n\trtlsdr_read_async_cb_t cb;\n\tvoid *cb_ctx;\n\tvolatile enum rtlsdr_async_status async_status;\n\tint async_cancel;\n\tint use_zerocopy;\n\t/* rtl demod context */\n\tuint32_t rate; /* Hz */\n\tuint32_t rtl_xtal; /* Hz */\n\tint fir[FIR_LEN];\n\tint direct_sampling;\n\tint rtl_vga_control;\n\t/* tuner context */\n\tenum rtlsdr_tuner tuner_type;\n\trtlsdr_tuner_iface_t *tuner;\n\tuint32_t tun_xtal; /* Hz */\n\tuint64_t freq; /* Hz */\n\tuint32_t bw;\n\tuint32_t offs_freq; /* Hz */\n\tint32_t  if_band_center_freq; /* Hz - rtlsdr_set_tuner_band_center() */\n\tint      tuner_if_freq;\n\tint      tuner_sideband;\n\tint      rtl_spectrum_sideband;  /* buffered last sideband. 1: LSB; 2: USB */\n\tint corr; /* ppm */\n\t/* int gain; * tenth dB */\n\tenum rtlsdr_ds_mode direct_sampling_mode;\n\tuint32_t direct_sampling_threshold; /* Hz */\n\tstruct e4k_state e4k_s;\n\tstruct r82xx_config r82xx_c;\n\tstruct r82xx_priv r82xx_p;\n\t/* soft tuner agc */\n\tstruct softagc_state softagc;\n\n\t/* -cs- Concurrent lock for the periodic reading of I2C registers */\n\tpthread_mutex_t cs_mutex;\n\tpthread_mutexattr_t cs_mutex_attr;\n\n\t/* UDP controller server */\n#ifdef WITH_UDP_SERVER\n#define UDP_TX_BUFLEN   1024\n\tunsigned udpPortNo;\t\t/* default: 32323 */\n\tint      override_if_freq;\n\tint      override_if_flag;\n\tint      last_if_freq;\n\tpthread_t srv_thread;\n\tSOCKET   udpS;\n\tstruct sockaddr_in server;\n\tstruct sockaddr_in si_other;\n\tint      srv_started;\n\tchar     buf[UDP_TX_BUFLEN];\n#ifdef _WIN32\n\tWSADATA  wsa;\n\tint      recv_len;\n\tint      slen;\n#else\n\tssize_t  recv_len;\n\tsocklen_t slen;\n#endif\n#endif\n\n\tint biast_gpio_pin_no;\n\tuint32_t gpio_state_known; /* bitmask over pins 0 .. 7 */\n\tuint32_t gpio_state; /* bitmask over pins 0 .. 7: = 0 == write, 1 == read */\n\n\tint called_set_opt;\n\n\t/* status */\n\tint dev_lost;\n\tint driver_active;\n\tunsigned int xfer_errors;\n\tint i2c_repeater_on;\n\tint rc_active;\n\tint verbose;\n\tint dev_num;\n\tchar manufact[256];\n\tchar product[256];\n};\n\nstatic int rtlsdr_demod_write_reg(rtlsdr_dev_t *dev, uint8_t page, uint16_t addr, uint16_t val, uint8_t len);\nstatic int rtlsdr_set_if_freq(rtlsdr_dev_t *dev, uint32_t freq);\nstatic int rtlsdr_update_ds(rtlsdr_dev_t *dev, uint64_t freq);\nstatic int rtlsdr_set_spectrum_inversion(rtlsdr_dev_t *dev, int sideband);\n\nstatic void softagc_init(rtlsdr_dev_t *dev);\nstatic void softagc_uninit(rtlsdr_dev_t *dev);\nstatic int reactivate_softagc(rtlsdr_dev_t *dev, enum softagc_stateT newState);\n\n/* generic tuner interface functions, shall be moved to the tuner implementations */\nint e4000_init(void *dev) {\n\trtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;\n\tdevt->e4k_s.i2c_addr = E4K_I2C_ADDR;\n\trtlsdr_get_xtal_freq(devt, NULL, &devt->e4k_s.vco.fosc);\n\tdevt->e4k_s.rtl_dev = dev;\n\treturn e4k_init(&devt->e4k_s);\n}\nint e4000_exit(void *dev) {\n\trtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;\n\treturn e4k_standby(&devt->e4k_s, 1);\n}\nint e4000_set_freq(void *dev, uint32_t freq) {\n\trtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;\n\treturn e4k_tune_freq(&devt->e4k_s, freq);\n}\n\nint e4000_set_bw(void *dev, int bw, uint32_t *applied_bw, int apply) {\n\tint r = 0;\n\trtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;\n\tif(!apply)\n\t\treturn 0;\n\n\tr |= e4k_if_filter_bw_set(&devt->e4k_s, E4K_IF_FILTER_MIX, bw);\n\tr |= e4k_if_filter_bw_set(&devt->e4k_s, E4K_IF_FILTER_RC, bw);\n\tr |= e4k_if_filter_bw_set(&devt->e4k_s, E4K_IF_FILTER_CHAN, bw);\n\n\treturn r;\n}\n\nint e4000_set_gain(void *dev, int gain) {\n\trtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;\n\tint mixgain = (gain > 340) ? 12 : 4;\n#if 0\n\tint enhgain = (gain - 420);\n#endif\n\tif(e4k_set_lna_gain(&devt->e4k_s, min(300, gain - mixgain * 10)) == -EINVAL)\n\t\treturn -1;\n\tif(e4k_mixer_gain_set(&devt->e4k_s, mixgain) == -EINVAL)\n\t\treturn -1;\n#if 0 /* enhanced mixer gain seems to have no effect */\n\tif(enhgain >= 0)\n\t\tif(e4k_set_enh_gain(&devt->e4k_s, enhgain) == -EINVAL)\n\t\t\treturn -1;\n#endif\n\treturn 0;\n}\nint e4000_set_if_gain(void *dev, int stage, int gain) {\n\trtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;\n\treturn e4k_if_gain_set(&devt->e4k_s, (uint8_t)stage, (int8_t)(gain / 10));\n}\nint e4000_set_gain_mode(void *dev, int manual) {\n\trtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;\n\treturn e4k_enable_manual_gain(&devt->e4k_s, manual);\n}\n\nint fc0012_exit(void *dev) { return 0; }\nint fc0012_set_freq(void *dev, uint32_t freq) {\n\t/* select V-band/U-band filter */\n\trtlsdr_set_gpio_bit(dev, 6, (freq > 300000000) ? 1 : 0);\n\treturn fc0012_set_params(dev, freq, 6000000);\n}\nint fc0012_set_bw(void *dev, int bw, uint32_t *applied_bw, int apply) { return 0; }\nint fc0012_set_gain_mode(void *dev, int manual) { return 0; }\nint _fc0012_set_i2c_register(void *dev, unsigned i2c_register, unsigned data, unsigned mask ) {\n\treturn fc0012_set_i2c_register(dev, i2c_register, data);\n}\n\nint _fc0013_init(void *dev) { return fc0013_init(dev); }\nint fc0013_exit(void *dev) { return 0; }\nint fc0013_set_freq(void *dev, uint32_t freq) {\n\treturn fc0013_set_params(dev, freq, 6000000);\n}\nint fc0013_set_bw(void *dev, int bw, uint32_t *applied_bw, int apply) { return 0; }\nint _fc0013_set_gain(void *dev, int gain) { return fc0013_set_lna_gain(dev, gain); }\n\nint fc2580_init(void *dev) { return fc2580_Initialize(dev); }\nint fc2580_exit(void *dev) { return 0; }\nint _fc2580_set_freq(void *dev, uint32_t freq) {\n\treturn fc2580_SetRfFreqHz(dev, freq);\n}\nint fc2580_set_bw(void *dev, int bw, uint32_t *applied_bw, int apply) {\n\tif(!apply)\n\t\treturn 0;\n\treturn fc2580_SetBandwidthMode(dev, 1);\n}\nint fc2580_set_gain(void *dev, int gain) { return 0; }\nint fc2580_set_gain_mode(void *dev, int manual) { return 0; }\n\nint r820t_init(void *dev) {\n\trtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;\n\tdevt->r82xx_p.rtl_dev = dev;\n\n\tif (devt->tuner_type == RTLSDR_TUNER_R828D) {\n\t\tdevt->r82xx_c.i2c_addr = R828D_I2C_ADDR;\n\t\tdevt->r82xx_c.rafael_chip = CHIP_R828D;\n\t} else {\n\t\tdevt->r82xx_c.i2c_addr = R820T_I2C_ADDR;\n\t\tdevt->r82xx_c.rafael_chip = CHIP_R820T;\n\t}\n\n\trtlsdr_get_xtal_freq(devt, NULL, &devt->r82xx_c.xtal);\n\n\tdevt->r82xx_c.max_i2c_msg_len = 8;\n\tdevt->r82xx_c.use_predetect = 0;\n\tdevt->r82xx_p.cfg = &devt->r82xx_c;\n\n\treturn r82xx_init(&devt->r82xx_p);\n}\nint r820t_exit(void *dev) {\n\trtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;\n\treturn r82xx_standby(&devt->r82xx_p);\n}\n\nint r820t_set_freq64(void *dev, uint64_t freq) {\n\tint r, ri, flip, sideband;\n\trtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;\n\tr = r82xx_set_freq64(&devt->r82xx_p, freq);\n\n\tsideband = r82xx_get_sideband(&devt->r82xx_p);\n\tflip = r82xx_flip_rtl_sideband(&devt->r82xx_p);\n\tri = rtlsdr_set_spectrum_inversion(devt, sideband ^ flip);\n\tif (ri) {\n\t\tif ( devt->verbose )\n\t\t\tfprintf(stderr, \"r820t_set_freq(%f MHz): rtlsdr_set_spectrum_inversion() returned %d\\n\", freq * 1E-6, r);\n\t\treturn ri;\n\t}\n\n\treturn r;\n}\n\nint r820t_set_freq(void *dev, uint32_t freq) {\n\treturn r820t_set_freq64(dev, (uint64_t)freq);\n}\n\n\nint r820t_set_bw(void *dev, int bw, uint32_t *applied_bw, int apply) {\n\tint r, iffreq;\n\trtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;\n\n\tiffreq = r82xx_set_bandwidth(&devt->r82xx_p, bw, devt->rate, applied_bw, apply);\n\tif(!apply)\n\t\treturn 0;\n\tif(iffreq < 0) {\n\t\tr = iffreq;\n\t\tif ( devt->verbose )\n\t\t\tfprintf(stderr, \"r820t_set_bw(%d): r82xx_set_bandwidth() returned error %d\\n\", bw, r);\n\t\treturn r;\n\t}\n\tdevt->tuner_if_freq = iffreq;\n\n\tiffreq = (devt->tuner_sideband)\t/* -1 for USB; +1 for LSB */\n\t\t? ( devt->tuner_if_freq - devt->if_band_center_freq )\n\t\t: ( devt->tuner_if_freq + devt->if_band_center_freq );\n\tr = rtlsdr_set_if_freq(devt, iffreq );\n\tif (r)\n\t{\n\t\tif ( devt->verbose )\n\t\t\tfprintf(stderr, \"r820t_set_bw(%d): rtlsdr_set_if_freq(%d) returned error %d\\n\", bw, iffreq, r);\n\t\treturn r;\n\t}\n\n\tr = rtlsdr_set_center_freq64(devt, devt->freq);\n\tif ( r && devt->verbose )\n\t\tfprintf(stderr, \"r820t_set_bw(%d): rtlsdr_set_center_freq(%f MHz) returned error %d\\n\", bw, devt->freq * 1E-6, r);\n\treturn r;\n}\n\nint r820t_set_bw_center(void *dev, int32_t if_band_center_freq) {\n\tint r, iffreq;\n\trtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;\n\n\tiffreq = r82xx_set_bw_center(&devt->r82xx_p, if_band_center_freq);\n\tif(iffreq < 0) {\n\t\tr = iffreq;\n\t\tif ( devt->verbose )\n\t\t\tfprintf(stderr, \"r820t_set_bw_center(%d): r82xx_set_bw_center() returned error %d\\n\", if_band_center_freq, r);\n\t\treturn r;\n\t}\n\tdevt->tuner_if_freq = iffreq;\n\tdevt->if_band_center_freq = if_band_center_freq;\n\n\tiffreq = (devt->tuner_sideband)\t/* -1 for USB; +1 for LSB */\n\t\t? ( devt->tuner_if_freq - devt->if_band_center_freq )\n\t\t: ( devt->tuner_if_freq + devt->if_band_center_freq );\n\tr = rtlsdr_set_if_freq(devt, iffreq );\n\tif (r)\n\t{\n\t\tif ( devt->verbose )\n\t\t\tfprintf(stderr, \"r820t_set_bw_center(%d): rtlsdr_set_if_freq(%d) returned error %d\\n\", if_band_center_freq, iffreq, r);\n\t\treturn r;\n\t}\n\n\tr = rtlsdr_set_center_freq64(devt, devt->freq);\n\tif ( r && devt->verbose )\n\t\tfprintf(stderr, \"r820t_set_bw_center(%d): rtlsdr_set_center_freq(%f MHz) returned error %d\\n\", if_band_center_freq, devt->freq * 1E-6, r);\n\treturn r;\n}\n\nint rtlsdr_vga_control( rtlsdr_dev_t* devt, int rc, int rtl_vga_control ) {\n\tif (rc < 0)\n\t\treturn rc;\n\tif ( rtl_vga_control != devt->rtl_vga_control ) {\n\t\t/* enable/disable RF AGC loop */\n\n#if USE_OLD_DAB_IF_GAIN == 0\n\t\trc = rtlsdr_demod_write_reg(devt, 1, 0x04, rtl_vga_control ? 0x80 : 0x00, 1);\n\t\tif ( devt->verbose )\n\t\t\tfprintf(stderr, \"rtlsdr_vga_control(%s) returned %d\\n\"\n\t\t\t\t, rtl_vga_control ? \"activate\" : \"deactivate\", rc );\n#endif\n\t\tdevt->rtl_vga_control = rtl_vga_control;\n\t}\n\treturn rc;\n}\n\nint r820t_set_gain(void *dev, int gain) {\n\tint rc, rtl_vga_control = 0;\n\trtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;\n\trc = r82xx_set_gain(&devt->r82xx_p, 1, gain, 0, 0, 0, 0, &rtl_vga_control);\n\trc = rtlsdr_vga_control(devt, rc, rtl_vga_control);\n\treturn rc;\n}\n\nint r820t_set_gain_ext(void *dev, int lna_gain, int mixer_gain, int vga_gain) {\n\tint rc, rtl_vga_control = 0;\n\trtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;\n\trc = r82xx_set_gain(&devt->r82xx_p, 0, 0, 1, lna_gain, mixer_gain, vga_gain, &rtl_vga_control);\n\trc = rtlsdr_vga_control(devt, rc, rtl_vga_control);\n\treturn rc;\n}\n\nint r820t_set_if_mode(void *dev, int if_mode) {\n\tint rc, rtl_vga_control = 0;\n\trtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;\n\trc = r82xx_set_if_mode(&devt->r82xx_p, if_mode, &rtl_vga_control);\n\trc = rtlsdr_vga_control(devt, rc, rtl_vga_control);\n\treturn rc;\n}\n\nint r820t_set_gain_mode(void *dev, int manual) {\n\tint rc, rtl_vga_control = 0;\n\trtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;\n\trc = r82xx_set_gain(&devt->r82xx_p, manual, 0, 0, 0, 0, 0, &rtl_vga_control);\n\trc = rtlsdr_vga_control(devt, rc, rtl_vga_control);\n\treturn rc;\n}\n\n\nunsigned r820t_get_i2c_register(void *dev, int reg) {\n\trtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;\n\treturn r82xx_read_cache_reg(&devt->r82xx_p,reg);\n}\nint r820t_set_i2c_register(void *dev, unsigned i2c_register, unsigned data, unsigned mask ) {\n\trtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;\n\treturn r82xx_set_i2c_register(&devt->r82xx_p, i2c_register, data, mask);\n}\n\n\n/* -cs- */\nint r820t_get_i2c_reg_array(void *dev, unsigned char* data, int len) {\n\trtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;\n\treturn r82xx_get_i2c_register(&devt->r82xx_p, data, len);\n}\n\nint r820t_set_sideband(void *dev, int sideband) {\n\tint r, flip;\n\trtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;\n\n\tif ( devt->verbose )\n\t\tfprintf(stderr, \"r820t_set_sideband(%d): r82xx_set_sideband() ..\\n\", sideband);\n\tr = r82xx_set_sideband(&devt->r82xx_p, sideband);\n\tif(r < 0) {\n\t\tif ( devt->verbose )\n\t\t\tfprintf(stderr, \"r820t_set_sideband(%d): r82xx_set_sideband() returned %d\\n\", sideband, r);\n\t\treturn r;\n\t}\n\n\tflip = r82xx_flip_rtl_sideband(&devt->r82xx_p);\n\n\tif ( devt->verbose )\n\t\tfprintf(stderr, \"r820t_set_sideband(%d): rtlsdr_set_spectrum_inversion() ^ %d from tuner ..\\n\", sideband, flip);\n\tr = rtlsdr_set_spectrum_inversion(devt, sideband ^ flip);\n\tif (r) {\n\t\tif ( devt->verbose )\n\t\t\tfprintf(stderr, \"r820t_set_sideband(%d): rtlsdr_set_spectrum_inversion() returned %d\\n\", sideband, r);\n\t\treturn r;\n\t}\n\n\tif (!devt->freq)\n\t\treturn r;\n\n\tif ( devt->verbose )\n\t\tfprintf(stderr, \"r820t_set_sideband(%d): rtlsdr_set_center_freq(%f MHz) ..\\n\", sideband, devt->freq * 1E-6);\n\tr = rtlsdr_set_center_freq64(devt, devt->freq);\n\tif (r) {\n\t\tif ( devt->verbose )\n\t\t\tfprintf(stderr, \"r820t_set_sideband(%d): rtlsdr_set_center_freq(%f MHz) returned %d\\n\", sideband, devt->freq * 1E-6, r);\n\t}\n\treturn r;\n}\n\nint r820t_set_i2c_override(void *dev, unsigned i2c_register, unsigned data, unsigned mask ) {\n\trtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;\n\treturn r82xx_set_i2c_override(&devt->r82xx_p, i2c_register, data, mask);\n}\n\n\n/* definition order must match enum rtlsdr_tuner */\nstatic rtlsdr_tuner_iface_t tuners[] = {\n\t{\n\t\tNULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL /* dummy for unknown tuners */\n\t},\n\t{\n\t\te4000_init, e4000_exit,\n\t\te4000_set_freq, NULL, e4000_set_bw, NULL, e4000_set_gain, e4000_set_if_gain,\n\t\te4000_set_gain_mode, NULL, NULL, NULL, NULL, NULL\n\t},\n\n\t{\n\t\tfc0012_init, fc0012_exit,\n\t\tfc0012_set_freq, NULL, fc0012_set_bw, NULL, fc0012_set_gain, NULL,\n\t\tfc0012_set_gain_mode, _fc0012_set_i2c_register, NULL, NULL, fc0012_get_i2c_register, NULL\n\t},\n\t{\n\t\t_fc0013_init, fc0013_exit,\n\t\tfc0013_set_freq, NULL, fc0013_set_bw, NULL, _fc0013_set_gain, NULL,\n\t\tfc0013_set_gain_mode, NULL, NULL, NULL, NULL, NULL\n\t},\n\t{\n\t\tfc2580_init, fc2580_exit,\n\t\t_fc2580_set_freq, NULL, fc2580_set_bw, NULL, fc2580_set_gain, NULL,\n\t\tfc2580_set_gain_mode, NULL, NULL, NULL, NULL, NULL\n\t},\n\t{\n\t\tr820t_init, r820t_exit,\n\t\tr820t_set_freq, r820t_set_freq64, r820t_set_bw, r820t_set_bw_center, r820t_set_gain, NULL,\n\t\tr820t_set_gain_mode, r820t_set_i2c_register, r820t_set_i2c_override, r820t_get_i2c_register, r820t_get_i2c_reg_array,\n\t\tr820t_set_sideband\n\t},\n\t{\n\t\tr820t_init, r820t_exit,\n\t\tr820t_set_freq, r820t_set_freq64, r820t_set_bw, r820t_set_bw_center, r820t_set_gain, NULL,\n\t\tr820t_set_gain_mode, r820t_set_i2c_register, r820t_set_i2c_override, r820t_get_i2c_register, r820t_get_i2c_reg_array,\n\t\tr820t_set_sideband\n\t},\n};\n\n\ntypedef struct rtlsdr_dongle {\n\tuint16_t vid;\n\tuint16_t pid;\n\tconst char *name;\n} rtlsdr_dongle_t;\n\n/*\n * Please add your device here and send a patch to osmocom-sdr@lists.osmocom.org\n */\nstatic rtlsdr_dongle_t known_devices[] = {\n\t{ 0x0bda, 0x2832, \"Generic RTL2832U\" },\n\t{ 0x0bda, 0x2838, \"Generic RTL2832U OEM\" },\n\t{ 0x0413, 0x6680, \"DigitalNow Quad DVB-T PCI-E card\" },\n\t{ 0x0413, 0x6f0f, \"Leadtek WinFast DTV Dongle mini D\" },\n\t{ 0x0458, 0x707f, \"Genius TVGo DVB-T03 USB dongle (Ver. B)\" },\n\t{ 0x0ccd, 0x00a9, \"Terratec Cinergy T Stick Black (rev 1)\" },\n\t{ 0x0ccd, 0x00b3, \"Terratec NOXON DAB/DAB+ USB dongle (rev 1)\" },\n\t{ 0x0ccd, 0x00b4, \"Terratec Deutschlandradio DAB Stick\" },\n\t{ 0x0ccd, 0x00b5, \"Terratec NOXON DAB Stick - Radio Energy\" },\n\t{ 0x0ccd, 0x00b7, \"Terratec Media Broadcast DAB Stick\" },\n\t{ 0x0ccd, 0x00b8, \"Terratec BR DAB Stick\" },\n\t{ 0x0ccd, 0x00b9, \"Terratec WDR DAB Stick\" },\n\t{ 0x0ccd, 0x00c0, \"Terratec MuellerVerlag DAB Stick\" },\n\t{ 0x0ccd, 0x00c6, \"Terratec Fraunhofer DAB Stick\" },\n\t{ 0x0ccd, 0x00d3, \"Terratec Cinergy T Stick RC (Rev.3)\" },\n\t{ 0x0ccd, 0x00d7, \"Terratec T Stick PLUS\" },\n\t{ 0x0ccd, 0x00e0, \"Terratec NOXON DAB/DAB+ USB dongle (rev 2)\" },\n\t{ 0x1209, 0x2832, \"Generic RTL2832U\" },\n\t{ 0x1554, 0x5020, \"PixelView PV-DT235U(RN)\" },\n\t{ 0x15f4, 0x0131, \"Astrometa DVB-T/DVB-T2\" },\n\t{ 0x15f4, 0x0133, \"HanfTek DAB+FM+DVB-T\" },\n\t{ 0x185b, 0x0620, \"Compro Videomate U620F\"},\n\t{ 0x185b, 0x0650, \"Compro Videomate U650F\"},\n\t{ 0x185b, 0x0680, \"Compro Videomate U680F\"},\n\t{ 0x1b80, 0xd393, \"GIGABYTE GT-U7300\" },\n\t{ 0x1b80, 0xd394, \"DIKOM USB-DVBT HD\" },\n\t{ 0x1b80, 0xd395, \"Peak 102569AGPK\" },\n\t{ 0x1b80, 0xd397, \"KWorld KW-UB450-T USB DVB-T Pico TV\" },\n\t{ 0x1b80, 0xd398, \"Zaapa ZT-MINDVBZP\" },\n\t{ 0x1b80, 0xd39d, \"SVEON STV20 DVB-T USB & FM\" },\n\t{ 0x1b80, 0xd3a4, \"Twintech UT-40\" },\n\t{ 0x1b80, 0xd3a8, \"ASUS U3100MINI_PLUS_V2\" },\n\t{ 0x1b80, 0xd3af, \"SVEON STV27 DVB-T USB & FM\" },\n\t{ 0x1b80, 0xd3b0, \"SVEON STV21 DVB-T USB & FM\" },\n\t{ 0x1d19, 0x1101, \"Dexatek DK DVB-T Dongle (Logilink VG0002A)\" },\n\t{ 0x1d19, 0x1102, \"Dexatek DK DVB-T Dongle (MSI DigiVox mini II V3.0)\" },\n\t{ 0x1d19, 0x1103, \"Dexatek Technology Ltd. DK 5217 DVB-T Dongle\" },\n\t{ 0x1d19, 0x1104, \"MSI DigiVox Micro HD\" },\n\t{ 0x1f4d, 0xa803, \"Sweex DVB-T USB\" },\n\t{ 0x1f4d, 0xb803, \"GTek T803\" },\n\t{ 0x1f4d, 0xc803, \"Lifeview LV5TDeluxe\" },\n\t{ 0x1f4d, 0xd286, \"MyGica TD312\" },\n\t{ 0x1f4d, 0xd803, \"PROlectrix DV107669\" },\n};\n\n#define DEFAULT_BUF_NUMBER\t15\n#define DEFAULT_BUF_LENGTH\t(16 * 32 * 512)\n/* buf_len:\n * must be multiple of 512 - else it will be overwritten\n * in rtlsdr_read_async() in librtlsdr.c with DEFAULT_BUF_LENGTH (= 16*32 *512 = 512 *512)\n *\n * -> 512*512 -> 1048 ms @ 250 kS  or  81.92 ms @ 3.2 MS (internal default)\n * ->  32*512 ->   65 ms @ 250 kS  or   5.12 ms @ 3.2 MS (new default)\n */\n\n\n#define DEF_RTL_XTAL_FREQ\t28800000\n#define MIN_RTL_XTAL_FREQ\t(DEF_RTL_XTAL_FREQ - 1000)\n#define MAX_RTL_XTAL_FREQ\t(DEF_RTL_XTAL_FREQ + 1000)\n\n#define CTRL_IN\t\t\t(LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN)\n#define CTRL_OUT\t\t(LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT)\n#define CTRL_TIMEOUT\t300\n#define BULK_TIMEOUT\t10000\n\n#define EEPROM_ADDR\t0xa0\n\nenum usb_reg {\n\tUSB_SYSCTL\t\t\t= 0x2000,\n\tUSB_CTRL\t\t\t= 0x2010,\n\tUSB_STAT\t\t\t= 0x2014,\n\tUSB_EPA_CFG\t\t\t= 0x2144,\n\tUSB_EPA_CTL\t\t\t= 0x2148,\n\tUSB_EPA_MAXPKT\t\t= 0x2158,\n\tUSB_EPA_MAXPKT_2\t= 0x215a,\n\tUSB_EPA_FIFO_CFG\t= 0x2160,\n};\n\nenum sys_reg {\n\tDEMOD_CTL\t\t= 0x3000,\n\tGPO\t\t\t\t= 0x3001,\n\tGPI\t\t\t\t= 0x3002,\n\tGPOE\t\t\t= 0x3003,\n\tGPD\t\t\t\t= 0x3004,\n\tSYSINTE\t\t\t= 0x3005,\n\tSYSINTS\t\t\t= 0x3006,\n\tGP_CFG0\t\t\t= 0x3007,\n\tGP_CFG1\t\t\t= 0x3008,\n\tSYSINTE_1\t\t= 0x3009,\n\tSYSINTS_1\t\t= 0x300a,\n\tDEMOD_CTL_1\t\t= 0x300b,\n\tIR_SUSPEND\t\t= 0x300c,\n\n\t/* IrDA registers */\n\tSYS_IRRC_PSR\t\t= 0x3020, /* IR protocol selection */\n\tSYS_IRRC_PER\t\t= 0x3024, /* IR protocol extension */\n\tSYS_IRRC_SF\t\t= 0x3028, /* IR sampling frequency */\n\tSYS_IRRC_DPIR\t\t= 0x302C, /* IR data package interval */\n\tSYS_IRRC_CR\t\t= 0x3030, /* IR control */\n\tSYS_IRRC_RP\t\t= 0x3034, /* IR read port */\n\tSYS_IRRC_SR\t\t= 0x3038, /* IR status */\n\t/* I2C master registers */\n\tSYS_I2CCR\t\t= 0x3040, /* I2C clock */\n\tSYS_I2CMCR\t\t= 0x3044, /* I2C master control */\n\tSYS_I2CMSTR\t\t= 0x3048, /* I2C master SCL timing */\n\tSYS_I2CMSR\t\t= 0x304C, /* I2C master status */\n\tSYS_I2CMFR\t\t= 0x3050, /* I2C master FIFO */\n\n\t/*\n\t * IR registers\n\t */\n\tIR_RX_BUF\t\t= 0xFC00,\n\tIR_RX_IE\t\t= 0xFD00,\n\tIR_RX_IF\t\t= 0xFD01,\n\tIR_RX_CTRL\t\t= 0xFD02,\n\tIR_RX_CFG\t\t= 0xFD03,\n\tIR_MAX_DURATION0\t= 0xFD04,\n\tIR_MAX_DURATION1\t= 0xFD05,\n\tIR_IDLE_LEN0\t\t= 0xFD06,\n\tIR_IDLE_LEN1\t\t= 0xFD07,\n\tIR_GLITCH_LEN\t\t= 0xFD08,\n\tIR_RX_BUF_CTRL\t\t= 0xFD09,\n\tIR_RX_BUF_DATA\t\t= 0xFD0A,\n\tIR_RX_BC\t\t= 0xFD0B,\n\tIR_RX_CLK\t\t= 0xFD0C,\n\tIR_RX_C_COUNT_L\t\t= 0xFD0D,\n\tIR_RX_C_COUNT_H\t\t= 0xFD0E,\n\tIR_SUSPEND_CTRL\t\t= 0xFD10,\n\tIR_ERR_TOL_CTRL\t\t= 0xFD11,\n\tIR_UNIT_LEN\t\t= 0xFD12,\n\tIR_ERR_TOL_LEN\t\t= 0xFD13,\n\tIR_MAX_H_TOL_LEN\t= 0xFD14,\n\tIR_MAX_L_TOL_LEN\t= 0xFD15,\n\tIR_MASK_CTRL\t\t= 0xFD16,\n\tIR_MASK_DATA\t\t= 0xFD17,\n\tIR_RES_MASK_ADDR\t= 0xFD18,\n\tIR_RES_MASK_T_LEN\t= 0xFD19,\n};\n\nenum blocks {\n\tDEMODB\t\t\t= 0,\n\tUSBB\t\t\t= 1,\n\tSYSB\t\t\t= 2,\n\tTUNB\t\t\t= 3,\n\tROMB\t\t\t= 4,\n\tIRB\t\t\t\t= 5,\n\tIICB\t\t\t= 6,\n};\n\n\nstatic const char * dsmode_str[] = {\n\"0: use I & Q\",\n\"1: use I\",\n\"2: use Q\",\n\"3: use I below threshold frequency\",\n\"4: use Q below threshold frequency\"\n};\n\n\nint rtlsdr_read_array(rtlsdr_dev_t *dev, uint8_t block, uint16_t addr, uint8_t *array, uint8_t len)\n{\n\tint r;\n\tuint16_t index = (block << 8);\n\tif (block == IRB) index = (SYSB << 8) | 0x01;\n\n\tr = libusb_control_transfer(dev->devh, CTRL_IN, 0, addr, index, array, len, CTRL_TIMEOUT);\n#if 0\n\tif (r < 0)\n\t\tfprintf(stderr, \"%s failed with %d\\n\", __FUNCTION__, r);\n#endif\n\treturn r;\n}\n\nint rtlsdr_write_array(rtlsdr_dev_t *dev, uint8_t block, uint16_t addr, uint8_t *array, uint8_t len)\n{\n\tint r;\n\tuint16_t index = (block << 8) | 0x10;\n\tif (block == IRB) index = (SYSB << 8) | 0x11;\n\n\tr = libusb_control_transfer(dev->devh, CTRL_OUT, 0, addr, index, array, len, CTRL_TIMEOUT);\n#if 0\n\tif (r < 0)\n\t\tfprintf(stderr, \"%s failed with %d\\n\", __FUNCTION__, r);\n#endif\n\treturn r;\n}\n\nint rtlsdr_i2c_write_reg(rtlsdr_dev_t *dev, uint8_t i2c_addr, uint8_t reg, uint8_t val)\n{\n\tuint16_t addr = i2c_addr;\n\tuint8_t data[2];\n\n\tdata[0] = reg;\n\tdata[1] = val;\n\treturn rtlsdr_write_array(dev, IICB, addr, (uint8_t *)&data, 2);\n}\n\nuint8_t rtlsdr_i2c_read_reg(rtlsdr_dev_t *dev, uint8_t i2c_addr, uint8_t reg)\n{\n\tuint16_t addr = i2c_addr;\n\tuint8_t data = 0;\n\n\trtlsdr_write_array(dev, IICB, addr, &reg, 1);\n\trtlsdr_read_array(dev, IICB, addr, &data, 1);\n\n\treturn data;\n}\n\nint rtlsdr_i2c_write(rtlsdr_dev_t *dev, uint8_t i2c_addr, uint8_t *buffer, int len)\n{\n\tuint16_t addr = i2c_addr;\n\n\tif (!dev)\n\t\treturn -1;\n\n\treturn rtlsdr_write_array(dev, IICB, addr, buffer, len);\n}\n\nint rtlsdr_i2c_read(rtlsdr_dev_t *dev, uint8_t i2c_addr, uint8_t *buffer, int len)\n{\n\tuint16_t addr = i2c_addr;\n\n\tif (!dev)\n\t\treturn -1;\n\n\treturn rtlsdr_read_array(dev, IICB, addr, buffer, len);\n}\n\nuint16_t rtlsdr_read_reg(rtlsdr_dev_t *dev, uint8_t block, uint16_t addr, uint8_t len)\n{\n\tint r;\n\tunsigned char data[2];\n\tuint16_t reg;\n\tuint16_t index = (block << 8);\n\tif (block == IRB) index = (SYSB << 8) | 0x01;\n\n\tr = libusb_control_transfer(dev->devh, CTRL_IN, 0, addr, index, data, len, CTRL_TIMEOUT);\n\n\tif (r < 0)\n\t\tfprintf(stderr, \"%s failed with %d\\n\", __FUNCTION__, r);\n\n\treg = (data[1] << 8) | data[0];\n\n\treturn reg;\n}\n\nint rtlsdr_write_reg(rtlsdr_dev_t *dev, uint8_t block, uint16_t addr, uint16_t val, uint8_t len)\n{\n\tint r;\n\tunsigned char data[2];\n\n\tuint16_t index = (block << 8) | 0x10;\n\tif (block == IRB) index = (SYSB << 8) | 0x11;\n\n\tif (len == 1)\n\t\tdata[0] = val & 0xff;\n\telse\n\t\tdata[0] = val >> 8;\n\n\tdata[1] = val & 0xff;\n\n\tr = libusb_control_transfer(dev->devh, CTRL_OUT, 0, addr, index, data, len, CTRL_TIMEOUT);\n\n\tif (r < 0)\n\t\tfprintf(stderr, \"%s failed with %d\\n\", __FUNCTION__, r);\n\n\treturn r;\n}\n\nuint16_t rtlsdr_demod_read_reg(rtlsdr_dev_t *dev, uint8_t page, uint16_t addr, uint8_t len)\n{\n\tint r;\n\tunsigned char data[2];\n\n\tuint16_t index = page;\n\tuint16_t reg;\n\taddr = (addr << 8) | 0x20;\n\n\tr = libusb_control_transfer(dev->devh, CTRL_IN, 0, addr, index, data, len, CTRL_TIMEOUT);\n\n\tif (r < 0)\n\t\tfprintf(stderr, \"%s failed with %d\\n\", __FUNCTION__, r);\n\n\treg = (data[1] << 8) | data[0];\n\n\treturn reg;\n}\n\nint rtlsdr_demod_write_reg(rtlsdr_dev_t *dev, uint8_t page, uint16_t addr, uint16_t val, uint8_t len)\n{\n\tint r;\n\tunsigned char data[2];\n\tuint16_t index = 0x10 | page;\n\taddr = (addr << 8) | 0x20;\n\n\tif (len == 1)\n\t\tdata[0] = val & 0xff;\n\telse\n\t\tdata[0] = val >> 8;\n\n\tdata[1] = val & 0xff;\n\n\tr = libusb_control_transfer(dev->devh, CTRL_OUT, 0, addr, index, data, len, CTRL_TIMEOUT);\n\n\tif (r < 0)\n\t\tfprintf(stderr, \"%s failed with %d\\n\", __FUNCTION__, r);\n\n\trtlsdr_demod_read_reg(dev, 0x0a, 0x01, 1);\n\n\treturn (r == len) ? 0 : -1;\n}\n\nint rtlsdr_set_gpio_bit(rtlsdr_dev_t *dev, uint8_t gpio, int val)\n{\n\tuint16_t r, retval;\n\n\tgpio = 1 << gpio;\n\tr = rtlsdr_read_reg(dev, SYSB, GPO, 1);\n\tr = val ? (r | gpio) : (r & ~gpio);\n\tretval = rtlsdr_write_reg(dev, SYSB, GPO, r, 1);\n\treturn retval;\n}\n\nint rtlsdr_set_gpio_output(rtlsdr_dev_t *dev, uint8_t gpio)\n{\n\tint r, retval = 0;\n\tgpio = 1 << gpio;\n\n\t/* state: bitmask over pins 0 .. 7: = 0 == write, 1 == read */\n\tif ( !(dev->gpio_state_known & gpio) || (dev->gpio_state & gpio) )\n\t{\n\t\tr = rtlsdr_read_reg(dev, SYSB, GPD, 1);\n\t\tretval = rtlsdr_write_reg(dev, SYSB, GPD, r & ~gpio, 1);\n\t\tif (retval < 0)\n\t\t\treturn retval;\n\t\tr = rtlsdr_read_reg(dev, SYSB, GPOE, 1);\n\t\tretval = rtlsdr_write_reg(dev, SYSB, GPOE, r | gpio, 1);\n\t\tif (retval < 0)\n\t\t\treturn retval;\n\n\t\tdev->gpio_state_known |= gpio;\n\t\tdev->gpio_state &= ~( (uint32_t)gpio );\n\t}\n\n\treturn retval;\n}\n\nint rtlsdr_get_gpio_bit(rtlsdr_dev_t *dev, uint8_t gpio, int *val)\n{\n\tuint16_t r;\n\n\tgpio = 1 << gpio;\n\tr = rtlsdr_read_reg(dev, SYSB, GPI, 1);\n\t*val = (r & gpio) ? 1 : 0;\n\treturn 0; /* no way to determine error with rtlsdr_read_reg() for now! */\n}\n\nint rtlsdr_set_gpio_input(rtlsdr_dev_t *dev, uint8_t gpio)\n{\n\tint r, retval = 0;\n\tgpio = 1 << gpio;\n\n\t/* state: bitmask over pins 0 .. 7: = 0 == write, 1 == read */\n\tif ( !(dev->gpio_state_known & gpio) || !(dev->gpio_state & gpio) )\n\t{\n\t\tr = rtlsdr_read_reg(dev, SYSB, GPD, 1);\n\t\tretval = rtlsdr_write_reg(dev, SYSB, GPD, r | gpio, 1);\n\t\tif (retval < 0)\n\t\t\treturn retval;\n\t\tr = rtlsdr_read_reg(dev, SYSB, GPOE, 1);\n\t\tretval = rtlsdr_write_reg(dev, SYSB, GPOE, r & ~gpio, 1);\n\t\tif (retval < 0)\n\t\t\treturn retval;\n\n\t\tdev->gpio_state_known |= gpio;\n\t\tdev->gpio_state |= ( (uint32_t)gpio );\n\t}\n\n\treturn retval;\n}\n\nint rtlsdr_set_gpio_status(rtlsdr_dev_t *dev, int *status )\n{\n\tint r;\n\tr = rtlsdr_read_reg(dev, SYSB, GPD, 1);\n\t*status = r;\n\treturn 0; /* no way to determine error with rtlsdr_read_reg() for now! */\n}\n\n\nint rtlsdr_get_gpio_byte(rtlsdr_dev_t *dev, int *val)\n{\n\t*val = rtlsdr_read_reg(dev, SYSB, GPI, 1);\n\treturn 0; /* no way to determine error with rtlsdr_read_reg() for now! */\n}\n\nint rtlsdr_set_gpio_byte(rtlsdr_dev_t *dev, int val)\n{\n\tint retval = rtlsdr_write_reg(dev, SYSB, GPO, val, 1);\n\treturn retval;\n}\n\n\nvoid rtlsdr_set_i2c_repeater(rtlsdr_dev_t *dev, int on)\n{\n\tif (on)\n\t\tpthread_mutex_lock(&dev->cs_mutex);\n\n\t/* hayguen: don't do early exit for mutex!\n\t * just skip rtlsdr_demod_write_reg() call\n\t * if (on == dev->i2c_repeater_on)\n\t *\treturn;\n\t */\n\n\tif (on != dev->i2c_repeater_on) {\n\t\tdev->i2c_repeater_on = on;\n\t\trtlsdr_demod_write_reg(dev, 1, 0x01, on ? 0x18 : 0x10, 1);\n\t}\n\n\tif (!on)\n\t\tpthread_mutex_unlock(&dev->cs_mutex);\n}\n\nint rtlsdr_set_fir(rtlsdr_dev_t *dev)\n{\n\tuint8_t fir[20];\n\n\tint i;\n\t/* format: int8_t[8] */\n\tfor (i = 0; i < 8; ++i) {\n\t\tconst int val = dev->fir[i];\n\t\tif (val < -128 || val > 127) {\n\t\t\treturn -1;\n\t\t}\n\t\tfir[i] = val;\n\t}\n\t/* format: int12_t[8] */\n\tfor (i = 0; i < 8; i += 2) {\n\t\tconst int val0 = dev->fir[8+i];\n\t\tconst int val1 = dev->fir[8+i+1];\n\t\tif (val0 < -2048 || val0 > 2047 || val1 < -2048 || val1 > 2047) {\n\t\t\treturn -1;\n\t\t}\n\t\tfir[8+i*3/2] = val0 >> 4;\n\t\tfir[8+i*3/2+1] = (val0 << 4) | ((val1 >> 8) & 0x0f);\n\t\tfir[8+i*3/2+2] = val1;\n\t}\n\n\tfor (i = 0; i < (int)sizeof(fir); i++) {\n\t\tif (rtlsdr_demod_write_reg(dev, 1, 0x1c + i, fir[i], 1))\n\t\t\t\treturn -1;\n\t}\n\n\treturn 0;\n}\n\nvoid rtlsdr_init_baseband(rtlsdr_dev_t *dev)\n{\n\tunsigned int i;\n\n\t/* initialize USB */\n\trtlsdr_write_reg(dev, USBB, USB_SYSCTL, 0x09, 1);\n\trtlsdr_write_reg(dev, USBB, USB_EPA_MAXPKT, 0x0002, 2);\n\trtlsdr_write_reg(dev, USBB, USB_EPA_CTL, 0x1002, 2);\n\n\t/* poweron demod */\n\trtlsdr_write_reg(dev, SYSB, DEMOD_CTL_1, 0x22, 1);\n\trtlsdr_write_reg(dev, SYSB, DEMOD_CTL, 0xe8, 1);\n\n\t/* reset demod (bit 3, soft_rst) */\n\trtlsdr_demod_write_reg(dev, 1, 0x01, 0x14, 1);\n\trtlsdr_demod_write_reg(dev, 1, 0x01, 0x10, 1);\n\n\t/* disable spectrum inversion and adjacent channel rejection */\n\trtlsdr_demod_write_reg(dev, 1, 0x15, 0x00, 1);\n\trtlsdr_demod_write_reg(dev, 1, 0x16, 0x0000, 2);\n\n\t/* clear both DDC shift and IF frequency registers\t*/\n\tfor (i = 0; i < 6; i++)\n\t\trtlsdr_demod_write_reg(dev, 1, 0x16 + i, 0x00, 1);\n\n\trtlsdr_set_fir(dev);\n\n\t/* enable SDR mode, disable DAGC (bit 5) */\n\trtlsdr_demod_write_reg(dev, 0, 0x19, 0x05, 1);\n\n\t/* init FSM state-holding register */\n\trtlsdr_demod_write_reg(dev, 1, 0x93, 0xf0, 1);\n\trtlsdr_demod_write_reg(dev, 1, 0x94, 0x0f, 1);\n\n\t/* disable AGC (en_dagc, bit 0) (this seems to have no effect) */\n\trtlsdr_demod_write_reg(dev, 1, 0x11, 0x00, 1);\n\n\t/* disable RF and IF AGC loop */\n#if USE_OLD_DAB_IF_GAIN == 0\n\trtlsdr_demod_write_reg(dev, 1, 0x04, 0x00, 1);\n#endif\n\tdev->rtl_vga_control = 0;\n\n\t/* disable PID filter (enable_PID = 0) */\n\trtlsdr_demod_write_reg(dev, 0, 0x61, 0x60, 1);\n\n\t/* opt_adc_iq = 0, default ADC_I/ADC_Q datapath */\n\trtlsdr_demod_write_reg(dev, 0, 0x06, 0x80, 1);\n\n\t/* Enable Zero-IF mode (en_bbin bit), DC cancellation (en_dc_est),\n\t * IQ estimation/compensation (en_iq_comp, en_iq_est) */\n\trtlsdr_demod_write_reg(dev, 1, 0xb1, 0x1b, 1);\n\n\t/* disable 4.096 MHz clock output on pin TP_CK0 */\n\trtlsdr_demod_write_reg(dev, 0, 0x0d, 0x83, 1);\n}\n\nint rtlsdr_deinit_baseband(rtlsdr_dev_t *dev)\n{\n\tint r = 0;\n\n\tif (!dev)\n\t\treturn -1;\n\n\tif (dev->tuner && dev->tuner->exit) {\n\t\trtlsdr_set_i2c_repeater(dev, 1);\n\t\tr = dev->tuner->exit(dev); /* deinitialize tuner */\n\t\trtlsdr_set_i2c_repeater(dev, 0);\n\t}\n\n\t/* poweroff demodulator and ADCs */\n\trtlsdr_write_reg(dev, SYSB, DEMOD_CTL, 0x20, 1);\n\n\treturn r;\n}\n\nstatic int rtlsdr_set_if_freq(rtlsdr_dev_t *dev, uint32_t freq)\n{\n\tuint32_t rtl_xtal;\n\tint32_t if_freq;\n\tuint8_t tmp;\n\tint r;\n\n\tif (!dev)\n\t\treturn -1;\n\n\t/* read corrected clock value */\n\tif (rtlsdr_get_xtal_freq(dev, &rtl_xtal, NULL))\n\t\treturn -2;\n\n#ifdef WITH_UDP_SERVER\n\tdev->last_if_freq = freq;\n\tif ( dev->override_if_flag ) {\n\t\tif ( dev->verbose )\n\t\t\tfprintf(stderr, \"overriding rtlsdr_set_if_freq(): modifying %u to %d Hz\\n\"\n\t\t\t\t\t, freq, dev->override_if_freq );\n\t\tfreq = dev->override_if_freq;\n\t\tif ( dev->override_if_flag == 1 )\n\t\t\tdev->override_if_flag = 0;\n\t}\n#endif\n\n\tif_freq = ((freq * TWO_POW(22)) / rtl_xtal) * (-1);\n\n\ttmp = (if_freq >> 16) & 0x3f;\n\tr = rtlsdr_demod_write_reg(dev, 1, 0x19, tmp, 1);\n\ttmp = (if_freq >> 8) & 0xff;\n\tr |= rtlsdr_demod_write_reg(dev, 1, 0x1a, tmp, 1);\n\ttmp = if_freq & 0xff;\n\tr |= rtlsdr_demod_write_reg(dev, 1, 0x1b, tmp, 1);\n\n\treturn r;\n}\n\nstatic int rtlsdr_set_spectrum_inversion(rtlsdr_dev_t *dev, int sideband)\n{\n\tint r = 0;\n\tif ( dev->rtl_spectrum_sideband != sideband + 1 )\n\t{\n\t\tif(sideband)\n\t\t\t/* disable spectrum inversion */\n\t\t\tr = rtlsdr_demod_write_reg(dev, 1, 0x15, 0x00, 1);\n\t\telse\n\t\t\t/* enable spectrum inversion */\n\t\t\tr = rtlsdr_demod_write_reg(dev, 1, 0x15, 0x01, 1);\n\n\t\tdev->rtl_spectrum_sideband = (r) ? 0 : (sideband + 1);\n\t}\n\treturn r;\n}\n\nint rtlsdr_set_sample_freq_correction(rtlsdr_dev_t *dev, int ppm)\n{\n\tint r = 0;\n\tuint8_t tmp;\n\tint16_t offs = ppm * (-1) * TWO_POW(24) / 1000000;\n\n\ttmp = offs & 0xff;\n\tr |= rtlsdr_demod_write_reg(dev, 1, 0x3f, tmp, 1);\n\ttmp = (offs >> 8) & 0x3f;\n\tr |= rtlsdr_demod_write_reg(dev, 1, 0x3e, tmp, 1);\n\n\treturn r;\n}\n\nint rtlsdr_set_xtal_freq(rtlsdr_dev_t *dev, uint32_t rtl_freq, uint32_t tuner_freq)\n{\n\tint r = 0;\n\n\t#if LOG_API_CALLS\n\tfprintf(stderr, \"LOG: rtlsdr_set_xtal_freq(rtl_freq %u, tuner_freq %u)\\n\", (unsigned)rtl_freq, (unsigned)tuner_freq);\n\t#endif\n\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return rtlsdr_rpc_set_xtal_freq(dev, rtl_freq, tuner_freq);\n\t}\n\t#endif\n\n\tif (!dev)\n\t\treturn -1;\n\n\tif (rtl_freq > 0 &&\n\t\t(rtl_freq < MIN_RTL_XTAL_FREQ || rtl_freq > MAX_RTL_XTAL_FREQ))\n\t\treturn -2;\n\n\tif (rtl_freq > 0 && dev->rtl_xtal != rtl_freq) {\n\t\tdev->rtl_xtal = rtl_freq;\n\n\t\t/* update xtal-dependent settings */\n\t\tif (dev->rate)\n\t\t\tr = rtlsdr_set_sample_rate(dev, dev->rate);\n\t}\n\n\tif (dev->tun_xtal != tuner_freq) {\n\t\tif (0 == tuner_freq)\n\t\t\tdev->tun_xtal = dev->rtl_xtal;\n\t\telse\n\t\t\tdev->tun_xtal = tuner_freq;\n\n\t\t/* read corrected clock value into e4k and r82xx structure */\n\t\tif (rtlsdr_get_xtal_freq(dev, NULL, &dev->e4k_s.vco.fosc) ||\n\t\t\trtlsdr_get_xtal_freq(dev, NULL, &dev->r82xx_c.xtal))\n\t\t\treturn -3;\n\n\t\t/* update xtal-dependent settings */\n\t\tif (dev->freq)\n\t\t\tr = rtlsdr_set_center_freq64(dev, dev->freq);\n\t}\n\n\treturn r;\n}\n\nint rtlsdr_get_xtal_freq(rtlsdr_dev_t *dev, uint32_t *rtl_freq, uint32_t *tuner_freq)\n{\n\t#if LOG_API_CALLS\n\tfprintf(stderr, \"LOG: rtlsdr_get_xtal_freq(rtl_freq, tuner_freq)\\n\");\n\t#endif\n\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return rtlsdr_rpc_get_xtal_freq(dev, rtl_freq, tuner_freq);\n\t}\n\t#endif\n\n\tif (!dev)\n\t\treturn -1;\n\n\t#define APPLY_PPM_CORR(val,ppm) (((val) * (1.0 + (ppm) / 1e6)))\n\n\tif (rtl_freq)\n\t\t*rtl_freq = (uint32_t) APPLY_PPM_CORR(dev->rtl_xtal, dev->corr);\n\n\tif (tuner_freq)\n\t\t*tuner_freq = (uint32_t) APPLY_PPM_CORR(dev->tun_xtal, dev->corr);\n\n\treturn 0;\n}\n\nint rtlsdr_get_usb_strings(rtlsdr_dev_t *dev, char *manufact, char *product,\n\t\t\t\t\t\t\tchar *serial)\n{\n\tstruct libusb_device_descriptor dd;\n\tlibusb_device *device = NULL;\n\tconst int buf_max = 256;\n\tint r = 0;\n\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return rtlsdr_rpc_get_usb_strings(dev, manufact, product, serial);\n\t}\n\t#endif\n\n\tif (!dev || !dev->devh)\n\t\treturn -1;\n\n\tdevice = libusb_get_device(dev->devh);\n\n\tr = libusb_get_device_descriptor(device, &dd);\n\tif (r < 0)\n\t\treturn -1;\n\n\tif (manufact) {\n\t\tmemset(manufact, 0, buf_max);\n\t\tlibusb_get_string_descriptor_ascii(dev->devh, dd.iManufacturer,\n\t\t\t\t\t\t\t (unsigned char *)manufact,\n\t\t\t\t\t\t\t buf_max);\n\t}\n\n\tif (product) {\n\t\tmemset(product, 0, buf_max);\n\t\tlibusb_get_string_descriptor_ascii(dev->devh, dd.iProduct,\n\t\t\t\t\t\t\t (unsigned char *)product,\n\t\t\t\t\t\t\t buf_max);\n\t}\n\n\tif (serial) {\n\t\tmemset(serial, 0, buf_max);\n\t\tlibusb_get_string_descriptor_ascii(dev->devh, dd.iSerialNumber,\n\t\t\t\t\t\t\t (unsigned char *)serial,\n\t\t\t\t\t\t\t buf_max);\n\t}\n\n\treturn 0;\n}\n\nint rtlsdr_write_eeprom(rtlsdr_dev_t *dev, uint8_t *data, uint8_t offset, uint16_t len)\n{\n\tint r = 0;\n\tint i;\n\tuint8_t cmd[2];\n\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return rtlsdr_rpc_write_eeprom(dev, data, offset, len);\n\t}\n\t#endif\n\n\tif (!dev)\n\t\treturn -1;\n\n\tif ((len + offset) > 256)\n\t\treturn -2;\n\n\tfor (i = 0; i < len; i++) {\n\t\tcmd[0] = i + offset;\n\t\tr = rtlsdr_write_array(dev, IICB, EEPROM_ADDR, cmd, 1);\n\t\tr = rtlsdr_read_array(dev, IICB, EEPROM_ADDR, &cmd[1], 1);\n\n\t\t/* only write the byte if it differs */\n\t\tif (cmd[1] == data[i])\n\t\t\tcontinue;\n\n\t\tcmd[1] = data[i];\n\t\tr = rtlsdr_write_array(dev, IICB, EEPROM_ADDR, cmd, 2);\n\t\tif (r != sizeof(cmd))\n\t\t\treturn -3;\n\n\t\t/* for some EEPROMs (e.g. ATC 240LC02) we need a delay\n\t\t * between write operations, otherwise they will fail */\n#ifdef _WIN32\n\t\tSleep(5);\n#else\n\t\tusleep(5000);\n#endif\n\t}\n\n\treturn 0;\n}\n\nint rtlsdr_read_eeprom(rtlsdr_dev_t *dev, uint8_t *data, uint8_t offset, uint16_t len)\n{\n\tint r = 0;\n\tint i;\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return rtlsdr_rpc_read_eeprom(dev, data, offset, len);\n\t}\n\t#endif\n\n\tif (!dev)\n\t\treturn -1;\n\n\tif ((len + offset) > 256)\n\t\treturn -2;\n\n\tr = rtlsdr_write_array(dev, IICB, EEPROM_ADDR, &offset, 1);\n\tif (r < 0)\n\t\treturn -3;\n\n\tfor (i = 0; i < len; i++) {\n\t\tr = rtlsdr_read_array(dev, IICB, EEPROM_ADDR, data + i, 1);\n\n\t\tif (r < 0)\n\t\t\treturn -3;\n\t}\n\n\treturn r;\n}\n\nint rtlsdr_set_center_freq(rtlsdr_dev_t *dev, uint32_t freq)\n{\n\tint r = -1;\n\n\t#if LOG_API_CALLS && LOG_API_SET_FREQ\n\tfprintf(stderr, \"LOG: rtlsdr_set_center_freq(freq %f MHz)\\n\", freq * 1E-6);\n\t#endif\n\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return rtlsdr_rpc_set_center_freq(dev, freq);\n\t}\n\t#endif\n\tif (!dev || !dev->tuner)\n\t\treturn -1;\n\n\tif (dev->direct_sampling_mode > RTLSDR_DS_Q)\n\t\trtlsdr_update_ds(dev, freq);\n\n\tif (dev->direct_sampling) {\n\t\tr = rtlsdr_set_if_freq(dev, freq);\n\t} else if (dev->tuner && dev->tuner->set_freq) {\n\t\trtlsdr_set_i2c_repeater(dev, 1);\n\t\tr = dev->tuner->set_freq(dev, freq - dev->offs_freq);\n\t\trtlsdr_set_i2c_repeater(dev, 0);\n\t}\n\n\tif (!r)\n\t\tdev->freq = freq;\n\telse\n\t\tdev->freq = 0;\n\n\treturn r;\n}\n\nint rtlsdr_set_center_freq64(rtlsdr_dev_t *dev, uint64_t freq)\n{\n\tint r = -1;\n\n\t#if LOG_API_CALLS && LOG_API_SET_FREQ\n\tfprintf(stderr, \"LOG: rtlsdr_set_center_freq64(freq %f MHz)\\n\", freq * 1E-6);\n\t#endif\n\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return rtlsdr_rpc_set_center_freq(dev, freq);\n\t}\n\t#endif\n\tif (!dev || !dev->tuner)\n\t\treturn -1;\n\n\tif (dev->direct_sampling_mode > RTLSDR_DS_Q)\n\t\trtlsdr_update_ds(dev, freq);\n\n\tif (dev->direct_sampling) {\n\t\tr = rtlsdr_set_if_freq(dev, freq);\n\t} else if (dev->tuner && dev->tuner->set_freq64) {\n\t\trtlsdr_set_i2c_repeater(dev, 1);\n\t\tr = dev->tuner->set_freq64(dev, freq - dev->offs_freq);\n\t\trtlsdr_set_i2c_repeater(dev, 0);\n\t} else if (dev->tuner && dev->tuner->set_freq) {\n\t\trtlsdr_set_i2c_repeater(dev, 1);\n\t\tr = dev->tuner->set_freq(dev, (uint32_t)freq - dev->offs_freq);\n\t\trtlsdr_set_i2c_repeater(dev, 0);\n\t}\n\n\tif (!r)\n\t\tdev->freq = freq;\n\telse\n\t\tdev->freq = 0;\n\n\treturn r;\n}\n\n\nint rtlsdr_is_tuner_PLL_locked(rtlsdr_dev_t *dev)\n{\n\tint r = -1;\n\n\t#if LOG_API_CALLS && LOG_API_SET_FREQ\n\tfprintf(stderr, \"LOG: rtlsdr_is_tuner_PLL_locked()\\n\");\n\t#endif\n\n\tif (!dev || !dev->tuner)\n\t\treturn -1;\n\n\tif (dev->tuner_type != RTLSDR_TUNER_R820T && dev->tuner_type != RTLSDR_TUNER_R828D )\n\t\treturn -2;\n\n\trtlsdr_set_i2c_repeater(dev, 1);\n\tr = r82xx_is_tuner_locked(&dev->r82xx_p);\n\trtlsdr_set_i2c_repeater(dev, 0);\n\n\treturn r;\n}\n\n\nuint32_t rtlsdr_get_center_freq(rtlsdr_dev_t *dev)\n{\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return rtlsdr_rpc_get_center_freq(dev);\n\t}\n\t#endif\n\n\tif (!dev)\n\t\treturn 0;\n\n\treturn dev->freq;\n}\n\nuint64_t rtlsdr_get_center_freq64(rtlsdr_dev_t *dev)\n{\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return rtlsdr_rpc_get_center_freq(dev);\n\t}\n\t#endif\n\n\tif (!dev)\n\t\treturn 0;\n\n\treturn dev->freq;\n}\n\nint rtlsdr_set_freq_correction(rtlsdr_dev_t *dev, int ppm)\n{\n\tint r = 0;\n\n\t#if LOG_API_CALLS\n\tfprintf(stderr, \"LOG: rtlsdr_set_freq_correction(ppm %d)\\n\", ppm);\n\t#endif\n\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return rtlsdr_rpc_set_freq_correction(dev, ppm);\n\t}\n\t#endif\n\n\tif (!dev)\n\t\treturn -1;\n\n\tif (dev->corr == ppm)\n\t\treturn -2;\n\n\tdev->corr = ppm;\n\n\tr |= rtlsdr_set_sample_freq_correction(dev, ppm);\n\n\t/* read corrected clock value into e4k and r82xx structure */\n\tif (rtlsdr_get_xtal_freq(dev, NULL, &dev->e4k_s.vco.fosc) ||\n\t\t\trtlsdr_get_xtal_freq(dev, NULL, &dev->r82xx_c.xtal))\n\t\treturn -3;\n\n\tif (dev->freq) /* retune to apply new correction value */\n\t\tr |= rtlsdr_set_center_freq64(dev, dev->freq);\n\n\treturn r;\n}\n\nint rtlsdr_get_freq_correction(rtlsdr_dev_t *dev)\n{\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return rtlsdr_rpc_get_freq_correction(dev);\n\t}\n\t#endif\n\n\tif (!dev)\n\t\treturn 0;\n\n\treturn dev->corr;\n}\n\nenum rtlsdr_tuner rtlsdr_get_tuner_type(rtlsdr_dev_t *dev)\n{\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return (enum rtlsdr_tuner)rtlsdr_rpc_get_tuner_type(dev);\n\t}\n\t#endif\n\n\tif (!dev)\n\t\treturn RTLSDR_TUNER_UNKNOWN;\n\n\treturn dev->tuner_type;\n}\n\nstatic\nconst int * get_tuner_gains(rtlsdr_dev_t *dev, int *pNum )\n{\n\t/* all gain values are expressed in tenths of a dB */\n\tstatic const int e4k_gains[] = { -10, 15, 40, 65, 90, 115, 140, 165, 190, 215,\n\t\t\t\t\t240, 290, 340, 420 };\n\tstatic const int fc0012_gains[] = { -99, -40, 71, 179, 192 };\n\tstatic const int fc0013_gains[] = { -99, -73, -65, -63, -60, -58, -54, 58, 61,\n\t\t\t\t\t\t\t \t  63, 65, 67, 68, 70, 71, 179, 181, 182,\n\t\t\t\t\t\t\t \t  184, 186, 188, 191, 197 };\n\tstatic const int fc2580_gains[] = { 0 /* no gain values */ };\n\tstatic const int r82xx_gains[] = { 0, 9, 14, 27, 37, 77, 87, 125, 144, 157,\n\t\t\t\t\t\t\t\t166, 197, 207, 229, 254, 280, 297, 328,\n\t\t\t\t\t\t \t\t338, 364, 372, 386, 402, 421, 434, 439,\n\t\t\t\t\t\t \t\t445, 480, 496 };\n\tstatic const int unknown_gains[] = { 0 /* no gain values */ };\n\n\tconst int *ptr = NULL;\n\tint len = 0;\n\n#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t\tif ( !dev->softagc.rpcGainValues )\n\t\t{\n\t\t\tdev->softagc.rpcNumGains = rtlsdr_rpc_get_tuner_gains(dev, NULL);\n\t\t\tif ( dev->softagc.rpcNumGains > 0 )\n\t\t\t{\n\t\t\t\tdev->softagc.rpcGainValues = malloc( dev->softagc.rpcNumGains * sizeof(int) );\n\t\t\t\tif ( dev->softagc.rpcGainValues )\n\t\t\t\t\trtlsdr_get_tuner_gains(dev, dev->softagc.rpcGainValues);\n\t\t\t}\n\t\t}\n\t\tif ( dev->softagc.rpcGainValues )\n\t\t{\n\t\t\t*pNum = dev->softagc.rpcNumGains;\n\t\t\treturn dev->softagc.rpcGainValues;\n\t\t}\n\t\t*pNum = 0;\n\t\treturn NULL;\n\t}\n#endif\n\n\tswitch (dev->tuner_type) {\n\tcase RTLSDR_TUNER_E4000:\n\t\tptr = e4k_gains; len = sizeof(e4k_gains);\n\t\tbreak;\n\tcase RTLSDR_TUNER_FC0012:\n\t\tptr = fc0012_gains; len = sizeof(fc0012_gains);\n\t\tbreak;\n\tcase RTLSDR_TUNER_FC0013:\n\t\tptr = fc0013_gains; len = sizeof(fc0013_gains);\n\t\tbreak;\n\tcase RTLSDR_TUNER_FC2580:\n\t\tptr = fc2580_gains; len = sizeof(fc2580_gains);\n\t\tbreak;\n\tcase RTLSDR_TUNER_R820T:\n\tcase RTLSDR_TUNER_R828D:\n\t\tptr = r82xx_gains; len = sizeof(r82xx_gains);\n\t\tbreak;\n\tdefault:\n\t\tptr = unknown_gains; len = sizeof(unknown_gains);\n\t\tbreak;\n\t}\n\n\t*pNum = len / sizeof(int);\n\treturn ptr;\n}\n\n\nint rtlsdr_get_tuner_gains(rtlsdr_dev_t *dev, int *gains)\n{\n\tconst int *ptr = NULL;\n\tint len = 0;\n\n\tif (!dev)\n\t\treturn -1;\n\n\tptr = get_tuner_gains(dev, &len );\n\tlen = len * sizeof(int);\n\n\tif (!gains) { /* no buffer provided, just return the count */\n\t\treturn len / sizeof(int);\n\t} else {\n\t\tif (len)\n\t\t\tmemcpy(gains, ptr, len);\n\n\t\treturn len / sizeof(int);\n\t}\n}\n\nint rtlsdr_set_and_get_tuner_bandwidth(rtlsdr_dev_t *dev, uint32_t bw, uint32_t *applied_bw, int apply_bw )\n{\n\tint r = 0;\n\n\t#if LOG_API_CALLS\n\tfprintf(stderr, \"LOG: rtlsdr_set_and_get_tuner_bandwidth(bw %u Hz, apply_bw %d)\\n\", (unsigned)bw, apply_bw);\n\t#endif\n\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n     return rtlsdr_rpc_set_and_get_tuner_bandwidth(dev, bw, applied_bw, apply_bw);\n\t}\n\t#endif\n\n\t*applied_bw = 0;\t\t/* unknown */\n\n\tif (!dev || !dev->tuner)\n\t\treturn -1;\n\n\tif(!apply_bw)\n\t{\n\t\tif (dev->tuner->set_bw) {\n\t\t\tr = dev->tuner->set_bw(dev, bw > 0 ? bw : dev->rate, applied_bw, apply_bw);\n\t\t}\n\t\treturn r;\n\t}\n\n\tif (dev->tuner->set_bw) {\n\t\trtlsdr_set_i2c_repeater(dev, 1);\n\t\tr = dev->tuner->set_bw(dev, bw > 0 ? bw : dev->rate, applied_bw, apply_bw);\n\t\trtlsdr_set_i2c_repeater(dev, 0);\n\t\treactivate_softagc(dev, SOFTSTATE_RESET);\n\t\tif (r)\n\t\t\treturn r;\n\t\tdev->bw = bw;\n\t}\n\treturn r;\n}\n\nint rtlsdr_set_tuner_bandwidth(rtlsdr_dev_t *dev, uint32_t bw )\n{\n\tuint32_t applied_bw = 0;\n\n\t#if LOG_API_CALLS\n\tfprintf(stderr, \"LOG: rtlsdr_set_tuner_bandwidth(bw %u Hz)\\n\", (unsigned)bw);\n\t#endif\n\n\treturn rtlsdr_set_and_get_tuner_bandwidth(dev, bw, &applied_bw, 1 /* =apply_bw */ );\n}\n\nint rtlsdr_set_tuner_band_center(rtlsdr_dev_t *dev, int32_t if_band_center_freq )\n{\n\tint r = -1;\n\tif (!dev || !dev->tuner || !dev->tuner->set_bw_center)\n\t\treturn -1;\n\n\t#if LOG_API_CALLS\n\tfprintf(stderr, \"LOG: rtlsdr_set_tuner_band_center(if_band_center_freq %d Hz)\\n\", (int)if_band_center_freq);\n\t#endif\n\n\treturn dev->tuner->set_bw_center(dev, if_band_center_freq);\n}\n\n\nint rtlsdr_set_tuner_gain(rtlsdr_dev_t *dev, int gain)\n{\n\tint r = 0;\n\n\t#if LOG_API_CALLS\n\tfprintf(stderr, \"LOG: rtlsdr_set_tuner_gain(%d /10 dB)\\n\", gain);\n\t#endif\n\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return rtlsdr_rpc_set_tuner_gain(dev, gain);\n\t}\n\t#endif\n\n\tif (!dev || !dev->tuner)\n\t\treturn -1;\n\n\tif (dev->tuner->set_gain) {\n\t\trtlsdr_set_i2c_repeater(dev, 1);\n\t\tr = dev->tuner->set_gain((void *)dev, gain);\n\t\trtlsdr_set_i2c_repeater(dev, 0);\n\t}\n\n\treturn r;\n}\n\nint rtlsdr_set_tuner_gain_ext(rtlsdr_dev_t *dev, int lna_gain, int mixer_gain, int vga_gain)\n{\n\tint r = 0;\n\n\tif (!dev || ( dev->tuner_type != RTLSDR_TUNER_R820T && dev->tuner_type != RTLSDR_TUNER_R828D ) )\n\t\treturn -1;\n\n\t#if LOG_API_CALLS\n\tfprintf(stderr, \"LOG: rtlsdr_set_tuner_gain_ext(indexes 0 .. 15: lna %d, mixer %d, vga %d)\\n\",\n\t\tlna_gain, mixer_gain, vga_gain );\n\t#endif\n\n\tif (dev->tuner->set_gain) {\n\t\trtlsdr_set_i2c_repeater(dev, 1);\n\t\tr = r820t_set_gain_ext((void *)dev, lna_gain, mixer_gain, vga_gain);\n\t\trtlsdr_set_i2c_repeater(dev, 0);\n\t}\n\n\treturn r;\n}\n\nint rtlsdr_set_tuner_if_mode(rtlsdr_dev_t *dev, int if_mode)\n{\n\tint r = 0;\n\n\tif (!dev || ( dev->tuner_type != RTLSDR_TUNER_R820T && dev->tuner_type != RTLSDR_TUNER_R828D ) )\n\t\treturn -1;\n\n\t#if LOG_API_CALLS\n\tfprintf(stderr, \"LOG: rtlsdr_set_tuner_if_mode(if_mode %d)\\n\", if_mode);\n\t#endif\n\n\tif (dev->tuner->set_gain) {\n\t\trtlsdr_set_i2c_repeater(dev, 1);\n\t\tr = r820t_set_if_mode((void *)dev, if_mode);\n\t\trtlsdr_set_i2c_repeater(dev, 0);\n\t}\n\n\treturn r;\n}\n\n\nint rtlsdr_get_tuner_gain(rtlsdr_dev_t *dev)\n{\n\tint rf_gain = 0;\n\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return rtlsdr_rpc_get_tuner_gain(dev);\n\t}\n\t#endif\n\n\tif (!dev)\n\t\treturn 0;\n\n\tif (dev->tuner_type == RTLSDR_TUNER_R820T)\n\t\trf_gain = r82xx_get_rf_gain(&dev->r82xx_p);\n\n\treturn rf_gain;\n}\n\nint rtlsdr_set_tuner_if_gain(rtlsdr_dev_t *dev, int stage, int gain)\n{\n\tint r = 0;\n\n\t#if LOG_API_CALLS\n\tfprintf(stderr, \"LOG: rtlsdr_set_tuner_if_gain(stage %d, gain %d /10 dB)\\n\",\n\t\tstage, gain );\n\t#endif\n\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return rtlsdr_rpc_set_tuner_if_gain(dev, stage, gain);\n\t}\n\t#endif\n\n\tif (!dev || !dev->tuner)\n\t\treturn -1;\n\n\tif (dev->tuner->set_if_gain) {\n\t\trtlsdr_set_i2c_repeater(dev, 1);\n\t\tr = dev->tuner->set_if_gain(dev, stage, gain);\n\t\trtlsdr_set_i2c_repeater(dev, 0);\n\t\treactivate_softagc(dev, SOFTSTATE_RESET);\n\t}\n\n\treturn r;\n}\n\nint rtlsdr_set_tuner_gain_mode(rtlsdr_dev_t *dev, int mode)\n{\n\tint r = 0;\n\n\t#if LOG_API_CALLS\n\tfprintf(stderr, \"LOG: rtlsdr_set_tuner_gain_mode(mgc mode %d => agc %d)\\n\",\n\t\tmode, (mode ? 0 : 1) );\n\t#endif\n\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return rtlsdr_rpc_set_tuner_gain_mode(dev, mode);\n\t}\n\t#endif\n\n\tif (!dev || !dev->tuner)\n\t\treturn -1;\n\n\tif (dev->tuner->set_gain_mode) {\n\t\tif ( dev->softagc.softAgcMode != SOFTAGC_OFF ) {\n\t\t\tmode = 1;\t\t/* use manual gain mode - for softagc */\n\t\t\tif ( dev->softagc.softAgcMode && dev->softagc.verbose )\n\t\t\t\tfprintf(stderr, \"rtlsdr_set_tuner_gain_mode() - overridden for softagc!\\n\");\n\t\t}\n\t\trtlsdr_set_i2c_repeater(dev, 1);\n\t\tr = dev->tuner->set_gain_mode((void *)dev, mode);\n\t\trtlsdr_set_i2c_repeater(dev, 0);\n\t}\n\n\treturn r;\n}\n\nint rtlsdr_set_tuner_sideband(rtlsdr_dev_t *dev, int sideband)\n{\n\tint r = 0, iffreq;\n\trtlsdr_dev_t *devt = dev;\n\n\tif (!dev || !dev->tuner)\n\t\treturn -1;\n\n\t#if LOG_API_CALLS\n\tfprintf(stderr, \"LOG: rtlsdr_set_tuner_sideband(sideband %d '%s')\\n\",\n\t\tsideband, (sideband ? \"Upper\" : \"Lower\") );\n\t#endif\n\n\tif (dev->tuner->set_sideband) {\n\t\tif ( devt->verbose )\n\t\t\tfprintf(stderr, \"rtlsdr_set_tuner_sideband(%d): tuner.set_sideband() ..\\n\", sideband);\n\n\t\trtlsdr_set_i2c_repeater(dev, 1);\n\t\tr = dev->tuner->set_sideband((void *)dev, sideband);\n\t\trtlsdr_set_i2c_repeater(dev, 0);\n\n\t\tif (r)\n\t\t{\n\t\t\tif ( devt->verbose )\n\t\t\t\tfprintf(stderr, \"rtlsdr_set_tuner_sideband(%d): tuner.set_sideband() returned error %d\\n\", sideband, r);\n\t\t\treturn r;\n\t\t}\n\t\tdevt->tuner_sideband = sideband;\n\n\t\tiffreq = (devt->tuner_sideband)\t/* -1 for USB; +1 for LSB */\n\t\t\t? ( devt->tuner_if_freq - devt->if_band_center_freq )\n\t\t\t: ( devt->tuner_if_freq + devt->if_band_center_freq );\n\t\tif ( devt->verbose ) {\n\t\t\tfprintf(stderr, \"rtlsdr_set_tuner_sideband(%d): rtlsdr_set_if_freq(%d) ..\\n\", sideband, iffreq);\n\t\t\tfprintf(stderr, \"rtlsdr_set_tuner_sideband(%d): iffreq = %d %c %d = %d\\n\", sideband,\n\t\t\t\tdevt->tuner_if_freq, (devt->tuner_sideband ? '-' : '+'), devt->if_band_center_freq,\n\t\t\t\tiffreq);\n\t\t}\n\t\tr = rtlsdr_set_if_freq(devt, iffreq );\n\t\tif (r)\n\t\t{\n\t\t\tif ( devt->verbose )\n\t\t\t\tfprintf(stderr, \"rtlsdr_set_tuner_sideband(%d): rtlsdr_set_if_freq(%d) returned error %d\\n\", sideband, iffreq, r);\n\t\t\treturn r;\n\t\t}\n\n\t\tif (!devt->freq)\n\t\t\treturn r;\n\t\tif (devt->verbose )\n\t\t\tfprintf(stderr, \"rtlsdr_set_tuner_sideband(%d): rtlsdr_set_center_freq64(%f MHz) ..\\n\", sideband, devt->freq * 1E-6);\n\t\tr = rtlsdr_set_center_freq64(devt, devt->freq);\n\t\tif (r && devt->verbose )\n\t\t\tfprintf(stderr, \"rtlsdr_set_tuner_sideband(%d): rtlsdr_set_center_freq(%f MHz) returned error %d\\n\", sideband, devt->freq * 1E-6, r);\n\n\t\treturn r;\n\t}\n\n\treturn r;\n}\n\nint rtlsdr_set_tuner_i2c_register(rtlsdr_dev_t *dev, unsigned i2c_register, unsigned mask /* byte */, unsigned data /* byte */ )\n{\n\tint r = 0;\n\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t\t/* TODO */\n\t\treturn -1;\n\t}\n\t#endif\n\n\tif (!dev || !dev->tuner)\n\t\treturn -1;\n\n\tif (dev->tuner->set_i2c_register) {\n\t\trtlsdr_set_i2c_repeater(dev, 1);\n\t\tr = dev->tuner->set_i2c_register((void *)dev, i2c_register, data, mask);\n\t\trtlsdr_set_i2c_repeater(dev, 0);\n\t}\n\treturn r;\n}\n\n/* -cs- */\nint rtlsdr_get_tuner_i2c_register(rtlsdr_dev_t *dev, unsigned char* data, int len)\n{\n\tint r = 0;\n\n\tif (!dev || !dev->tuner)\n\t\treturn -1;\n\n\tif (dev->tuner->get_i2c_register) {\n\t\trtlsdr_set_i2c_repeater(dev, 1);\n\t\tr = dev->tuner->get_i2c_reg_array((void *)dev, data, len);\n\t\trtlsdr_set_i2c_repeater(dev, 0);\n\t}\n\treturn r;\n}\n\n\nint rtlsdr_set_tuner_i2c_override(rtlsdr_dev_t *dev, unsigned i2c_register, unsigned mask /* byte */, unsigned data /* byte */ )\n{\n\tint r = 0;\n\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t\t/* TODO */\n\t\treturn -1;\n\t}\n\t#endif\n\n\tif (!dev || !dev->tuner)\n\t\treturn -1;\n\n\tif (dev->tuner->set_i2c_override) {\n\t\trtlsdr_set_i2c_repeater(dev, 1);\n\t\tr = dev->tuner->set_i2c_override((void *)dev, i2c_register, data, mask);\n\t\trtlsdr_set_i2c_repeater(dev, 0);\n\t}\n\treturn r;\n}\n\n\nint rtlsdr_set_sample_rate(rtlsdr_dev_t *dev, uint32_t samp_rate)\n{\n\tint r = 0;\n\tuint16_t tmp;\n\tuint32_t rsamp_ratio, real_rsamp_ratio;\n\tdouble real_rate;\n\n\t#if LOG_API_CALLS\n\tfprintf(stderr, \"LOG: rtlsdr_set_sample_rate(samp_rate %u)\\n\", (unsigned)samp_rate);\n\t#endif\n\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return rtlsdr_rpc_set_sample_rate(dev, samp_rate);\n\t}\n\t#endif\n\n\tif (!dev)\n\t\treturn -1;\n\n\t/* check if the rate is supported by the resampler */\n\tif ((samp_rate <= 225000) || (samp_rate > 3200000) ||\n\t\t ((samp_rate > 300000) && (samp_rate <= 900000))) {\n\t\tfprintf(stderr, \"Invalid sample rate: %u Hz\\n\", samp_rate);\n\t\treturn -EINVAL;\n\t}\n\n\trsamp_ratio = (dev->rtl_xtal * TWO_POW(22)) / samp_rate;\n\trsamp_ratio &= 0x0ffffffc;\n\n\treal_rsamp_ratio = rsamp_ratio | ((rsamp_ratio & 0x08000000) << 1);\n\treal_rate = (dev->rtl_xtal * TWO_POW(22)) / real_rsamp_ratio;\n\n\tif ( ((double)samp_rate) != real_rate )\n\t\tfprintf(stderr, \"Exact sample rate is: %f Hz\\n\", real_rate);\n\n\tdev->rate = (uint32_t)real_rate;\n\n\tif (dev->tuner && dev->tuner->set_bw) {\n\t\tuint32_t applied_bw = 0;\n\t\trtlsdr_set_i2c_repeater(dev, 1);\n\t\tdev->tuner->set_bw(dev, dev->bw > 0 ? dev->bw : dev->rate, &applied_bw, 1);\n\t\trtlsdr_set_i2c_repeater(dev, 0);\n\t}\n\n\ttmp = (rsamp_ratio >> 16);\n\tr |= rtlsdr_demod_write_reg(dev, 1, 0x9f, tmp, 2);\n\ttmp = rsamp_ratio & 0xffff;\n\tr |= rtlsdr_demod_write_reg(dev, 1, 0xa1, tmp, 2);\n\n\tr |= rtlsdr_set_sample_freq_correction(dev, dev->corr);\n\n\t/* reset demod (bit 3, soft_rst) */\n\tr |= rtlsdr_demod_write_reg(dev, 1, 0x01, 0x14, 1);\n\tr |= rtlsdr_demod_write_reg(dev, 1, 0x01, 0x10, 1);\n\n\t/* recalculate offset frequency if offset tuning is enabled */\n\tif (dev->offs_freq)\n\t\trtlsdr_set_offset_tuning(dev, 1);\n\n\tif ( reactivate_softagc(dev, SOFTSTATE_RESET) ) {\n\t\tdev->softagc.deadTimeSps = 0;\n\t\tdev->softagc.scanTimeSps = 0;\n\t}\n\n\treturn r;\n}\n\nuint32_t rtlsdr_get_sample_rate(rtlsdr_dev_t *dev)\n{\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return rtlsdr_rpc_get_sample_rate(dev);\n\t}\n\t#endif\n\n\tif (!dev)\n\t\treturn 0;\n\n\treturn dev->rate;\n}\n\nint rtlsdr_set_testmode(rtlsdr_dev_t *dev, int on)\n{\n\t#if LOG_API_CALLS\n\tfprintf(stderr, \"LOG: rtlsdr_set_testmode(on %d)\\n\", on);\n\t#endif\n\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return rtlsdr_rpc_set_testmode(dev, on);\n\t}\n\t#endif\n\n\tif (!dev)\n\t\treturn -1;\n\n\treturn rtlsdr_demod_write_reg(dev, 0, 0x19, on ? 0x03 : 0x05, 1);\n}\n\nint rtlsdr_set_agc_mode(rtlsdr_dev_t *dev, int on)\n{\n\t#if LOG_API_CALLS\n\tfprintf(stderr, \"LOG: rtlsdr_set_agc_mode(on %d for digital AGC in RTL2832)\\n\", on);\n\t#endif\n\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t\treturn rtlsdr_rpc_set_agc_mode(dev, on);\n\t}\n\t#endif\n\n\tif (!dev)\n\t\treturn -1;\n\n\treturn rtlsdr_demod_write_reg(dev, 0, 0x19, on ? 0x25 : 0x05, 1);\n}\n\nint rtlsdr_set_direct_sampling(rtlsdr_dev_t *dev, int on)\n{\n\tint r = 0;\n\n\t#if LOG_API_CALLS\n\tfprintf(stderr, \"LOG: rtlsdr_set_direct_sampling(on %d - 1 = I-ADC, 2 = Q-ADC)\\n\", on);\n\t#endif\n\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return rtlsdr_rpc_set_direct_sampling(dev, on);\n\t}\n\t#endif\n\n\tif (!dev)\n\t\treturn -1;\n\n\tif (on) {\n\t\tif (dev->tuner && dev->tuner->exit) {\n\t\t\trtlsdr_set_i2c_repeater(dev, 1);\n\t\t\tr = dev->tuner->exit(dev);\n\t\t\trtlsdr_set_i2c_repeater(dev, 0);\n\t\t}\n\n\t\t/* disable Zero-IF mode */\n\t\tr |= rtlsdr_demod_write_reg(dev, 1, 0xb1, 0x1a, 1);\n\n\t\t/* disable spectrum inversion */\n\t\tr |= rtlsdr_demod_write_reg(dev, 1, 0x15, 0x00, 1);\n\n\t\t/* only enable In-phase ADC input */\n\t\tr |= rtlsdr_demod_write_reg(dev, 0, 0x08, 0x4d, 1);\n\n\t\t/* swap I and Q ADC, this allows to select between two inputs */\n\t\tr |= rtlsdr_demod_write_reg(dev, 0, 0x06, (on > 1) ? 0x90 : 0x80, 1);\n\n\t\tfprintf(stderr, \"Enabled direct sampling mode, input %i\\n\", on);\n\t\tdev->direct_sampling = on;\n\t} else {\n\t\tif (dev->tuner && dev->tuner->init) {\n\t\t\trtlsdr_set_i2c_repeater(dev, 1);\n\t\t\tr |= dev->tuner->init(dev);\n\t\t\trtlsdr_set_i2c_repeater(dev, 0);\n\t\t}\n\n\t\tif ((dev->tuner_type == RTLSDR_TUNER_R820T) ||\n\t\t\t\t(dev->tuner_type == RTLSDR_TUNER_R828D)) {\n\t\t\tr |= rtlsdr_set_if_freq(dev, R82XX_IF_FREQ);\n\n\t\t\t/* enable spectrum inversion */\n\t\t\tr |= rtlsdr_demod_write_reg(dev, 1, 0x15, 0x01, 1);\n\t\t} else {\n\t\t\tr |= rtlsdr_set_if_freq(dev, 0);\n\n\t\t\t/* enable In-phase + Quadrature ADC input */\n\t\t\tr |= rtlsdr_demod_write_reg(dev, 0, 0x08, 0xcd, 1);\n\n\t\t\t/* Enable Zero-IF mode */\n\t\t\tr |= rtlsdr_demod_write_reg(dev, 1, 0xb1, 0x1b, 1);\n\t\t}\n\n\t\t/* opt_adc_iq = 0, default ADC_I/ADC_Q datapath */\n\t\tr |= rtlsdr_demod_write_reg(dev, 0, 0x06, 0x80, 1);\n\n\t\tfprintf(stderr, \"Disabled direct sampling mode\\n\");\n\t\tdev->direct_sampling = 0;\n\t}\n\n\tr |= rtlsdr_set_center_freq64(dev, dev->freq);\n\n\treturn r;\n}\n\nint rtlsdr_get_direct_sampling(rtlsdr_dev_t *dev)\n{\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return rtlsdr_rpc_get_direct_sampling(dev);\n\t}\n\t#endif\n \n\tif (!dev)\n\t\treturn -1;\n\n\treturn dev->direct_sampling;\n}\n\nint rtlsdr_set_ds_mode(rtlsdr_dev_t *dev, enum rtlsdr_ds_mode mode, uint32_t freq_threshold)\n{\n\tuint64_t center_freq;\n\tif (!dev)\n\t\treturn -1;\n\n\t#if LOG_API_CALLS\n\tfprintf(stderr, \"LOG: rtlsdr_set_ds_mode(mode %d, freq threshold %u Hz)\\n\",\n\t\t(int)mode, (unsigned)freq_threshold);\n\t#endif\n\n\tcenter_freq = rtlsdr_get_center_freq64(dev);\n\tif ( !center_freq )\n\t\treturn -2;\n\n\tif (!freq_threshold) {\n\t\tswitch(dev->tuner_type) {\n\t\tdefault:\n\t\tcase RTLSDR_TUNER_UNKNOWN:\tfreq_threshold = 28800000; break; /* no idea!!! */\n\t\tcase RTLSDR_TUNER_E4000:\tfreq_threshold = 50*1000000; break; /* E4K_FLO_MIN_MHZ */\n\t\tcase RTLSDR_TUNER_FC0012:\tfreq_threshold = 28800000; break; /* no idea!!! */\n\t\tcase RTLSDR_TUNER_FC0013:\tfreq_threshold = 28800000; break; /* no idea!!! */\n\t\tcase RTLSDR_TUNER_FC2580:\tfreq_threshold = 28800000; break; /* no idea!!! */\n\t\tcase RTLSDR_TUNER_R820T:\tfreq_threshold = 24000000; break; /* ~ */\n\t\tcase RTLSDR_TUNER_R828D:\tfreq_threshold = 28800000; break; /* no idea!!! */\n\t\t}\n\t}\n\n\tdev->direct_sampling_mode = mode;\n\tdev->direct_sampling_threshold = freq_threshold;\n\n\tif (mode <= RTLSDR_DS_Q)\n\t\trtlsdr_set_direct_sampling(dev, mode);\n\n\treturn rtlsdr_set_center_freq64(dev, center_freq);\n}\n\nstatic int rtlsdr_update_ds(rtlsdr_dev_t *dev, uint64_t freq)\n{\n\tint new_ds = 0;\n\tint curr_ds = rtlsdr_get_direct_sampling(dev);\n\tif ( curr_ds < 0 )\n\t\treturn -1;\n\n\tswitch (dev->direct_sampling_mode) {\n\tdefault:\n\tcase RTLSDR_DS_IQ:\t\tbreak;\n\tcase RTLSDR_DS_I:\t\tnew_ds = 1; break;\n\tcase RTLSDR_DS_Q:\t\tnew_ds = 2; break;\n\tcase RTLSDR_DS_I_BELOW:\tnew_ds = (freq < dev->direct_sampling_threshold) ? 1 : 0; break;\n\tcase RTLSDR_DS_Q_BELOW:\tnew_ds = (freq < dev->direct_sampling_threshold) ? 2 : 0; break;\n\t}\n\n\t//if ( dev->verbose )\n\t//\tfprintf(stderr, \"rtlsdr_update_ds(%u Hz) --> ds = %d for mode %s\\n\",\n\t//\t\tfreq, new_ds, dsmode_str[dev->direct_sampling_mode] );\n\n\tif ( curr_ds != new_ds )\n\t\treturn rtlsdr_set_direct_sampling(dev, new_ds);\n\n\treturn 0;\n}\n\nint rtlsdr_set_offset_tuning(rtlsdr_dev_t *dev, int on)\n{\n\tint r = 0;\n\tint bw;\n\n\t#if LOG_API_CALLS\n\tfprintf(stderr, \"LOG: rtlsdr_set_offset_tuning(on %d)\\n\", on);\n\t#endif\n\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return rtlsdr_rpc_set_offset_tuning(dev, on);\n\t}\n\t#endif\n\n\tif (!dev)\n\t\treturn -1;\n\n\tif ((dev->tuner_type == RTLSDR_TUNER_R820T) ||\n\t\t\t(dev->tuner_type == RTLSDR_TUNER_R828D))\n\t\treturn -2;\n\n\tif (dev->direct_sampling)\n\t\treturn -3;\n\n\t/* based on keenerds 1/f noise measurements */\n\tdev->offs_freq = on ? ((dev->rate / 2) * 170 / 100) : 0;\n\tr |= rtlsdr_set_if_freq(dev, dev->offs_freq);\n\n\tif (dev->tuner && dev->tuner->set_bw) {\n\t\tuint32_t applied_bw = 0;\n\t\trtlsdr_set_i2c_repeater(dev, 1);\n\t\tif (on) {\n\t\t\tbw = 2 * dev->offs_freq;\n\t\t} else if (dev->bw > 0) {\n\t\t\tbw = dev->bw;\n\t\t} else {\n\t\t\tbw = dev->rate;\n\t\t}\n\t\tdev->tuner->set_bw(dev, bw, &applied_bw, 1);\n\t\trtlsdr_set_i2c_repeater(dev, 0);\n\t}\n\n\tif (dev->freq > dev->offs_freq)\n\t\tr |= rtlsdr_set_center_freq64(dev, dev->freq);\n\n\treturn r;\n}\n\nint rtlsdr_get_offset_tuning(rtlsdr_dev_t *dev)\n{\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return rtlsdr_rpc_get_offset_tuning(dev);\n\t}\n\t#endif\n\n\tif (!dev)\n\t\treturn -1;\n\n\treturn (dev->offs_freq) ? 1 : 0;\n}\n\nint rtlsdr_set_dithering(rtlsdr_dev_t *dev, int dither)\n{\n\tif (dev->tuner_type == RTLSDR_TUNER_R820T) {\n\t\treturn r82xx_set_dither(&dev->r82xx_p, dither);\n\t}\n\treturn 1;\n}\n\nstatic rtlsdr_dongle_t *find_known_device(uint16_t vid, uint16_t pid)\n{\n\tunsigned int i;\n\trtlsdr_dongle_t *device = NULL;\n\n\tfor (i = 0; i < sizeof(known_devices)/sizeof(rtlsdr_dongle_t); i++ ) {\n\t\tif (known_devices[i].vid == vid && known_devices[i].pid == pid) {\n\t\t\tdevice = &known_devices[i];\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn device;\n}\n\nuint32_t rtlsdr_get_device_count(void)\n{\n\tint i,r;\n\tlibusb_context *ctx;\n\tlibusb_device **list;\n\tuint32_t device_count = 0;\n\tstruct libusb_device_descriptor dd;\n\tssize_t cnt;\n\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return rtlsdr_rpc_get_device_count();\n\t}\n\t#endif\n\n\tr = libusb_init(&ctx);\n\tif(r < 0)\n\t\treturn 0;\n\n\tcnt = libusb_get_device_list(ctx, &list);\n\n\tfor (i = 0; i < cnt; i++) {\n\t\tlibusb_get_device_descriptor(list[i], &dd);\n\n\t\tif (find_known_device(dd.idVendor, dd.idProduct))\n\t\t\tdevice_count++;\n\t}\n\n\tlibusb_free_device_list(list, 1);\n\n\tlibusb_exit(ctx);\n\n\treturn device_count;\n}\n\nconst char *rtlsdr_get_device_name(uint32_t index)\n{\n\tint i,r;\n\tlibusb_context *ctx;\n\tlibusb_device **list;\n\tstruct libusb_device_descriptor dd;\n\trtlsdr_dongle_t *device = NULL;\n\tuint32_t device_count = 0;\n\tssize_t cnt;\n\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return rtlsdr_rpc_get_device_name(index);\n\t}\n\t#endif\n\n\tr = libusb_init(&ctx);\n\tif(r < 0)\n\t\treturn \"\";\n\n\tcnt = libusb_get_device_list(ctx, &list);\n\n\tfor (i = 0; i < cnt; i++) {\n\t\tlibusb_get_device_descriptor(list[i], &dd);\n\n\t\tdevice = find_known_device(dd.idVendor, dd.idProduct);\n\n\t\tif (device) {\n\t\t\tdevice_count++;\n\n\t\t\tif (index == device_count - 1)\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tlibusb_free_device_list(list, 1);\n\n\tlibusb_exit(ctx);\n\n\tif (device)\n\t\treturn device->name;\n\telse\n\t\treturn \"\";\n}\n\nint rtlsdr_get_device_usb_strings(uint32_t index, char *manufact,\n\t\t\t\t\t char *product, char *serial)\n{\n\tint r = -2;\n\tint i;\n\tlibusb_context *ctx;\n\tlibusb_device **list;\n\tstruct libusb_device_descriptor dd;\n\trtlsdr_dongle_t *device = NULL;\n\trtlsdr_dev_t devt;\n\tuint32_t device_count = 0;\n\tssize_t cnt;\n\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return rtlsdr_rpc_get_device_usb_strings\n\t    (index, manufact, product, serial);\n\t}\n\t#endif\n\n\tr = libusb_init(&ctx);\n\tif(r < 0)\n\t\treturn r;\n\n\tcnt = libusb_get_device_list(ctx, &list);\n\n\tfor (i = 0; i < cnt; i++) {\n\t\tlibusb_get_device_descriptor(list[i], &dd);\n\n\t\tdevice = find_known_device(dd.idVendor, dd.idProduct);\n\n\t\tif (device) {\n\t\t\tdevice_count++;\n\n\t\t\tif (index == device_count - 1) {\n\t\t\t\tr = libusb_open(list[i], &devt.devh);\n\t\t\t\tif (!r) {\n\t\t\t\t\tr = rtlsdr_get_usb_strings(&devt,\n\t\t\t\t\t\t\t\t\t manufact,\n\t\t\t\t\t\t\t\t\t product,\n\t\t\t\t\t\t\t\t\t serial);\n\t\t\t\t\tlibusb_close(devt.devh);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tlibusb_free_device_list(list, 1);\n\n\tlibusb_exit(ctx);\n\n\treturn r;\n}\n\nint rtlsdr_get_index_by_serial(const char *serial)\n{\n\tint i, cnt, r;\n\tchar str[256];\n\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return rtlsdr_rpc_get_index_by_serial(serial);\n\t}\n\t#endif\n\n\tif (!serial)\n\t\treturn -1;\n\n\tcnt = rtlsdr_get_device_count();\n\n\tif (!cnt)\n\t\treturn -2;\n\n\tfor (i = 0; i < cnt; i++) {\n\t\tr = rtlsdr_get_device_usb_strings(i, NULL, NULL, str);\n\t\tif (!r && !strcmp(serial, str))\n\t\t\treturn i;\n\t}\n\n\treturn -3;\n}\n\n/* UDP controller server */\n#ifdef WITH_UDP_SERVER\n\nstatic int parseNum(const char * pacNum) {\n\tint numBase = 10;\t\t\t/* assume decimal */\n\tint sgn = 1;\t\t\t\t/* sign: +/- 1 */\n\tint val = 0;\n\tconst char * pac = pacNum + 1;\n\tif ( !pacNum || !pacNum[0] )\n\t\treturn 0;\n\n\tif ( pacNum[0] == 'd' )\t\t\t/* decimal system */\n\t\tnumBase = 10;\n\telse if ( pacNum[0] == 'x' )\t\t/* hexadecimal system */\n\t\tnumBase = 16;\n\telse if ( pacNum[0] == 'b' )\t/* binary system */\n\t\tnumBase = 2;\n\telse\n\t\tpac = pacNum;\n\n\tif ( *pac == '-' ) {\n\t\tsgn = -1;\n\t\t++pac;\n\t}\n\n\twhile ( *pac )\n\t{\n\t\tint digitValue = ( '0' <= *pac && *pac <= '9' ) ? (*pac - '0')\n\t\t\t: ( 'A' <= *pac && *pac <= 'F' ) ? (*pac + 10 - 'A') : (*pac + 10 - 'a');\n\t\tif ( digitValue >= 0 && digitValue < numBase ) {\n\t\t\tval = val * numBase + digitValue;\n\t\t\t++pac;\n\t\t\tcontinue;\n\t\t}\n\t\telse if ( *pac == '\\'' || *pac == '.' || *pac == '_' ) {\t/* ignore some delimiter chars */\n\t\t\t++pac;\n\t\t\tcontinue;\n\t\t}\n\t\telse\n\t\t\tbreak;\n\t}\n\n\treturn val * sgn;\n}\n\n#endif\n\nstatic double parseFreq(char *s)\n/* standard suffixes */\n{\n\tchar last;\n\tint len;\n\tdouble suff = 1.0;\n\tlen = strlen(s);\n\t/* allow formatting spaces from .csv command file */\n\twhile ( len > 1 && isspace(s[len-1]) )\t--len;\n\tlast = s[len-1];\n\ts[len-1] = '\\0';\n\tswitch (last) {\n\t\tcase 'g':\n\t\tcase 'G':\n\t\t\tsuff *= 1e3;\n\t\t\t/* fall-through */\n\t\tcase 'm':\n\t\tcase 'M':\n\t\t\tsuff *= 1e3;\n\t\t\t/* fall-through */\n\t\tcase 'k':\n\t\tcase 'K':\n\t\t\tsuff *= 1e3;\n\t\t\tsuff *= atof(s);\n\t\t\ts[len-1] = last;\n\t\t\treturn suff;\n\t}\n\ts[len-1] = last;\n\treturn atof(s);\n}\n\n/* UDP controller server */\n#ifdef WITH_UDP_SERVER\n\nstatic const char * formatInHex(char * buf, int v, int num_digits) {\n\tstatic const char tab[] = \"0123456789ABCDEF\";\n\tint nibbleVal, nibbleNo, off = 0;\n\tbuf[off++] = 'x';\n\tfor ( nibbleNo = num_digits -1; nibbleNo >= 0; --nibbleNo ) {\n\t\tif ( (nibbleNo % 4) == 3 && nibbleNo != num_digits -1 )\n\t\t\tbuf[off++] = '\\'';\n\t\tnibbleVal = ( ((uint32_t)v) >> (nibbleNo * 4) ) & 0x0f;\n\t\tbuf[off++] = tab[nibbleVal];\n\t}\n\tbuf[off++] = 0;\n\treturn buf;\n}\n\nstatic const char * formatInBin(char * buf, int v, int num_digits) {\n\tstatic const char tab[] = \"01\";\n\tint bitVal, bitNo, off = 0;\n\tbuf[off++] = 'b';\n\tfor ( bitNo = num_digits -1; bitNo >= 0; --bitNo ) {\n\t\tif ( (bitNo % 4) == 3 && bitNo != num_digits -1 )\n\t\t\tbuf[off++] = '\\'';\n\t\tbitVal = ( ((uint32_t)v) >> bitNo ) & 1;\n\t\tbuf[off++] = tab[bitVal];\n\t}\n\tbuf[off++] = 0;\n\treturn buf;\n}\n\nstatic int parse(char *message, rtlsdr_dev_t *dev)\n{\n\tchar binBufA[64], binBufB[64];\n\tchar hexBufA[16], hexBufB[16];\n\tchar *str1, *token, *saveptr;\n\tchar response[UDP_TX_BUFLEN];\n\tdouble freqVal = -1;\n\tint comm = 0, parsedVal = 0, iVal = 0;\n\tint val = 0;\n\tuint32_t applied_bw = 0;\n\tuint8_t mask = 0xff, reg=0;\n\tuint32_t freq;\n\tuint64_t freq64;\n\tint32_t bandcenter;\n\tint sideband;\n\tint retCode;\n\n\tstr1 = message;\n\tmemset(response,'\\0', UDP_TX_BUFLEN);\n\n\tstr1[100] = 0;\n\tstr1[strlen(str1)-1] = 0;\n\n\t/* first token == command */\n\ttoken = strtok_r(str1, \" \\t\", &saveptr);\n\tif ( !token )\n\t{\n\t\tsprintf(response,\"?\\n\");\n\t\tsendto(dev->udpS, response, strlen(response), 0, (struct sockaddr*) &dev->si_other, dev->slen);\n\t\treturn 0;\n\t}\n\n\t/* commands:\n\t * g <register>            # get tuner i2c register\n\t * s <register> <value> [<mask>] # set tuner i2c register once\n\t * S <register> <value> [<mask>] # set tuner i2c register permanent\n\t * \n\t * i <IFfrequency>         # set tuner IF frequency once. value in [ 0 .. 28 800 000 ] or < 0 for reset\n\t * I <IFfrequency>         # set tuner IF frequency permanent\n\t * \n\t * f <RFfrequency>         # set rtl center frequency\n\t * b <bandwidth>           # set tuner bandwidth\n\t * c <frequency>           # set tuner bandwidth center in output. value in [ -1 600 000 .. 1 600 000 ]\n\t * v <sideband>            # set tuner sideband inversion\n\t *\n\t * a <tunerIFmode>         #  0: VGA = auto\n\t *                         #  g in -5000 .. +5000: VGA = g / 10 dB\n\t *                         # 10000+x: VGA idx = x\n\t * m <gain>                # set tuner gain\n\t * \n\t * M <gainMode>            # 0 : tuner agc off; digital rtl agc off\n\t *                         # 1 : tuner agc on ; digital rtl agc off\n\t *                         # 2 : tuner agc off; digital rtl agc on\n\t *                         # 3 : tuner agc on ; digital rtl agc on\n\t * \n\t * \n\t * ********** not implemented yet\n\t * \n\t * e <lna> <mixer> <vga>   # set extended tuner gain - for R820 tuner\n\n\t * RTLSDR_API int rtlsdr_set_tuner_gain_mode(rtlsdr_dev_t *dev, int manual);\n\t * RTLSDR_API int rtlsdr_set_agc_mode(rtlsdr_dev_t *dev, int on);\n\t * \n\t * RTLSDR_API int rtlsdr_set_tuner_gain_ext(rtlsdr_dev_t *dev, int lna_gain, int mixer_gain, int vga_gain);\n\t * RTLSDR_API int rtlsdr_get_tuner_gain(rtlsdr_dev_t *dev);\n\t * RTLSDR_API int rtlsdr_set_tuner_gain(rtlsdr_dev_t *dev, int gain);\n\t * \n\t */\n\n\t/* commands with register args: 64 | x */\n\tif (!strcmp(token, \"g\")) comm = 64 + 1;\n\tif (!strcmp(token, \"s\")) comm = 64 + 2;\n\tif (!strcmp(token, \"S\")) comm = 64 + 3;\n\tif (!strcmp(token, \"i\")) comm = 128 + 1;\n\tif (!strcmp(token, \"I\")) comm = 128 + 2;\n\tif (!strcmp(token, \"f\")) comm = 256 + 1;\n\tif (!strcmp(token, \"b\")) comm = 256 + 2;\n\tif (!strcmp(token, \"c\")) comm = 256 + 3;\n\tif (!strcmp(token, \"v\")) comm = 256 + 4;\n\tif (!strcmp(token, \"a\")) comm = 512 + 1;\n\tif (!strcmp(token, \"m\")) comm = 512 + 2;\n\tif (!strcmp(token, \"M\")) comm = 512 + 3;\n\tif (!strcmp(token, \"h\")) comm = 1024;\n\n\tif ( comm & 64 ) {\n\t\ttoken = strtok_r(NULL, \" \\t\", &saveptr);\n\t\tparsedVal = parseNum(token);\n\t\tif ( (!token) || (comm >= (64+2) && parsedVal < 5) || (parsedVal > 32) ) {\n\t\t\tsprintf(response,\"?\\n\");\n\t\t\tif (sendto(dev->udpS, response, strlen(response), 0, (struct sockaddr*) &dev->si_other, dev->slen) == SOCKET_ERROR) {\n\t\t\t\t/* perror(\"send\"); */\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\treturn 0;\n\t\t}\n\t\treg = (uint8_t)parsedVal;\t/* 1st arg: register address */\n\t\tif ( dev->verbose && PRINT_UDP_SRV_MSGS )\n\t\t\tfprintf(stderr, \"parsed register %d from token '%s'\\n\", reg, token);\n\n\t\tif (token)\n\t\t\ttoken = strtok_r(NULL, \" \\t\", &saveptr);\n\t\tif ( (!token) && (comm >= 64+2)) {\t/* set requires additional parameter: the value */\n\t\t\tsprintf(response,\"?\\n\");\n\t\t\tif (sendto(dev->udpS, response, strlen(response), 0, (struct sockaddr*) &dev->si_other, dev->slen) == SOCKET_ERROR) {\n\t\t\t\t/* perror(\"send\"); */\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\treturn 0;\n\t\t} else if (comm >= 64+2) {\n\t\t\tparsedVal = parseNum(token);\t\t/* set: 2nd arg: value */\n\t\t\tiVal = parsedVal;\n\t\t\tif ( dev->verbose && PRINT_UDP_SRV_MSGS )\n\t\t\t\tfprintf(stderr, \"parsed value %d = %03X from token '%s'\\n\", iVal, iVal, token);\n\t\t}\n\n\t\tif (token)\n\t\t\ttoken = strtok_r(NULL, \" \\t\", &saveptr);\n\t\tif (!token) {\n\t\t\tmask = 0xff;\t\t/* default mask */\n\t\t} else  {\n\t\t\tparsedVal = parseNum(token);\t\t/* set: 3rd optional arg: mask */\n\t\t\tmask = (uint8_t)( parsedVal & 0xff );\n\t\t\tif ( dev->verbose && PRINT_UDP_SRV_MSGS )\n\t\t\t\tfprintf(stderr, \"parsed mask %d = %02X from token '%s'\\n\", parsedVal, parsedVal, token);\n\t\t}\n\n\t\tif (comm == 64 + 1) {\n\t\t\tval = dev->tuner->get_i2c_register(dev, reg);\n\t\t\tsprintf(response,\"! %d = %s = %s\\n\", val\n\t\t\t\t, formatInHex(hexBufA, val, 2)\n\t\t\t\t, formatInBin(binBufA, val, 8) );\n\t\t\tif ( dev->verbose && PRINT_UDP_SRV_MSGS )\n\t\t\t{\n\t\t\t\tfprintf(stderr, \"parsed 'get i2c register %d = x%02X'\\n\", reg, reg);\n\t\t\t\tfprintf(stderr, \"\\tresponse: %s\\n\", response);\n\t\t\t}\n\t\t\tval = sendto(dev->udpS, response, strlen(response), 0, (struct sockaddr*) &dev->si_other, dev->slen);\n\t\t\tif (val<0) {\n\t\t\t\t/* printf(\"error sending\\n\"); */\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t} else if (comm == 64 +2 || comm == 64 +3 ) {\n\t\t\tif ( dev->verbose && PRINT_UDP_SRV_MSGS )\n\t\t\t{\n\t\t\t\tfprintf(stderr, \"parsed 'set i2c register %s %d = x%02X  value %d = %s = %s  with mask %s = %s'\\n\"\n\t\t\t\t\t\t, ( comm == (64 +3) ? (iVal > 255 ? \"override clear \" : \"override \") : \"\" )\n\t\t\t\t\t\t, reg, reg\n\t\t\t\t\t\t, val, formatInHex(hexBufA, iVal, 3), formatInBin(binBufA, iVal, 12)\n\t\t\t\t\t\t, formatInHex(hexBufB, (int)mask, 2), formatInBin(binBufB, (int)mask, 8) );\n\t\t\t\tfprintf(stderr, \"\\tresponse: %s\\n\", response);\n\t\t\t}\n\t\t\tif ( dev->tuner->set_i2c_register && dev->tuner->set_i2c_override ) {\n\t\t\t\trtlsdr_set_i2c_repeater(dev, 1);\n\t\t\t\tif (comm == 64 +2) {\n\t\t\t\t\tif (PRINT_UDP_SRV_MSGS)\n\t\t\t\t\t\tfprintf(stderr, \"calling tuner->set_i2c_register( reg %d, value %02X, mask %02X)\\n\", reg, iVal, mask);\n\t\t\t\t\tval = dev->tuner->set_i2c_register(dev, reg, iVal, mask);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (PRINT_UDP_SRV_MSGS)\n\t\t\t\t\t\tfprintf(stderr, \"calling tuner->set_i2c_override( reg %d, value %02X, mask %02X)\\n\", reg, iVal, mask);\n\t\t\t\t\tval = dev->tuner->set_i2c_override(dev, reg, iVal, mask);\n\t\t\t\t}\n\t\t\t\trtlsdr_set_i2c_repeater(dev, 0);\n\t\t\t}\n\t\t\tsprintf(response,\"! %d\\n\", (int)val);\n\t\t\t/* printf(\"%d %d %d\\n\", reg, val, mask); */\n\t\t\tval = sendto(dev->udpS, response, strlen(response), 0, (struct sockaddr*) &dev->si_other, dev->slen);\n\t\t\tif ( val < 0 ) {\n\t\t\t\t/* printf(\"error sending\\n\"); */\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t} else {\n\t\t\tsprintf(response,\"?\\n\");\n\t\t\tif ( dev->verbose && PRINT_UDP_SRV_MSGS )\n\t\t\t{\n\t\t\t\tfprintf(stderr, \"parsed unknown command!\\n\");\n\t\t\t\tfprintf(stderr, \"\\tresponse: %s\\n\", response);\n\t\t\t}\n\t\t\tsendto(dev->udpS, response, strlen(response), 0, (struct sockaddr*) &dev->si_other, dev->slen);\n\t\t}\n\t}\n\telse if ( comm & 128 ) {\n\t\ttoken = strtok_r(NULL, \" \\t\", &saveptr);\n\t\tfreqVal = parseFreq(token);\n\t\tif ( freqVal < 0 ) {\n\t\t\tdev->override_if_freq = 0;\n\t\t\tdev->override_if_flag = 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdev->override_if_freq = (int)freqVal;\n\t\t\tdev->override_if_flag = ( comm == (128 + 1) ) ? 1 : 2;\n\t\t}\n\t\t/* set last bandwidth .. which also has to set the IF frequency */\n\t\trtlsdr_set_and_get_tuner_bandwidth(dev, dev->bw, &applied_bw, 1 );\n\t\trtlsdr_set_center_freq64(dev, dev->freq);\n\t}\n\telse if ( comm & 256 ) {\n\t\ttoken = strtok_r(NULL, \" \\t\", &saveptr);\n\t\tfreqVal = parseFreq(token);\n\t\tretCode = -1;\n\t\tswitch (comm & 63) {\n\t\tcase 1: /* frequency */\n\t\t\tfreq64 = (uint64_t)(freqVal + 0.5);\n\t\t\tif ( dev->verbose && PRINT_UDP_SRV_MSGS )\n\t\t\t\tfprintf(stderr, \"parsed RF frequency = %f MHz from token '%s'\\n\", freq64 * 1E-6, token);\n\t\t\tretCode = rtlsdr_set_center_freq64(dev, freq64);\n\t\t\tif ( dev->verbose && PRINT_UDP_SRV_MSGS )\n\t\t\t\tfprintf(stderr, \"  rtlsdr_set_center_freq() returned %d\\n\", retCode);\n\t\t\tbreak;\n\t\tcase 2: /* bandwidth */\n\t\t\tfreq = (uint32_t)freqVal;\n\t\t\tif ( dev->verbose && PRINT_UDP_SRV_MSGS )\n\t\t\t\tfprintf(stderr, \"parsed bandwidth = %u Hz from token '%s'\\n\", (unsigned)freq, token);\n\t\t\tretCode = rtlsdr_set_and_get_tuner_bandwidth(dev, freq, &applied_bw, 1);\n\t\t\tif ( dev->verbose && PRINT_UDP_SRV_MSGS )\n\t\t\t\tfprintf(stderr, \"  rtlsdr_set_and_get_tuner_bandwidth() returned %d and bw %u\\n\", retCode, applied_bw);\n\t\t\tbreak;\n\t\tcase 3: /* band center */\n\t\t\tbandcenter = (int32_t)freqVal;\n\t\t\tif ( dev->verbose && PRINT_UDP_SRV_MSGS )\n\t\t\t\tfprintf(stderr, \"parsed bandcenter = %d Hz from token '%s'\\n\", (int)bandcenter, token);\n\t\t\tretCode = rtlsdr_set_tuner_band_center(dev, bandcenter);\n\t\t\tif ( dev->verbose && PRINT_UDP_SRV_MSGS )\n\t\t\t\tfprintf(stderr, \"  rtlsdr_set_tuner_band_center() returned %d\\n\", retCode);\n\t\t\tbreak;\n\t\tcase 4: /* sideband */\n\t\t\tsideband = (int32_t)freqVal;\n\t\t\tif ( dev->verbose && PRINT_UDP_SRV_MSGS )\n\t\t\t\tfprintf(stderr, \"parsed sideband = %d = %s from token '%s'\\n\",\n\t\t\t\t\tsideband, (sideband ? \"USB\" : \"LSB\"), token);\n\t\t\tretCode = rtlsdr_set_tuner_sideband(dev, sideband);\n\t\t\tif ( dev->verbose && PRINT_UDP_SRV_MSGS )\n\t\t\t\tfprintf(stderr, \"  rtlsdr_set_tuner_sideband() returned %d\\n\", retCode);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\t}\n\telse if ( comm & 512 ) {\n\t\ttoken = strtok_r(NULL, \" \\t\", &saveptr);\n\t\tparsedVal = parseNum(token);\n\t\tif ( !token ) {\n\t\t\tsprintf(response,\"?\\n\");\n\t\t\tif (sendto(dev->udpS, response, strlen(response), 0, (struct sockaddr*) &dev->si_other, dev->slen) == SOCKET_ERROR) {\n\t\t\t\t/* perror(\"send\"); */\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\treturn 0;\n\t\t}\n\t\tswitch (comm & 63) {\n\t\tcase 1: /* agc variant */\n\t\t\tif ( dev->verbose && PRINT_UDP_SRV_MSGS )\n\t\t\t\tfprintf(stderr, \"parsed if mode %d from token '%s'\\n\", parsedVal, token);\n\t\t\tretCode = rtlsdr_set_tuner_if_mode(dev, parsedVal);\n\t\t\tif ( dev->verbose && PRINT_UDP_SRV_MSGS )\n\t\t\t\tfprintf(stderr, \"  rtlsdr_set_tuner_if_mode() returned %d\\n\", retCode);\n\t\t\tbreak;\n\t\tcase 2: /* manual gain */\n\t\t\tif ( dev->verbose && PRINT_UDP_SRV_MSGS )\n\t\t\t\tfprintf(stderr, \"parsed tuner gain %d tenth dB from token '%s'\\n\", parsedVal, token);\n\t\t\tretCode = rtlsdr_set_tuner_gain(dev, parsedVal);\n\t\t\tif ( dev->verbose && PRINT_UDP_SRV_MSGS )\n\t\t\t\tfprintf(stderr, \"  rtlsdr_set_tuner_gain() returned %d\\n\", retCode);\n\t\t\tbreak;\n\t\tcase 3: /* gainMode */\n\t\t\tif ( dev->verbose && PRINT_UDP_SRV_MSGS )\n\t\t\t\tfprintf(stderr, \"parsed gainMode %d with tuner AGC '%s' and RTL AGC '%s' from token '%s'\\n\"\n\t\t\t\t\t\t, parsedVal\n\t\t\t\t\t\t, ( (parsedVal & 1) == 1 ) ? \"on\" : \"off\"\n\t\t\t\t\t\t, ( (parsedVal & 2) == 2 ) ? \"on\" : \"off\"\n\t\t\t\t\t\t, token );\n\t\t\tretCode = rtlsdr_set_tuner_gain_mode(dev, ( (parsedVal & 1) == 0 ) ? 1 : 0 );\n\t\t\tif ( dev->verbose && PRINT_UDP_SRV_MSGS )\n\t\t\t\tfprintf(stderr, \"  rtlsdr_set_tuner_gain_mode() returned %d\\n\", retCode);\n\t\t\tretCode = rtlsdr_set_agc_mode(dev, ( (parsedVal & 2) == 2 ) ? 1 : 0 );\n\t\t\tif ( dev->verbose && PRINT_UDP_SRV_MSGS )\n\t\t\t\tfprintf(stderr, \"  rtlsdr_set_agc_mode() returned %d\\n\", retCode);\n\t\t\tbreak;\n\t\t}\n\t}\n\telse if ( comm & 1024 ) {\n\t\tsprintf(response,\n\t\t\t\"g <register>                  # get content of I2C ..\\n\"\n\t\t\t\"s <register> <value> [<mask>] # set conten\\n\"\n\t\t\t\"S <register> <value> [<mask>] # set content - keeping value in future\\n\"\n\t\t\t\"i <IFfrequency>  # set IF frequency [0 .. 28'800'000]\\n\"\n\t\t\t\"f <RFfrequency>  # set center frequency\\n\"\n\t\t\t\"b <bandwidth>    # set tuner bandwidth\\n\"\n\t\t\t\"c <frequency>    # set tuner bw center in output [-1'600'000 .. 1'600'000]\\n\"\n\t\t\t\"v <sideband>     # set tuner sideband: 0 for LSB, 1 for USB\\n\"\n\t\t\t\"a <tunerIFmode>  # set VGA: 0 for auto; in tenth dB or 10000+idx\\n\"\n\t\t\t\"m <tuner gain>   # set tuner gain\\n\"\n\t\t\t\"M <gainMode>     # 0 .. 3: digital rtl agc (0..1) * 2 + tuner agc (0..1)\\n\" );\n\t\tsendto(dev->udpS, response, strlen(response), 0, (struct sockaddr*) &dev->si_other, dev->slen);\n\t\tif (PRINT_UDP_SRV_MSGS)\n\t\t\tfprintf(stderr, \"udp server command help:\\n%s\\n\", response);\n\t}\n\n\t{\n\t\tsprintf(response,\"?\\n\");\n\t\tsendto(dev->udpS, response, strlen(response), 0, (struct sockaddr*) &dev->si_other, dev->slen);\n\t}\n\treturn 0;\n}\n\nvoid * srv_server(void *vdev)\n{\n\tint ret;\n\trtlsdr_dev_t * dev = (rtlsdr_dev_t *)vdev;\n\tdev->slen = sizeof(dev->si_other);\n\n#ifdef _WIN32\n\t/* Initialise winsock */\n\tif (WSAStartup(MAKEWORD(2,2),&dev->wsa) != 0) {\n\t\tfprintf(stderr, \"Failed to initialize WinSock; continue without UDP server. Error Code : %d\\n\",LAST_SOCK_ERROR());\n\t\treturn NULL;\n\t}\n#endif\n\t/* Create a socket */\n\tdev->udpS = socket(AF_INET , SOCK_DGRAM , IPPROTO_UDP );\n\tif(dev->udpS == INVALID_SOCKET) {\n\t\tfprintf(stderr, \"Could not create socket for UDP server : %d\\n\" , LAST_SOCK_ERROR());\n\t\treturn NULL;\n\t}\n\n\tmemset(&dev->server,0,sizeof(dev->server));\n\tdev->server.sin_family = AF_INET;\n\tdev->server.sin_addr.s_addr = INADDR_ANY;\n\tdev->server.sin_port = htons( dev->udpPortNo );\n\n\tret = bind(dev->udpS, (struct sockaddr *)&dev->server , sizeof(dev->server));\n\tif(ret == SOCKET_ERROR) {\n\t\tfprintf(stderr, \"Bind failed for UDP server with error code : %d\\n\" , LAST_SOCK_ERROR());\n\t\tclosesocket(dev->udpS);\n\t\treturn NULL;\n\t}\n\n\t/* keep listening for data */\n\twhile(1) {\n\t\t/* clear the buffer by filling null, it might have previously received data */\n\t\tmemset(dev->buf,'\\0', UDP_TX_BUFLEN);\n\t\t/* try to receive some data, this is a blocking call */\n\t\tdev->recv_len = recvfrom(dev->udpS, dev->buf, UDP_TX_BUFLEN-1, 0, (struct sockaddr *) &dev->si_other, &dev->slen);\n\t\tif (dev->recv_len == SOCKET_ERROR) {\n\t\t\tfprintf(stderr, \"recvfrom() for UDP server failed with error code %d. Shutting down UDP server.\\n\" , LAST_SOCK_ERROR());\n\t\t\tbreak;\n\t\t}\n\n\t\tif ( dev->verbose )\n\t\t\tfprintf(stderr, \"received udp: %s\\n\", dev->buf);\n\t\tparse( dev->buf, dev );\n\t\t/* print details of the client/peer and the data received */\n\t\t/* printf(\"Received packet from %s:%d\\n\", inet_ntoa(si_other.sin_addr), ntohs(si_other.sin_port)); */\n\t\t/* printf(\"Data: %s\\n\" , buf); */\n\t}\n\tclosesocket(dev->udpS);\n#ifdef _WIN32\n\t/* application might still use WinSock! */\n\t/* WSACleanup(); */\n#endif\n\treturn NULL;\n}\n\n#endif\n\n/* Returns true if the manufact_check and product_check strings match what is in the dongles EEPROM */\nint rtlsdr_check_dongle_model(void *dev, char *manufact_check, char *product_check) {\n\tif ((strcmp(((rtlsdr_dev_t *)dev)->manufact, manufact_check) == 0 && strcmp(((rtlsdr_dev_t *)dev)->product, product_check) == 0))\n\t{\n\t\treturn 1;\n\t}\n\n\treturn 0;\n}\n\nint rtlsdr_open(rtlsdr_dev_t **out_dev, uint32_t index)\n{\n\tint r;\n\tint i;\n\tlibusb_device **list;\n\trtlsdr_dev_t *dev = NULL;\n\tlibusb_device *device = NULL;\n\tuint32_t device_count = 0;\n\tstruct libusb_device_descriptor dd;\n\tuint8_t reg;\n\tssize_t cnt;\n\n\t#if LOG_API_CALLS\n\tfprintf(stderr, \"LOG: rtlsdr_open(%u)\\n\", (unsigned)index);\n\t#endif\n\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return rtlsdr_rpc_open((void**)out_dev, index);\n\t}\n\t#endif\n\n\tdev = malloc(sizeof(rtlsdr_dev_t));\n\tif (NULL == dev)\n\t\treturn -ENOMEM;\n\n\tmemset(dev, 0, sizeof(rtlsdr_dev_t));\n\tmemcpy(dev->fir, fir_default, sizeof(fir_default));\n\n\tr = libusb_init(&dev->ctx);\n\tif(r < 0){\n\t\tfree(dev);\n\t\treturn -1;\n\t}\n\n\tpthread_mutexattr_init(&dev->cs_mutex_attr);\n\tpthread_mutexattr_settype(&dev->cs_mutex_attr, PTHREAD_MUTEX_RECURSIVE);\n\tpthread_mutex_init(&dev->cs_mutex, &dev->cs_mutex_attr);\n\n\tdev->rtl_vga_control = 0;\n\tdev->biast_gpio_pin_no = 0;\n\tdev->gpio_state_known = 0;\n\tdev->gpio_state = 0;\n\tdev->called_set_opt = 0;\n\n\tdev->r82xx_c.harmonic = 0;\n\n\t/* fprintf(stderr, \"\\n*********************************\\ninit/overwrite tuner VCO settings\\n\"); */\n\tdev->r82xx_c.vco_curr_min = 0xff;  /* VCO min/max current for R18/0x12 bits [7:5] in 0 .. 7. use 0xff for default */\n\tdev->r82xx_c.vco_curr_max = 0xff;  /* value is inverted: programmed is 7-value, that 0 is lowest current */\n\tdev->r82xx_c.vco_algo = 0x00;\n\tdev->r82xx_c.verbose = 0;\n\n\t/* dev->softagc.command_thread; */\n\tdev->softagc.agcState = SOFTSTATE_OFF;\n\tdev->softagc.softAgcMode = SOFTAGC_OFF;\t/* SOFTAGC_FREQ_CHANGE SOFTAGC_ATTEN SOFTAGC_ALL */\n\tdev->softagc.verbose = 0;\n\tdev->softagc.scanTimeMs = 100;\t/* parameter: default: 100 ms */\n\tdev->softagc.deadTimeMs = 1;\t/* parameter: default: 1 ms */\n\tdev->softagc.scanTimeSps = 0;\n\tdev->softagc.deadTimeSps = 0;\n\tdev->softagc.rpcNumGains = 0;\n\tdev->softagc.rpcGainValues = NULL;\n\n\t/* UDP controller server */\n#ifdef WITH_UDP_SERVER\n\tdev->udpPortNo = 0;\t/* default port 32323 .. but deactivated - by default */\n\tdev->override_if_freq = 0;\n\tdev->override_if_flag = 0;\n#endif\n\n\tdev->dev_num = index;\n\tdev->dev_lost = 1;\n\n\tcnt = libusb_get_device_list(dev->ctx, &list);\n\n\tfor (i = 0; i < cnt; i++) {\n\t\tdevice = list[i];\n\n\t\tlibusb_get_device_descriptor(list[i], &dd);\n\n\t\tif (find_known_device(dd.idVendor, dd.idProduct)) {\n\t\t\tdevice_count++;\n\t\t}\n\n\t\tif (index == device_count - 1)\n\t\t\tbreak;\n\n\t\tdevice = NULL;\n\t}\n\n\tif (!device) {\n\t\tr = -1;\n\t\tgoto err;\n\t}\n\n\tr = libusb_open(device, &dev->devh);\n\tif (r < 0) {\n\t\tlibusb_free_device_list(list, 1);\n\t\tfprintf(stderr, \"usb_open error %d\\n\", r);\n\t\tif(r == LIBUSB_ERROR_ACCESS)\n\t\t\tfprintf(stderr, \"Please fix the device permissions, e.g. \"\n\t\t\t\"by installing the udev rules file rtl-sdr.rules\\n\");\n\t\tgoto err;\n\t}\n\n\tlibusb_free_device_list(list, 1);\n\n\tif (libusb_kernel_driver_active(dev->devh, 0) == 1) {\n\t\tdev->driver_active = 1;\n\n#ifdef DETACH_KERNEL_DRIVER\n\t\tif (!libusb_detach_kernel_driver(dev->devh, 0)) {\n\t\t\tfprintf(stderr, \"Detached kernel driver\\n\");\n\t\t} else {\n\t\t\tfprintf(stderr, \"Detaching kernel driver failed!\");\n\t\t\tgoto err;\n\t\t}\n#else\n\t\tfprintf(stderr, \"\\nKernel driver is active, or device is \"\n\t\t\t\t\"claimed by second instance of librtlsdr.\"\n\t\t\t\t\"\\nIn the first case, please either detach\"\n\t\t\t\t\" or blacklist the kernel module\\n\"\n\t\t\t\t\"(dvb_usb_rtl28xxu), or enable automatic\"\n\t\t\t\t\" detaching at compile time.\\n\\n\");\n#endif\n\t}\n\n\tr = libusb_claim_interface(dev->devh, 0);\n\tif (r < 0) {\n\t\tfprintf(stderr, \"usb_claim_interface error %d\\n\", r);\n\t\tgoto err;\n\t}\n\n\tdev->rtl_xtal = DEF_RTL_XTAL_FREQ;\n\n\t/* perform a dummy write, if it fails, reset the device */\n\tif (rtlsdr_write_reg(dev, USBB, USB_SYSCTL, 0x09, 1) < 0) {\n\t\tfprintf(stderr, \"Resetting device...\\n\");\n\t\tlibusb_reset_device(dev->devh);\n\t}\n\n\trtlsdr_init_baseband(dev);\n\tdev->dev_lost = 0;\n\n\t/* Get device manufacturer and product id */\n\tr = rtlsdr_get_usb_strings(dev, dev->manufact, dev->product, NULL);\n\n\t/* Probe tuners */\n\trtlsdr_set_i2c_repeater(dev, 1);  /* C++ style RAII would be fine! */\n\n\treg = rtlsdr_i2c_read_reg(dev, E4K_I2C_ADDR, E4K_CHECK_ADDR);\n\tif (reg == E4K_CHECK_VAL) {\n\t\tfprintf(stderr, \"Found Elonics E4000 tuner\\n\");\n\t\tdev->tuner_type = RTLSDR_TUNER_E4000;\n\t\tgoto found;\n\t}\n\n\treg = rtlsdr_i2c_read_reg(dev, FC0013_I2C_ADDR, FC0013_CHECK_ADDR);\n\tif (reg == FC0013_CHECK_VAL) {\n\t\tfprintf(stderr, \"Found Fitipower FC0013 tuner\\n\");\n\t\tdev->tuner_type = RTLSDR_TUNER_FC0013;\n\t\tgoto found;\n\t}\n\n\treg = rtlsdr_i2c_read_reg(dev, R820T_I2C_ADDR, R82XX_CHECK_ADDR);\n\tif (reg == R82XX_CHECK_VAL) {\n\t\tfprintf(stderr, \"Found Rafael Micro R820T/2 tuner\\n\");\n\t\tdev->tuner_type = RTLSDR_TUNER_R820T;\n\t\tgoto found;\n\t}\n\n\treg = rtlsdr_i2c_read_reg(dev, R828D_I2C_ADDR, R82XX_CHECK_ADDR);\n\tif (reg == R82XX_CHECK_VAL) {\n\t\tfprintf(stderr, \"Found Rafael Micro R828D tuner\\n\");\n\n\t\tif (rtlsdr_check_dongle_model(dev, \"RTLSDRBlog\", \"Blog V4\"))\n\t\t{\n\t\t\tfprintf(stderr, \"RTL-SDR Blog V4 Detected\\n\");\n\t\t}\n\n\t\tdev->tuner_type = RTLSDR_TUNER_R828D;\n\t\tgoto found;\n\t}\n\n\t/* initialise GPIOs */\n\trtlsdr_set_gpio_output(dev, 4);\n\n\t/* reset tuner before probing */\n\trtlsdr_set_gpio_bit(dev, 4, 1);\n\trtlsdr_set_gpio_bit(dev, 4, 0);\n\n\treg = rtlsdr_i2c_read_reg(dev, FC2580_I2C_ADDR, FC2580_CHECK_ADDR);\n\tif ((reg & 0x7f) == FC2580_CHECK_VAL) {\n\t\tfprintf(stderr, \"Found FCI 2580 tuner\\n\");\n\t\tdev->tuner_type = RTLSDR_TUNER_FC2580;\n\t\tgoto found;\n\t}\n\n\treg = rtlsdr_i2c_read_reg(dev, FC0012_I2C_ADDR, FC0012_CHECK_ADDR);\n\tif (reg == FC0012_CHECK_VAL) {\n\t\tfprintf(stderr, \"Found Fitipower FC0012 tuner\\n\");\n\t\trtlsdr_set_gpio_output(dev, 6);\n\t\tdev->tuner_type = RTLSDR_TUNER_FC0012;\n\t\t/* rtlsdr_set_gpio_output(dev, 5); */\n\t\t/* rtlsdr_set_gpio_bit(dev, 5, 1); */\n\t\tgoto found;\n\t}\n\nfound:\n\t/* use the rtl clock value by default */\n\tdev->tun_xtal = dev->rtl_xtal;\n\tdev->tuner = &tuners[dev->tuner_type];\n\n\tswitch (dev->tuner_type) {\n\tcase RTLSDR_TUNER_FC2580:\n#if USE_OLD_DAB_IF_GAIN\n\t\tdev->tun_xtal = FC2580_XTAL_FREQ;\n#endif\n\t\tbreak;\n\tcase RTLSDR_TUNER_E4000:\n#if USE_OLD_DAB_IF_GAIN\n\t\trtlsdr_demod_write_reg(dev, 1, 0x12, 0x5a, 1);//DVBT_DAGC_TRG_VAL\n\t\trtlsdr_demod_write_reg(dev, 1, 0x02, 0x40, 1);//DVBT_AGC_TARG_VAL_0\n\t\trtlsdr_demod_write_reg(dev, 1, 0x03, 0x5a, 1);//DVBT_AGC_TARG_VAL_8_1\n\t\trtlsdr_demod_write_reg(dev, 1, 0xc7, 0x30, 1);//DVBT_AAGC_LOOP_GAIN\n\t\trtlsdr_demod_write_reg(dev, 1, 0x04, 0xd0, 1);//DVBT_LOOP_GAIN2_3_0\n\t\trtlsdr_demod_write_reg(dev, 1, 0x05, 0xbe, 1);//DVBT_LOOP_GAIN2_4\n\t\trtlsdr_demod_write_reg(dev, 1, 0xc8, 0x18, 1);//DVBT_LOOP_GAIN3\n\t\trtlsdr_demod_write_reg(dev, 1, 0x06, 0x35, 1);//DVBT_VTOP1\n\t\trtlsdr_demod_write_reg(dev, 1, 0xc9, 0x21, 1);//DVBT_VTOP2\n\t\trtlsdr_demod_write_reg(dev, 1, 0xca, 0x21, 1);//DVBT_VTOP3\n\t\trtlsdr_demod_write_reg(dev, 1, 0xcb, 0x00, 1);//DVBT_KRF1\n\t\trtlsdr_demod_write_reg(dev, 1, 0x07, 0x40, 1);//DVBT_KRF2\n\t\trtlsdr_demod_write_reg(dev, 1, 0xcd, 0x10, 1);//DVBT_KRF3\n\t\trtlsdr_demod_write_reg(dev, 1, 0xce, 0x10, 1);//DVBT_KRF4\n\t\trtlsdr_demod_write_reg(dev, 0, 0x11, 0xe9d4, 2);//DVBT_AD7_SETTING\n\t\trtlsdr_demod_write_reg(dev, 1, 0xe5, 0xf0, 1);//DVBT_EN_GI_PGA\n\t\trtlsdr_demod_write_reg(dev, 1, 0xd9, 0x00, 1);//DVBT_THD_LOCK_UP\n\t\trtlsdr_demod_write_reg(dev, 1, 0xdb, 0x00, 1);//DVBT_THD_LOCK_DW\n\t\trtlsdr_demod_write_reg(dev, 1, 0xdd, 0x14, 1);//DVBT_THD_UP1\n\t\trtlsdr_demod_write_reg(dev, 1, 0xde, 0xec, 1);//DVBT_THD_DW1\n\t\trtlsdr_demod_write_reg(dev, 1, 0xd8, 0x0c, 1);//DVBT_INTER_CNT_LEN\n\t\trtlsdr_demod_write_reg(dev, 1, 0xe6, 0x02, 1);//DVBT_GI_PGA_STATE\n\t\trtlsdr_demod_write_reg(dev, 1, 0xd7, 0x09, 1);//DVBT_EN_AGC_PGA\n\t\trtlsdr_demod_write_reg(dev, 0, 0x10, 0x49, 1);//DVBT_REG_GPO\n\t\trtlsdr_demod_write_reg(dev, 0, 0x0d, 0x85, 1);//DVBT_REG_MON,DVBT_REG_MONSEL\n\t\trtlsdr_demod_write_reg(dev, 0, 0x13, 0x02, 1);\n#endif\n\t\tbreak;\n\tcase RTLSDR_TUNER_FC0012:\n\tcase RTLSDR_TUNER_FC0013:\n#if USE_OLD_DAB_IF_GAIN\n\t\trtlsdr_demod_write_reg(dev, 1, 0x12, 0x5a, 1);//DVBT_DAGC_TRG_VAL\n\t\trtlsdr_demod_write_reg(dev, 1, 0x02, 0x40, 1);//DVBT_AGC_TARG_VAL_0\n\t\trtlsdr_demod_write_reg(dev, 1, 0x03, 0x5a, 1);//DVBT_AGC_TARG_VAL_8_1\n\t\trtlsdr_demod_write_reg(dev, 1, 0xc7, 0x2c, 1);//DVBT_AAGC_LOOP_GAIN\n\t\trtlsdr_demod_write_reg(dev, 1, 0x04, 0xcc, 1);//DVBT_LOOP_GAIN2_3_0\n\t\trtlsdr_demod_write_reg(dev, 1, 0x05, 0xbe, 1);//DVBT_LOOP_GAIN2_4\n\t\trtlsdr_demod_write_reg(dev, 1, 0xc8, 0x16, 1);//DVBT_LOOP_GAIN3\n\t\trtlsdr_demod_write_reg(dev, 1, 0x06, 0x35, 1);//DVBT_VTOP1\n\t\trtlsdr_demod_write_reg(dev, 1, 0xc9, 0x21, 1);//DVBT_VTOP2\n\t\trtlsdr_demod_write_reg(dev, 1, 0xca, 0x21, 1);//DVBT_VTOP3\n\t\trtlsdr_demod_write_reg(dev, 1, 0xcb, 0x00, 1);//DVBT_KRF1\n\t\trtlsdr_demod_write_reg(dev, 1, 0x07, 0x40, 1);//DVBT_KRF2\n\t\trtlsdr_demod_write_reg(dev, 1, 0xcd, 0x10, 1);//DVBT_KRF3\n\t\trtlsdr_demod_write_reg(dev, 1, 0xce, 0x10, 1);//DVBT_KRF4\n\t\trtlsdr_demod_write_reg(dev, 0, 0x11, 0xe9bf, 2);//DVBT_AD7_SETTING\n\t\trtlsdr_demod_write_reg(dev, 1, 0xe5, 0xf0, 1);//DVBT_EN_GI_PGA\n\t\trtlsdr_demod_write_reg(dev, 1, 0xd9, 0x00, 1);//DVBT_THD_LOCK_UP\n\t\trtlsdr_demod_write_reg(dev, 1, 0xdb, 0x00, 1);//DVBT_THD_LOCK_DW\n\t\trtlsdr_demod_write_reg(dev, 1, 0xdd, 0x11, 1);//DVBT_THD_UP1\n\t\trtlsdr_demod_write_reg(dev, 1, 0xde, 0xef, 1);//DVBT_THD_DW1\n\t\trtlsdr_demod_write_reg(dev, 1, 0xd8, 0x0c, 1);//DVBT_INTER_CNT_LEN\n\t\trtlsdr_demod_write_reg(dev, 1, 0xe6, 0x02, 1);//DVBT_GI_PGA_STATE\n\t\trtlsdr_demod_write_reg(dev, 1, 0xd7, 0x09, 1);//DVBT_EN_AGC_PGA\n#endif\n\t\tbreak;\n\tcase RTLSDR_TUNER_R828D:\n\t\t// If NOT an RTL-SDR Blog V4, set typical R828D 16 MHz freq. Otherwise, keep at 28.8 MHz.\n\t\tif (!(rtlsdr_check_dongle_model(dev, \"RTLSDRBlog\", \"Blog V4\")))\n\t\t{\n\t\t\tdev->tun_xtal = R828D_XTAL_FREQ;\n\t\t}\n\t\t/* fall-through */\n\tcase RTLSDR_TUNER_R820T:\n#if USE_OLD_DAB_IF_GAIN\n\t\trtlsdr_demod_write_reg(dev, 1, 0x12, 0x5a, 1);//DVBT_DAGC_TRG_VAL\n\t\trtlsdr_demod_write_reg(dev, 1, 0x02, 0x40, 1);//DVBT_AGC_TARG_VAL_0\n\t\trtlsdr_demod_write_reg(dev, 1, 0x03, 0x80, 1);//DVBT_AGC_TARG_VAL_8_1\n\t\trtlsdr_demod_write_reg(dev, 1, 0xc7, 0x24, 1);//DVBT_AAGC_LOOP_GAIN\n\t\trtlsdr_demod_write_reg(dev, 1, 0x04, 0xcc, 1);//DVBT_LOOP_GAIN2_3_0\n\t\trtlsdr_demod_write_reg(dev, 1, 0x05, 0xbe, 1);//DVBT_LOOP_GAIN2_4\n\t\trtlsdr_demod_write_reg(dev, 1, 0xc8, 0x14, 1);//DVBT_LOOP_GAIN3\n\t\trtlsdr_demod_write_reg(dev, 1, 0x06, 0x35, 1);//DVBT_VTOP1\n\t\trtlsdr_demod_write_reg(dev, 1, 0xc9, 0x21, 1);//DVBT_VTOP2\n\t\trtlsdr_demod_write_reg(dev, 1, 0xca, 0x21, 1);//DVBT_VTOP3\n\t\trtlsdr_demod_write_reg(dev, 1, 0xcb, 0x00, 1);//DVBT_KRF1\n\t\trtlsdr_demod_write_reg(dev, 1, 0x07, 0x40, 1);//DVBT_KRF2\n\t\trtlsdr_demod_write_reg(dev, 1, 0xcd, 0x10, 1);//DVBT_KRF3\n\t\trtlsdr_demod_write_reg(dev, 1, 0xce, 0x10, 1);//DVBT_KRF4\n\t\trtlsdr_demod_write_reg(dev, 0, 0x11, 0xe9f4, 2);//DVBT_AD7_SETTING\n#endif\n\t\t/* disable Zero-IF mode */\n\t\trtlsdr_demod_write_reg(dev, 1, 0xb1, 0x1a, 1);\n\t\t/* only enable In-phase ADC input */\n\t\trtlsdr_demod_write_reg(dev, 0, 0x08, 0x4d, 1);\n\t\t/* the R82XX use 3.57 MHz IF for the DVB-T 6 MHz mode, and\n\t\t * 4.57 MHz for the 8 MHz mode */\n\t\trtlsdr_set_if_freq(dev, R82XX_IF_FREQ);\n\t\t/* enable spectrum inversion */\n\t\trtlsdr_demod_write_reg(dev, 1, 0x15, 0x01, 1);\n\t\tbreak;\n\tcase RTLSDR_TUNER_UNKNOWN:\n\t\tfprintf(stderr, \"No supported tuner found\\n\");\n\t\trtlsdr_set_direct_sampling(dev, 1);\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n\n\tif (dev->tuner->init)\n\t\tr = dev->tuner->init(dev);\n\n\trtlsdr_set_i2c_repeater(dev, 0);\n\n#if INIT_R820T_TUNER_GAIN\n\tif ( dev->tuner_type == RTLSDR_TUNER_R820T )\n\t{\n\t\trtlsdr_set_tuner_if_mode(dev, 10000 + 11);\n\t\trtlsdr_set_tuner_gain_mode(dev, 0);\n\t}\n#endif\n\n\t*out_dev = dev;\n\treturn 0;\nerr:\n\tif (dev) {\n\t\tif (dev->devh)\n\t\t\tlibusb_close(dev->devh);\n\n\t\tif (dev->ctx)\n\t\t\tlibusb_exit(dev->ctx);\n\n\t\tfree(dev);\n\t}\n\n\treturn r;\n}\n\nint rtlsdr_close(rtlsdr_dev_t *dev)\n{\n\t#if LOG_API_CALLS\n\tfprintf(stderr, \"LOG: rtlsdr_close()\\n\");\n\t#endif\n\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return rtlsdr_rpc_close(dev);\n\t}\n\t#endif\n\n\tif (!dev)\n\t\treturn -1;\n\n\t/* automatic de-activation of bias-T */\n\t/* no: keep last bias-tee status, that rtl_biast hasn't to be called again */\n\t/* rtlsdr_set_bias_tee(dev, 0); */\n\n\tif(!dev->dev_lost) {\n\t\t/* block until all async operations have been completed (if any) */\n\t\twhile (RTLSDR_INACTIVE != dev->async_status) {\n#ifdef _WIN32\n\t\t\tSleep(1);\n#else\n\t\t\tusleep(1000);\n#endif\n\t\t}\n\n\t\trtlsdr_deinit_baseband(dev);\n\t}\n\telse {\n\t\tfprintf(stderr, \"Resetting device...\\n\");\n\t\tlibusb_reset_device(dev->devh);\n\t}\n\n\tsoftagc_uninit(dev);\n\tpthread_mutex_destroy(&dev->cs_mutex);\n\n\tlibusb_release_interface(dev->devh, 0);\n\n#ifdef DETACH_KERNEL_DRIVER\n\tif (dev->driver_active) {\n\t\tif (!libusb_attach_kernel_driver(dev->devh, 0))\n\t\t\tfprintf(stderr, \"Reattached kernel driver\\n\");\n\t\telse\n\t\t\tfprintf(stderr, \"Reattaching kernel driver failed!\\n\");\n\t}\n#endif\n\n\tlibusb_close(dev->devh);\n\n\tlibusb_exit(dev->ctx);\n\n\tfree(dev);\n\n\treturn 0;\n}\n\nint rtlsdr_reset_buffer(rtlsdr_dev_t *dev)\n{\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return rtlsdr_rpc_reset_buffer(dev);\n\t}\n\t#endif\n\n\tif (!dev)\n\t\treturn -1;\n\n\trtlsdr_write_reg(dev, USBB, USB_EPA_CTL, 0x1002, 2);\n\trtlsdr_write_reg(dev, USBB, USB_EPA_CTL, 0x0000, 2);\n\n\treturn 0;\n}\n\n\nstatic void rtlsdr_process_env_opts(rtlsdr_dev_t *dev)\n{\n\tchar * opts = getenv(\"LIBRTLSDR_OPT\");\n\tif ( opts ) {\n\t\tfprintf(stderr, \"process options '%s' from environment 'LIBRTLSDR_OPT'\\n\", opts);\n\t\trtlsdr_set_opt_string(dev, opts, 1);\n\t}\n\tdev->called_set_opt = 1;\n}\n\n\nint rtlsdr_read_sync(rtlsdr_dev_t *dev, void *buf, int len, int *n_read)\n{\n\tif (dev && !dev->called_set_opt )\n\t\trtlsdr_process_env_opts(dev);\n\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return rtlsdr_rpc_read_sync(dev, buf, len, n_read);\n\t}\n\t#endif\n\n\tif (!dev)\n\t\treturn -1;\n\n\treturn libusb_bulk_transfer(dev->devh, 0x81, buf, len, n_read, BULK_TIMEOUT);\n}\n\n\n/* return == softagc got activated */\nstatic int reactivate_softagc(rtlsdr_dev_t *dev, enum softagc_stateT newState)\n{\n\tif ( dev->softagc.softAgcMode > SOFTAGC_OFF )\n\t{\n\t\tif ( dev->softagc.agcState != SOFTSTATE_OFF\n\t\t\t && dev->softagc.softAgcMode >= SOFTAGC_AUTO )\n\t\t{\n\t\t\t/* softagc already running -> nothing to do */\n\t\t\tif ( dev->softagc.verbose )\n\t\t\t\tfprintf(stderr, \"rtlsdr reactivate_softagc(): state already %d\\n\", dev->softagc.agcState);\n\t\t\treturn 1;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdev->softagc.agcState =  newState;\n\t\t\tif ( dev->softagc.verbose )\n\t\t\t\tfprintf(stderr, \"rtlsdr reactivate_softagc switched to state %d\\n\", newState);\n\t\t\treturn 1;\n\t\t}\n\t}\n\tif ( dev->softagc.verbose )\n\t\tfprintf(stderr, \"*** rtlsdr reactivate_softagc(): Soft AGC is inactive!\\n\");\n\treturn 0;\n}\n\nstatic void *softagc_control_worker(void *arg)\n{\n\trtlsdr_dev_t *dev = (rtlsdr_dev_t *)arg;\n\tstruct softagc_state *agc = &dev->softagc;\n\twhile(1) {\n\t\tsafe_cond_wait(&agc->cond, &agc->mutex);\n\n\t\tif ( agc->exit_command_thread )\n\t\t\tpthread_exit(0);\n\n\t\tif ( agc->command_changeGain )\n\t\t{\n\t\t\t/* no need for extra mutex/buffer: next call is after DEAD_TIME */\n\t\t\tagc->command_changeGain = 0;\n\t\t\trtlsdr_set_tuner_gain( dev, dev->softagc.command_newGain );\n\t\t\tdev->softagc.remainingDeadSps = dev->softagc.deadTimeSps;\n\t\t\tif ( dev->softagc.verbose )\n\t\t\t\tfprintf(stderr, \"rtlsdr softagc_control_worker(): applied gain %d\\n\"\n\t\t\t\t\t, dev->softagc.command_newGain );\n\t\t}\n\t}\n}\n\nstatic void softagc_init(rtlsdr_dev_t *dev)\n{\n\tpthread_attr_t attr;\n\t/* prepare thread */\n\tdev->softagc.exit_command_thread = 0;\n\tdev->softagc.command_newGain = 0;\n\tdev->softagc.command_changeGain = 0;\n\t/* create thread */\n\tpthread_attr_init(&attr);\n\tpthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);\n\tpthread_mutex_init(&dev->softagc.mutex, NULL);\n\tpthread_cond_init(&dev->softagc.cond, NULL);\n\tpthread_create( &dev->softagc.command_thread, &attr, softagc_control_worker, dev);\n\tpthread_attr_destroy(&attr);\n\t/* manual gain mode for \"softagc\" */\n\trtlsdr_set_tuner_gain_mode(dev, 1 );\n}\n\nstatic void softagc_uninit(rtlsdr_dev_t *dev)\n{\n\tif ( dev->softagc.softAgcMode == SOFTAGC_OFF )\n\t\treturn;\n\n\tdev->softagc.exit_command_thread = 1;\n\tsafe_cond_signal(&dev->softagc.cond, &dev->softagc.mutex);\n\tpthread_join(dev->softagc.command_thread, NULL);\n\tpthread_cond_destroy(&dev->softagc.cond);\n\tpthread_mutex_destroy(&dev->softagc.mutex);\n}\n\n/* return == keepBlock */\nstatic int softagc(rtlsdr_dev_t *dev, unsigned char *buf, int len)\n{\n\tstruct softagc_state * agc = &dev->softagc;\n\tint distrib[16];\n\n\tif ( agc->agcState == SOFTSTATE_INIT )\n\t{\n\t\tagc->agcState = SOFTSTATE_RESET;\n#if 0\n\t\tfprintf(stderr, \"*** init softagc gainmode\\n\");\n#endif\n\t\treturn 0;\t\t/* throw away this block */\n\t}\n\telse if ( agc->agcState == SOFTSTATE_RESET )\n\t{\n\t\tint k, numGains = 0;\n\t\tconst int * gains = get_tuner_gains(dev, &numGains );\n#if 0\n\t\tfprintf(stderr, \"*** rtlsdr softagc: get_tuner_gains() delivered %d values\\n\", numGains);\n#endif\n\n\t\tif ( ! numGains )\n\t\t{\n\t\t\t/* device is not initialized yet */\n\t\t\treturn 1;\n\t\t}\n\n\t\tif ( numGains == 1 )\n\t\t{\n\t\t\tagc->softAgcMode = SOFTAGC_OFF;\n\t\t\tagc->agcState = SOFTSTATE_OFF;\n\t\t\tif ( dev->verbose || dev->softagc.verbose )\n\t\t\t\tfprintf(stderr, \"*** rtlsdr softagc(): just single gain -> deactivating\\n\");\n\t\t\treturn 1;\n\t\t}\n\n\t\t/* initialize measurement */\n\t\tif (!agc->scanTimeSps)\n\t\t\tagc->scanTimeSps = (int)( (agc->scanTimeMs * dev->rate) / 1000 );\n\t\tif (!agc->deadTimeSps)\n\t\t\tagc->deadTimeSps = (int)( (agc->deadTimeMs * dev->rate) / 1000 );\n\n\t\tagc->remainingDeadSps = INT_MAX;\n\t\tagc->remainingScanSps = agc->scanTimeSps;\n\n\t\tagc->numInHisto = 0;\n\t\tfor ( k = 0; k < 16; ++k )\n\t\t\tagc->histo[k] = 0;\n\n\t\tdev->softagc.gainIdx = numGains - 1;\n\t\tdev->softagc.command_newGain = gains[dev->softagc.gainIdx];\n\t\tdev->softagc.command_changeGain = 1;\n\t\tsafe_cond_signal(&dev->softagc.cond, &dev->softagc.mutex);\n\t\tif ( dev->softagc.verbose )\n\t\t\tfprintf(stderr, \"rtlsdr softagc(): set maximum gain %d / 10 dB at idx %d\\n\"\n\t\t\t\t, gains[dev->softagc.gainIdx]\n\t\t\t\t, dev->softagc.gainIdx );\n\n\t\tagc->agcState = SOFTSTATE_RESET_CONT;\n\t\treturn 0;\n\t}\n\n\tif ( agc->remainingDeadSps == INT_MAX )\n\t\treturn 0;\n\tif ( agc->remainingDeadSps )\n\t{\n\t\tif ( agc->remainingDeadSps >= len/2 )\n\t\t{\n\t\t\t/* fprintf(stderr, \"cont waiting dead samples: received %d of remaining %d smp\\n\", len, agc->remainingDeadSps); */\n\t\t\tagc->remainingDeadSps -= len/2;\n\t\t\treturn ( agc->agcState == SOFTSTATE_RESET_CONT ) ? 0 : 1;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tbuf = buf + ( 2 * agc->remainingDeadSps);\n\t\t\tlen -= 2 * agc->remainingDeadSps;\n\t\t\tagc->remainingDeadSps = 0;\n\t\t}\n\t}\n\n\t/* finish when arrived at lowest possible gain */\n\tif ( ! agc->gainIdx && agc->agcState == SOFTSTATE_RESET_CONT )\n\t{\n\t\tagc->agcState = SOFTSTATE_OFF;\n\t\t/* TODO: try deactivating Bias-T */\n\t\tif ( dev->softagc.verbose )\n\t\t\tfprintf(stderr, \"rtlsdr softagc(): gain idx is 0 -> finish soft agc\\n\");\n\t\treturn 1;\n\t}\n\n\t/* calculate histogram and distribution */\n\t{\n\t\tint * histo = &(agc->histo[0]);\n\t\tint i, k;\n\t\tfor ( i = 0; i < len; ++i )\n\t\t{\n\t\t\tif ( buf[i] >= 128 )\n\t\t\t\t++histo[ ( (unsigned)buf[i] -128) >> 3 ];\t\t/* -128 ==> max is then 127 == 7 bit */\n\t\t\telse\n\t\t\t\t++histo[ ( 127 - (unsigned)buf[i] ) >> 3 ];\n\t\t}\n\t\tagc->numInHisto += len;\n\t\tagc->remainingScanSps -= len/2;\n\n\t\tdistrib[15] = histo[15];\n\t\tfor ( k = 14; k >= 8; --k )\n\t\t\tdistrib[k] = distrib[k+1] + histo[k];\n\t}\n\n\t/* detect oversteering */\n\tif ( 64 * distrib[15] >= agc->numInHisto\t/* max more often than 1.56% (= 100/64) of all near 1 */\n\t   ||16 * distrib[12] >= agc->numInHisto\t/* more often than 6.25% of all >= 0.75 */\n\t   || 4 * distrib[ 8] >= agc->numInHisto )\t/* more often than 25% of all >= 0.5 */\n\t{\n\t\tconst int N = agc->numInHisto;\n#if 0\n\t\tfprintf(stderr, \"dp[8-15]: \");\n\t\tfor ( int k = 8; k < 16; ++k )\n\t\t\tfprintf(stderr, \"%d:%d, \", k, (distrib[k] * 100) / N);\n\t\tfprintf(stderr, \"\\ttotal %d\\n\", N);\n#endif\n\n\t\tif ( agc->gainIdx > 0 )\n\t\t{\n\t\t\tint k, numGains = 0;\n\t\t\tconst int * gains = get_tuner_gains(dev, &numGains );\n\n\t\t\tagc->remainingDeadSps = INT_MAX;\n\t\t\tagc->remainingScanSps = agc->scanTimeSps;\n\t\t\tagc->numInHisto = 0;\n\t\t\tfor ( k = 0; k < 16; ++k )\n\t\t\t\tagc->histo[k] = 0;\n\n\t\t\t-- agc->gainIdx;\n\t\t\tagc->command_newGain = gains[agc->gainIdx];\n\t\t\tagc->command_changeGain = 1;\n\t\t\tsafe_cond_signal(&agc->cond, &agc->mutex);\n\t\t}\n\t\treturn ( agc->agcState == SOFTSTATE_RESET_CONT ) ? 0 : 1;\n\t}\n\n\tif ( agc->remainingScanSps < 0 )\n\t{\n\t\t/* TODO: check if we should increase gain .. or even activate Bias-T */\n\t\tif ( dev->softagc.verbose )\n\t\t\tfprintf(stderr, \"*** rtlsdr softagc(): no more remaining samples to wait for\\n\");\n\n\t\tagc->remainingScanSps = 0;\n\t\tswitch ( agc->softAgcMode )\n\t\t{\n\t\tcase SOFTAGC_OFF:\n\t\tcase SOFTAGC_ON_CHANGE:\n\t\t\tswitch ( agc->agcState )\n\t\t\t{\n\t\t\tcase SOFTSTATE_OFF:\n\t\t\tcase SOFTSTATE_RESET_CONT:\n\t\t\t\tagc->agcState = SOFTSTATE_OFF;\n\t\t\t\tif ( dev->softagc.verbose )\n\t\t\t\t\tfprintf(stderr, \"softagc finished. now mode %d, state %d\\n\", agc->softAgcMode, agc->agcState);\n\t\t\t\treturn 1;\n\t\t\tcase SOFTSTATE_ON:\n\t\t\tcase SOFTSTATE_RESET:\n\t\t\tcase SOFTSTATE_INIT:\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase SOFTAGC_AUTO_ATTEN:\n\t\tcase SOFTAGC_AUTO:\n\t\t\tagc->agcState = SOFTSTATE_ON;\n\t\t\treturn 1;\n\t\t}\n\t}\n\t\n\treturn ( agc->agcState == SOFTSTATE_RESET_CONT ) ? 0 : 1;\n}\n\n\nstatic void LIBUSB_CALL _libusb_callback(struct libusb_transfer *xfer)\n{\n\trtlsdr_dev_t *dev = (rtlsdr_dev_t *)xfer->user_data;\n\n\tif (LIBUSB_TRANSFER_COMPLETED == xfer->status) {\n\t\tint keepBlock = 1;\n\t\tif ( dev->softagc.agcState != SOFTSTATE_OFF )\n\t\t\tkeepBlock = softagc(dev, xfer->buffer, xfer->actual_length);\n\n\t\tif (dev->cb && keepBlock)\n\t\t\tdev->cb(xfer->buffer, xfer->actual_length, dev->cb_ctx);\n\n\t\tlibusb_submit_transfer(xfer); /* resubmit transfer */\n\t\tdev->xfer_errors = 0;\n\t} else if (LIBUSB_TRANSFER_CANCELLED != xfer->status) {\n#ifndef _WIN32\n\t\tif (LIBUSB_TRANSFER_ERROR == xfer->status ||\n\t\t\t\tLIBUSB_TRANSFER_TIMED_OUT == xfer->status)\n\t\t\tdev->xfer_errors++;\n\n\t\tif (dev->xfer_errors >= dev->xfer_buf_num ||\n\t\t\t\tLIBUSB_TRANSFER_NO_DEVICE == xfer->status) {\n#endif\n\t\t\tdev->dev_lost = 1;\n\t\t\trtlsdr_cancel_async(dev);\n\t\t\tfprintf(stderr, \"cb transfer status: %d, \"\n\t\t\t\t\"canceling...\\n\", xfer->status);\n#ifndef _WIN32\n\t\t}\n#endif\n\t}\n}\n\nint rtlsdr_wait_async(rtlsdr_dev_t *dev, rtlsdr_read_async_cb_t cb, void *ctx)\n{\n\tif (dev && !dev->called_set_opt )\n\t\trtlsdr_process_env_opts(dev);\n\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return rtlsdr_rpc_wait_async(dev, cb, ctx);\n\t}\n\t#endif\n\n\treturn rtlsdr_read_async(dev, cb, ctx, 0, 0);\n}\n\nstatic int _rtlsdr_alloc_async_buffers(rtlsdr_dev_t *dev)\n{\n\tunsigned int i;\n\n\tif (!dev)\n\t\treturn -1;\n\n\tif (!dev->xfer) {\n\t\tdev->xfer = malloc(dev->xfer_buf_num *\n\t\t\t\t\t sizeof(struct libusb_transfer *));\n\n\t\tfor(i = 0; i < dev->xfer_buf_num; ++i)\n\t\t\tdev->xfer[i] = libusb_alloc_transfer(0);\n\t}\n\n\tif (dev->xfer_buf)\n\t\treturn -2;\n\n\tdev->xfer_buf = malloc(dev->xfer_buf_num * sizeof(unsigned char *));\n\tmemset(dev->xfer_buf, 0, dev->xfer_buf_num * sizeof(unsigned char *));\n\n#if defined (__linux__) && LIBUSB_API_VERSION >= 0x01000105\n\tfprintf(stderr, \"Allocating %d zero-copy buffers\\n\", dev->xfer_buf_num);\n\n\tdev->use_zerocopy = 1;\n\tfor (i = 0; i < dev->xfer_buf_num; ++i) {\n\t\tdev->xfer_buf[i] = libusb_dev_mem_alloc(dev->devh, dev->xfer_buf_len);\n\n\t\tif (!dev->xfer_buf[i]) {\n\t\t\tfprintf(stderr, \"Failed to allocate zero-copy \"\n\t\t\t\t\t\"buffer for transfer %d\\nFalling \"\n\t\t\t\t\t\"back to buffers in userspace\\n\", i);\n\n\t\t\tdev->use_zerocopy = 0;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t/* zero-copy buffer allocation failed (partially or completely)\n\t * we need to free the buffers again if already allocated */\n\tif (!dev->use_zerocopy) {\n\t\tfor (i = 0; i < dev->xfer_buf_num; ++i) {\n\t\t\tif (dev->xfer_buf[i])\n\t\t\t\tlibusb_dev_mem_free(dev->devh,\n\t\t\t\t\t\t    dev->xfer_buf[i],\n\t\t\t\t\t\t    dev->xfer_buf_len);\n\t\t}\n\t}\n#endif\n\n\t/* no zero-copy available, allocate buffers in userspace */\n\tif (!dev->use_zerocopy) {\n\t\tfprintf(stderr, \"Allocating %d (non-zero-copy) user-space buffers\\n\", dev->xfer_buf_num);\n\t\tfor (i = 0; i < dev->xfer_buf_num; ++i) {\n\t\t\tdev->xfer_buf[i] = malloc(dev->xfer_buf_len);\n\n\t\t\tif (!dev->xfer_buf[i])\n\t\t\t\treturn -ENOMEM;\n\t\t}\n\t}\n\n\treturn 0;\n}\n\nstatic int _rtlsdr_free_async_buffers(rtlsdr_dev_t *dev)\n{\n\tunsigned int i;\n\n\tif (!dev)\n\t\treturn -1;\n\n\tif (dev->xfer) {\n\t\tfor(i = 0; i < dev->xfer_buf_num; ++i) {\n\t\t\tif (dev->xfer[i]) {\n\t\t\t\tlibusb_free_transfer(dev->xfer[i]);\n\t\t\t}\n\t\t}\n\n\t\tfree(dev->xfer);\n\t\tdev->xfer = NULL;\n\t}\n\n\tif (dev->xfer_buf) {\n\t\tfor (i = 0; i < dev->xfer_buf_num; ++i) {\n\t\t\tif (dev->xfer_buf[i]) {\n\t\t\t\tif (dev->use_zerocopy) {\n#if defined (__linux__) && LIBUSB_API_VERSION >= 0x01000105\n\t\t\t\t\tlibusb_dev_mem_free(dev->devh,\n\t\t\t\t\t\t\t    dev->xfer_buf[i],\n\t\t\t\t\t\t\t    dev->xfer_buf_len);\n#endif\n\t\t\t\t} else {\n\t\t\t\t\tfree(dev->xfer_buf[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfree(dev->xfer_buf);\n\t\tdev->xfer_buf = NULL;\n\t}\n\n\treturn 0;\n}\n\nint rtlsdr_read_async(rtlsdr_dev_t *dev, rtlsdr_read_async_cb_t cb, void *ctx,\n\t\t\t\tuint32_t buf_num, uint32_t buf_len)\n{\n\tunsigned int i;\n\tint r = 0;\n\tstruct timeval tv = { 1, 0 };\n\tstruct timeval zerotv = { 0, 0 };\n\tenum rtlsdr_async_status next_status = RTLSDR_INACTIVE;\n\n\tif (dev && !dev->called_set_opt )\n\t\trtlsdr_process_env_opts(dev);\n\n\t#if LOG_API_CALLS\n\tfprintf(stderr, \"LOG: rtlsdr_read_async(buf_num %u, buf_len %u)\\n\",\n\t\t(unsigned)buf_num, (unsigned)buf_len);\n\t#endif\n\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return rtlsdr_rpc_read_async(dev, cb, ctx, buf_num, buf_len);\n\t}\n\t#endif\n\n\tif (!dev)\n\t\treturn -1;\n\n\tif (RTLSDR_INACTIVE != dev->async_status)\n\t\treturn -2;\n\n\tdev->async_status = RTLSDR_RUNNING;\n\tdev->async_cancel = 0;\n\n\tdev->cb = cb;\n\tdev->cb_ctx = ctx;\n\n\tif (buf_num > 0)\n\t\tdev->xfer_buf_num = buf_num;\n\telse\n\t\tdev->xfer_buf_num = DEFAULT_BUF_NUMBER;\n\n\tif (buf_len > 0 && buf_len % 512 == 0) /* len must be multiple of 512 */\n\t\tdev->xfer_buf_len = buf_len;\n\telse\n\t\tdev->xfer_buf_len = DEFAULT_BUF_LENGTH;\n\n\t_rtlsdr_alloc_async_buffers(dev);\n\n\tfor(i = 0; i < dev->xfer_buf_num; ++i) {\n\t\tlibusb_fill_bulk_transfer(dev->xfer[i],\n\t\t\t\t\t\tdev->devh,\n\t\t\t\t\t\t0x81,\n\t\t\t\t\t\tdev->xfer_buf[i],\n\t\t\t\t\t\tdev->xfer_buf_len,\n\t\t\t\t\t\t_libusb_callback,\n\t\t\t\t\t\t(void *)dev,\n\t\t\t\t\t\tBULK_TIMEOUT);\n\n\t\tr = libusb_submit_transfer(dev->xfer[i]);\n\t\tif (r < 0) {\n\t\t\tfprintf(stderr, \"Failed to submit transfer %i\\n\"\n\t\t\t\t\t\"Please increase your allowed \"\n\t\t\t\t\t\"usbfs buffer size with the \"\n\t\t\t\t\t\"following command:\\n\"\n\t\t\t\t\t\"echo 0 > /sys/module/usbcore\"\n\t\t\t\t\t\"/parameters/usbfs_memory_mb\\n\", i);\n\t\t\tdev->async_status = RTLSDR_CANCELING;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\twhile (RTLSDR_INACTIVE != dev->async_status) {\n\t\tr = libusb_handle_events_timeout_completed(dev->ctx, &tv,\n\t\t\t\t\t\t\t\t&dev->async_cancel);\n\t\tif (r < 0) {\n\t\t\t/*fprintf(stderr, \"handle_events returned: %d\\n\", r);*/\n\t\t\tif (r == LIBUSB_ERROR_INTERRUPTED) /* stray signal */\n\t\t\t\tcontinue;\n\t\t\tbreak;\n\t\t}\n\n\t\tif (RTLSDR_CANCELING == dev->async_status) {\n\t\t\tnext_status = RTLSDR_INACTIVE;\n\n\t\t\tif (!dev->xfer)\n\t\t\t\tbreak;\n\n\t\t\tfor(i = 0; i < dev->xfer_buf_num; ++i) {\n\t\t\t\tif (!dev->xfer[i])\n\t\t\t\t\tcontinue;\n\n\t\t\t\tif (LIBUSB_TRANSFER_CANCELLED !=\n\t\t\t\t\t\tdev->xfer[i]->status) {\n\t\t\t\t\tr = libusb_cancel_transfer(dev->xfer[i]);\n\t\t\t\t\t/* handle events after canceling\n\t\t\t\t\t * to allow transfer status to\n\t\t\t\t\t * propagate */\n\t\t\t\t\tlibusb_handle_events_timeout_completed(dev->ctx,\n\t\t\t\t\t\t\t\t\t\t\t\t &zerotv, NULL);\n\t\t\t\t\tif (r < 0)\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tnext_status = RTLSDR_CANCELING;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (dev->dev_lost || RTLSDR_INACTIVE == next_status) {\n\t\t\t\t/* handle any events that still need to\n\t\t\t\t * be handled before exiting after we\n\t\t\t\t * just cancelled all transfers */\n\t\t\t\tlibusb_handle_events_timeout_completed(dev->ctx,\n\t\t\t\t\t\t\t\t\t\t\t &zerotv, NULL);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t_rtlsdr_free_async_buffers(dev);\n\n\tdev->async_status = next_status;\n\n\treturn r;\n}\n\nint rtlsdr_cancel_async(rtlsdr_dev_t *dev)\n{\n\t#ifdef _ENABLE_RPC\n\tif (rtlsdr_rpc_is_enabled())\n\t{\n\t  return rtlsdr_rpc_cancel_async(dev);\n\t}\n\t#endif\n\n\tif (!dev)\n\t\treturn -1;\n\n\t/* if streaming, try to cancel gracefully */\n\tif (RTLSDR_RUNNING == dev->async_status) {\n\t\tdev->async_status = RTLSDR_CANCELING;\n\t\tdev->async_cancel = 1;\n\t\treturn 0;\n\t}\n\n\t/* if called while in pending state, change the state forcefully */\n#if 0\n\tif (RTLSDR_INACTIVE != dev->async_status) {\n\t\tdev->async_status = RTLSDR_INACTIVE;\n\t\treturn 0;\n\t}\n#endif\n\treturn -2;\n}\n\nuint32_t rtlsdr_get_tuner_clock(void *dev)\n{\n\tuint32_t tuner_freq;\n\n\tif (!dev)\n\t\treturn 0;\n\n\t/* read corrected clock value */\n\tif (rtlsdr_get_xtal_freq((rtlsdr_dev_t *)dev, NULL, &tuner_freq))\n\t\treturn 0;\n\n\treturn tuner_freq;\n}\n\nint rtlsdr_i2c_write_fn(void *dev, uint8_t addr, uint8_t *buf, int len)\n{\n\tif (dev)\n\t\treturn rtlsdr_i2c_write(((rtlsdr_dev_t *)dev), addr, buf, len);\n\n\treturn -1;\n}\n\nint rtlsdr_i2c_read_fn(void *dev, uint8_t addr, uint8_t *buf, int len)\n{\n\tif (dev)\n\t\treturn rtlsdr_i2c_read(((rtlsdr_dev_t *)dev), addr, buf, len);\n\n\treturn -1;\n}\n\n/* Infrared (IR) sensor support\n * based on Linux dvb_usb_rtl28xxu drivers/media/usb/dvb-usb-v2/rtl28xxu.h\n * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>\n * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>\n * Copyright (C) 2012 Thomas Mair <thomas.mair86@googlemail.com>\n */\n\nstruct rtl28xxu_req {\n\tuint16_t value;\n\tuint16_t index;\n\tuint16_t size;\n\tuint8_t *data;\n};\n\nstruct rtl28xxu_reg_val {\n\tuint16_t reg;\n\tuint8_t val;\n};\n\nstruct rtl28xxu_reg_val_mask {\n\tint block;\n\tuint16_t reg;\n\tuint8_t val;\n\tuint8_t mask;\n};\n\nstatic int rtlsdr_read_regs(rtlsdr_dev_t *dev, uint8_t block, uint16_t addr, uint8_t *data, uint8_t len)\n{\n\tint r;\n\tuint16_t index = (block << 8);\n\tif (block == IRB) index = (SYSB << 8) | 0x01;\n\n\tr = libusb_control_transfer(dev->devh, CTRL_IN, 0, addr, index, data, len, CTRL_TIMEOUT);\n\n\tif (r < 0)\n\t\tfprintf(stderr, \"%s failed with %d\\n\", __FUNCTION__, r);\n\n\treturn r;\n}\n\nstatic int rtlsdr_write_reg_mask(rtlsdr_dev_t *d, int block, uint16_t reg, uint8_t val,\n\t\tuint8_t mask)\n{\n\tuint8_t tmp;\n\n\t/* no need for read if whole reg is written */\n\tif (mask != 0xff) {\n\t\ttmp = rtlsdr_read_reg(d, block, reg, 1);\n\n\t\tval &= mask;\n\t\ttmp &= ~mask;\n\t\tval |= tmp;\n\t}\n\n\treturn rtlsdr_write_reg(d, block, reg, (uint16_t)val, 1);\n}\n\n#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))\n\nint rtlsdr_ir_query(rtlsdr_dev_t *d, uint8_t *buf, size_t buf_len)\n{\n\tint ret = -1;\n\tsize_t i, len;\n\tstatic const struct rtl28xxu_reg_val_mask refresh_tab[] = {\n\t\t{IRB, IR_RX_IF,\t\t\t   0x03, 0xff},\n\t\t{IRB, IR_RX_BUF_CTRL,\t\t 0x80, 0xff},\n\t\t{IRB, IR_RX_CTRL,\t\t\t 0x80, 0xff},\n\t};\n\n\t/* init remote controller */\n\tif (!d->rc_active) {\n\t\t/* fprintf(stderr, \"initializing remote controller\\n\"); */\n\t\tstatic const struct rtl28xxu_reg_val_mask init_tab[] = {\n\t\t\t{USBB, DEMOD_CTL,\t\t\t 0x00, 0x04},\n\t\t\t{USBB, DEMOD_CTL,\t\t\t 0x00, 0x08},\n\t\t\t{USBB, USB_CTRL,\t\t\t  0x20, 0x20},\n\t\t\t{USBB, GPD,\t\t\t\t   0x00, 0x08},\n\t\t\t{USBB, GPOE,\t\t\t\t  0x08, 0x08},\n\t\t\t{USBB, GPO,\t\t\t\t   0x08, 0x08},\n\t\t\t{IRB, IR_MAX_DURATION0,\t   0xd0, 0xff},\n\t\t\t{IRB, IR_MAX_DURATION1,\t   0x07, 0xff},\n\t\t\t{IRB, IR_IDLE_LEN0,\t\t   0xc0, 0xff},\n\t\t\t{IRB, IR_IDLE_LEN1,\t\t   0x00, 0xff},\n\t\t\t{IRB, IR_GLITCH_LEN,\t\t  0x03, 0xff},\n\t\t\t{IRB, IR_RX_CLK,\t\t\t  0x09, 0xff},\n\t\t\t{IRB, IR_RX_CFG,\t\t\t  0x1c, 0xff},\n\t\t\t{IRB, IR_MAX_H_TOL_LEN,\t   0x1e, 0xff},\n\t\t\t{IRB, IR_MAX_L_TOL_LEN,\t   0x1e, 0xff},\n\t\t\t{IRB, IR_RX_CTRL,\t\t\t 0x80, 0xff},\n\t\t};\n\n\t\tfor (i = 0; i < ARRAY_SIZE(init_tab); i++) {\n\t\t\tret = rtlsdr_write_reg_mask(d, init_tab[i].block, init_tab[i].reg,\n\t\t\t\t\tinit_tab[i].val, init_tab[i].mask);\n\t\t\tif (ret < 0) {\n\t\t\t\tfprintf(stderr, \"write %ld reg %d %.4x %.2x %.2x failed\\n\", (unsigned long)i, init_tab[i].block,\n\t\t\t\t\t\tinit_tab[i].reg, init_tab[i].val, init_tab[i].mask);\n\t\t\t\tgoto err;\n\t\t\t}\n\t\t}\n\n\t\td->rc_active = 1;\n\t\t/* fprintf(stderr, \"rc active\\n\"); */\n\t}\n\t/* TODO: option to ir disable */\n\n\tbuf[0] = rtlsdr_read_reg(d, IRB, IR_RX_IF, 1);\n\n\tif (buf[0] != 0x83) {\n\t\tif (buf[0] == 0 || /* no IR signal */\n\t\t\t/* also observed: 0x82, 0x81 - with lengths 1, 5, 0.. unknown, sometimes occurs at edges\n\t\t\t   \"IR not ready\"? causes a -7 timeout if we read */\n\t\t\tbuf[0] == 0x82 || buf[0] == 0x81) {\n\t\t\t/* graceful exit */\n\t\t} else {\n\t\t\tfprintf(stderr, \"read IR_RX_IF unexpected: %.2x\\n\", buf[0]);\n\t\t}\n\n\t\tret = 0;\n\t\tgoto exit;\n\t}\n\n\tbuf[0] = rtlsdr_read_reg(d, IRB, IR_RX_BC, 1);\n\n\tlen = buf[0];\n\t/* fprintf(stderr, \"read IR_RX_BC len=%d\\n\", len); */\n\n\tif (len > buf_len) {\n\t\t/* fprintf(stderr, \"read IR_RX_BC too large for buffer, %lu > %lu\\n\", buf_len, buf_len); */\n\t\tgoto exit;\n\t}\n\n\t/* read raw code from hw */\n\tret = rtlsdr_read_regs(d, IRB, IR_RX_BUF, buf, len);\n\tif (ret < 0)\n\t\tgoto err;\n\n\t/* let hw receive new code */\n\tfor (i = 0; i < ARRAY_SIZE(refresh_tab); i++) {\n\t\tret = rtlsdr_write_reg_mask(d, refresh_tab[i].block, refresh_tab[i].reg,\n\t\t\t\trefresh_tab[i].val, refresh_tab[i].mask);\n\t\tif (ret < 0)\n\t\t\tgoto err;\n\t}\n\n\t/* On success return length */\n\tret = len;\n\nexit:\n\treturn ret;\nerr:\n\tprintf(\"failed=%d\\n\", ret);\n\treturn ret;\n}\n\nint rtlsdr_set_bias_tee_gpio(rtlsdr_dev_t *dev, int gpio, int on)\n{\n\tif (!dev)\n\t\treturn -1;\n\n\t#if LOG_API_CALLS\n\tfprintf(stderr, \"LOG: rtlsdr_set_bias_tee_gpio(gpio %d, on %d)\\n\",\n\t\tgpio, on);\n\t#endif\n\n\trtlsdr_set_gpio_output(dev, gpio);\n\trtlsdr_set_gpio_bit(dev, gpio, on);\n\treactivate_softagc(dev, SOFTSTATE_RESET);\n\n\treturn 0;\n}\n\nint rtlsdr_set_bias_tee(rtlsdr_dev_t *dev, int on)\n{\n\tif (!dev)\n\t\treturn -1;\n\n\treturn rtlsdr_set_bias_tee_gpio(dev, dev->biast_gpio_pin_no, on);\n}\n\nint rtlsdr_set_harmonic_rx(rtlsdr_dev_t *dev, int harmonic)\n{\n\tif (!dev)\n\t\treturn -1;\n\n\tif ( dev->tuner_type == RTLSDR_TUNER_R820T )\n\t{\n\t\tif ( 0 <= harmonic && harmonic <= 16 )\n\t\t{\n\t\t\tdev->r82xx_c.harmonic = harmonic;\n\t\t\treturn 0;\n\t\t}\n\t\treturn -2;\n\t}\n\telse\n\t\treturn -3;\n}\n\n\nconst char * rtlsdr_get_opt_help(int longInfo)\n{\n\tif ( longInfo )\n\t\treturn\n\t\t\"\\t[-O\\tset RTL driver options seperated with ':', e.g. -O 'bc=30000:agc=0' ]\\n\"\n\t\t\"\\t\\tf=<freqHz>            set tuner frequency\\n\"\n\t\t\"\\t\\tbw=<bw_in_kHz>        set tuner bandwidth\\n\"\n\t\t\"\\t\\tbc=<if_in_Hz>         set band center relative to the complex-base-band '0' frequency\\n\"\n\t\t\"\\t\\t                        puts the tuner frequency onto this if frequency (default: 0)\\n\"\n\t\t\"\\t\\tsb=<sideband>         set tuner sideband/mirror: 'L' or '0' for lower side band,\\n\"\n\t\t\"\\t\\t                        'U' or '1' for upper side band. default for R820T/2: 'L'\\n\"\n\t\t\"\\t\\tagc=<tuner_gain_mode> activates tuner agc with '1'. deactivates with '0'\\n\"\n\t\t\"\\t\\tgain=<tenth_dB>       set tuner gain. 400 for 40.0 dB\\n\"\n\t\t\"\\t\\tifm=<tuner_if_mode>   set R820T/2 tuner's variable-gain-amplifier (VGA). default: 10011\\n\"\n\t\t\"\\t\\t                        0: activate agc controlled from RTL2832's feedback\\n\"\n\t\t\"\\t\\t                        around 0: set gain in 10th dB. 408 for +40.8 dB\\n\"\n\t\t\"\\t\\t                        5000+val: set gain to val in 10th dB. 5408 for +40.8 dB\\n\"\n\t\t\"\\t\\t                        10000+idx: set gain idx 0 .. 15: 10015 for maximum gain\\n\"\n\t\t\"\\t\\tdagc=<rtl_agc>        set RTL2832's digital agc (after ADC). 1 to activate. 0 to deactivate\\n\"\n\t\t\"\\t\\tds=<direct_sampling>  deactivate/bypass tuner with 1\\n\"\n\t\t\"\\t\\tdm=<ds_mode_thresh>   set dynamic direct threshold mode or threshold frequency:\\n\"\n\t\t\"\\t\\t                        0: use I & Q; 1: use I; 2: use Q; 3: use I below threshold frequency;\\n\"\n\t\t\"\\t\\t                        4: use Q below threshold frequency (=RTL-SDR v3)\\n\"\n\t\t\"\\t\\t                        other values set the threshold frequency\\n\"\n#if ENBALE_R820T_HARM_OPT\n\t\t\"\\t\\tharm=<Nth_harmonic>   R820T/2: use Nth harmonic for frequencies above 1.76 GHz. default: 5\\n\"\n#endif\n#if ENABLE_VCO_OPTIONS\n\t\t\"\\t\\tvcocmin=<current>     set R820T/2 VCO current min: 0..7: higher value is more current\\n\"\n\t\t\"\\t\\tvcocmax=<current>     set R820T/2 VCO current max: 0..7\\n\"\n\t\t\"\\t\\tvcoalgo=<algo>        set R820T/2 VCO algorithm. 0: default. 1: with vcomax=3.9G. 2: Youssef/Carl\\n\"\n#endif\n\t\t\"\\t\\tTp=<gpio_pin>         set GPIO pin for Bias T, default =0 for rtl-sdr.com compatible V3\\n\"\n\t\t\"\\t\\tT=<bias_tee>          1 activates power at antenna one some dongles, e.g. rtl-sdr.com's V3\\n\"\n#ifdef WITH_UDP_SERVER\n\t\t\"\\t\\tport=<udp_port>       1 or tcp port number activates UDP server. default: 0.\\n\"\n\t\t\"\\t\\t                        default port number: 32323\\n\"\n#endif\n\t\t;\n\telse\n\t\treturn\n\t\t\"\\t[-O\\tset RTL options string seperated with ':', e.g. -O 'bc=30000:agc=0' ]\\n\"\n\t\t\"\\t\\tverbose:f=<freqHz>:bw=<bw_in_kHz>:bc=<if_in_Hz>:sb=<sideband>\\n\"\n\t\t\"\\t\\tagc=<tuner_gain_mode>:gain=<tenth_dB>:ifm=<tuner_if_mode>:dagc=<rtl_agc>\\n\"\n#if ENBALE_R820T_HARM_OPT\n\t\t\"\\t\\tharm=<harmonic>\\n\"\n#endif\n#if ENABLE_VCO_OPTIONS\n\t\t\"\\t\\tds=<direct_sampling>:dm=<ds_mode_thresh>:vcocmin=<c>:vcocmax=<c>:vcoalgo=<a>\\n\"\n\t\t\"\\t\\tT=<bias_tee>\\n\"\n#else\n\t\t\"\\t\\tds=<direct_sampling>:dm=<ds_mode_thresh>:T=<bias_tee>\\n\"\n#endif\n#ifdef WITH_UDP_SERVER\n\t\t\"\\t\\tport=<udp_port default with 1>\\n\"\n#endif\n\t\t;\n}\n\nint rtlsdr_set_opt_string(rtlsdr_dev_t *dev, const char *opts, int verbose)\n{\n\tchar * optStr, * optPart;\n\tint retAll = 0;\n\n\tif (!dev)\n\t\treturn -1;\n\n\tdev->called_set_opt = 1;\n\n\t/* set some defaults */\n\tdev->softagc.deadTimeMs = 100;\n\tdev->softagc.scanTimeMs = 100;\n\n\toptStr = strdup(opts);\n\tif (!optStr)\n\t\treturn -1;\n\n\toptPart = strtok(optStr, \":,\");\n\twhile (optPart)\n\t{\n\t\tint ret = 0;\n\t\t//if (verbose || dev->verbose)\n\t\t//\tfprintf(stderr, \"\\nrtlsdr_set_opt_string(): parsing option '%s'\\n\", optPart);\n\t\tif (!strcmp(optPart, \"verbose\") || !strcmp(optPart, \"v\")) {\n\t\t\tfprintf(stderr, \"\\nrtlsdr_set_opt_string(): parsed option verbose\\n\");\n\t\t\tverbose = ++dev->verbose;\n\t\t\tdev->r82xx_c.verbose = verbose;\n\t\t\tret = 0;\n\t\t}\n\t\telse if (!strncmp(optPart, \"f=\", 2)) {\n\t\t\tdouble freqDbl = parseFreq(optPart + 2);\n\t\t\tuint64_t freq = (uint64_t)(freqDbl + 0.5);\n\t\t\tif (verbose)\n\t\t\t\tfprintf(stderr, \"\\nrtlsdr_set_opt_string(): parsed frequency %f MHz\\n\", freq * 1E-6);\n\t\t\tret = rtlsdr_set_center_freq64(dev, freq);\n\t\t}\n\t\telse if (!strncmp(optPart, \"bw=\", 3)) {\n\t\t\tuint32_t bw = (uint32_t)( atol(optPart +3) * 1000 );\n\t\t\tif (verbose)\n\t\t\t\tfprintf(stderr, \"\\nrtlsdr_set_opt_string(): parsed bandwidth %u\\n\", (unsigned)bw);\n\t\t\tret = rtlsdr_set_tuner_bandwidth(dev, bw);\n\t\t}\n\t\telse if (!strncmp(optPart, \"bc=\", 3)) {\n\t\t\tdouble freqDbl = parseFreq(optPart + 3);\n\t\t\tint32_t if_band_center_freq = (int32_t)(freqDbl + 0.5);\n\t\t\tif (verbose)\n\t\t\t\tfprintf(stderr, \"\\nrtlsdr_set_opt_string(): parsed band center %d\\n\", (int)if_band_center_freq);\n\t\t\tret = rtlsdr_set_tuner_band_center(dev, if_band_center_freq );\n\t\t}\n\t\telse if (!strncmp(optPart, \"sb=\", 3)) {\n\t\t\tint32_t sideband = (int32_t)(atoi(optPart +3));\n\t\t\tif (!strcmp(optPart +3, \"L\") || !strcmp(optPart +3, \"l\") || !strcmp(optPart +3, \"0\"))\n\t\t\t\tsideband = 0;\n\t\t\telse if (!strcmp(optPart +3, \"U\") || !strcmp(optPart +3, \"u\") || !strcmp(optPart +3, \"1\"))\n\t\t\t\tsideband = 1;\n\t\t\tif (verbose)\n\t\t\t\tfprintf(stderr, \"\\nrtlsdr_set_opt_string(): parsed sideband %d == %s\\n\", (int)sideband, (sideband ? \"Upper\" : \"Lower\") );\n\t\t\tret = rtlsdr_set_tuner_sideband(dev, sideband );\n\t\t}\n\t\telse if (!strncmp(optPart, \"agc=\", 4)) {\n\t\t\tint manual = 1 - atoi(optPart +4);\t/* invert logic */\n\t\t\tif (verbose)\n\t\t\t\tfprintf(stderr, \"\\nrtlsdr_set_opt_string(): parsed tuner gain mode, manual=%d\\n\", manual);\n\t\t\tret = rtlsdr_set_tuner_gain_mode(dev, manual);\n\t\t}\n\t\telse if (!strncmp(optPart, \"gain=\", 5)) {\n\t\t\tint gain = atoi(optPart +5);\n\t\t\tif (verbose)\n\t\t\t\tfprintf(stderr, \"\\nrtlsdr_set_opt_string(): parsed tuner gain = %d /10 dB\\n\", gain);\n\t\t\tret = rtlsdr_set_tuner_gain(dev, gain);\n\t\t}\n\t\telse if (!strncmp(optPart, \"agcv=\", 5)) {  /* previous option name */\n\t\t\tint agcv = atoi(optPart +5);\n\t\t\tif (verbose)\n\t\t\t\tfprintf(stderr, \"\\nrtlsdr_set_opt_string(): parsed tuner if_mode = %d\\n\", agcv);\n\t\t\tif (agcv < 0)\n\t\t\t\tagcv = 0;\n\t\t\tret = rtlsdr_set_tuner_if_mode(dev, agcv);\n\t\t}\n\t\telse if (!strncmp(optPart, \"ifm=\", 4)) {   /* new option name */\n\t\t\tint ifmode = atoi(optPart +4);\n\t\t\tif (verbose)\n\t\t\t\tfprintf(stderr, \"\\nrtlsdr_set_opt_string(): parsed tuner if_mode = %d\\n\", ifmode);\n\t\t\tret = rtlsdr_set_tuner_if_mode(dev, ifmode);\n\t\t}\n\t\telse if (!strncmp(optPart, \"dagc=\", 5)) {\n\t\t\tint on = atoi(optPart +5);\n\t\t\tif (verbose)\n\t\t\t\tfprintf(stderr, \"\\nrtlsdr_set_opt_string(): parsed rtl/digital gain mode %d\\n\", on);\n\t\t\tret = rtlsdr_set_agc_mode(dev, on);\n\t\t}\n\t\telse if (!strncmp(optPart, \"ds=\", 3)) {\n\t\t\tint on = atoi(optPart +3);\n\t\t\tif (verbose)\n\t\t\t\tfprintf(stderr, \"\\nrtlsdr_set_opt_string(): parsed direct sampling config %d\\n\", on);\n\t\t\tret = rtlsdr_set_direct_sampling(dev, on);\n\t\t}\n\t\telse if (!strncmp(optPart, \"dm=\", 3)) {\n\t\t\tuint32_t dm = (uint32_t)parseFreq(optPart + 3);\n\t\t\tif (verbose) {\n\t\t\t\tif (dm <= RTLSDR_DS_Q_BELOW)\n\t\t\t\t\tfprintf(stderr, \"\\nrtlsdr_set_opt_string(): parsed direct sampling mode %u == %s\\n\", dm, dsmode_str[dm]);\n\t\t\t\telse\n\t\t\t\t\tfprintf(stderr, \"\\nrtlsdr_set_opt_string(): parsed direct sampling threshold %u\\n\", dm);\n\t\t\t}\n\t\t\tif (dm <= RTLSDR_DS_Q_BELOW)\n\t\t\t\tdev->direct_sampling_mode = (enum rtlsdr_ds_mode)dm;\n\t\t\telse\n\t\t\t\tdev->direct_sampling_threshold = dm;\n\t\t\tret = rtlsdr_set_ds_mode(dev, dev->direct_sampling_mode, dev->direct_sampling_threshold);\n\t\t}\n#if ENBALE_R820T_HARM_OPT\n\t\telse if (!strncmp(optPart, \"harm=\", 5)) {\n\t\t\tint harmonic = atoi(optPart +5);\n\t\t\tif ( 0 <= harmonic && harmonic <= 16 )\n\t\t\t{\n\t\t\t\tdev->r82xx_c.harmonic = harmonic;\n\t\t\t\tret = 0;\n\t\t\t\tif (verbose)\n\t\t\t\t\tfprintf(stderr, \"\\nrtlsdr_set_opt_string(): parsed harmonic config %d\\n\", harmonic);\n\t\t\t} else if (verbose) {\n\t\t\t\tfprintf(stderr, \"\\nrtlsdr_set_opt_string(): error parsing harmonic config: valid range 0 .. 16\\n\");\n\t\t\t\tret = 1;\n\t\t\t}\n\t\t}\n#endif\n#if ENABLE_VCO_OPTIONS\n\t\telse if (!strncmp(optPart, \"vcocmin=\", 8)) {\n\t\t\tint current = atoi(optPart +8);\n\t\t\tif ( 0 <= current && current <= 7 )\n\t\t\t{\n\t\t\t\tdev->r82xx_c.vco_curr_min = 7 - current;\n\t\t\t\tret = 0;\n\t\t\t\tif (verbose)\n\t\t\t\t\tfprintf(stderr, \"\\nrtlsdr_set_opt_string(): parsed vcocmin config %d\\n\", current);\n\t\t\t} else if (verbose) {\n\t\t\t\tfprintf(stderr, \"\\nrtlsdr_set_opt_string(): error parsing vcocmin config: valid range 0 .. 7\\n\");\n\t\t\t\tret = 1;\n\t\t\t}\n\t\t}\n\t\telse if (!strncmp(optPart, \"vcocmax=\", 8)) {\n\t\t\tint current = atoi(optPart +8);\n\t\t\tif ( 0 <= current && current <= 7 )\n\t\t\t{\n\t\t\t\tdev->r82xx_c.vco_curr_max = 7 - current;\n\t\t\t\tret = 0;\n\t\t\t\tif (verbose)\n\t\t\t\t\tfprintf(stderr, \"\\nrtlsdr_set_opt_string(): parsed vcocmax config %d\\n\", current);\n\t\t\t} else if (verbose) {\n\t\t\t\tfprintf(stderr, \"\\nrtlsdr_set_opt_string(): error parsing vcocmax config: valid range 0 .. 7\\n\");\n\t\t\t\tret = 1;\n\t\t\t}\n\t\t}\n\t\telse if (!strncmp(optPart, \"vcoalgo=\", 8)) {\n\t\t\tint algo = atoi(optPart +8);\n\t\t\tif ( 0 <= algo && algo <= 2 )\n\t\t\t{\n\t\t\t\tdev->r82xx_c.vco_curr_max = algo;\n\t\t\t\tret = 0;\n\t\t\t\tif (verbose)\n\t\t\t\t\tfprintf(stderr, \"\\nrtlsdr_set_opt_string(): parsed vcoalgo config %d\\n\", algo);\n\t\t\t} else if (verbose) {\n\t\t\t\tfprintf(stderr, \"\\nrtlsdr_set_opt_string(): error parsing vcoalgo config: valid range 0 .. 2\\n\");\n\t\t\t\tret = 1;\n\t\t\t}\n\t\t}\n#endif\n\t\telse if (!strncmp(optPart, \"tp=\", 3) || !strncmp(optPart, \"Tp=\", 3) || !strncmp(optPart, \"TP=\", 3) ) {\n\t\t\tint gpio_pin_no = atoi(optPart +3);\n\t\t\tif (verbose)\n\t\t\t\tfprintf(stderr, \"\\nrtlsdr_set_opt_string(): parsed bias tee GPIO pin %d\\n\", gpio_pin_no);\n\t\t\tdev->biast_gpio_pin_no = gpio_pin_no;\n\t\t}\n\t\telse if (!strncmp(optPart, \"t=\", 2) || !strncmp(optPart, \"T=\", 2)) {\n\t\t\tint on = atoi(optPart +2);\n\t\t\tif (verbose)\n\t\t\t\tfprintf(stderr, \"\\nrtlsdr_set_opt_string(): parsed bias tee %d\\n\", on);\n\t\t\tret = rtlsdr_set_bias_tee(dev, on);\n\t\t}\n\t\telse if (!strncmp(optPart, \"softagc=\", 8)) {\n\t\t\tint on = atoi(optPart +8);\n\t\t\tif (verbose)\n\t\t\t\tfprintf(stderr, \"\\nrtlsdr_set_opt_string(): parsed soft agc mode %d\\n\", on);\n\t\t\tdev->softagc.softAgcMode = on;\n\t\t\tdev->softagc.agcState = on ? SOFTSTATE_INIT : SOFTSTATE_OFF;\n\t\t}\n\t\telse if (!strncmp(optPart, \"softscantime=\", 13)) {\n\t\t\tfloat d = atof(optPart +13);\n\t\t\tif (verbose)\n\t\t\t\tfprintf(stderr, \"\\nrtlsdr_set_opt_string(): parsed soft agc scan time %f ms\\n\", d);\n\t\t\tdev->softagc.scanTimeMs = d;\n\t\t}\n\t\telse if (!strncmp(optPart, \"softdeadtime=\", 13)) {\n\t\t\tfloat d = atof(optPart +13);\n\t\t\tif (verbose)\n\t\t\t\tfprintf(stderr, \"\\nrtlsdr_set_opt_string(): parsed soft agc dead time %f ms\\n\", d);\n\t\t\tdev->softagc.deadTimeMs = d;\n\t\t}\n\t\telse if (!strcmp(optPart, \"softverbose\")) {\n\t\t\tfprintf(stderr, \"\\nrtlsdr_set_opt_string(): parsed option softverbose for softagc\\n\");\n\t\t\tdev->softagc.verbose = 1;\n\t\t\tret = 0;\n\t\t}\n#ifdef WITH_UDP_SERVER\n\t\telse if (!strncmp(optPart, \"port=\", 5)) {\n\t\t\tint udpPortNo = atoi(optPart +5);\n\t\t\tif ( udpPortNo == 1 )\n\t\t\t\tudpPortNo = 32323;\n\t\t\tudpPortNo &= 0xffff;\n\t\t\tif (verbose)\n\t\t\t\tfprintf(stderr, \"rtlsdr_set_opt_string(): UDP control server port %d\\n\", udpPortNo);\n\t\t\tdev->udpPortNo = udpPortNo;\n\t\t}\n#endif\n\t\telse if (*optPart) {\n\t\t\tif (verbose)\n\t\t\t\tfprintf(stderr, \"\\nrtlsdr_set_opt_string(): parsed unknown option '%s'\\n\", optPart);\n\t\t\tret = -1;  /* unknown option */\n\t\t}\n\t\telse {\n\t\t\tif (verbose)\n\t\t\t\tfprintf(stderr, \"\\nrtlsdr_set_opt_string(): skip empty option '%s'\\n\", optPart);\n\t\t\tret = 0;\n\t\t}\n\t\tif (verbose)\n\t\t\tfprintf(stderr, \"  application of parsed option returned %d\\n\", ret);\n\t\tif (ret < 0)\n\t\t\tretAll = ret;\n\t\toptPart = strtok(NULL, \":,\");\n\t}\n\n\tif ( dev->softagc.agcState != SOFTSTATE_OFF )\n\t\tsoftagc_init(dev);\n\n#ifdef WITH_UDP_SERVER\n\tif (dev->udpPortNo && dev->srv_started == 0 && dev->tuner_type==RTLSDR_TUNER_R820T) {\n\t\t/* signal(SIGPIPE, SIG_IGN); */\n\t\tif(pthread_create(&dev->srv_thread, NULL, srv_server, dev)) {\n\t\t\tfprintf(stderr, \"Error creating thread\\n\");\n\t\t}\n\t\telse {\n\t\t\tdev->srv_started = 1;\n\t\t\tfprintf(stderr, \"UDP server started on port %u\\n\", dev->udpPortNo);\n\t\t}\n\t}\n#endif\n\n\tfree(optStr);\n\treturn retAll;\n}\n\n\nconst char * rtlsdr_get_ver_id() {\n\treturn APP_VER_ID \" (\" __DATE__ \")\";\n}\n\nuint32_t rtlsdr_get_version() {\n\treturn ((uint32_t)APP_VER_MAJOR << 16 ) | ((uint32_t)APP_VER_MINOR );\n}\n\n\n"
  },
  {
    "path": "src/rtl_adsb.c",
    "content": "/*\n * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver\n * Copyright (C) 2012 by Steve Markgraf <steve@steve-m.de>\n * Copyright (C) 2012 by Hoernchen <la@tfc-server.de>\n * Copyright (C) 2012 by Kyle Keen <keenerd@gmail.com>\n * Copyright (C) 2012 by Youssef Touil <youssef@sdrsharp.com>\n * Copyright (C) 2012 by Ian Gilmour <ian@sdrsharp.com>\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n\n#include <errno.h>\n#include <signal.h>\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <math.h>\n\n#ifndef _WIN32\n#include <unistd.h>\n#else\n#include <windows.h>\n#include <fcntl.h>\n#include <io.h>\n#include \"getopt/getopt.h\"\n#endif\n \n#ifdef NEED_PTHREADS_WORKARROUND\n#define HAVE_STRUCT_TIMESPEC\n#endif\n#include <pthread.h>\n#include <libusb.h>\n\n#include <rtl-sdr.h>\n#include <rtl_app_ver.h>\n#include \"convenience/convenience.h\"\n#include \"convenience/rtl_convenience.h\"\n\n#ifdef _WIN32\n#define sleep Sleep\n#if defined(_MSC_VER) && (_MSC_VER < 1800)\n#define round(x) (x > 0.0 ? floor(x + 0.5): ceil(x - 0.5))\n#endif\n#endif\n\n#define ADSB_RATE\t\t\t2000000\n#define ADSB_FREQ\t\t\t1090000000\n#define DEFAULT_ASYNC_BUF_NUMBER\t12\n#define DEFAULT_BUF_LENGTH\t\t(16 * 16384)\n#define AUTO_GAIN\t\t\t-100\n\n#define MESSAGEGO    253\n#define OVERWRITE    254\n#define BADSAMPLE    255\n\nstatic pthread_t demod_thread;\nstatic pthread_cond_t ready;\nstatic pthread_mutex_t ready_m;\nstatic volatile int do_exit = 0;\nstatic rtlsdr_dev_t *dev = NULL;\n\nuint16_t squares[256];\n\n/* todo, bundle these up in a struct */\nuint8_t *buffer;  /* also abused for uint16_t */\nint verbose_output = 0;\nint short_output = 0;\nint quality = 10;\nint allowed_errors = 5;\nFILE *file;\nint adsb_frame[14];\n#define preamble_len\t16\n#define long_frame\t\t112\n#define short_frame\t\t56\n\n/* signals are not threadsafe by default */\n#define safe_cond_signal(n, m) pthread_mutex_lock(m); pthread_cond_signal(n); pthread_mutex_unlock(m)\n#define safe_cond_wait(n, m) pthread_mutex_lock(m); pthread_cond_wait(n, m); pthread_mutex_unlock(m)\n\nvoid usage(void)\n{\n\tfprintf(stderr,\n\t\t\"rtl_adsb, a simple ADS-B decoder\\n\"\n\t\t\"rtl_adsb version %d.%d %s (%s)\\n\"\n\t\t\"rtl-sdr  library %d.%d %s\\n\\n\",\n\t\tAPP_VER_MAJOR, APP_VER_MINOR, APP_VER_ID, __DATE__,\n\t\trtlsdr_get_version() >>16, rtlsdr_get_version() & 0xFFFF,\n\t\trtlsdr_get_ver_id() );\n\tfprintf(stderr,\n\t\t\"Usage:\\trtl_adsb [-R] [-g gain] [-p ppm] [output file]\\n\"\n\t\t\"\\t[-d device_index or serial (default: 0)]\\n\"\n\t\t\"\\t[-V verbove output (default: off)]\\n\"\n\t\t\"\\t[-S show short frames (default: off)]\\n\"\n\t\t\"\\t[-Q quality (0: no sanity checks, 0.5: half bit, 1: one bit (default), 2: two bits)]\\n\"\n\t\t\"\\t[-e allowed_errors (default: 5)]\\n\"\n\t\t\"\\t[-g tuner_gain (default: automatic)]\\n\"\n\t\t\"\\t[-p ppm_error (default: 0)]\\n\"\n\t\t\"\\t[-T enable bias-T on GPIO PIN 0 (works for rtl-sdr.com v3 dongles)]\\n\"\n\t\t\"\\tfilename (a '-' dumps samples to stdout)\\n\"\n\t\t\"\\t (omitting the filename also uses stdout)\\n\\n\"\n\t\t\"Streaming with netcat:\\n\"\n\t\t\"\\trtl_adsb | netcat -lp 8080\\n\"\n\t\t\"\\twhile true; do rtl_adsb | nc -lp 8080; done\\n\"\n\t\t\"Streaming with socat:\\n\"\n\t\t\"\\trtl_adsb | socat -u - TCP4:sdrsharp.com:47806\\n\"\n\t\t\"\\n\");\n\texit(1);\n}\n\n#ifdef _WIN32\nBOOL WINAPI\nsighandler(int signum)\n{\n\tif (CTRL_C_EVENT == signum) {\n\t\tfprintf(stderr, \"Signal caught, exiting!\\n\");\n\t\tdo_exit = 1;\n\t\trtlsdr_cancel_async(dev);\n\t\treturn TRUE;\n\t}\n\treturn FALSE;\n}\n#else\nstatic void sighandler(int signum)\n{\n\tfprintf(stderr, \"Signal caught, exiting!\\n\");\n\tdo_exit = 1;\n\trtlsdr_cancel_async(dev);\n}\n#endif\n\nvoid display(int *frame, int len)\n{\n\tint i, df;\n\tif (!short_output && len <= short_frame) {\n\t\treturn;}\n\tdf = (frame[0] >> 3) & 0x1f;\n\tif (quality == 0 && !(df==11 || df==17 || df==18 || df==19)) {\n\t\treturn;}\n\tfprintf(file, \"*\");\n\tfor (i=0; i<((len+7)/8); i++) {\n\t\tfprintf(file, \"%02x\", frame[i]);}\n\tfprintf(file, \";\\r\\n\");\n\tif (!verbose_output) {\n\t\treturn;}\n\tfprintf(file, \"DF=%i CA=%i\\n\", df, frame[0] & 0x07);\n\tfprintf(file, \"ICAO Address=%06x\\n\", frame[1] << 16 | frame[2] << 8 | frame[3]);\n\tif (len <= short_frame) {\n\t\treturn;}\n\tfprintf(file, \"PI=0x%06x\\n\",  frame[11] << 16 | frame[12] << 8 | frame[13]);\n\tfprintf(file, \"Type Code=%i S.Type/Ant.=%x\\n\", (frame[4] >> 3) & 0x1f, frame[4] & 0x07);\n\tfprintf(file, \"--------------\\n\");\n}\n\nint abs8(int x)\n/* do not subtract 127 from the raw iq, this handles it */\n{\n\tif (x >= 127) {\n\t\treturn x - 127;}\n\treturn 127 - x;\n}\n\nvoid squares_precompute(void)\n/* equiv to abs(x-128) ^ 2 */\n{\n\tint i, j;\n\t// todo, check if this LUT is actually any faster\n\tfor (i=0; i<256; i++) {\n\t\tj = abs8(i);\n\t\tsquares[i] = (uint16_t)(j*j);\n\t}\n}\n\nint magnitute(uint8_t *buf, int len)\n/* takes i/q, changes buf in place (16 bit), returns new len (16 bit) */\n{\n\tint i;\n\tuint16_t *m;\n\tfor (i=0; i<len; i+=2) {\n\t\tm = (uint16_t*)(&buf[i]);\n\t\t*m = squares[buf[i]] + squares[buf[i+1]];\n\t}\n\treturn len/2;\n}\n\nstatic inline uint16_t single_manchester(uint16_t a, uint16_t b, uint16_t c, uint16_t d)\n/* takes 4 consecutive real samples, return 0 or 1, BADSAMPLE on error */\n{\n\tint bit, bit_p;\n\tbit_p = a > b;\n\tbit   = c > d;\n\n\tif (quality == 0) {\n\t\treturn bit;}\n\n\tif (quality == 5) {\n\t\tif ( bit &&  bit_p && b > c) {\n\t\t\treturn BADSAMPLE;}\n\t\tif (!bit && !bit_p && b < c) {\n\t\t\treturn BADSAMPLE;}\n\t\treturn bit;\n\t}\n\n\tif (quality == 10) {\n\t\tif ( bit &&  bit_p && c > b) {\n\t\t\treturn 1;}\n\t\tif ( bit && !bit_p && d < b) {\n\t\t\treturn 1;}\n\t\tif (!bit &&  bit_p && d > b) {\n\t\t\treturn 0;}\n\t\tif (!bit && !bit_p && c < b) {\n\t\t\treturn 0;}\n\t\treturn BADSAMPLE;\n\t}\n\n\tif ( bit &&  bit_p && c > b && d < a) {\n\t\treturn 1;}\n\tif ( bit && !bit_p && c > a && d < b) {\n\t\treturn 1;}\n\tif (!bit &&  bit_p && c < a && d > b) {\n\t\treturn 0;}\n\tif (!bit && !bit_p && c < b && d > a) {\n\t\treturn 0;}\n\treturn BADSAMPLE;\n}\n\nstatic inline uint16_t min16(uint16_t a, uint16_t b)\n{\n\treturn a<b ? a : b;\n}\n\nstatic inline uint16_t max16(uint16_t a, uint16_t b)\n{\n\treturn a>b ? a : b;\n}\n\nstatic inline int preamble(uint16_t *buf, int i)\n/* returns 0/1 for preamble at index i */\n{\n\tint i2;\n\tuint16_t low  = 0;\n\tuint16_t high = 65535;\n\tfor (i2=0; i2<preamble_len; i2++) {\n\t\tswitch (i2) {\n\t\t\tcase 0:\n\t\t\tcase 2:\n\t\t\tcase 7:\n\t\t\tcase 9:\n\t\t\t\t//high = min16(high, buf[i+i2]);\n\t\t\t\thigh = buf[i+i2];\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\t//low  = max16(low,  buf[i+i2]);\n\t\t\t\tlow = buf[i+i2];\n\t\t\t\tbreak;\n\t\t}\n\t\tif (high <= low) {\n\t\t\treturn 0;}\n\t}\n\treturn 1;\n}\n\nvoid manchester(uint16_t *buf, int len)\n/* overwrites magnitude buffer with valid bits (BADSAMPLE on errors) */\n{\n\t/* a and b hold old values to verify local manchester */\n\tuint16_t a=0, b=0;\n\tuint16_t bit;\n\tint i, i2, start, errors;\n\tint maximum_i = len - 1;        // len-1 since we look at i and i+1\n\t// todo, allow wrap across buffers\n\ti = 0;\n\twhile (i < maximum_i) {\n\t\t/* find preamble */\n\t\tfor ( ; i < (len - preamble_len); i++) {\n\t\t\tif (!preamble(buf, i)) {\n\t\t\t\tcontinue;}\n\t\t\ta = buf[i];\n\t\t\tb = buf[i+1];\n\t\t\tfor (i2=0; i2<preamble_len; i2++) {\n\t\t\t\tbuf[i+i2] = MESSAGEGO;}\n\t\t\ti += preamble_len;\n\t\t\tbreak;\n\t\t}\n\t\ti2 = start = i;\n\t\terrors = 0;\n\t\t/* mark bits until encoding breaks */\n\t\tfor ( ; i < maximum_i; i+=2, i2++) {\n\t\t\tbit = single_manchester(a, b, buf[i], buf[i+1]);\n\t\t\ta = buf[i];\n\t\t\tb = buf[i+1];\n\t\t\tif (bit == BADSAMPLE) {\n\t\t\t\terrors += 1;\n\t\t\t\tif (errors > allowed_errors) {\n\t\t\t\t\tbuf[i2] = BADSAMPLE;\n\t\t\t\t\tbreak;\n\t\t\t\t} else {\n\t\t\t\t\tbit = a > b;\n\t\t\t\t\t/* these don't have to match the bit */\n\t\t\t\t\ta = 0;\n\t\t\t\t\tb = 65535;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbuf[i] = buf[i+1] = OVERWRITE;\n\t\t\tbuf[i2] = bit;\n\t\t}\n\t}\n}\n\nvoid messages(uint16_t *buf, int len)\n{\n\tint i, data_i, index, shift, frame_len;\n\t// todo, allow wrap across buffers\n\tfor (i=0; i<len; i++) {\n\t\tif (buf[i] > 1) {\n\t\t\tcontinue;}\n\t\tframe_len = long_frame;\n\t\tdata_i = 0;\n\t\tfor (index=0; index<14; index++) {\n\t\t\tadsb_frame[index] = 0;}\n\t\tfor(; i<len && buf[i]<=1 && data_i<frame_len; i++, data_i++) {\n\t\t\tif (buf[i]) {\n\t\t\t\tindex = data_i / 8;\n\t\t\t\tshift = 7 - (data_i % 8);\n\t\t\t\tadsb_frame[index] |= (uint8_t)(1<<shift);\n\t\t\t}\n\t\t\tif (data_i == 7) {\n\t\t\t\tif (adsb_frame[0] == 0) {\n\t\t\t\t    break;}\n\t\t\t\tif (adsb_frame[0] & 0x80) {\n\t\t\t\t\tframe_len = long_frame;}\n\t\t\t\telse {\n\t\t\t\t\tframe_len = short_frame;}\n\t\t\t}\n\t\t}\n\t\tif (data_i < (frame_len-1)) {\n\t\t\tcontinue;}\n\t\tdisplay(adsb_frame, frame_len);\n\t\tfflush(file);\n\t}\n}\n\nstatic void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)\n{\n\tif (do_exit) {\n\t\treturn;}\n\tmemcpy(buffer, buf, len);\n\tsafe_cond_signal(&ready, &ready_m);\n}\n\nstatic void *demod_thread_fn(void *arg)\n{\n\tint len;\n\twhile (!do_exit) {\n\t\tsafe_cond_wait(&ready, &ready_m);\n\t\tlen = magnitute(buffer, DEFAULT_BUF_LENGTH);\n\t\tmanchester((uint16_t*)buffer, len);\n\t\tmessages((uint16_t*)buffer, len);\n\t}\n\trtlsdr_cancel_async(dev);\n\treturn 0;\n}\n\nint main(int argc, char **argv)\n{\n#ifndef _WIN32\n\tstruct sigaction sigact;\n#endif\n\tchar *filename = NULL;\n\tint r, opt;\n\tint gain = AUTO_GAIN; /* tenths of a dB */\n\tint dev_index = 0;\n\tint dev_given = 0;\n\tint ppm_error = 0;\n\tint enable_biastee = 0;\n\tpthread_cond_init(&ready, NULL);\n\tpthread_mutex_init(&ready_m, NULL);\n\tsquares_precompute();\n\n\twhile ((opt = getopt(argc, argv, \"d:g:p:e:Q:VST\")) != -1)\n\t{\n\t\tswitch (opt) {\n\t\tcase 'd':\n\t\t\tdev_index = verbose_device_search(optarg);\n\t\t\tdev_given = 1;\n\t\t\tbreak;\n\t\tcase 'g':\n\t\t\tgain = (int)(atof(optarg) * 10);\n\t\t\tbreak;\n\t\tcase 'p':\n\t\t\tppm_error = atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'V':\n\t\t\tverbose_output = 1;\n\t\t\tbreak;\n\t\tcase 'S':\n\t\t\tshort_output = 1;\n\t\t\tbreak;\n\t\tcase 'e':\n\t\t\tallowed_errors = atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'Q':\n\t\t\tquality = (int)(atof(optarg) * 10);\n\t\t\tbreak;\n\t\tcase 'T':\n\t\t\tenable_biastee = 1;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tusage();\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tif (argc <= optind) {\n\t\tfilename = \"-\";\n\t} else {\n\t\tfilename = argv[optind];\n\t}\n\n\tbuffer = malloc(DEFAULT_BUF_LENGTH * sizeof(uint8_t));\n\n\tif (!dev_given) {\n\t\tdev_index = verbose_device_search(\"0\");\n\t}\n\n\tif (dev_index < 0) {\n\t\texit(1);\n\t}\n\n\tr = rtlsdr_open(&dev, (uint32_t)dev_index);\n\tif (r < 0) {\n\t\tfprintf(stderr, \"Failed to open rtlsdr device #%d.\\n\", dev_index);\n\t\texit(1);\n\t}\n#ifndef _WIN32\n\tsigact.sa_handler = sighandler;\n\tsigemptyset(&sigact.sa_mask);\n\tsigact.sa_flags = 0;\n\tsigaction(SIGINT, &sigact, NULL);\n\tsigaction(SIGTERM, &sigact, NULL);\n\tsigaction(SIGQUIT, &sigact, NULL);\n\tsigaction(SIGPIPE, &sigact, NULL);\n#else\n\tSetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE );\n#endif\n\n\tif (strcmp(filename, \"-\") == 0) { /* Write samples to stdout */\n\t\tfile = stdout;\n\t\tsetvbuf(stdout, NULL, _IONBF, 0);\n#ifdef _WIN32\n\t\t_setmode(_fileno(file), _O_BINARY);\n#endif\n\t} else {\n\t\tfile = fopen(filename, \"wb\");\n\t\tif (!file) {\n\t\t\tfprintf(stderr, \"Failed to open %s\\n\", filename);\n\t\t\texit(1);\n\t\t}\n\t}\n\n\t/* Set the tuner gain */\n\tif (gain == AUTO_GAIN) {\n\t\tverbose_auto_gain(dev);\n\t} else {\n\t\tgain = nearest_gain(dev, gain);\n\t\tverbose_gain_set(dev, gain);\n\t}\n\n\tverbose_ppm_set(dev, ppm_error);\n\tr = rtlsdr_set_agc_mode(dev, 1);\n\n\t/* Set the tuner frequency */\n\tverbose_set_frequency(dev, ADSB_FREQ);\n\n\t/* Set the sample rate */\n\tverbose_set_sample_rate(dev, ADSB_RATE);\n\n\trtlsdr_set_bias_tee(dev, enable_biastee);\n\tif (enable_biastee)\n\t\tfprintf(stderr, \"activated bias-T on GPIO PIN 0\\n\");\n\n\t/* Reset endpoint before we start reading from it (mandatory) */\n\tverbose_reset_buffer(dev);\n\n\tpthread_create(&demod_thread, NULL, demod_thread_fn, (void *)(NULL));\n\trtlsdr_read_async(dev, rtlsdr_callback, (void *)(NULL),\n\t\t\t      DEFAULT_ASYNC_BUF_NUMBER,\n\t\t\t      DEFAULT_BUF_LENGTH);\n\n\tif (do_exit) {\n\t\tfprintf(stderr, \"\\nUser cancel, exiting...\\n\");}\n\telse {\n\t\tfprintf(stderr, \"\\nLibrary error %d, exiting...\\n\", r);}\n\trtlsdr_cancel_async(dev);\n\tpthread_cancel(demod_thread);\n\tpthread_join(demod_thread, NULL);\n\tpthread_cond_destroy(&ready);\n\tpthread_mutex_destroy(&ready_m);\n\n\tif (file != stdout) {\n\t\tfclose(file);}\n\n\trtlsdr_close(dev);\n\tfree(buffer);\n\treturn r >= 0 ? r : -r;\n}\n\n"
  },
  {
    "path": "src/rtl_app_ver.h.in",
    "content": "#ifndef __RTL_APP_VER_H\n#define __RTL_APP_VER_H\n\n#define APP_VER_MAJOR\t@MAJOR_VERSION@\n#define APP_VER_MINOR\t@MINOR_VERSION@\n#define APP_VER_ID\t\"github.com/librtlsdr\"\n\n#define VER_TO_STRING(x)\t#x\n#define VAL_VER_TO_STR(x)\tVER_TO_STRING(x)\n\n#endif\n"
  },
  {
    "path": "src/rtl_biast.c",
    "content": "/*\n * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver\n * rtl_biast, tool to set bias tee gpio output\n * Copyright (C) 2012 by Steve Markgraf <steve@steve-m.de>\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#ifndef _WIN32\n#include <unistd.h>\n#else\n#include <windows.h>\n#include \"getopt/getopt.h\"\n#endif\n\n#include <rtl-sdr.h>\n#include <rtl_app_ver.h>\n#include \"convenience/convenience.h\"\n#include \"convenience/rtl_convenience.h\"\n\nstatic rtlsdr_dev_t *dev = NULL;\n\nvoid usage(void)\n{\n\tfprintf(stderr,\n\t\t\"rtl_biast, a tool for switching the RTL-SDR.com\\n\"\n\t\t\"bias tee or any GPIO ON and OFF. Example to activate\\n\"\n\t\t\"the bias tee: rtl_biast -d 0 -b 1\\n\"\n\t\t\"Any GPIO:     rtl_biast -d 0 -g 1 -b 1\\n\"\n\t\t\"rtl_biast version %d.%d %s (%s)\\n\"\n\t\t\"rtl-sdr   library %d.%d %s\\n\\n\",\n\t\tAPP_VER_MAJOR, APP_VER_MINOR, APP_VER_ID, __DATE__,\n\t\trtlsdr_get_version() >>16, rtlsdr_get_version() & 0xFFFF,\n\t\trtlsdr_get_ver_id() );\n\tfprintf(stderr,\n\t\t\"Usage:\\trtl_biast [-options]\\n\"\n\t\t\"\\t[-d device_index (default: 0)]\\n\"\n\t\t\"\\t[-g GPIO select (default: 0)]\\n\"\n\t\t\"\\t[-b set write bias_on (default: 0, in output mode)]\\n\"\n\t\t\"\\t[-r read pin (in input mode)]\\n\"\n\t\t\"\\t[-w write pin (in output mode)]\\n\"\n\t\t\"\\t[-s read all GPIO pins status (0 = write, 1 = read ?? )]\\n\"\n\t\t\"\\t[-R read all GPIO pins ?? ]\\n\");\n\texit(1);\n}\n\nint main(int argc, char **argv)\n{\n\tint i, r, opt, val;\n\tint dev_index = 0;\n\tint dev_given = 0;\n\tint write_pin_given = 0;\n\tint read_pin_given = 0;\n\tint read_all_given = 0;\n\tint req_status = 0;\n\tuint32_t bias_on = 0;\n\tint gpio_pin = 0;\n\tint device_count;\n\n\twhile ((opt = getopt(argc, argv, \"d:b:w:g:srRh?\")) != -1) {\n\t\tswitch (opt) {\n\t\tcase 'd':\n\t\t\tdev_index = verbose_device_search(optarg);\n\t\t\tdev_given = 1;\n\t\t\tbreak;\n\t\tcase 'b':\n\t\tcase 'w':\n\t\t\tbias_on = atoi(optarg);\n\t\t\twrite_pin_given = 1;\n\t\t\tbreak;\n\t\tcase 'g':\n\t\t\tgpio_pin = atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'r':\n\t\t\tread_pin_given = 1;\n\t\t\tbreak;\n\t\tcase 'R':\n\t\t\tread_all_given = 1;\n\t\t\tbreak;\n\t\tcase 's':\n\t\t\treq_status = 1;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tusage();\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (!dev_given) {\n\t\tdev_index = verbose_device_search(\"0\");\n\t}\n\n\tif (dev_index < 0) {\n\t\texit(1);\n\t}\n\n\tr = rtlsdr_open(&dev, dev_index);\n\tif (r < 0)\n\t{\n\t\tfprintf(stderr, \"error opening device with index %d\\n\", dev_index);\n\t\treturn -r;\n\t}\n\n\tif (write_pin_given)\n\t{\n\t\tr = rtlsdr_set_bias_tee_gpio(dev, gpio_pin, bias_on);\n\t\tif (r < 0)\n\t\t\tfprintf(stderr, \"error setting value %d on pin %d\\n\", bias_on, gpio_pin);\n\t}\n\n\telse if (read_pin_given)\n\t{\n\t\tr = rtlsdr_set_gpio_input(dev, gpio_pin);\n\t\tif (r < 0)\n\t\t\tfprintf(stderr, \"error configuring pin %d to input\\n\", gpio_pin);\n\n\t\tr = rtlsdr_get_gpio_bit(dev, gpio_pin, &val);\n\t\tif (r < 0)\n\t\t\tfprintf(stderr, \"error reading value for pin %d\\n\", gpio_pin);\n\t\telse\n\t\t\tprintf(\"value %d at pin %d\\n\", val, gpio_pin);\n\t}\n\n\telse if (read_all_given)\n\t{\n\t\tr = rtlsdr_get_gpio_byte(dev, &val);\n\t\tif (r < 0)\n\t\t\tfprintf(stderr, \"error reading value for all pins\\n\");\n\t\telse\n\t\t{\n\t\t\tprintf(\"GPIO 0x%02x = bin \", val);\n\t\t\tfor (gpio_pin = 7; gpio_pin >= 4; --gpio_pin)\n\t\t\t\tprintf(\"%d\", ((val >> gpio_pin) & 1));\n\t\t\tprintf(\" \");\n\t\t\tfor (gpio_pin = 3; gpio_pin >= 0; --gpio_pin)\n\t\t\t\tprintf(\"%d\", ((val >> gpio_pin) & 1));\n\t\t\tprintf(\"\\n\");\n\t\t}\n\t}\n\n\telse if (req_status)\n\t{\n\t\tr = rtlsdr_set_gpio_status(dev, &val);\n\t\tif (r < 0)\n\t\t\tfprintf(stderr, \"error reading status for all pins\\n\");\n\t\telse\n\t\t{\n\t\t\tprintf(\"STATUS 0x%02x = bin \", val);\n\t\t\tfor (gpio_pin = 7; gpio_pin >= 4; --gpio_pin)\n\t\t\t\tprintf(\"%d\", ((val >> gpio_pin) & 1));\n\t\t\tprintf(\" \");\n\t\t\tfor (gpio_pin = 3; gpio_pin >= 0; --gpio_pin)\n\t\t\t\tprintf(\"%d\", ((val >> gpio_pin) & 1));\n\t\t\tprintf(\"\\n\");\n\t\t}\n\t}\n\n\telse\n\t{\n\t\tusage();\n\t\tr = -1;\n\t}\n\nexit:\n\t/*\n\t * Note - rtlsdr_close() in this tree does not clear the bias tee\n\t * GPIO line, so it leaves the bias tee enabled if a client program\n\t * doesn't explictly disable it.\n\t *\n\t * If that behaviour changes then another rtlsdr_close() will be\n\t * needed that takes some extension flags, and one of them should\n\t * be to either explicitly close the biast or leave it alone.\n\t */\n\trtlsdr_close(dev);\n\n\treturn r >= 0 ? r : -r;\n}\n"
  },
  {
    "path": "src/rtl_eeprom.c",
    "content": "/*\n * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver\n * rtl_eeprom, EEPROM modification tool\n * Copyright (C) 2012 by Steve Markgraf <steve@steve-m.de>\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#ifndef _WIN32\n#include <unistd.h>\n#else\n#include <windows.h>\n#include \"getopt/getopt.h\"\n#endif\n\n#include <rtl-sdr.h>\n#include <rtl_app_ver.h>\n\n#define EEPROM_SIZE\t256\n#define MAX_STR_SIZE\t256\n#define STR_OFFSET\t0x09\n\nstatic rtlsdr_dev_t *dev = NULL;\n\ntypedef struct rtlsdr_config {\n\tuint16_t vendor_id;\n\tuint16_t product_id;\n\tchar manufacturer[MAX_STR_SIZE];\n\tchar product[MAX_STR_SIZE];\n\tchar serial[MAX_STR_SIZE];\n\tint have_serial;\n\tint enable_ir;\n\tint remote_wakeup;\n} rtlsdr_config_t;\n\nvoid dump_config(rtlsdr_config_t *conf)\n{\n\tfprintf(stderr, \"__________________________________________\\n\");\n\tfprintf(stderr, \"Vendor ID:\\t\\t0x%04x\\n\", conf->vendor_id);\n\tfprintf(stderr, \"Product ID:\\t\\t0x%04x\\n\", conf->product_id);\n\tfprintf(stderr, \"Manufacturer:\\t\\t%s\\n\", conf->manufacturer);\n\tfprintf(stderr, \"Product:\\t\\t%s\\n\", conf->product);\n\tfprintf(stderr, \"Serial number:\\t\\t%s\\n\", conf->serial);\n\tfprintf(stderr, \"Serial number enabled:\\t\");\n\tfprintf(stderr, conf->have_serial ? \"yes\\n\": \"no\\n\");\n\tfprintf(stderr, \"IR endpoint enabled:\\t\");\n\tfprintf(stderr, conf->enable_ir ? \"yes\\n\": \"no\\n\");\n\tfprintf(stderr, \"Remote wakeup enabled:\\t\");\n\tfprintf(stderr, conf->remote_wakeup ? \"yes\\n\": \"no\\n\");\n\tfprintf(stderr, \"__________________________________________\\n\");\n}\n\nvoid usage(void)\n{\n\tfprintf(stderr,\n\t\t\"rtl_eeprom, an EEPROM programming tool for RTL2832 based SDR-receivers\\n\"\n\t\t\"rtl_eeprom version %d.%d %s (%s)\\n\"\n\t\t\"rtl-sdr    library %d.%d %s\\n\\n\",\n\t\tAPP_VER_MAJOR, APP_VER_MINOR, APP_VER_ID, __DATE__,\n\t\trtlsdr_get_version() >>16, rtlsdr_get_version() & 0xFFFF,\n\t\trtlsdr_get_ver_id() );\n\tfprintf(stderr,\n\t\t\"Usage:\\trtl_eeprom [-options]\\n\"\n\t\t\"\\t[-d device_index (default: 0)]\\n\"\n\t\t\"\\t[-m <str> set manufacturer string]\\n\"\n\t\t\"\\t[-p <str> set product string]\\n\"\n\t\t\"\\t[-M <id> set manufacturer ID (aka vendor ID) in hexadecimal]\\n\"\n\t\t\"\\t[-P <id> set product ID in hexadecimal]\\n\"\n\t\t\"\\t[-n sets manufacturer and product ID to 0x1209/0x2832]\\n\"\n\t\t\"\\t[    as with '-g realtek_sdr']\\n\"\n\t\t\"\\t[-s <str> set serial number string]\\n\"\n\t\t\"\\t[-i <0,1> disable/enable IR-endpoint]\\n\"\n\t\t\"\\t[-g <conf> generate default config and write to device]\\n\"\n\t\t\"\\t[   <conf> can be one of:]\\n\"\n\t\t\"\\t[   realtek\\t\\tRealtek default (as without EEPROM)]\\n\"\n\t\t\"\\t[   realtek_oem\\t\\tRealtek default OEM with EEPROM]\\n\"\n\t\t\"\\t[   noxon\\t\\tTerratec NOXON DAB Stick]\\n\"\n\t\t\"\\t[   terratec_black\\tTerratec T Stick Black]\\n\"\n\t\t\"\\t[   terratec_plus\\tTerratec T Stick+ (DVB-T/DAB)]\\n\"\n\t\t\"\\t[   realtek_sdr\\t\\tRealtek SDR - without DVB compatibility]\\n\"\n\t\t\"\\t[-w <filename> write dumped file to device]\\n\"\n\t\t\"\\t[-r <filename> dump EEPROM to file]\\n\"\n\t\t\"\\t[-h display this help text]\\n\"\n\t\t\"\\nUse on your own risk, especially -w, -M and -P!\\n\");\n\texit(1);\n}\n\nint get_string_descriptor(int pos, uint8_t *data, char *str)\n{\n\tint len, i, j = 0;\n\n\tlen = data[pos];\n\n\tif (data[pos + 1] != 0x03)\n\t\tfprintf(stderr, \"Error: invalid string descriptor!\\n\");\n\n\tfor (i = 2; i < len; i += 2)\n\t\tstr[j++] = data[pos + i];\n\n\tstr[j] = 0x00;\n\n\treturn pos + i;\n}\n\nint set_string_descriptor(int pos, uint8_t *data, char *str)\n{\n\tint i = 0, j = 2;\n\n\tif (pos < 0)\n\t\treturn -1;\n\n\tdata[pos + 1] = 0x03;\n\n\twhile (str[i] != 0x00) {\n\t\tif ((pos + j) >= 78) {\n\t\t\tfprintf(stderr, \"Error: string too long, truncated!\\n\");\n\t\t\treturn -1;\n\t\t}\n\t\tdata[pos + j++] = str[i++];\n\t\tdata[pos + j++] = 0x00;\n\t}\n\n\tdata[pos] = j;\n\n\treturn pos + j;\n}\n\nint parse_eeprom_to_conf(rtlsdr_config_t *conf, uint8_t *dat)\n{\n\tint pos;\n\n\tif ((dat[0] != 0x28) || (dat[1] != 0x32))\n\t\tfprintf(stderr, \"Error: invalid RTL2832 EEPROM header!\\n\");\n\n\tconf->vendor_id = dat[2] | (dat[3] << 8);\n\tconf->product_id = dat[4] | (dat[5] << 8);\n\tconf->have_serial = (dat[6] == 0xa5) ? 1 : 0;\n\tconf->remote_wakeup = (dat[7] & 0x01) ? 1 : 0;\n\tconf->enable_ir = (dat[7] & 0x02) ? 1 : 0;\n\n\tpos = get_string_descriptor(STR_OFFSET, dat, conf->manufacturer);\n\tpos = get_string_descriptor(pos, dat, conf->product);\n\tget_string_descriptor(pos, dat, conf->serial);\n\n\treturn 0;\n}\n\nint gen_eeprom_from_conf(rtlsdr_config_t *conf, uint8_t *dat)\n{\n\tint pos;\n\n\tdat[0] = 0x28;\n\tdat[1] = 0x32;\n\tdat[2] = conf->vendor_id & 0xff;\n\tdat[3] = (conf->vendor_id >> 8) & 0xff ;\n\tdat[4] = conf->product_id & 0xff;\n\tdat[5] = (conf->product_id >> 8) & 0xff;\n\tdat[6] = conf->have_serial ? 0xa5 : 0x00;\n\tdat[7] = 0x14;\n\tdat[7] |= conf->remote_wakeup ? 0x01 : 0x00;\n\tdat[7] |= conf->enable_ir ? 0x02 : 0x00;\n\tdat[8] = 0x02;\n\n\tpos = set_string_descriptor(STR_OFFSET, dat, conf->manufacturer);\n\tpos = set_string_descriptor(pos, dat, conf->product);\n\tpos = set_string_descriptor(pos, dat, conf->serial);\n\n\tdat[78] = 0x00;\t\t/* length of IR config */\n\n\treturn pos;\n}\n\nenum configs {\n\tCONF_NONE = 0,\n\tREALTEK,\n\tREALTEK_EEPROM,\n\tTERRATEC_NOXON,\n\tTERRATEC_T_BLACK,\n\tTERRATEC_T_PLUS,\n\tREALTEK_SDR,\n};\n\nvoid gen_default_conf(rtlsdr_config_t *conf, int config)\n{\n\tswitch (config) {\n\tcase REALTEK:\n\t\tfprintf(stderr, \"Realtek default (as without EEPROM)\\n\");\n\t\tconf->vendor_id = 0x0bda;\n\t\tconf->product_id = 0x2832;\n\t\tstrcpy(conf->manufacturer, \"Generic\");\n\t\tstrcpy(conf->product, \"RTL2832U DVB-T\");\n\t\tstrcpy(conf->serial, \"0\");\n\t\tconf->have_serial = 1;\n\t\tconf->enable_ir = 0;\n\t\tconf->remote_wakeup = 1;\n\t\tbreak;\n\tcase REALTEK_EEPROM:\n\t\tfprintf(stderr, \"Realtek default OEM with EEPROM\\n\");\n\t\tconf->vendor_id = 0x0bda;\n\t\tconf->product_id = 0x2838;\n\t\tstrcpy(conf->manufacturer, \"Realtek\");\n\t\tstrcpy(conf->product, \"RTL2838UHIDIR\");\n\t\tstrcpy(conf->serial, \"00000001\");\n\t\tconf->have_serial = 1;\n\t\tconf->enable_ir = 1;\n\t\tconf->remote_wakeup = 0;\n\t\tbreak;\n\tcase TERRATEC_NOXON:\n\t\tfprintf(stderr, \"Terratec NOXON DAB Stick\\n\");\n\t\tconf->vendor_id = 0x0ccd;\n\t\tconf->product_id = 0x00b3;\n\t\tstrcpy(conf->manufacturer, \"NOXON\");\n\t\tstrcpy(conf->product, \"DAB Stick\");\n\t\tstrcpy(conf->serial, \"0\");\n\t\tconf->have_serial = 1;\n\t\tconf->enable_ir = 0;\n\t\tconf->remote_wakeup = 1;\n\t\tbreak;\n\tcase TERRATEC_T_BLACK:\n\t\tfprintf(stderr, \"Terratec T Stick Black\\n\");\n\t\tconf->vendor_id = 0x0ccd;\n\t\tconf->product_id = 0x00a9;\n\t\tstrcpy(conf->manufacturer, \"Realtek\");\n\t\tstrcpy(conf->product, \"RTL2838UHIDIR\");\n\t\tstrcpy(conf->serial, \"00000001\");\n\t\tconf->have_serial = 1;\n\t\tconf->enable_ir = 1;\n\t\tconf->remote_wakeup = 0;\n\t\tbreak;\n\tcase TERRATEC_T_PLUS:\n\t\tfprintf(stderr, \"Terratec ran T Stick+\\n\");\n\t\tconf->vendor_id = 0x0ccd;\n\t\tconf->product_id = 0x00d7;\n\t\tstrcpy(conf->manufacturer, \"Realtek\");\n\t\tstrcpy(conf->product, \"RTL2838UHIDIR\");\n\t\tstrcpy(conf->serial, \"00000001\");\n\t\tconf->have_serial = 1;\n\t\tconf->enable_ir = 1;\n\t\tconf->remote_wakeup = 0;\n\t\tbreak;\n\tcase REALTEK_SDR:\n\t\tfprintf(stderr, \"Realtek SDR\\n\");\n\t\tconf->vendor_id = 0x1209;\n\t\tconf->product_id = 0x2832;\n\t\tstrcpy(conf->manufacturer, \"Realtek\");\n\t\tstrcpy(conf->product, \"RTL2832U_SDR\");\n\t\tstrcpy(conf->serial, \"00000001\");\n\t\tconf->have_serial = 1;\n\t\tconf->enable_ir = 0;\n\t\tconf->remote_wakeup = 0;\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t};\n}\n\nint main(int argc, char **argv)\n{\n\tint i, r, opt;\n\tuint32_t dev_index = 0;\n\tint device_count;\n\tchar *filename = NULL;\n\tFILE *file = NULL;\n\tchar *manuf_str = NULL;\n\tchar *product_str = NULL;\n\tint manuf_id = 0;\n\tint product_id = 0;\n\tchar *serial_str = NULL;\n\tuint8_t buf[EEPROM_SIZE];\n\trtlsdr_config_t conf;\n\tint flash_file = 0;\n\tint default_config = 0;\n\tint change = 0;\n\tint ir_endpoint = 0;\n\tchar ch;\n\n\twhile ((opt = getopt(argc, argv, \"d:m:p:M:P:ns:i:g:w:r:h?\")) != -1) {\n\t\tswitch (opt) {\n\t\tcase 'd':\n\t\t\tdev_index = atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'm':\n\t\t\tmanuf_str = optarg;\n\t\t\tchange = 1;\n\t\t\tbreak;\n\t\tcase 'p':\n\t\t\tproduct_str = optarg;\n\t\t\tchange = 1;\n\t\t\tbreak;\n\t\tcase 'M':\n\t\t\tmanuf_id = (int)strtol(optarg, NULL, 16);\n\t\t\tchange = 1;\n\t\t\tbreak;\n\t\tcase 'P':\n\t\t\tproduct_id = (int)strtol(optarg, NULL, 16);\n\t\t\tchange = 1;\n\t\t\tbreak;\n\t\tcase 'n':\n\t\t\tmanuf_id = 0x1209;\n\t\t\tproduct_id = 0x2832;\n\t\t\tchange = 1;\n\t\t\tbreak;\n\t\tcase 's':\n\t\t\tserial_str = optarg;\n\t\t\tchange = 1;\n\t\t\tbreak;\n\t\tcase 'i':\n\t\t\tir_endpoint = (atoi(optarg) > 0) ? 1 : -1;\n\t\t\tchange = 1;\n\t\t\tbreak;\n\t\tcase 'g':\n\t\t\tif (!strcmp(optarg, \"realtek\"))\n\t\t\t\tdefault_config = REALTEK;\n\t\t\telse if (!strcmp(optarg, \"realtek_oem\"))\n\t\t\t\tdefault_config = REALTEK_EEPROM;\n\t\t\telse if (!strcmp(optarg, \"noxon\"))\n\t\t\t\tdefault_config = TERRATEC_NOXON;\n\t\t\telse if (!strcmp(optarg, \"terratec_black\"))\n\t\t\t\tdefault_config = TERRATEC_T_BLACK;\n\t\t\telse if (!strcmp(optarg, \"terratec_plus\"))\n\t\t\t\tdefault_config = TERRATEC_T_PLUS;\n\t\t\telse if (!strcmp(optarg, \"realtek_sdr\"))\n\t\t\t\tdefault_config = REALTEK_SDR;\n\t\t\tif (default_config != CONF_NONE)\n\t\t\t\tchange = 1;\n\t\t\tbreak;\n\t\tcase 'w':\n\t\t\tflash_file = 1;\n\t\t\tchange = 1;\n\t\t\t/* fall-through */\n\t\tcase 'r':\n\t\t\tfilename = optarg;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tusage();\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tdevice_count = rtlsdr_get_device_count();\n\tif (!device_count) {\n\t\tfprintf(stderr, \"No supported devices found.\\n\");\n\t\texit(1);\n\t}\n\n\tfprintf(stderr, \"Found %d device(s):\\n\", device_count);\n\tfor (i = 0; i < device_count; i++)\n\t\tfprintf(stderr, \"  %d:  %s\\n\", i, rtlsdr_get_device_name(i));\n\tfprintf(stderr, \"\\n\");\n\n\tfprintf(stderr, \"Using device %d: %s\\n\",\n\t\tdev_index,\n\t\trtlsdr_get_device_name(dev_index));\n\n\tr = rtlsdr_open(&dev, dev_index);\n\tif (r < 0) {\n\t\tfprintf(stderr, \"Failed to open rtlsdr device #%d.\\n\", dev_index);\n\t\texit(1);\n\t}\n\n\tfprintf(stderr, \"\\n\");\n\n\tr = rtlsdr_read_eeprom(dev, buf, 0, EEPROM_SIZE);\n\tif (r < 0) {\n\t\tif (r == -3)\n\t\t\tfprintf(stderr, \"No EEPROM has been found.\\n\");\n\t\telse\n\t\t\tfprintf(stderr, \"Failed to read EEPROM, err %i.\\n\", r);\n\t\tgoto exit;\n\t}\n\n\tif (r < 0)\n\t\treturn -1;\n\n\tfprintf(stderr, \"Current configuration:\\n\");\n\tparse_eeprom_to_conf(&conf, buf);\n\tdump_config(&conf);\n\n\tif (filename) {\n\t\tfile = fopen(filename, flash_file ? \"rb\" : \"wb\");\n\t\tif (!file) {\n\t\t\tfprintf(stderr, \"Error opening file!\\n\");\n\t\t\tgoto exit;\n\t\t}\n\t\tif (flash_file) {\n\t\t\tif (fread(buf, 1, sizeof(buf), file) != sizeof(buf))\n\t\t\t\tfprintf(stderr, \"Error reading file!\\n\");\n\t\t} else {\n\t\t\tif (fwrite(buf, 1, sizeof(buf), file) != sizeof(buf))\n\t\t\t\tfprintf(stderr, \"Short write, exiting!\\n\");\n\t\t\telse\n\t\t\t\tfprintf(stderr, \"\\nDump to %s successful.\\n\", filename);\n\t\t}\n\t}\n\n\tif (manuf_str) {\n\t\tint len = strlen(manuf_str);\n\t\tif (len > MAX_STR_SIZE)\n\t\t\tlen = MAX_STR_SIZE;\n\t\tmemset(&conf.manufacturer[0], 0, MAX_STR_SIZE * sizeof(char));\n\t\tmemcpy(&conf.manufacturer[0], manuf_str,  len * sizeof(char));\n\t}\n\n\tif (product_str) {\n\t\tint len = strlen(product_str);\n\t\tif (len > MAX_STR_SIZE)\n\t\t\tlen = MAX_STR_SIZE;\n\t\tmemset(&conf.product[0], 0, MAX_STR_SIZE  * sizeof(char));\n\t\tmemcpy(&conf.product[0], product_str, len * sizeof(char));\n\t}\n\n\tif (manuf_id > 0)\n\t\tconf.vendor_id = manuf_id;\n\n\tif (product_id > 0)\n\t\tconf.product_id = product_id;\n\n\tif (serial_str) {\n\t\tint len = strlen(serial_str);\n\t\tif (len > MAX_STR_SIZE)\n\t\t\tlen = MAX_STR_SIZE;\n\t\tconf.have_serial = 1;\n\t\tmemset(&conf.serial[0], 0, MAX_STR_SIZE * sizeof(char));\n\t\tmemcpy(&conf.serial[0], serial_str, len * sizeof(char));\n\t}\n\n\tif (ir_endpoint != 0)\n\t\t conf.enable_ir = (ir_endpoint > 0) ? 1 : 0;\n\n\tif (!change)\n\t\tgoto exit;\n\n\tfprintf(stderr, \"\\nNew configuration:\\n\");\n\n\tif (default_config != CONF_NONE)\n\t\tgen_default_conf(&conf, default_config);\n\n\tif (!flash_file) {\n\t\tif (gen_eeprom_from_conf(&conf, buf) < 0)\n\t\t\tgoto exit;\n\t}\n\n\tparse_eeprom_to_conf(&conf, buf);\n\tdump_config(&conf);\n\n\tfprintf(stderr, \"Write new configuration to device [y/n]? \");\n\n\twhile ((ch = getchar())) {\n\t\tif (ch != 'y')\n\t\t\tgoto exit;\n\t\telse\n\t\t\tbreak;\n\t}\n\n\tr = rtlsdr_write_eeprom(dev, buf, 0, flash_file ? EEPROM_SIZE : 128);\n\tif (r < 0)\n\t\tfprintf(stderr, \"Error while writing EEPROM: %i\\n\", r);\n\telse\n\t\tfprintf(stderr, \"\\nConfiguration successfully written.\\n\"\n\t\t\t\t\"Please replug the device for changes\"\n\t\t\t\t\" to take effect.\\n\");\n\nexit:\n\tif (file)\n\t\tfclose(file);\n\n\trtlsdr_close(dev);\n\n\treturn r >= 0 ? r : -r;\n}\n"
  },
  {
    "path": "src/rtl_fm.c",
    "content": "/*\n * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver\n * Copyright (C) 2012 by Steve Markgraf <steve@steve-m.de>\n * Copyright (C) 2012 by Hoernchen <la@tfc-server.de>\n * Copyright (C) 2012 by Kyle Keen <keenerd@gmail.com>\n * Copyright (C) 2013 by Elias Oenal <EliasOenal@gmail.com>\n * Copyright (C) 2015 by Hayati Ayguen <h_ayguen@web.de>\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n\n/*\n * written because people could not do real time\n * FM demod on Atom hardware with GNU radio\n * based on rtl_sdr.c and rtl_tcp.c\n *\n * lots of locks, but that is okay\n * (no many-to-many locks)\n *\n * todo:\n *\t   sanity checks\n *\t   scale squelch to other input parameters\n *\t   test all the demodulations\n *\t   pad output on hop\n *\t   frequency ranges could be stored better\n *\t   scaled AM demod amplification\n *\t   auto-hop after time limit\n *\t   peak detector to tune onto stronger signals\n *\t   fifo for active hop frequency\n *\t   clips\n *\t   noise squelch\n *\t   merge stereo patch\n *\t   merge soft agc patch\n *\t   merge udp patch\n *\t   testmode to detect overruns\n *\t   watchdog to reset bad dongle\n *\t   fix oversampling\n */\n\n#include <errno.h>\n#include <signal.h>\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <ctype.h>\n\n#ifndef _WIN32\n#include <unistd.h>\n#else\n#include <windows.h>\n#include <fcntl.h>\n#include <io.h>\n#include \"getopt/getopt.h\"\n#define usleep(x) Sleep(x/1000)\n#if defined(_MSC_VER) && (_MSC_VER < 1900)\n#define snprintf _snprintf\n#endif\n#if defined(_MSC_VER) && (_MSC_VER < 1800)\n#define round(x) (x > 0.0 ? floor(x + 0.5): ceil(x - 0.5))\n#endif\n#define _USE_MATH_DEFINES\n#endif\n\n#ifdef NEED_PTHREADS_WORKARROUND\n#define HAVE_STRUCT_TIMESPEC\n#endif\n\n#include <math.h>\n#include <pthread.h>\n#include <libusb.h>\n\n#include <rtl-sdr.h>\n#include <rtl_app_ver.h>\n#include \"convenience/convenience.h\"\n#include \"convenience/rtl_convenience.h\"\n#include \"convenience/wavewrite.h\"\n\n#define DEFAULT_SAMPLE_RATE\t\t24000\n#define DEFAULT_BUF_LENGTH\t\t(1 * 16384)\n#define MAXIMUM_OVERSAMPLE\t\t16\n#define MAXIMUM_BUF_LENGTH\t\t(MAXIMUM_OVERSAMPLE * DEFAULT_BUF_LENGTH)\n#define AUTO_GAIN\t\t\t\t-100\n#define DEFAULT_BUFFER_DUMP\t\t4096\n\n#define FREQUENCIES_LIMIT\t\t1024\n\nstatic int BufferDump = DEFAULT_BUFFER_DUMP;\nstatic int OutputToStdout = 1;\nstatic int MinCaptureRate = 1000000;\n\nstatic volatile int do_exit = 0;\nstatic int lcm_post[17] = {1,1,1,3,1,5,3,7,1,9,5,11,3,13,7,15,1};\nstatic int ACTUAL_BUF_LENGTH;\n\nstatic int *atan_lut = NULL;\nstatic int atan_lut_size = 131072; /* 512 KB */\nstatic int atan_lut_coef = 8;\n\nstatic int verbosity = 0;\nstatic int printLevels = 0;\nstatic int printLevelNo = 1;\nstatic int levelMax = 0;\nstatic int levelMaxMax = 0;\nstatic double levelSum = 0.0;\nstatic int32_t prev_if_band_center_freq = 0;\n\n\nenum trigExpr { crit_IN =0, crit_OUT, crit_LT, crit_GT };\nchar * aCritStr[] = { \"in\", \"out\", \"<\", \">\" };\n\ntime_t stop_time;\nint duration = 0;\n\n\nstruct cmd_state\n{\n\tconst char * filename;\n\tFILE * file;\n\tint lineNo;\n\tchar acLine[4096];\n\tint checkADCmax;\n\tint checkADCrms;\n\tuint64_t prevFreq;\n\tuint64_t freq;\n\tint prevGain;\n\tuint32_t prevBandwidth;\n\tint gain;\n\tenum trigExpr trigCrit;\n\tdouble refLevel;\n\tdouble refLevelTol;\n\tint numMeas;\n\tint numBlockTrigger;\n\tchar * command;\n\tchar * args;\n\tdouble levelSum;\n\tint numSummed;\n\tint omitFirstFreqLevels;\n\tint waitTrigger[FREQUENCIES_LIMIT];\n\tint statNumLevels[FREQUENCIES_LIMIT];\n\tuint64_t statFreq[FREQUENCIES_LIMIT];\n\tdouble statSumLevels[FREQUENCIES_LIMIT];\n\tfloat statMinLevel[FREQUENCIES_LIMIT];\n\tfloat statMaxLevel[FREQUENCIES_LIMIT];\n};\n\nstruct dongle_state\n{\n\tint\t  exit_flag;\n\tpthread_t thread;\n\trtlsdr_dev_t *dev;\n\tint\t  dev_index;\n\tuint64_t userFreq;\n\tuint64_t freq;\n\tuint32_t rate;\n\tuint32_t bandwidth;\n\tint\t  bccorner;  /* -1 for low band corner, 0 for band center, +1 for high band corner */\n\tint\t  gain;\n\tint16_t  buf16[MAXIMUM_BUF_LENGTH];\n\tuint32_t buf_len;\n\tint\t  ppm_error;\n\tint\t  offset_tuning;\n\tint\t  direct_sampling;\n\tint\t  mute;\n\tstruct demod_state *demod_target;\n\tdouble samplePowSum;\n\tint samplePowCount;\n\tunsigned char sampleMax;\n};\n\nstruct demod_state\n{\n\tint\t  exit_flag;\n\tpthread_t thread;\n\tint16_t  lowpassed[MAXIMUM_BUF_LENGTH];\n\tint\t  lp_len;\n\tint16_t  lp_i_hist[10][6];\n\tint16_t  lp_q_hist[10][6];\n\tint16_t  result[MAXIMUM_BUF_LENGTH];\n\tint16_t  droop_i_hist[9];\n\tint16_t  droop_q_hist[9];\n\tint\t  result_len;\n\tint\t  rate_in;\n\tint\t  rate_out;\n\tint\t  rate_out2;\n\tint\t  now_r, now_j;\n\tint\t  pre_r, pre_j;\n\tint\t  prev_index;\n\tint\t  downsample;\t/* min 1, max 256 */\n\tint\t  post_downsample;\n\tint\t  output_scale;\n\tint\t  squelch_level, conseq_squelch, squelch_hits, terminate_on_squelch;\n\tint\t  downsample_passes;\n\tint\t  comp_fir_size;\n\tint\t  custom_atan;\n\tint\t  deemph, deemph_a;\n\tint\t  now_lpr;\n\tint\t  prev_lpr_index;\n\tint\t  dc_block_audio, dc_avg, adc_block_const;\n\tint\t  dc_block_raw, dc_avgI, dc_avgQ, rdc_block_const;\n\tvoid\t (*mode_demod)(struct demod_state*);\n\tpthread_rwlock_t rw;\n\tpthread_cond_t ready;\n\tpthread_mutex_t ready_m;\n\tstruct output_state *output_target;\n\tstruct cmd_state *cmd;\n};\n\nstruct output_state\n{\n\tint\t  exit_flag;\n\tpthread_t thread;\n\tFILE\t *file;\n\tchar\t *filename;\n\tchar\t *tempfilename;\n\tint16_t  result[MAXIMUM_BUF_LENGTH];\n\tint\t  result_len;\n\tint\t  rate;\n\tpthread_rwlock_t rw;\n\tpthread_cond_t ready;\n\tpthread_mutex_t ready_m;\n};\n\nstruct controller_state\n{\n\tint\t  exit_flag;\n\tpthread_t thread;\n\tuint32_t freqs[FREQUENCIES_LIMIT];\n\tint\t  freq_len;\n\tint\t  freq_now;\n\tint\t  edge;\n\tint\t  wb_mode;\n\tpthread_cond_t hop;\n\tpthread_mutex_t hop_m;\n\tstruct cmd_state *cmd;\n};\n\n/* multiple of these, eventually */\nstruct dongle_state dongle;\nstruct demod_state demod;\nstruct output_state output;\nstruct controller_state controller;\nstruct cmd_state cmd;\n\n\nvoid usage(void)\n{\n\tfprintf(stderr,\n\t\t\"rtl_fm, a simple demodulator for RTL2832 based SDR-receivers\\n\"\n\t\t\"rtl_fm  version %d.%d %s (%s)\\n\"\n\t\t\"rtl-sdr library %d.%d %s\\n\\n\",\n\t\tAPP_VER_MAJOR, APP_VER_MINOR, APP_VER_ID, __DATE__,\n\t\trtlsdr_get_version() >>16, rtlsdr_get_version() & 0xFFFF,\n\t\trtlsdr_get_ver_id() );\n\tfprintf(stderr,\n\t\t\"Usage:\\trtl_fm -f freq [-options] [filename]\\n\"\n\t\t\"\\t-f frequency_to_tune_to [Hz]\\n\"\n\t\t\"\\t\tuse multiple -f for scanning (requires squelch)\\n\"\n\t\t\"\\t\tranges supported, -f 118M:137M:25k\\n\"\n\t\t\"\\t[-C command_filename: command file with comma seperated values (.csv). sets modulation 'raw']\\n\"\n\t\t\"\\t\\tcommand file contains lines with: freq,gain,trig-crit,trig_level,trig_tolerance,#meas,#blocks,trigger_command,arguments\\n\"\n\t\t\"\\t\\t with trig_crit one of 'in', 'out', 'lt' or 'gt'\\n\"\n\t\t\"\\t[-B num_samples at capture rate: remove that many samples at capture_rate after changing frequency (default: 4096)]\\n\"\n\t\t\"\\t[-m minimum_capture_rate Hz (default: 1m, min=900k, max=3.2m)]\\n\"\n\t\t\"\\t[-v increase verbosity (default: 0)]\\n\"\n\t\t\"\\t[-M modulation (default: fm)]\\n\"\n\t\t\"\\t\tfm or nbfm or nfm, wbfm or wfm, raw or iq, am, usb, lsb\\n\"\n\t\t\"\\t\twbfm == -M fm -s 170k -o 4 -A fast -r 32k -l 0 -E deemp\\n\"\n\t\t\"\\t\traw mode outputs 2x16 bit IQ pairs\\n\"\n\t\t\"\\t[-s sample_rate (default: 24k)]\\n\"\n\t\t\"\\t[-d device_index or serial (default: 0)]\\n\"\n\t\t\"\\t[-T enable bias-T on GPIO PIN 0 (works for rtl-sdr.com v3 dongles)]\\n\"\n\t\t\"\\t[-D direct_sampling_mode (default: 0, 1 = I, 2 = Q, 3 = I below threshold, 4 = Q below threshold)]\\n\"\n\t\t\"\\t[-D direct_sampling_threshold_frequency (default: 0 use tuner specific frequency threshold for 3 and 4)]\\n\"\n\t\t\"\\t[-g tuner_gain (default: automatic)]\\n\"\n\t\t\"\\t[-w tuner_bandwidth in Hz (default: automatic)]\\n\"\n\t\t\"\\t[-W length of single buffer in units of 512 samples (default: 32 was 256)]\\n\"\n\t\t\"\\t[-l squelch_level (default: 0/off)]\\n\"\n\t\t\"\\t[-L N  prints levels every N calculations]\\n\"\n\t\t\"\\t\toutput are comma separated values (csv):\\n\"\n\t\t\"\\t\tavg rms since last output, max rms since last output, overall max rms, squelch (paramed), rms, rms level, avg rms level\\n\"\n\t\t\"\\t[-c de-emphasis_time_constant in us for wbfm. 'us' or 'eu' for 75/50 us (default: us)]\\n\"\n#if 0\n\t\t\"\\t\tfor fm squelch is inverted\\n\"\n#endif\n\t\t\"\\t[-o oversampling (default: 1, 4 recommended)]\\n\"\n\t\t\"\\t[-p ppm_error (default: 0)]\\n\"\n\t\t\"\\t[-R run_seconds] specify number of seconds to run\\n\"\n\t\t\"\\t[-E enable_option (default: none)]\\n\"\n\t\t\"\\t\tuse multiple -E to enable multiple options\\n\"\n\t\t\"\\t\tedge:   enable lower edge tuning\\n\"\n\t\t\"\\t\trdc:    enable dc blocking filter on raw I/Q data at capture rate\\n\"\n\t\t\"\\t\tadc:    enable dc blocking filter on demodulated audio\\n\"\n\t\t\"\\t\tdc:     same as adc\\n\"\n\t\t\"\\t\trtlagc: enable rtl2832's digital agc (default: off)\\n\"\n\t\t\"\\t\tagc:    same as rtlagc\\n\"\n\t\t\"\\t\tdeemp:  enable de-emphasis filter\\n\"\n\t\t\"\\t\tdirect: enable direct sampling (bypasses tuner, uses rtl2832 xtal)\\n\"\n\t\t\"\\t\toffset: enable offset tuning (only e4000 tuner)\\n\"\n\t\t\"\\t\tbcc:    use tuner bandwidths center as band center (default)\\n\"\n\t\t\"\\t\tbclo:   use tuner bandwidths low  corner as band center\\n\"\n\t\t\"\\t\tbchi:   use tuner bandwidths high corner as band center\\n\"\n\t\t\"%s\"\n\t\t\"\\t[-q dc_avg_factor for option rdc (default: 9)]\\n\"\n\t\t\"\\t[-n disables demodulation output to stdout/file]\\n\"\n\t\t\"\\t[-H write wave Header to file (default: off)]\\n\"\n\t\t\"\\t\tlimitation: only 1st tuned frequency will be written into the header!\\n\"\n\t\t\"\\tfilename ('-' means stdout)\\n\"\n\t\t\"\\t\tomitting the filename also uses stdout\\n\\n\"\n\t\t\"Experimental options:\\n\"\n\t\t\"\\t[-r resample_rate (default: none / same as -s)]\\n\"\n\t\t\"\\t[-t squelch_delay (default: 10)]\\n\"\n\t\t\"\\t\t+values will mute/scan, -values will exit\\n\"\n\t\t\"\\t[-F fir_size (default: off)]\\n\"\n\t\t\"\\t\tenables low-leakage downsample filter\\n\"\n\t\t\"\\t\tsize can be 0 or 9.  0 has bad roll off\\n\"\n\t\t\"\\t[-A std/fast/lut/ale choose atan math (default: std)]\\n\"\n#if 0\n\t\t\"\\t[-C clip_path (default: off)\\n\"\n\t\t\"\\t (create time stamped raw clips, requires squelch)\\n\"\n\t\t\"\\t (path must have '\\%s' and will expand to date_time_freq)\\n\"\n\t\t\"\\t[-H hop_fifo (default: off)\\n\"\n\t\t\"\\t (fifo will contain the active frequency)\\n\"\n#endif\n\t\t\"\\n\"\n\t\t\"Produces signed 16 bit ints, use Sox or aplay to hear them.\\n\"\n\t\t\"\\trtl_fm ... | play -t raw -r 24k -es -b 16 -c 1 -V1 -\\n\"\n\t\t\"\\t\t\t   | aplay -r 24000 -f S16_LE -t raw -c 1\\n\"\n\t\t\"\\t  -M wbfm  | play -r 32k ... \\n\"\n\t\t\"\\t  -s 22050 | multimon -t raw /dev/stdin\\n\\n\"\n\t\t, rtlsdr_get_opt_help(1) );\n\texit(1);\n}\n\n#ifdef _WIN32\nBOOL WINAPI\nsighandler(int signum)\n{\n\tif (CTRL_C_EVENT == signum) {\n\t\tfprintf(stderr, \"Signal caught, exiting!\\n\");\n\t\tdo_exit = 1;\n\t\trtlsdr_cancel_async(dongle.dev);\n\t\treturn TRUE;\n\t}\n\treturn FALSE;\n}\n#else\nstatic void sighandler(int signum)\n{\n\tfprintf(stderr, \"Signal caught, exiting!\\n\");\n\tdo_exit = 1;\n\trtlsdr_cancel_async(dongle.dev);\n}\n#endif\n\n/* more cond dumbness */\n#define safe_cond_signal(n, m) do { pthread_mutex_lock(m); pthread_cond_signal(n); pthread_mutex_unlock(m); } while (0)\n#define safe_cond_wait(n, m)   do { pthread_mutex_lock(m); pthread_cond_wait(n, m); pthread_mutex_unlock(m); } while (0)\n\n/* {length, coef, coef, coef}  and scaled by 2^15\n   for now, only length 9, optimal way to get +85% bandwidth */\n#define CIC_TABLE_MAX 10\nint cic_9_tables[][10] = {\n\t{0,},\n\t{9, -156,  -97, 2798, -15489, 61019, -15489, 2798,  -97, -156},\n\t{9, -128, -568, 5593, -24125, 74126, -24125, 5593, -568, -128},\n\t{9, -129, -639, 6187, -26281, 77511, -26281, 6187, -639, -129},\n\t{9, -122, -612, 6082, -26353, 77818, -26353, 6082, -612, -122},\n\t{9, -120, -602, 6015, -26269, 77757, -26269, 6015, -602, -120},\n\t{9, -120, -582, 5951, -26128, 77542, -26128, 5951, -582, -120},\n\t{9, -119, -580, 5931, -26094, 77505, -26094, 5931, -580, -119},\n\t{9, -119, -578, 5921, -26077, 77484, -26077, 5921, -578, -119},\n\t{9, -119, -577, 5917, -26067, 77473, -26067, 5917, -577, -119},\n\t{9, -199, -362, 5303, -25505, 77489, -25505, 5303, -362, -199},\n};\n\n#if defined(_MSC_VER) && (_MSC_VER < 1800)\ndouble log2(double n)\n{\n\treturn log(n) / log(2.0);\n}\n#endif\n\n\n/* uint8_t negation = 255 - x */\n#define NEG_U8( x )     ( 255 - x )\n/* MUL_PLUS_J:    (a + j*b ) * j =  -b + j *  a */\n/* MUL_MINUS_ONE: (a + j*b ) * -1 = -a + j * -b */\n/* MUL_MINUS_J:   (a + j*b ) * -j =  b + j * -a */\n#define MUL_PLUS_J_U8( X, J )\t\\\n    tmp = X[J]; \\\n    X[J] = NEG_U8( X[J+1] ); \\\n    X[J+1] = tmp\n\n#define MUL_MINUS_ONE_U8( X, J ) \\\n    X[J] = NEG_U8( X[J] ); \\\n    X[J+1] = NEG_U8( X[J+1] )\n\n#define MUL_MINUS_J_U8( X, J ) \\\n    tmp = X[J]; \\\n    X[J] = X[J+1]; \\\n    X[J+1] = NEG_U8( tmp )\n\n\n#define MUL_PLUS_J_INT( X, J )\t\\\n    tmp = X[J]; \\\n    X[J] = - X[J+1]; \\\n    X[J+1] = tmp\n\n#define MUL_MINUS_ONE_INT( X, J ) \\\n    X[J] = - X[J]; \\\n    X[J+1] = - X[J+1]\n\n#define MUL_MINUS_J_INT( X, J ) \\\n    tmp = X[J]; \\\n    X[J] = X[J+1]; \\\n    X[J+1] = -tmp\n\n\nvoid rotate16_90(int16_t *buf, uint32_t len)\n{\n\t/* 90 degree rotation is 1, +j, -1, -j */\n\tuint32_t i;\n\tint16_t tmp;\n\tfor (i=0; i<len; i+=8) {\n\t\tMUL_PLUS_J_INT( buf, i+2 );\n\t\tMUL_MINUS_ONE_INT( buf, i+4 );\n\t\tMUL_MINUS_J_INT( buf, i+6 );\n\t}\n}\n\nvoid rotate16_neg90(int16_t *buf, uint32_t len)\n{\n\t/* -90 degree rotation is 1, -j, -1, +j */\n\tuint32_t i;\n\tint16_t tmp;\n\tfor (i=0; i<len; i+=8) {\n\t\tMUL_MINUS_J_INT( buf, i+2 );\n\t\tMUL_MINUS_ONE_INT( buf, i+4 );\n\t\tMUL_PLUS_J_INT( buf, i+6 );\n\t}\n}\n\n\nvoid rotate_90(unsigned char *buf, uint32_t len)\n{\n\t/* 90 degree rotation is 1, +j, -1, -j */\n\tuint32_t i;\n\tunsigned char tmp;\n\tfor (i=0; i<len; i+=8) {\n\t\tMUL_PLUS_J_U8( buf, i+2 );\n\t\tMUL_MINUS_ONE_U8( buf, i+4 );\n\t\tMUL_MINUS_J_U8( buf, i+6 );\n\t}\n}\n\nvoid rotate_neg90(unsigned char *buf, uint32_t len)\n{\n\t/* -90 degree rotation is 1, -j, -1, +j */\n\tuint32_t i;\n\tunsigned char tmp;\n\tfor (i=0; i<len; i+=8) {\n\t\tMUL_MINUS_J_U8( buf, 2 );\n\t\tMUL_MINUS_ONE_U8( buf, 4 );\n\t\tMUL_PLUS_J_U8( buf, 6 );\n\t}\n}\n\nvoid low_pass(struct demod_state *d)\n/* simple square window FIR */\n{\n\tint i=0, i2=0;\n\twhile (i < d->lp_len) {\n\t\td->now_r += d->lowpassed[i];\n\t\td->now_j += d->lowpassed[i+1];\n\t\ti += 2;\n\t\td->prev_index++;\n\t\tif (d->prev_index < d->downsample) {\n\t\t\tcontinue;\n\t\t}\n\t\td->lowpassed[i2]   = d->now_r; /* * d->output_scale; */\n\t\td->lowpassed[i2+1] = d->now_j; /* * d->output_scale; */\n\t\td->prev_index = 0;\n\t\td->now_r = 0;\n\t\td->now_j = 0;\n\t\ti2 += 2;\n\t}\n\td->lp_len = i2;\n}\n\nstatic char * trim(char * s) {\n\tchar *p = s;\n\tint l = strlen(p);\n\n\twhile(isspace(p[l - 1])) p[--l] = 0;\n\twhile(*p && isspace(*p)) ++p;\n\n\treturn p;\n}\n\n\nstatic void cmd_init(struct cmd_state *c)\n{\n\tint k;\n\tc->filename = NULL;\n\tc->file = NULL;\n\tc->lineNo = 1;\n\tc->checkADCmax = 0;\n\tc->checkADCrms = 0;\n\tc->prevFreq = -1;\n\tc->prevGain = -200;\n\tc->prevBandwidth = -1;\n\tc->freq = 0;\n\tc->gain = 0;\n\tc->trigCrit = crit_IN;\n\tc->refLevel = 0.0;\n\tc->refLevelTol = 0.0;\n\tc->numMeas = 0;\n\tc->numBlockTrigger = 0;\n\tc->command = NULL;\n\tc->args = NULL;\n\tc->levelSum = 0.0;\n\tc->numSummed = 0;\n\tc->omitFirstFreqLevels = 3;\n\tfor (k = 0; k < FREQUENCIES_LIMIT; k++) {\n\t\tc->waitTrigger[k] = 0;\n\t\tc->statNumLevels[k] = 0;\n\t\tc->statFreq[k] = 0;\n\t\tc->statSumLevels[k] = 0.0;\n\t\tc->statMinLevel[k] = 0.0F;\n\t\tc->statMaxLevel[k] = 0.0F;\n\t}\n}\n\nstatic int toNextCmdLine(struct cmd_state *c)\n{\n\tconst char * delim = \",\";\n\tchar * pLine = NULL;\n\tchar * pCmdFreq = NULL;\n\tchar * pCmdGain = NULL;\n\tchar * pCmdTrigCrit = NULL;\n\tchar * pCmdLevel = NULL;\n\tchar * pCmdTol = NULL;\n\tchar * pCmdNumMeas = NULL;\n\tchar * pCmdNumBlockTrigger = NULL;\n\tint numValidLines = 1;  /* assume valid lines */\n\twhile (1) {\n\t\tif (c->file && feof(c->file)) {\n\t\t\tif (!numValidLines) {\n\t\t\t\tfprintf(stderr, \"error: command file '%s' does not contain any valid lines!\\n\", c->filename);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tfclose(c->file);\n\t\t\tc->file = NULL;\n\t\t}\n\t\tif (!c->file) {\n\t\t\tc->file = fopen(c->filename, \"r\");\n\t\t\tnumValidLines = 0;\n\t\t\tc->lineNo = 0;\n\t\t}\n\t\tif (!c->file)\n\t\t\treturn 0;\n\t\tpLine = fgets(c->acLine, 4096, c->file);\n\t\tif (!pLine) {\n\t\t\tcontinue;\n\t\t}\n\t\tc->lineNo++;\n\t\tpLine = trim(c->acLine);\n\t\tif (pLine[0]=='#' || pLine[0]==0)\n\t\t\tcontinue;  /* detect comment lines and empty lines */\n\n\t\tpCmdFreq = strtok(pLine, delim);\n\t\tif (!pCmdFreq) { fprintf(stderr, \"error parsing frequency in line %d of command file!\\n\", c->lineNo); continue; }\n\t\tpCmdFreq = trim(pCmdFreq);\n\t\t/* check keywords */\n\t\tif (!strcmp(pCmdFreq, \"adc\") || !strcmp(pCmdFreq, \"adcmax\")) {\n\t\t\tc->checkADCmax = 1;\n\t\t\tcontinue;\n\t\t}\n\t\telse if (!strcmp(pCmdFreq, \"adcrms\")) {\n\t\t\tc->checkADCrms = 1;\n\t\t\tcontinue;\n\t\t}\n\t\tc->freq = (uint64_t)atofs(pCmdFreq);\n\n\t\tpCmdGain = strtok(NULL, delim);\n\t\tif (!pCmdGain) { fprintf(stderr, \"error parsing gain in line %d of command file!\\n\", c->lineNo); continue; }\n\t\tpCmdGain = trim(pCmdGain);\n\t\tif (!strcmp(pCmdGain,\"auto\") || !strcmp(pCmdGain,\"a\"))\n\t\t\tc->gain = AUTO_GAIN;\n\t\telse\n\t\t\tc->gain = (int)(atof(pCmdGain) * 10);\n\n\t\tpCmdTrigCrit = strtok(NULL, delim);\n\t\tif (!pCmdTrigCrit) { fprintf(stderr, \"error parsing expr in line %d of command file!\\n\", c->lineNo); continue; }\n\t\tpCmdTrigCrit = trim(pCmdTrigCrit);\n\t\tif (!strcmp(pCmdTrigCrit,\"in\"))\t\t\tc->trigCrit = crit_IN;\n\t\telse if (!strcmp(pCmdTrigCrit,\"==\"))\tc->trigCrit = crit_IN;\n\t\telse if (!strcmp(pCmdTrigCrit,\"out\"))\tc->trigCrit = crit_OUT;\n\t\telse if (!strcmp(pCmdTrigCrit,\"!=\"))\tc->trigCrit = crit_OUT;\n\t\telse if (!strcmp(pCmdTrigCrit,\"<>\"))\tc->trigCrit = crit_OUT;\n\t\telse if (!strcmp(pCmdTrigCrit,\"lt\"))\tc->trigCrit = crit_LT;\n\t\telse if (!strcmp(pCmdTrigCrit,\"<\"))\t\tc->trigCrit = crit_LT;\n\t\telse if (!strcmp(pCmdTrigCrit,\"gt\"))\tc->trigCrit = crit_GT;\n\t\telse if (!strcmp(pCmdTrigCrit,\">\"))\t\tc->trigCrit = crit_GT;\n\t\telse { fprintf(stderr, \"error parsing expr in line %d of command file!\\n\", c->lineNo); continue; }\n\n\t\tpCmdLevel = strtok(NULL, delim);\n\t\tif (!pCmdLevel) { fprintf(stderr, \"error parsing level in line %d of command file!\\n\", c->lineNo); continue; }\n\t\tc->refLevel = atof(trim(pCmdLevel));\n\n\t\tpCmdTol = strtok(NULL, delim);\n\t\tif (!pCmdTol) { fprintf(stderr, \"error parsing tolerance in line %d of command file!\\n\", c->lineNo); continue; }\n\t\tc->refLevelTol = atof(trim(pCmdTol));\n\n\t\tpCmdNumMeas = strtok(NULL, delim);\n\t\tif (!pCmdNumMeas) { fprintf(stderr, \"error parsing #measurements in line %d of command file!\\n\", c->lineNo); continue; }\n\t\tc->numMeas = atoi(trim(pCmdNumMeas));\n\t\tif (c->numMeas <= 0) { fprintf(stderr, \"warning: fixed #measurements from %d to 10 in line %d of command file!\\n\", c->numMeas, c->lineNo); c->numMeas=10; }\n\n\t\tpCmdNumBlockTrigger = strtok(NULL, delim);\n\t\tif (!pCmdNumBlockTrigger) { fprintf(stderr, \"error parsing #blockTrigger in line %d of command file!\\n\", c->lineNo); continue; }\n\t\tc->numBlockTrigger = atoi(trim(pCmdNumBlockTrigger));\n\n\t\tc->command = strtok(NULL, delim);\n\t\t/* no check: allow empty string. just trim it */\n\t\tif (c->command)\n\t\t\tc->command = trim(c->command);\n\n\t\tc->args = strtok(NULL, delim);\n\t\t/* no check: allow empty string. just trim it */\n\t\tif (c->args)\n\t\t\tc->args = trim(c->args);\n\n\t\tif (verbosity >= 2)\n\t\t\tfprintf(stderr, \"read from cmd file: freq %.3f kHz, gain %0.1f dB, level %s {%.1f +/- %.1f}, cmd '%s %s'\\n\",\n\t\t\t\tc->freq /1000.0, c->gain /10.0, \n\t\t\t\taCritStr[c->trigCrit], c->refLevel, c->refLevelTol,\n\t\t\t\t(c->command ? c->command : \"%\"), (c->args ? c->args : \"\") );\n\n\t\tnumValidLines++;\n\t\treturn 1;\n\t}\n\n\treturn 0;\n}\n\nstatic int testTrigCrit(struct cmd_state *c, double level)\n{\n\tswitch(c->trigCrit)\n\t{\n\tcase crit_IN:\treturn ( c->refLevel-c->refLevelTol <= level && level <= c->refLevel+c->refLevelTol );\n\tcase crit_OUT:\treturn ( c->refLevel-c->refLevelTol > level || level > c->refLevel+c->refLevelTol );\n\tcase crit_LT:\treturn ( level < c->refLevel-c->refLevelTol );\n\tcase crit_GT:\treturn ( level > c->refLevel+c->refLevelTol );\n\t}\n\treturn 0;\n}\n\nstatic void checkTriggerCommand(struct cmd_state *c, unsigned char adcSampleMax, double powerSum, int powerCount )\n{\n\tchar acRepFreq[32], acRepGain[32], acRepMLevel[32], acRepRefLevel[32], acRepRefTolerance[32];\n\tchar * execSearchStrings[7] = { \"!freq!\", \"!gain!\", \"!mlevel!\", \"!crit!\", \"!reflevel!\", \"!reftol!\", NULL };\n\tchar * execReplaceStrings[7] = { acRepFreq, acRepGain, acRepMLevel, NULL, acRepRefLevel, acRepRefTolerance, NULL };\n\tdouble triggerLevel;\n\tdouble adcRms = 0.0;\n\tint k, triggerCommand = 0;\n\tint adcMax = (int)adcSampleMax - 127;\n\tchar adcText[128];\n\n\tif (c->numSummed != c->numMeas)\n\t\treturn;\n\n\tif (c->omitFirstFreqLevels) {\n\t\t/* workaround: measured levels of first controlled frequency looks wrong! */\n\t\tc->omitFirstFreqLevels--;\n\t\treturn;\n\t}\n\n\t/* decrease all counters */\n\tfor ( k = 0; k < FREQUENCIES_LIMIT; k++ ) {\n\t\tif ( c->waitTrigger[k] > 0 ) {\n\t\t\tc->waitTrigger[k] -= c->numMeas;\n\t\t\tif ( c->waitTrigger[k] < 0 )\n\t\t\t\tc->waitTrigger[k] = 0;\n\t\t}\n\t}\n\ttriggerLevel = 20.0 * log10( 1E-10 + c->levelSum / c->numSummed );\n\ttriggerCommand = testTrigCrit(c, triggerLevel);\n\n\t/* update statistics */\n\tif ( c->lineNo < FREQUENCIES_LIMIT ) {\n\t\tif ( c->statNumLevels[c->lineNo] == 0 ) {\n\t\t\t++c->statNumLevels[c->lineNo];\n\t\t\tc->statFreq[c->lineNo] = c->freq;\n\t\t\tc->statSumLevels[c->lineNo] = triggerLevel;\n\t\t\tc->statMinLevel[c->lineNo] = (float)triggerLevel;\n\t\t\tc->statMaxLevel[c->lineNo] = (float)triggerLevel;\n\t\t} else if ( c->statFreq[c->lineNo] == c->freq ) {\n\t\t\t++c->statNumLevels[c->lineNo];\n\t\t\tc->statSumLevels[c->lineNo] += triggerLevel;\n\t\t\tif ( c->statMinLevel[c->lineNo] > (float)triggerLevel )\n\t\t\t\tc->statMinLevel[c->lineNo] = (float)triggerLevel;\n\t\t\tif ( c->statMaxLevel[c->lineNo] < (float)triggerLevel )\n\t\t\t\tc->statMaxLevel[c->lineNo] = (float)triggerLevel;\n\t\t}\n\t}\n\n\tadcText[0] = 0;\n\tif (c->checkADCmax && c->checkADCrms) {\n\t\tadcRms = (powerCount >0) ? sqrt( powerSum / powerCount ) : -1.0;\n\t\tsprintf(adcText, \"adc max %3d%s rms %5.1f \", adcMax, (adcMax>=64 ? (adcMax>=120 ? \"!!\" : \"! \" ) : \"  \"), adcRms );\n\t}\n\telse if (c->checkADCmax)\n\t\tsprintf(adcText, \"adc max %3d%s \", adcMax, (adcMax>=64 ? (adcMax>=120 ? \"!!\" : \"! \" ) : \"  \") );\n\telse if (c->checkADCrms) {\n\t\tadcRms = (powerCount >0) ? sqrt( powerSum / powerCount ) : -1.0;\n\t\tsprintf(adcText, \"adc rms %5.1f \", adcRms );\n\t}\n\n\tif ( c->lineNo < FREQUENCIES_LIMIT && c->waitTrigger[c->lineNo] <= 0 ) {\n\t\t\tc->waitTrigger[c->lineNo] = triggerCommand ? c->numBlockTrigger : 0;\n\t\t\tif (verbosity)\n\t\t\t\tfprintf(stderr, \"%.3f kHz: gain %4.1f + level %4.1f dB %s=> %s\\n\",\n\t\t\t\t\t(double)c->freq /1000.0, 0.1*c->gain, triggerLevel, adcText,\n\t\t\t\t\t(triggerCommand ? \"activates trigger\" : \"does not trigger\") );\n\t\t\tif (triggerCommand && c->command && c->command[0]) {\n\t\t\t\tfprintf(stderr, \"command to trigger is '%s %s'\\n\", c->command, c->args);\n\t\t\t\t/* prepare search/replace of special parameters for command arguments */\n\t\t\t\tsnprintf(acRepFreq, 32, \"%.0f\", (double)c->freq);\n\t\t\t\tsnprintf(acRepGain, 32, \"%d\", c->gain);\n\t\t\t\tsnprintf(acRepMLevel, 32, \"%d\", (int)(0.5 + triggerLevel*10.0) );\n\t\t\t\texecReplaceStrings[3] = aCritStr[c->trigCrit];\n\t\t\t\tsnprintf(acRepRefLevel, 32, \"%d\", (int)(0.5 + c->refLevel*10.0) );\n\t\t\t\tsnprintf(acRepRefTolerance, 32, \"%d\", (int)(0.5 + c->refLevelTol*10.0) );\n\t\t\t\texecuteInBackground( c->command, c->args, execSearchStrings, execReplaceStrings );\n\t\t\t}\n\t} else if (verbosity) {\n\t\tfprintf(stderr, \"%.3f kHz: gain %4.1f + level %4.1f dB %s=> %s, blocks for %d\\n\",\n\t\t\t(double)c->freq /1000.0, 0.1*c->gain, triggerLevel, adcText, (triggerCommand ? \"would trigger\" : \"does not trigger\"),\n\t\t\t(c->lineNo < FREQUENCIES_LIMIT ? c->waitTrigger[c->lineNo] : -1 ) );\n\t}\n\tc->numSummed++;\n}\n\n\nint low_pass_simple(int16_t *signal2, int len, int step)\n/* no wrap around, length must be multiple of step */\n{\n\tint i, i2, sum;\n\tfor(i=0; i < len; i+=step) {\n\t\tsum = 0;\n\t\tfor(i2=0; i2<step; i2++) {\n\t\t\tsum += (int)signal2[i + i2];\n\t\t}\n\t\t/* signal2[i/step] = (int16_t)(sum / step); */\n\t\tsignal2[i/step] = (int16_t)(sum);\n\t}\n\tsignal2[i/step + 1] = signal2[i/step];\n\treturn len / step;\n}\n\nvoid low_pass_real(struct demod_state *s)\n/* simple square window FIR */\n/* add support for upsampling? */\n{\n\tint i=0, i2=0;\n\tint fast = (int)s->rate_out;\n\tint slow = s->rate_out2;\n\twhile (i < s->result_len) {\n\t\ts->now_lpr += s->result[i];\n\t\ti++;\n\t\ts->prev_lpr_index += slow;\n\t\tif (s->prev_lpr_index < fast) {\n\t\t\tcontinue;\n\t\t}\n\t\ts->result[i2] = (int16_t)(s->now_lpr / (fast/slow));\n\t\ts->prev_lpr_index -= fast;\n\t\ts->now_lpr = 0;\n\t\ti2 += 1;\n\t}\n\ts->result_len = i2;\n}\n\nvoid fifth_order(int16_t *data, int length, int16_t *hist)\n/* for half of interleaved data */\n{\n\tint i;\n\tint16_t a, b, c, d, e, f;\n\ta = hist[1];\n\tb = hist[2];\n\tc = hist[3];\n\td = hist[4];\n\te = hist[5];\n\tf = data[0];\n\t/* a downsample should improve resolution, so don't fully shift */\n\tdata[0] = (a + (b+e)*5 + (c+d)*10 + f) >> 4;\n\tfor (i=4; i<length; i+=4) {\n\t\ta = c;\n\t\tb = d;\n\t\tc = e;\n\t\td = f;\n\t\te = data[i-2];\n\t\tf = data[i];\n\t\tdata[i/2] = (a + (b+e)*5 + (c+d)*10 + f) >> 4;\n\t}\n\t/* archive */\n\thist[0] = a;\n\thist[1] = b;\n\thist[2] = c;\n\thist[3] = d;\n\thist[4] = e;\n\thist[5] = f;\n}\n\nvoid generic_fir(int16_t *data, int length, int *fir, int16_t *hist)\n/* Okay, not at all generic.  Assumes length 9, fix that eventually. */\n{\n\tint d, temp, sum;\n\tfor (d=0; d<length; d+=2) {\n\t\ttemp = data[d];\n\t\tsum = 0;\n\t\tsum += (hist[0] + hist[8]) * fir[1];\n\t\tsum += (hist[1] + hist[7]) * fir[2];\n\t\tsum += (hist[2] + hist[6]) * fir[3];\n\t\tsum += (hist[3] + hist[5]) * fir[4];\n\t\tsum +=\t\t\thist[4]  * fir[5];\n\t\tdata[d] = sum >> 15 ;\n\t\thist[0] = hist[1];\n\t\thist[1] = hist[2];\n\t\thist[2] = hist[3];\n\t\thist[3] = hist[4];\n\t\thist[4] = hist[5];\n\t\thist[5] = hist[6];\n\t\thist[6] = hist[7];\n\t\thist[7] = hist[8];\n\t\thist[8] = temp;\n\t}\n}\n\n/* define our own complex math ops\n   because ARMv5 has no hardware float */\n\nvoid multiply(int ar, int aj, int br, int bj, int *cr, int *cj)\n{\n\t*cr = ar*br - aj*bj;\n\t*cj = aj*br + ar*bj;\n}\n\nint polar_discriminant(int ar, int aj, int br, int bj)\n{\n\tint cr, cj;\n\tdouble angle;\n\tmultiply(ar, aj, br, -bj, &cr, &cj);\n\tangle = atan2((double)cj, (double)cr);\n\treturn (int)(angle / 3.14159 * (1<<14));\n}\n\nint fast_atan2(int y, int x)\n/* pre scaled for int16 */\n{\n\tint yabs, angle;\n\tint pi4=(1<<12), pi34=3*(1<<12);  /* note pi = 1<<14 */\n\tif (x==0 && y==0) {\n\t\treturn 0;\n\t}\n\tyabs = y;\n\tif (yabs < 0) {\n\t\tyabs = -yabs;\n\t}\n\tif (x >= 0) {\n\t\tangle = pi4  - pi4 * (x-yabs) / (x+yabs);\n\t} else {\n\t\tangle = pi34 - pi4 * (x+yabs) / (yabs-x);\n\t}\n\tif (y < 0) {\n\t\treturn -angle;\n\t}\n\treturn angle;\n}\n\nint polar_disc_fast(int ar, int aj, int br, int bj)\n{\n\tint cr, cj;\n\tmultiply(ar, aj, br, -bj, &cr, &cj);\n\treturn fast_atan2(cj, cr);\n}\n\nint atan_lut_init(void)\n{\n\tint i = 0;\n\n\tatan_lut = malloc(atan_lut_size * sizeof(int));\n\n\tfor (i = 0; i < atan_lut_size; i++) {\n\t\tatan_lut[i] = (int) (atan((double) i / (1<<atan_lut_coef)) / 3.14159 * (1<<14));\n\t}\n\n\treturn 0;\n}\n\nint polar_disc_lut(int ar, int aj, int br, int bj)\n{\n\tint cr, cj, x, x_abs;\n\n\tmultiply(ar, aj, br, -bj, &cr, &cj);\n\n\t/* special cases */\n\tif (cr == 0 || cj == 0) {\n\t\tif (cr == 0 && cj == 0)\n\t\t\t{return 0;}\n\t\tif (cr == 0 && cj > 0)\n\t\t\t{return 1 << 13;}\n\t\tif (cr == 0 && cj < 0)\n\t\t\t{return -(1 << 13);}\n\t\tif (cj == 0 && cr > 0)\n\t\t\t{return 0;}\n\t\tif (cj == 0 && cr < 0)\n\t\t\t{return 1 << 14;}\n\t}\n\n\t/* real range -32768 - 32768 use 64x range -> absolute maximum: 2097152 */\n\tx = (cj << atan_lut_coef) / cr;\n\tx_abs = abs(x);\n\n\tif (x_abs >= atan_lut_size) {\n\t\t/* we can use linear range, but it is not necessary */\n\t\treturn (cj > 0) ? 1<<13 : -(1<<13);\n\t}\n\n\tif (x > 0) {\n\t\treturn (cj > 0) ? atan_lut[x] : atan_lut[x] - (1<<14);\n\t} else {\n\t\treturn (cj > 0) ? (1<<14) - atan_lut[-x] : -atan_lut[-x];\n\t}\n\n\treturn 0;\n}\n\nint esbensen(int ar, int aj, int br, int bj)\n/*\n  input signal: s(t) = a*exp(-i*w*t+p)\n  a = amplitude, w = angular freq, p = phase difference\n  solve w\n  s' = -i(w)*a*exp(-i*w*t+p)\n  s'*conj(s) = -i*w*a*a\n  s'*conj(s) / |s|^2 = -i*w\n*/\n{\n\tint cj, dr, dj;\n\tint scaled_pi = 2608; /* 1<<14 / (2*pi) */\n\tdr = (br - ar) * 2;\n\tdj = (bj - aj) * 2;\n\tcj = bj*dr - br*dj; /* imag(ds*conj(s)) */\n\treturn (scaled_pi * cj / (ar*ar+aj*aj+1));\n}\n\nvoid fm_demod(struct demod_state *fm)\n{\n\tint i, pcm;\n\tint16_t *lp = fm->lowpassed;\n\tpcm = polar_discriminant(lp[0], lp[1],\n\t\tfm->pre_r, fm->pre_j);\n\tfm->result[0] = (int16_t)pcm;\n\tfor (i = 2; i < (fm->lp_len-1); i += 2) {\n\t\tswitch (fm->custom_atan) {\n\t\tcase 0:\n\t\t\tpcm = polar_discriminant(lp[i], lp[i+1],\n\t\t\t\tlp[i-2], lp[i-1]);\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\tpcm = polar_disc_fast(lp[i], lp[i+1],\n\t\t\t\tlp[i-2], lp[i-1]);\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\tpcm = polar_disc_lut(lp[i], lp[i+1],\n\t\t\t\tlp[i-2], lp[i-1]);\n\t\t\tbreak;\n\t\tcase 3:\n\t\t\tpcm = esbensen(lp[i], lp[i+1],\n\t\t\t\tlp[i-2], lp[i-1]);\n\t\t\tbreak;\n\t\t}\n\t\tfm->result[i/2] = (int16_t)pcm;\n\t}\n\tfm->pre_r = lp[fm->lp_len - 2];\n\tfm->pre_j = lp[fm->lp_len - 1];\n\tfm->result_len = fm->lp_len/2;\n}\n\nvoid am_demod(struct demod_state *fm)\n/* todo, fix this extreme laziness */\n{\n\tint i, pcm;\n\tint16_t *lp = fm->lowpassed;\n\tint16_t *r  = fm->result;\n\tfor (i = 0; i < fm->lp_len; i += 2) {\n\t\t/* hypot uses floats but won't overflow\n\t\t* r[i/2] = (int16_t)hypot(lp[i], lp[i+1]);\n\t\t*/\n\t\tpcm = lp[i] * lp[i];\n\t\tpcm += lp[i+1] * lp[i+1];\n\t\tr[i/2] = (int16_t)sqrt(pcm) * fm->output_scale;\n\t}\n\tfm->result_len = fm->lp_len/2;\n\t/* lowpass? (3khz)  highpass?  (dc) */\n}\n\nvoid usb_demod(struct demod_state *fm)\n{\n\tint i, pcm;\n\tint16_t *lp = fm->lowpassed;\n\tint16_t *r  = fm->result;\n\tfor (i = 0; i < fm->lp_len; i += 2) {\n\t\tpcm = lp[i] + lp[i+1];\n\t\tr[i/2] = (int16_t)pcm * fm->output_scale;\n\t}\n\tfm->result_len = fm->lp_len/2;\n}\n\nvoid lsb_demod(struct demod_state *fm)\n{\n\tint i, pcm;\n\tint16_t *lp = fm->lowpassed;\n\tint16_t *r  = fm->result;\n\tfor (i = 0; i < fm->lp_len; i += 2) {\n\t\tpcm = lp[i] - lp[i+1];\n\t\tr[i/2] = (int16_t)pcm * fm->output_scale;\n\t}\n\tfm->result_len = fm->lp_len/2;\n}\n\nvoid raw_demod(struct demod_state *fm)\n{\n\tint i;\n\tfor (i = 0; i < fm->lp_len; i++) {\n\t\tfm->result[i] = (int16_t)fm->lowpassed[i];\n\t}\n\tfm->result_len = fm->lp_len;\n}\n\nvoid deemph_filter(struct demod_state *fm)\n{\n\tstatic int avg;  /* cheating... */\n\tint i, d;\n\t/* de-emph IIR\n\t * avg = avg * (1 - alpha) + sample * alpha;\n\t */\n\tfor (i = 0; i < fm->result_len; i++) {\n\t\td = fm->result[i] - avg;\n\t\tif (d > 0) {\n\t\t\tavg += (d + fm->deemph_a/2) / fm->deemph_a;\n\t\t} else {\n\t\t\tavg += (d - fm->deemph_a/2) / fm->deemph_a;\n\t\t}\n\t\tfm->result[i] = (int16_t)avg;\n\t}\n}\n\nvoid dc_block_audio_filter(struct demod_state *fm)\n{\n\tint i, avg;\n\tint64_t sum = 0;\n\tfor (i=0; i < fm->result_len; i++) {\n\t\tsum += fm->result[i];\n\t}\n\tavg = sum / fm->result_len;\n\tavg = (avg + fm->dc_avg * fm->adc_block_const) / ( fm->adc_block_const + 1 );\n\tfor (i=0; i < fm->result_len; i++) {\n\t\tfm->result[i] -= avg;\n\t}\n\tfm->dc_avg = avg;\n}\n\nvoid dc_block_raw_filter(struct demod_state *fm, int16_t *buf, int len)\n{\n\t/* derived from dc_block_audio_filter,\n\t\trunning over the raw I/Q components\n\t*/\n\tint i, avgI, avgQ;\n\tint64_t sumI = 0;\n\tint64_t sumQ = 0;\n\tfor (i = 0; i < len; i += 2) {\n\t\tsumI += buf[i];\n\t\tsumQ += buf[i+1];\n\t}\n\tavgI = sumI / ( len / 2 );\n\tavgQ = sumQ / ( len / 2 );\n\tavgI = (avgI + fm->dc_avgI * fm->rdc_block_const) / ( fm->rdc_block_const + 1 );\n\tavgQ = (avgQ + fm->dc_avgQ * fm->rdc_block_const) / ( fm->rdc_block_const + 1 );\n\tfor (i = 0; i < len; i += 2) {\n\t\tbuf[i] -= avgI;\n\t\tbuf[i+1] -= avgQ;\n\t}\n\tfm->dc_avgI = avgI;\n\tfm->dc_avgQ = avgQ;\n}\nint mad(int16_t *samples, int len, int step)\n/* mean average deviation */\n{\n\tint i=0, sum=0, ave=0;\n\tif (len == 0)\n\t\t{return 0;}\n\tfor (i=0; i<len; i+=step) {\n\t\tsum += samples[i];\n\t}\n\tave = sum / (len * step);\n\tsum = 0;\n\tfor (i=0; i<len; i+=step) {\n\t\tsum += abs(samples[i] - ave);\n\t}\n\treturn sum / (len / step);\n}\n\nint rms(int16_t *samples, int len, int step, int omitDCfix)\n/* largely lifted from rtl_power */\n{\n\tdouble dc, err;\n\tint i, num;\n\tint32_t t, s;\n\tuint32_t p;  /* use sign bit to prevent overflow */\n\n\tp = 0;\n\tt = 0L;\n\twhile (len > step * 32768) /* 8 bit squared = 16 bit. limit to 2^16 for 32 bit squared sum */\n\t\t++step;  /* increase step to prevent overflow */\n\tfor (i=0; i<len; i+=step) {\n\t\ts = (long)samples[i];\n\t\tt += s;\n\t\tp += s * s;\n\t}\n\n\tif (omitDCfix) {\n\t\t/* DC is already corrected. No need to do it again */\n\t\tnum = len / step;\n\t\treturn (int)sqrt( (double)(p) / num );\n\t}\n\n\t/* correct for dc offset in squares */\n\tdc = (double)(t*step) / (double)len;\n\terr = t * 2 * dc - dc * dc * len;\n\n\treturn (int)sqrt((p-err) / len);\n}\n\nvoid arbitrary_upsample(int16_t *buf1, int16_t *buf2, int len1, int len2)\n/* linear interpolation, len1 < len2 */\n{\n\tint i = 1;\n\tint j = 0;\n\tint tick = 0;\n\tdouble frac;  /* use integers... */\n\twhile (j < len2) {\n\t\tfrac = (double)tick / (double)len2;\n\t\tbuf2[j] = (int16_t)(buf1[i-1]*(1-frac) + buf1[i]*frac);\n\t\tj++;\n\t\ttick += len1;\n\t\tif (tick > len2) {\n\t\t\ttick -= len2;\n\t\t\ti++;\n\t\t}\n\t\tif (i >= len1) {\n\t\t\ti = len1 - 1;\n\t\t\ttick = len2;\n\t\t}\n\t}\n}\n\nvoid arbitrary_downsample(int16_t *buf1, int16_t *buf2, int len1, int len2)\n/* fractional boxcar lowpass, len1 > len2 */\n{\n\tint i = 1;\n\tint j = 0;\n\tint tick = 0;\n\tdouble remainder = 0;\n\tdouble frac;  /* use integers... */\n\tbuf2[0] = 0;\n\twhile (j < len2) {\n\t\tfrac = 1.0;\n\t\tif ((tick + len2) > len1) {\n\t\t\tfrac = (double)(len1 - tick) / (double)len2;}\n\t\tbuf2[j] += (int16_t)((double)buf1[i] * frac + remainder);\n\t\tremainder = (double)buf1[i] * (1.0-frac);\n\t\ttick += len2;\n\t\ti++;\n\t\tif (tick > len1) {\n\t\t\tj++;\n\t\t\tbuf2[j] = 0;\n\t\t\ttick -= len1;\n\t\t}\n\t\tif (i >= len1) {\n\t\t\ti = len1 - 1;\n\t\t\ttick = len1;\n\t\t}\n\t}\n\tfor (j=0; j<len2; j++) {\n\t\tbuf2[j] = buf2[j] * len2 / len1;}\n}\n\nvoid arbitrary_resample(int16_t *buf1, int16_t *buf2, int len1, int len2)\n/* up to you to calculate lengths and make sure it does not go OOB\n * okay for buffers to overlap, if you are downsampling */\n{\n\tif (len1 < len2) {\n\t\tarbitrary_upsample(buf1, buf2, len1, len2);\n\t} else {\n\t\tarbitrary_downsample(buf1, buf2, len1, len2);\n\t}\n}\n\nvoid full_demod(struct demod_state *d)\n{\n\tstruct cmd_state *c = d->cmd;\n\tdouble freqK, avgRms, rmsLevel, avgRmsLevel;\n\tint i, ds_p;\n\tint sr = 0;\n\tstatic int printBlockLen = 1;\n\tds_p = d->downsample_passes;\n\tif (ds_p) {\n\t\tfor (i=0; i < ds_p; i++) {\n\t\t\tfifth_order(d->lowpassed,   (d->lp_len >> i), d->lp_i_hist[i]);\n\t\t\tfifth_order(d->lowpassed+1, (d->lp_len >> i) - 1, d->lp_q_hist[i]);\n\t\t}\n\t\td->lp_len = d->lp_len >> ds_p;\n\t\t/* droop compensation */\n\t\tif (d->comp_fir_size == 9 && ds_p <= CIC_TABLE_MAX) {\n\t\t\tgeneric_fir(d->lowpassed, d->lp_len,\n\t\t\t\tcic_9_tables[ds_p], d->droop_i_hist);\n\t\t\tgeneric_fir(d->lowpassed+1, d->lp_len-1,\n\t\t\t\tcic_9_tables[ds_p], d->droop_q_hist);\n\t\t}\n\t} else {\n\t\tlow_pass(d);\n\t}\n\t/* power squelch */\n\tif (d->squelch_level) {\n\t\tsr = rms(d->lowpassed, d->lp_len, 1, d->dc_block_raw);\n\t\tif (sr >= 0) {\n\t\t\tif (sr < d->squelch_level) {\n\t\t\t\td->squelch_hits++;\n\t\t\t\tfor (i=0; i<d->lp_len; i++) {\n\t\t\t\t\td->lowpassed[i] = 0;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\td->squelch_hits = 0;}\n\t\t}\n\t}\n\n\tif (printLevels) {\n\t\tif (!sr)\n\t\t\tsr = rms(d->lowpassed, d->lp_len, 1, d->dc_block_raw);\n\t\t--printLevelNo;\n\t\tif (printLevels && sr >= 0) {\n\t\t\tlevelSum += sr;\n\t\t\tif (levelMax < sr)\t\tlevelMax = sr;\n\t\t\tif (levelMaxMax < sr)\tlevelMaxMax = sr;\n\t\t\tif  (!printLevelNo) {\n\t\t\t\tprintLevelNo = printLevels;\n\t\t\t\tfreqK = dongle.userFreq /1000.0;\n\t\t\t\tavgRms = levelSum / printLevels;\n\t\t\t\trmsLevel = 20.0 * log10( 1E-10 + sr );\n\t\t\t\tavgRmsLevel = 20.0 * log10( 1E-10 + avgRms );\n\t\t\t\tfprintf(stderr, \"%.3f kHz, %.1f avg rms, %d max rms, %d max max rms, %d squelch rms, %d rms, %.1f dB rms level, %.2f dB avg rms level\\n\",\n\t\t\t\t\tfreqK, avgRms, levelMax, levelMaxMax, d->squelch_level, sr, rmsLevel, avgRmsLevel );\n\t\t\t\tlevelMax = 0;\n\t\t\t\tlevelSum = 0;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (c->filename) {\n\t\tif (!sr)\n\t\t\tsr = rms(d->lowpassed, d->lp_len, 1, d->dc_block_raw);\n\t\tif ( printBlockLen && verbosity ) {\n\t\t\tfprintf(stderr, \"block length for rms after decimation is %d samples\\n\", d->lp_len);\n\t\t\tif ( d->lp_len < 128 )\n\t\t\t\tfprintf(stderr, \"\\n  WARNING: increase block length with option -W\\n\\n\");\n\t\t\t--printBlockLen;\n\t\t}\n\t\tif (!c->numSummed)\n\t\t\tc->levelSum = 0;\n\t\tif (c->numSummed < c->numMeas && sr >= 0) {\n\t\t\tc->levelSum += sr;\n\t\t\tc->numSummed++;\n\t\t}\n\t}\n\n\td->mode_demod(d);  /* lowpassed -> result */\n\tif (d->mode_demod == &raw_demod) {\n\t\treturn;\n\t}\n\t/* todo, fm noise squelch */\n\t/* use nicer filter here too? */\n\tif (d->post_downsample > 1) {\n\t\td->result_len = low_pass_simple(d->result, d->result_len, d->post_downsample);}\n\tif (d->deemph) {\n\t\tdeemph_filter(d);}\n\tif (d->dc_block_audio) {\n\t\tdc_block_audio_filter(d);}\n\tif (d->rate_out2 > 0) {\n\t\tlow_pass_real(d);\n\t\t/* arbitrary_resample(d->result, d->result, d->result_len, d->result_len * d->rate_out2 / d->rate_out); */\n\t}\n}\n\nstatic void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)\n{\n\tstruct dongle_state *s = ctx;\n\tstruct demod_state *d = s->demod_target;\n\tstruct cmd_state *c = d->cmd;\n\tint i, muteLen = s->mute;\n\tunsigned char sampleMax;\n\tuint32_t sampleP, samplePowSum = 0.0;\n\tint samplePowCount = 0, step = 2;\n\ttime_t rawtime;\n\n\tif (do_exit) {\n\t\treturn;}\n\tif (!ctx) {\n\t\treturn;}\n\ttime(&rawtime);\n\tif (duration > 0 && rawtime >= stop_time) {\n\t\tdo_exit = 1;\n\t\tfprintf(stderr, \"Time expired, exiting!\\n\");\n\t\trtlsdr_cancel_async(dongle.dev);\n\t}\n\tif (s->mute) {\n\t\tif(muteLen > (int)len)\n\t\t\tmuteLen = len;\n\t\ts->mute -= muteLen;  /* we may need to mute multiple blocks */\n\t\tif(!c->filename) {\n\t\t\tfor (i=0; i<muteLen; i++)\n\t\t\t\tbuf[i] = 127;\n\t\t}\n\t\t/* reset adc max and power */\n\t\ts->samplePowSum = 0.0;\n\t\ts->samplePowCount = 0;\n\t\ts->sampleMax = 0;\n\t}\n\t/* OR all samples to allow checking overflow\n\t * - before conversion to 16 bit and before DC filtering.\n\t * we only get bitmask of positive samples (after -127) but that won't matter */\n\tif (c->checkADCmax ) {\n\t\tsampleMax = s->sampleMax;\n\t\tfor (i=0; i<(int)len; i++) {\n\t\t\tif ( buf[i] > sampleMax )\n\t\t\t\tsampleMax = buf[i];\n\t\t}\n\t\ts->sampleMax = sampleMax;\n\t}\n\tif (c->checkADCrms ) {\n\t\twhile ( (int)len >= 16384 * step )\n\t\t\tstep += 2;\n\t\tfor (i=0; i<(int)len; i+= step) {\n\t\t\tsampleP  = ( (int)buf[i]   -127 ) * ( (int)buf[i]   -127 );  /* I^2 */\n\t\t\tsampleP += ( (int)buf[i+1] -127 ) * ( (int)buf[i+1] -127 );  /* Q^2 */\n\t\t\tsamplePowSum += sampleP;\n\t\t\t++samplePowCount;\n\t\t}\n\t\ts->samplePowSum += (double)samplePowSum / samplePowCount;\n\t\ts->samplePowCount += 1;\n\t}\n\t/* 1st: convert to 16 bit - to allow easier calculation of DC */\n\tfor (i=0; i<(int)len; i++) {\n\t\ts->buf16[i] = ( (int16_t)buf[i] - 127 );\n\t}\n\t/* 2nd: do DC filtering BEFORE up-mixing */\n\tif (d->dc_block_raw) {\n\t\tdc_block_raw_filter(d, s->buf16, (int)len);\n\t}\n\tif (muteLen && c->filename)\n\t\treturn;\t/* \"mute\" after the dc_block_raw_filter(), giving it time to remove the new DC */\n\t/* 3rd: down-mixing */\n\tif (!s->offset_tuning) {\n\t\trotate16_neg90(s->buf16, (int)len);\n\t}\n\tpthread_rwlock_wrlock(&d->rw);\n\tmemcpy(d->lowpassed, s->buf16, 2*len);\n\td->lp_len = len;\n\tpthread_rwlock_unlock(&d->rw);\n\tsafe_cond_signal(&d->ready, &d->ready_m);\n}\n\nstatic void *dongle_thread_fn(void *arg)\n{\n\tstruct dongle_state *s = arg;\n\trtlsdr_read_async(s->dev, rtlsdr_callback, s, 0, s->buf_len);\n\treturn 0;\n}\n\nstatic void *demod_thread_fn(void *arg)\n{\n\tstruct demod_state *d = arg;\n\tstruct output_state *o = d->output_target;\n\tstruct cmd_state *c = d->cmd;\n\twhile (!do_exit) {\n\t\tsafe_cond_wait(&d->ready, &d->ready_m);\n\t\tpthread_rwlock_wrlock(&d->rw);\n\t\tfull_demod(d);\n\t\tpthread_rwlock_unlock(&d->rw);\n\t\tif (d->exit_flag) {\n\t\t\tdo_exit = 1;\n\t\t}\n\t\tif (d->squelch_level && d->squelch_hits > d->conseq_squelch) {\n\t\t\td->squelch_hits = d->conseq_squelch + 1;  /* hair trigger */\n\t\t\tsafe_cond_signal(&controller.hop, &controller.hop_m);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (do_exit)\n\t\t\tbreak;\n\n\t\tif (c->filename && c->numSummed >= c->numMeas) {\n\t\t\tcheckTriggerCommand(c, dongle.sampleMax, dongle.samplePowSum, dongle.samplePowCount);\n\n\t\t\tsafe_cond_signal(&controller.hop, &controller.hop_m);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (OutputToStdout) {\n\t\t\tpthread_rwlock_wrlock(&o->rw);\n\t\t\tmemcpy(o->result, d->result, 2*d->result_len);\n\t\t\to->result_len = d->result_len;\n\t\t\tpthread_rwlock_unlock(&o->rw);\n\t\t\tsafe_cond_signal(&o->ready, &o->ready_m);\n\t\t}\n\t}\n\treturn 0;\n}\n\nstatic void *output_thread_fn(void *arg)\n{\n\tstruct output_state *s = arg;\n\tif (!waveHdrStarted) {\n\t\twhile (!do_exit) {\n\t\t\t/* use timedwait and pad out under runs */\n\t\t\tsafe_cond_wait(&s->ready, &s->ready_m);\n\t\t\tpthread_rwlock_rdlock(&s->rw);\n\t\t\tfwrite(s->result, 2, s->result_len, s->file);\n\t\t\tpthread_rwlock_unlock(&s->rw);\n\t\t}\n\t} else {\n\t\twhile (!do_exit) {\n\t\t\t/* use timedwait and pad out under runs */\n\t\t\tsafe_cond_wait(&s->ready, &s->ready_m);\n\t\t\tpthread_rwlock_rdlock(&s->rw);\n\t\t\t/* distinguish for endianness: wave requires little endian */\n\t\t\twaveWriteSamples(s->file, s->result, s->result_len, 0);\n\t\t\tpthread_rwlock_unlock(&s->rw);\n\t\t}\n\t}\n\treturn 0;\n}\n\nstatic void optimal_settings(uint64_t freq, uint32_t rate)\n{\n\t/* giant ball of hacks\n\t * seems unable to do a single pass, 2:1\n\t */\n\tuint64_t capture_freq;\n\tuint32_t capture_rate;\n\tstruct dongle_state *d = &dongle;\n\tstruct demod_state *dm = &demod;\n\tstruct controller_state *cs = &controller;\n\tdm->downsample = (MinCaptureRate / dm->rate_in) + 1;\n\tif (dm->downsample_passes) {\n\t\tdm->downsample_passes = (int)log2(dm->downsample) + 1;\n\t\tdm->downsample = 1 << dm->downsample_passes;\n\t}\n\tif (verbosity >= 2) {\n\t\tfprintf(stderr, \"downsample_passes = %d (= # of fifth_order() iterations), downsample = %d\\n\", dm->downsample_passes, dm->downsample );\n\t}\n\tcapture_freq = freq;\n\tcapture_rate = dm->downsample * dm->rate_in;\n\tif (verbosity >= 2)\n\t\tfprintf(stderr, \"capture_rate = dm->downsample * dm->rate_in = %d * %d = %d\\n\", dm->downsample, dm->rate_in, capture_rate );\n\tif (!d->offset_tuning) {\n\t\tcapture_freq = freq - capture_rate/4;\n\t\tif (verbosity >= 2)\n\t\t\tfprintf(stderr, \"optimal_settings(freq = %f MHz): capture_freq = freq - capture_rate/4 = %f MHz\\n\", freq * 1E-6, capture_freq * 1E-6 );\n\t}\n\tcapture_freq += cs->edge * dm->rate_in / 2;\n\tif (verbosity >= 2)\n\t\tfprintf(stderr, \"optimal_settings(freq = %f MHz): capture_freq +=  cs->edge * dm->rate_in / 2 = %d * %d / 2 = %f MHz\\n\", freq * 1E-6, cs->edge, dm->rate_in, capture_freq * 1E-6 );\n\tdm->output_scale = (1<<15) / (128 * dm->downsample);\n\tif (dm->output_scale < 1) {\n\t\tdm->output_scale = 1;}\n\tif (dm->mode_demod == &fm_demod) {\n\t\tdm->output_scale = 1;}\n\td->userFreq = freq;\n\td->freq = capture_freq;\n\td->rate = capture_rate;\n\tif (verbosity >= 2)\n\t\tfprintf(stderr, \"optimal_settings(freq = %f MHz) delivers freq %f MHz, rate %.0f\\n\", freq * 1E-6, d->freq * 1E-6, (double)d->rate );\n}\n\nstatic void *controller_thread_fn(void *arg)\n{\n\t/* thoughts for multiple dongles\n\t * might be no good using a controller thread if retune/rate blocks\n\t */\n\tint i, r, execWaitHop = 1;\n\tint32_t if_band_center_freq = 0;\n\tstruct controller_state *s = arg;\n\tstruct cmd_state *c = s->cmd;\n\n\tif (s->wb_mode) {\n\t\tif (verbosity)\n\t\t\tfprintf(stderr, \"wbfm: adding 16000 Hz to every input frequency\\n\");\n\t\tfor (i=0; i < s->freq_len; i++) {\n\t\t\ts->freqs[i] += 16000;}\n\t}\n\n\t/* set up primary channel */\n\tif (c->filename) {\n\t\tdongle.mute = dongle.rate; /* over a second - until parametrized the dongle */\n\t\ttoNextCmdLine(c);\n\t\t/*fprintf(stderr, \"\\nswitched to next command line. new freq %u\\n\", c->freq);*/\n\t\ts->freqs[0] = c->freq;\n\t\texecWaitHop = 0;\n\t}\n\n\toptimal_settings(s->freqs[0], demod.rate_in);\n\tif (dongle.direct_sampling) {\n\t\tverbose_direct_sampling(dongle.dev, 1);}\n\tif (dongle.offset_tuning) {\n\t\tverbose_offset_tuning(dongle.dev);}\n\n\t/* Set the frequency */\n\tif (verbosity) {\n\t\tfprintf(stderr, \"verbose_set_frequency(%f MHz)\\n\", dongle.userFreq * 1E-6);\n\t\tif (!dongle.offset_tuning)\n\t\t\tfprintf(stderr, \"  frequency is away from parametrized one, to avoid negative impact from dc\\n\");\n\t}\n\tverbose_set_frequency(dongle.dev, dongle.freq);\n\tfprintf(stderr, \"Oversampling input by: %ix.\\n\", demod.downsample);\n\tfprintf(stderr, \"Oversampling output by: %ix.\\n\", demod.post_downsample);\n\tfprintf(stderr, \"Buffer size: %0.2fms\\n\",\n\t\t1000 * 0.5 * (float)ACTUAL_BUF_LENGTH / (float)dongle.rate);\n\n\t/* Set the sample rate */\n\tif (verbosity)\n\t\tfprintf(stderr, \"verbose_set_sample_rate(%.0f Hz)\\n\", (double)dongle.rate);\n\tverbose_set_sample_rate(dongle.dev, dongle.rate);\n\tfprintf(stderr, \"Output at %u Hz.\\n\", demod.rate_in/demod.post_downsample);\n\n\tif ( dongle.bandwidth ) {\n\t\tif_band_center_freq = dongle.userFreq - dongle.freq;\n\t\tif (dongle.bccorner < 0)\n\t\t\tif_band_center_freq += ( dongle.bandwidth - demod.rate_out ) / 2;\n\t\telse if (dongle.bccorner > 0)\n\t\t\tif_band_center_freq -= ( dongle.bandwidth - demod.rate_out ) / 2;\n\n\t\tif ( prev_if_band_center_freq != if_band_center_freq ) {\n\t\t\tr = rtlsdr_set_tuner_band_center(dongle.dev, if_band_center_freq );\n\t\t\tif (r)\n\t\t\t\tfprintf(stderr, \"WARNING: Failed to set band center.\\n\");\n\t\t\telse {\n\t\t\t\tprev_if_band_center_freq = if_band_center_freq;\n\t\t\t\tif (verbosity)\n\t\t\t\t\tfprintf(stderr, \"rtlsdr_set_tuner_band_center(%.0f Hz) successful\\n\", (double)if_band_center_freq);\n\t\t\t}\n\t\t}\n\t}\n\n\twhile (!do_exit) {\n\t\tif (execWaitHop)\n\t\t\tsafe_cond_wait(&s->hop, &s->hop_m);\n\t\texecWaitHop = 1;  /* execute following safe_cond_wait()'s */\n\t\t/* fprintf(stderr, \"\\nreceived hop condition\\n\"); */\n\t\tif (s->freq_len <= 1 && !c->filename) {\n\t\t\tcontinue;}\n\t\tif (!c->filename) {\n\t\t\t/* hacky hopping */\n\t\t\ts->freq_now = (s->freq_now + 1) % s->freq_len;\n\t\t\toptimal_settings(s->freqs[s->freq_now], demod.rate_in);\n\t\t\trtlsdr_set_center_freq64(dongle.dev, dongle.freq);\n\t\t\tif ( dongle.bandwidth ) {\n\t\t\t\tif_band_center_freq = dongle.userFreq - dongle.freq;\n\t\t\t\tif ( prev_if_band_center_freq != if_band_center_freq ) {\n\t\t\t\t\tr = rtlsdr_set_tuner_band_center(dongle.dev, if_band_center_freq );\n\t\t\t\t\tif (r)\n\t\t\t\t\t\tfprintf(stderr, \"WARNING: Failed to set band center.\\n\");\n\t\t\t\t\telse {\n\t\t\t\t\t\tprev_if_band_center_freq = if_band_center_freq;\n\t\t\t\t\t\tif (verbosity)\n\t\t\t\t\t\t\tfprintf(stderr, \"rtlsdr_set_tuner_band_center(%.0f Hz) successful\\n\", (double)if_band_center_freq);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tdongle.mute = DEFAULT_BUFFER_DUMP;\n\t\t} else {\n\t\t\tdongle.mute = 2 * dongle.rate; /* over a second - until parametrized the dongle */\n\t\t\tc->numSummed = 0;\n\n\t\t\ttoNextCmdLine(c);\n\n\t\t\toptimal_settings(c->freq, demod.rate_in);\n\t\t\t/* 1- set center frequency */\n\t\t\tif (c->prevFreq != dongle.freq) {\n\t\t\t\trtlsdr_set_center_freq64(dongle.dev, dongle.freq);\n\t\t\t\tc->prevFreq = dongle.freq;\n\t\t\t}\n\t\t\t/* 2- Set the tuner gain */\n\t\t\tif (c->prevGain != c->gain) {\n\t\t\t\tif (c->gain == AUTO_GAIN) {\n\t\t\t\t\tr = rtlsdr_set_tuner_gain_mode(dongle.dev, 0);\n\t\t\t\t\tif (r != 0)\n\t\t\t\t\t\tfprintf(stderr, \"WARNING: Failed to set automatic tuner gain.\\n\");\n\t\t\t\t\telse\n\t\t\t\t\t\tc->prevGain = c->gain;\n\t\t\t\t} else {\n\t\t\t\t\tc->gain = nearest_gain(dongle.dev, c->gain);\n\t\t\t\t\tr = rtlsdr_set_tuner_gain_mode(dongle.dev, 1);\n\t\t\t\t\tif (r < 0)\n\t\t\t\t\t\tfprintf(stderr, \"WARNING: Failed to enable manual gain.\\n\");\n\t\t\t\t\telse {\n\t\t\t\t\t\tr = rtlsdr_set_tuner_gain(dongle.dev, c->gain);\n\t\t\t\t\t\tif (r != 0)\n\t\t\t\t\t\t\tfprintf(stderr, \"WARNING: Failed to set tuner gain.\\n\");\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tc->prevGain = c->gain;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t/* 3- Set tuner bandwidth */\n\t\t\tif (c->prevBandwidth != dongle.bandwidth) {\n\t\t\t\tr = rtlsdr_set_tuner_bandwidth(dongle.dev, dongle.bandwidth);\n\t\t\t\tif (r < 0)\n\t\t\t\t\tfprintf(stderr, \"WARNING: Failed to set bandwidth.\\n\");\n\t\t\t\telse\n\t\t\t\t\tc->prevBandwidth = dongle.bandwidth;\n\t\t\t}\n\t\t\t/*  */\n\t\t\tif ( dongle.bandwidth ) {\n\t\t\t\tif_band_center_freq = dongle.userFreq - dongle.freq;\n\t\t\t\tif ( prev_if_band_center_freq != if_band_center_freq ) {\n\t\t\t\t\tr = rtlsdr_set_tuner_band_center(dongle.dev, if_band_center_freq );\n\t\t\t\t\tif (r)\n\t\t\t\t\t\tfprintf(stderr, \"WARNING: Failed to set band center.\\n\");\n\t\t\t\t\telse {\n\t\t\t\t\t\tprev_if_band_center_freq = if_band_center_freq;\n\t\t\t\t\t\tif (verbosity)\n\t\t\t\t\t\t\tfprintf(stderr, \"rtlsdr_set_tuner_band_center(%.0f Hz) successful\\n\", (double)if_band_center_freq);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t/* 4- Set ADC samplerate *\n\t\t\tr = rtlsdr_set_sample_rate(dongle.dev, dongle.rate);\n\t\t\tif (r < 0)\n\t\t\t\tfprintf(stderr, \"WARNING: Failed to set sample rate.\\n\");\n\t\t\t*/\n\n\t\t\tc->levelSum = 0;\n\t\t\tc->numSummed = 0;\n\t\t\t/* reset DC filters */\n\t\t\tdemod.dc_avg = 0;\n\t\t\tdemod.dc_avgI = 0;\n\t\t\tdemod.dc_avgQ = 0;\n\t\t\tdongle.mute = BufferDump;\n\t\t\t/* reset adc max and power */\n\t\t\tdongle.samplePowSum = 0.0;\n\t\t\tdongle.samplePowCount = 0;\n\t\t\tdongle.sampleMax = 0;\n\t\t}\n\n\t}\n\treturn 0;\n}\n\nvoid frequency_range(struct controller_state *s, char *arg)\n{\n\tchar *start, *stop, *step;\n\tint i;\n\tstart = arg;\n\tstop = strchr(start, ':') + 1;\n\tstop[-1] = '\\0';\n\tstep = strchr(stop, ':') + 1;\n\tstep[-1] = '\\0';\n\tfor(i=(int)atofs(start); i<=(int)atofs(stop); i+=(int)atofs(step))\n\t{\n\t\ts->freqs[s->freq_len] = (uint32_t)i;\n\t\ts->freq_len++;\n\t\tif (s->freq_len >= FREQUENCIES_LIMIT) {\n\t\t\tbreak;}\n\t}\n\tstop[-1] = ':';\n\tstep[-1] = ':';\n}\n\nvoid dongle_init(struct dongle_state *s)\n{\n\ts->rate = DEFAULT_SAMPLE_RATE;\n\ts->gain = AUTO_GAIN; /* tenths of a dB */\n\ts->mute = 0;\n\ts->direct_sampling = 0;\n\ts->offset_tuning = 0;\n\ts->demod_target = &demod;\n\ts->samplePowSum = 0.0;\n\ts->samplePowCount = 0;\n\ts->sampleMax = 0;\n\ts->bandwidth = 0;\n\ts->bccorner = 0;\n\ts->buf_len = 32 * 512;  /* see rtl_tcp */\n}\n\nvoid demod_init(struct demod_state *s)\n{\n\ts->rate_in = DEFAULT_SAMPLE_RATE;\n\ts->rate_out = DEFAULT_SAMPLE_RATE;\n\ts->squelch_level = 0;\n\ts->conseq_squelch = 10;\n\ts->terminate_on_squelch = 0;\n\ts->squelch_hits = 11;\n\ts->downsample_passes = 0;\n\ts->comp_fir_size = 0;\n\ts->prev_index = 0;\n\ts->post_downsample = 1;\t// once this works, default = 4\n\ts->custom_atan = 0;\n\ts->deemph = 0;\n\ts->rate_out2 = -1;\t// flag for disabled\n\ts->mode_demod = &fm_demod;\n\ts->pre_j = s->pre_r = s->now_r = s->now_j = 0;\n\ts->prev_lpr_index = 0;\n\ts->deemph_a = 0;\n\ts->now_lpr = 0;\n\ts->dc_block_audio = 0;\n\ts->dc_avg = 0;\n\ts->adc_block_const = 9;\n\ts->dc_block_raw = 0;\n\ts->dc_avgI = 0;\n\ts->dc_avgQ = 0;\n\ts->rdc_block_const = 9;\n\tpthread_rwlock_init(&s->rw, NULL);\n\tpthread_cond_init(&s->ready, NULL);\n\tpthread_mutex_init(&s->ready_m, NULL);\n\ts->output_target = &output;\n\ts->cmd = &cmd;\n}\n\nvoid demod_cleanup(struct demod_state *s)\n{\n\tpthread_rwlock_destroy(&s->rw);\n\tpthread_cond_destroy(&s->ready);\n\tpthread_mutex_destroy(&s->ready_m);\n}\n\nvoid output_init(struct output_state *s)\n{\n\ts->rate = DEFAULT_SAMPLE_RATE;\n\tpthread_rwlock_init(&s->rw, NULL);\n\tpthread_cond_init(&s->ready, NULL);\n\tpthread_mutex_init(&s->ready_m, NULL);\n}\n\nvoid output_cleanup(struct output_state *s)\n{\n\tpthread_rwlock_destroy(&s->rw);\n\tpthread_cond_destroy(&s->ready);\n\tpthread_mutex_destroy(&s->ready_m);\n}\n\nvoid controller_init(struct controller_state *s)\n{\n\ts->freqs[0] = 100000000;\n\ts->freq_len = 0;\n\ts->edge = 0;\n\ts->wb_mode = 0;\n\tpthread_cond_init(&s->hop, NULL);\n\tpthread_mutex_init(&s->hop_m, NULL);\n\ts->cmd = &cmd;\n}\n\nvoid controller_cleanup(struct controller_state *s)\n{\n\tpthread_cond_destroy(&s->hop);\n\tpthread_mutex_destroy(&s->hop_m);\n}\n\nvoid sanity_checks(void)\n{\n\tif (controller.freq_len == 0) {\n\t\tfprintf(stderr, \"Please specify a frequency.\\n\");\n\t\texit(1);\n\t}\n\n\tif (controller.freq_len >= FREQUENCIES_LIMIT) {\n\t\tfprintf(stderr, \"Too many channels, maximum %i.\\n\", FREQUENCIES_LIMIT);\n\t\texit(1);\n\t}\n\n\tif (controller.freq_len > 1 && demod.squelch_level == 0) {\n\t\tfprintf(stderr, \"Please specify a squelch level.  Required for scanning multiple frequencies.\\n\");\n\t\texit(1);\n\t}\n\n}\n\nint main(int argc, char **argv)\n{\n#ifndef _WIN32\n\tstruct sigaction sigact;\n#endif\n\tint r, opt;\n\tint dev_given = 0;\n\tint writeWav = 0;\n\tint custom_ppm = 0;\n\tint enable_biastee = 0;\n\tconst char * rtlOpts = NULL;\n\tenum rtlsdr_ds_mode ds_mode = RTLSDR_DS_IQ;\n\tuint32_t ds_temp, ds_threshold = 0;\n\tint timeConstant = 75; /* default: U.S. 75 uS */\n\tint rtlagc = 0;\n\tdongle_init(&dongle);\n\tdemod_init(&demod);\n\toutput_init(&output);\n\tcontroller_init(&controller);\n\tcmd_init(&cmd);\n\n\twhile ((opt = getopt(argc, argv, \"d:f:g:s:b:l:o:t:r:p:R:E:O:F:A:M:hTC:B:m:L:q:c:w:W:D:nHv\")) != -1) {\n\t\tswitch (opt) {\n\t\tcase 'd':\n\t\t\tdongle.dev_index = verbose_device_search(optarg);\n\t\t\tdev_given = 1;\n\t\t\tbreak;\n\t\tcase 'f':\n\t\t\tif (controller.freq_len >= FREQUENCIES_LIMIT) {\n\t\t\t\tbreak;}\n\t\t\tif (strchr(optarg, ':'))\n\t\t\t\t{frequency_range(&controller, optarg);}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcontroller.freqs[controller.freq_len] = (uint32_t)atofs(optarg);\n\t\t\t\tcontroller.freq_len++;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'C':\n\t\t\tcmd.filename = optarg;\n\t\t\tdemod.mode_demod = &raw_demod;\n\t\t\tbreak;\n\t\tcase 'm':\n\t\t\tMinCaptureRate = (int)atofs(optarg);\n\t\t\tbreak;\n\t\tcase 'B':\n\t\t\tBufferDump = atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'n':\n\t\t\tOutputToStdout = 0;\n\t\t\tbreak;\n\t\tcase 'g':\n\t\t\tdongle.gain = (int)(atof(optarg) * 10);\n\t\t\tbreak;\n\t\tcase 'l':\n\t\t\tdemod.squelch_level = (int)atof(optarg);\n\t\t\tbreak;\n\t\tcase 'L':\n\t\t\tprintLevels = (int)atof(optarg);\n\t\t\tbreak;\n\t\tcase 's':\n\t\t\tdemod.rate_in = (uint32_t)atofs(optarg);\n\t\t\tdemod.rate_out = (uint32_t)atofs(optarg);\n\t\t\tbreak;\n\t\tcase 'r':\n\t\t\toutput.rate = (int)atofs(optarg);\n\t\t\tdemod.rate_out2 = (int)atofs(optarg);\n\t\t\tbreak;\n\t\tcase 'o':\n\t\t\tfprintf(stderr, \"Warning: -o is very buggy\\n\");\n\t\t\tdemod.post_downsample = (int)atof(optarg);\n\t\t\tif (demod.post_downsample < 1 || demod.post_downsample > MAXIMUM_OVERSAMPLE) {\n\t\t\t\tfprintf(stderr, \"Oversample must be between 1 and %i\\n\", MAXIMUM_OVERSAMPLE);}\n\t\t\tbreak;\n\t\tcase 't':\n\t\t\tdemod.conseq_squelch = (int)atof(optarg);\n\t\t\tif (demod.conseq_squelch < 0) {\n\t\t\t\tdemod.conseq_squelch = -demod.conseq_squelch;\n\t\t\t\tdemod.terminate_on_squelch = 1;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'p':\n\t\t\tdongle.ppm_error = atoi(optarg);\n\t\t\tcustom_ppm = 1;\n\t\t\tbreak;\n\t\tcase 'R':\n\t\t\ttime(&stop_time);\n\t\t\tduration = atoi(optarg);\n\t\t\tif (duration < 1) {\n\t\t\t\tfprintf(stderr, \"Duration '%s' was not positive integer; will continue indefinitely\\n\", optarg);\n\t\t\t} else {\n\t\t\t\tstop_time += duration;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'E':\n\t\t\tif (strcmp(\"edge\",  optarg) == 0) {\n\t\t\t\tcontroller.edge = 1;}\n\t\t\tif (strcmp(\"dc\", optarg) == 0 || strcmp(\"adc\", optarg) == 0) {\n\t\t\t\tdemod.dc_block_audio = 1;}\n\t\t\tif (strcmp(\"rdc\", optarg) == 0) {\n\t\t\t\tdemod.dc_block_raw = 1;}\n\t\t\tif (strcmp(\"deemp\",  optarg) == 0) {\n\t\t\t\tdemod.deemph = 1;}\n\t\t\tif (strcmp(\"direct\",  optarg) == 0) {\n\t\t\t\tdongle.direct_sampling = 1;}\n\t\t\tif (strcmp(\"offset\",  optarg) == 0) {\n\t\t\t\tdongle.offset_tuning = 1;}\n\t\t\tif (strcmp(\"rtlagc\", optarg) == 0 || strcmp(\"agc\", optarg) == 0) {\n\t\t\t\trtlagc = 1;}\n\t\t\tif (strcmp(\"bclo\", optarg) == 0 || strcmp(\"bcL\", optarg) == 0 || strcmp(\"bcl\", optarg) == 0) {\n\t\t\t\tdongle.bccorner = -1; }\n\t\t\tif (strcmp(\"bcc\", optarg) == 0 || strcmp(\"bcC\", optarg) == 0) {\n\t\t\t\tdongle.bccorner = 0; }\n\t\t\tif (strcmp(\"bchi\", optarg) == 0 || strcmp(\"bcH\", optarg) == 0 || strcmp(\"bch\", optarg) == 0) {\n\t\t\t\tdongle.bccorner = 1; }\n\t\t\tbreak;\n\t\tcase 'O':\n\t\t\trtlOpts = optarg;\n\t\t\tbreak;\n\t\tcase 'q':\n\t\t\tdemod.rdc_block_const = atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'F':\n\t\t\tdemod.downsample_passes = 1;  /* truthy placeholder */\n\t\t\tdemod.comp_fir_size = atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'A':\n\t\t\tif (strcmp(\"std\",  optarg) == 0) {\n\t\t\t\tdemod.custom_atan = 0;}\n\t\t\tif (strcmp(\"fast\", optarg) == 0) {\n\t\t\t\tdemod.custom_atan = 1;}\n\t\t\tif (strcmp(\"lut\",  optarg) == 0) {\n\t\t\t\tatan_lut_init();\n\t\t\t\tdemod.custom_atan = 2;}\n\t\t\tif (strcmp(\"ale\", optarg) == 0) {\n\t\t\t\tdemod.custom_atan = 3;}\n\t\t\tbreak;\n\t\tcase 'M':\n\t\t\tif (strcmp(\"nbfm\",  optarg) == 0 || strcmp(\"nfm\",  optarg) == 0 || strcmp(\"fm\",  optarg) == 0) {\n\t\t\t\tdemod.mode_demod = &fm_demod;}\n\t\t\tif (strcmp(\"raw\",  optarg) == 0 || strcmp(\"iq\",  optarg) == 0) {\n\t\t\t\tdemod.mode_demod = &raw_demod;}\n\t\t\tif (strcmp(\"am\",  optarg) == 0) {\n\t\t\t\tdemod.mode_demod = &am_demod;}\n\t\t\tif (strcmp(\"usb\", optarg) == 0) {\n\t\t\t\tdemod.mode_demod = &usb_demod;}\n\t\t\tif (strcmp(\"lsb\", optarg) == 0) {\n\t\t\t\tdemod.mode_demod = &lsb_demod;}\n\t\t\tif (strcmp(\"wbfm\",  optarg) == 0 || strcmp(\"wfm\",  optarg) == 0) {\n\t\t\t\tcontroller.wb_mode = 1;\n\t\t\t\tdemod.mode_demod = &fm_demod;\n\t\t\t\tdemod.rate_in = 170000;\n\t\t\t\tdemod.rate_out = 170000;\n\t\t\t\tdemod.rate_out2 = 32000;\n\t\t\t\toutput.rate = 32000;\n\t\t\t\tdemod.custom_atan = 1;\n\t\t\t\t//demod.post_downsample = 4;\n\t\t\t\tdemod.deemph = 1;\n\t\t\t\tdemod.squelch_level = 0;}\n\t\t\tbreak;\n\t\tcase 'T':\n\t\t\tenable_biastee = 1;\n\t\t\tbreak;\n\t\tcase 'c':\n\t\t\tif (strcmp(\"us\",  optarg) == 0)\n\t\t\t\ttimeConstant = 75;\n\t\t\telse if (strcmp(\"eu\", optarg) == 0)\n\t\t\t\ttimeConstant = 50;\n\t\t\telse\n\t\t\t\ttimeConstant = (int)atof(optarg);\n\t\t\tbreak;\n\t\tcase 'D':\n\t\t\tds_temp = (uint32_t)( atofs(optarg) + 0.5 );\n\t\t\tif (ds_temp <= RTLSDR_DS_Q_BELOW)\n\t\t\t\tds_mode = (enum rtlsdr_ds_mode)ds_temp;\n\t\t\telse\n\t\t\t\tds_threshold = ds_temp;\n\t\t\tbreak;\n\t\tcase 'H':\n\t\t\twriteWav = 1;\n\t\t\tbreak;\n\t\tcase 'v':\n\t\t\t++verbosity;\n\t\t\tbreak;\n\t\tcase 'w':\n\t\t\tdongle.bandwidth = (uint32_t)atofs(optarg);\n\t\t\tbreak;\n\t\tcase 'W':\n\t\t\tdongle.buf_len = 512 * atoi(optarg);\n\t\t\tif (dongle.buf_len > MAXIMUM_BUF_LENGTH)\n\t\t\t\tdongle.buf_len = MAXIMUM_BUF_LENGTH;\n\t\t\tbreak;\n\t\tcase 'h':\n\t\tcase '?':\n\t\tdefault:\n\t\t\tusage();\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (verbosity)\n\t\tfprintf(stderr, \"verbosity set to %d\\n\", verbosity);\n\n\t/* quadruple sample_rate to limit to Δθ to ±π/2 */\n\tdemod.rate_in *= demod.post_downsample;\n\n\tif (!output.rate) {\n\t\toutput.rate = demod.rate_out;}\n\n\tsanity_checks();\n\n\tif (controller.freq_len > 1) {\n\t\tdemod.terminate_on_squelch = 0;}\n\n\tif (optind < argc) {\n\t\toutput.filename = argv[optind];\n\t} else {\n\t\toutput.filename = \"-\";\n\t}\n\n\tACTUAL_BUF_LENGTH = lcm_post[demod.post_downsample] * DEFAULT_BUF_LENGTH;\n\n\tif (!dev_given) {\n\t\tdongle.dev_index = verbose_device_search(\"0\");\n\t}\n\n\tif (dongle.dev_index < 0) {\n\t\texit(1);\n\t}\n\n\tr = rtlsdr_open(&dongle.dev, (uint32_t)dongle.dev_index);\n\tif (r < 0) {\n\t\tfprintf(stderr, \"Failed to open rtlsdr device #%d.\\n\", dongle.dev_index);\n\t\texit(1);\n\t}\n#ifndef _WIN32\n\tsigact.sa_handler = sighandler;\n\tsigemptyset(&sigact.sa_mask);\n\tsigact.sa_flags = 0;\n\tsigaction(SIGINT, &sigact, NULL);\n\tsigaction(SIGTERM, &sigact, NULL);\n\tsigaction(SIGQUIT, &sigact, NULL);\n\tsigaction(SIGPIPE, &sigact, NULL);\n#else\n\tSetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE );\n#endif\n\n\tif (demod.deemph) {\n\t\tdouble tc = (double)timeConstant * 1e-6;\n\t\tdemod.deemph_a = (int)round(1.0/((1.0-exp(-1.0/(demod.rate_out * tc)))));\n\t\tif (verbosity)\n\t\t\tfprintf(stderr, \"using wbfm deemphasis filter with time constant %d us\\n\", timeConstant );\n\t}\n\n\t/* Set the tuner gain */\n\tif (dongle.gain == AUTO_GAIN) {\n\t\tverbose_auto_gain(dongle.dev);\n\t} else {\n\t\tdongle.gain = nearest_gain(dongle.dev, dongle.gain);\n\t\tverbose_gain_set(dongle.dev, dongle.gain);\n\t}\n\n\trtlsdr_set_agc_mode(dongle.dev, rtlagc);\n\n\trtlsdr_set_bias_tee(dongle.dev, enable_biastee);\n\tif (enable_biastee)\n\t\tfprintf(stderr, \"activated bias-T on GPIO PIN 0\\n\");\n\n\tverbose_ppm_set(dongle.dev, dongle.ppm_error);\n\n\t/* Set direct sampling with threshold */\n\trtlsdr_set_ds_mode(dongle.dev, ds_mode, ds_threshold);\n\n\tverbose_set_bandwidth(dongle.dev, dongle.bandwidth);\n\n\tif (verbosity && dongle.bandwidth)\n\t{\n\t\tint r;\n\t\tuint32_t in_bw, out_bw, last_bw = 0;\n\t\tfprintf(stderr, \"Supported bandwidth values in kHz:\\n\");\n\t\tfor ( in_bw = 1; in_bw < 3200; ++in_bw )\n\t\t{\n\t\t\tr = rtlsdr_set_and_get_tuner_bandwidth(dongle.dev, in_bw*1000, &out_bw, 0 /* =apply_bw */);\n\t\t\tif ( r == 0 && out_bw != 0 && ( out_bw != last_bw || in_bw == 1 ) )\n\t\t\t\tfprintf(stderr, \"%s%.1f\", (in_bw==1 ? \"\" : \", \"), out_bw/1000.0 );\n\t\t\tlast_bw = out_bw;\n\t\t}\n\t\tfprintf(stderr,\"\\n\");\n\t}\n\n\tif (rtlOpts) {\n\t\trtlsdr_set_opt_string(dongle.dev, rtlOpts, verbosity);\n\t}\n\n\tif (strcmp(output.filename, \"-\") == 0) { /* Write samples to stdout */\n\t\toutput.file = stdout;\n#ifdef _WIN32\n\t\t_setmode(_fileno(output.file), _O_BINARY);\n#endif\n\t} else {\n\t\tconst char * filename_to_open = output.filename;\n\t\tif (writeWav) {\n\t\t\toutput.tempfilename = malloc( strlen(output.filename)+8 );\n\t\t\tstrcpy(output.tempfilename, output.filename);\n\t\t\tstrcat(output.tempfilename, \".tmp\");\n\t\t\tfilename_to_open = output.tempfilename;\n\t\t}\n \t\toutput.file = fopen(filename_to_open, \"wb\");\n\t\tif (!output.file) {\n\t\t\tfprintf(stderr, \"Failed to open %s\\n\", filename_to_open);\n\t\t\texit(1);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfprintf(stderr, \"Open %s for write\\n\", filename_to_open);\n\t\t\tif (writeWav) {\n\t\t\t\tint nChan = (demod.mode_demod == &raw_demod) ? 2 : 1;\n\t\t\t\tint srate = (demod.rate_out2 > 0) ? demod.rate_out2 : demod.rate_out;\n\t\t\t\tuint32_t f = controller.freqs[0];\t/* only 1st frequency!!! */\n\t\t\t\twaveWriteHeader(srate, f, 16, nChan, output.file);\n\t\t\t}\n\t\t}\n\t}\n\n\t//r = rtlsdr_set_testmode(dongle.dev, 1);\n\n\t/* Reset endpoint before we start reading from it (mandatory) */\n\tverbose_reset_buffer(dongle.dev);\n\n\tpthread_create(&controller.thread, NULL, controller_thread_fn, (void *)(&controller));\n\tusleep(1000000); /* it looks, that startup of dongle level takes some time at startup! */\n\tpthread_create(&output.thread, NULL, output_thread_fn, (void *)(&output));\n\tpthread_create(&demod.thread, NULL, demod_thread_fn, (void *)(&demod));\n\tpthread_create(&dongle.thread, NULL, dongle_thread_fn, (void *)(&dongle));\n\n\twhile (!do_exit) {\n\t\tusleep(100000);\n\t}\n\n\tif (do_exit) {\n\t\tfprintf(stderr, \"\\nUser cancel, exiting...\\n\");}\n\telse {\n\t\tfprintf(stderr, \"\\nLibrary error %d, exiting...\\n\", r);}\n\n\trtlsdr_cancel_async(dongle.dev);\n\tpthread_join(dongle.thread, NULL);\n\tsafe_cond_signal(&demod.ready, &demod.ready_m);\n\tpthread_join(demod.thread, NULL);\n\tsafe_cond_signal(&output.ready, &output.ready_m);\n\tpthread_join(output.thread, NULL);\n\tsafe_cond_signal(&controller.hop, &controller.hop_m);\n\tpthread_join(controller.thread, NULL);\n\n\t/* dongle_cleanup(&dongle); */\n\tdemod_cleanup(&demod);\n\toutput_cleanup(&output);\n\tcontroller_cleanup(&controller);\n\n\tif (cmd.filename) {\n\t\tint k;\n\t\t/* output scan statistics */\n\t\tfor (k = 0; k < FREQUENCIES_LIMIT; k++) {\n\t\t\tif (cmd.statNumLevels[k] > 0)\n\t\t\t\tfprintf(stderr, \"%.0f, %.1f, %.2f, %.1f\\n\", (double)(cmd.statFreq[k]), cmd.statMinLevel[k], cmd.statSumLevels[k] / cmd.statNumLevels[k], cmd.statMaxLevel[k] );\n\t\t}\n\t}\n\n\tif (output.file != stdout) {\n\t\tif (writeWav) {\n\t\t\tint r;\n\t\t\twaveFinalizeHeader(output.file);\n\t\t\tfclose(output.file);\n\t\t\tremove(output.filename);\t/* delete, in case file already exists */\n\t\t\tr = rename( output.tempfilename, output.filename );\t/* #include <stdio.h> */\n\t\t\tif ( r )\n\t\t\t\tfprintf( stderr, \"%s: error %d '%s' renaming'%s' to '%s'\\n\"\n\t\t\t\t\t, argv[0], errno, strerror(errno), output.tempfilename, output.filename );\n\t\t} else {\n\t\t\tfclose(output.file);\n\t\t}\n\t}\n\n\trtlsdr_close(dongle.dev);\n\treturn r >= 0 ? r : -r;\n}\n\n/* vim: tabstop=8:softtabstop=8:shiftwidth=8:noexpandtab */\n"
  },
  {
    "path": "src/rtl_ir.c",
    "content": "/*\n * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver\n * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>\n * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>\n * Copyright (C) 2012 Thomas Mair <thomas.mair86@googlemail.com>\n * Copyright (C) 2012 by Steve Markgraf <steve@steve-m.de>\n * Copyright (C) 2012 by Hoernchen <la@tfc-server.de>\n * Copyright (C) 2012 by Kyle Keen <keenerd@gmail.com>\n * Copyright (C) 2013 by Elias Oenal <EliasOenal@gmail.com>\n * Copyright (C) 2016 by Robert X. Seger <rseger@gmx.co.uk>\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n\n#include <errno.h>\n#include <signal.h>\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#ifndef _WIN32\n#include <unistd.h>\n#else\n#include <windows.h>\n#include <fcntl.h>\n#include <io.h>\n#include \"getopt/getopt.h\"\n#define usleep(x) Sleep(x/1000)\n#if defined(_MSC_VER) && (_MSC_VER < 1800)\n#define round(x) (x > 0.0 ? floor(x + 0.5): ceil(x - 0.5))\n#endif\n#define _USE_MATH_DEFINES\n#endif\n\n#include <math.h>\n#include <libusb.h>\n\n#include <rtl-sdr.h>\n#include <rtl_app_ver.h>\n#include \"convenience/convenience.h\"\n#include \"convenience/rtl_convenience.h\"\n\nstatic volatile int do_exit = 0;\n\nstruct dongle_state\n{\n\tint      exit_flag;\n\trtlsdr_dev_t *dev;\n\tint      dev_index;\n};\n\nvoid dongle_init(struct dongle_state *s)\n{\n    memset(s, 0, sizeof(struct dongle_state));\n}\n\nstruct dongle_state dongle;\n\nvoid usage(void)\n{\n\tfprintf(stderr,\n\t\t\"rtl_ir, display received IR signals\\n\"\n\t\t\"rtl_ir  version %d.%d %s (%s)\\n\"\n\t\t\"rtl-sdr library %d.%d %s\\n\\n\",\n\t\tAPP_VER_MAJOR, APP_VER_MINOR, APP_VER_ID, __DATE__,\n\t\trtlsdr_get_version() >>16, rtlsdr_get_version() & 0xFFFF,\n\t\trtlsdr_get_ver_id() );\n\tfprintf(stderr,\n\t\t\"Usage:\\trtl_ir [-options]\\n\"\n\t\t\"\\t[-d device_index (default: 0)]\\n\"\n\t\t\"\\t[-w wait_usec]\\tDelay to wait before each iteration (10000)\\n\"\n\t\t\"\\t[-c max_count]\\tMaximum number of loop iterations (0)\\n\"\n\t\t\"\\t[-b]\\tDisplay output in binary (default), pulse=1, space=0; each 20 usec\\n\"\n\t\t\"\\t[-t]\\tDisplay output in text format\\n\"\n\t\t\"\\t[-x]\\tDisplay output in raw packed bytes, MSB=pulse/space, 7LSB=duration*20 usec\\n\"\n\t\t\"\\t[-h]\\tHelp\\n\"\n\t\t);\n\texit(1);\n}\n\n#ifdef _WIN32\nBOOL WINAPI\nsighandler(int signum)\n{\n\tif (CTRL_C_EVENT == signum) {\n\t\tfprintf(stderr, \"Signal caught, exiting!\\n\");\n\t\tdo_exit = 1;\n\t\trtlsdr_cancel_async(dongle.dev);\n\t\treturn TRUE;\n\t}\n\treturn FALSE;\n}\n#else\nstatic void sighandler(int signum)\n{\n\tfprintf(stderr, \"Signal caught, exiting!\\n\");\n\tdo_exit = 1;\n\trtlsdr_cancel_async(dongle.dev);\n}\n#endif\n\n\nint main(int argc, char **argv) {\n#ifndef _WIN32\n\tstruct sigaction sigact;\n#endif\n\tint r, opt;\n\tint i, j;\n\tint dev_given = 0;\n\tunsigned int wait_usec = 100000;\n\tint max_count = 0, iteration_count = 0;\n\tint output_binary = 0, output_text = 0, output_packed = 0;\n\tuint8_t buf[128] = { 0 };\n\n\tdongle_init(&dongle);\n\n\twhile ((opt = getopt(argc, argv, \"d:c:w:btxh\")) != -1) {\n\t\tswitch (opt) {\n\t\tcase 'd':\n\t\t\tdongle.dev_index = verbose_device_search(optarg);\n\t\t\tdev_given = 1;\n\t\t\tbreak;\n\t\tcase 'w':\n\t\t\twait_usec = atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'c':\n\t\t\tmax_count = atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'b':\n\t\t\toutput_binary = 1;\n\t\t\tbreak;\n\t\tcase 't':\n\t\t\toutput_text = 1;\n\t\t\tbreak;\n\t\tcase 'x':\n\t\t\toutput_packed = 1;\n\t\t\tbreak;\n\t\tcase 'h':\n\t\tdefault:\n\t\t\tusage();\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (dongle.dev_index < 0) {\n\t\texit(1);\n\t}\n\n\tr = rtlsdr_open(&dongle.dev, (uint32_t)dongle.dev_index);\n\tif (r < 0) {\n\t\tfprintf(stderr, \"Failed to open rtlsdr device #%d.\\n\", dongle.dev_index);\n\t\texit(1);\n\t}\n#ifndef _WIN32\n\tsigact.sa_handler = sighandler;\n\tsigemptyset(&sigact.sa_mask);\n\tsigact.sa_flags = 0;\n\tsigaction(SIGINT, &sigact, NULL);\n\tsigaction(SIGTERM, &sigact, NULL);\n\tsigaction(SIGQUIT, &sigact, NULL);\n\tsigaction(SIGPIPE, &sigact, NULL);\n#else\n\tSetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE );\n#endif\n\n\tverbose_reset_buffer(dongle.dev);\n\n\tif (!output_binary && !output_text && !output_packed)\n\t\toutput_binary = 1;\n\n\twhile (!do_exit) {\n\t\tusleep(wait_usec);\n\n\t\tr = rtlsdr_ir_query(dongle.dev, buf, sizeof(buf));\n\t\tif (r < 0) {\n\t\t\tfprintf(stderr, \"rtlsdr_ir_query failed: %d\\n\", r);\n\t\t}\n\n\t\tfor (i = 0; i < r; i++) {\n\t\t\tint pulse = buf[i] >> 7;\n\t\t\tint duration = buf[i] & 0x7f;\n\n\t\t\tif (output_text) {\n\t\t\t\tprintf(\"pulse %d, duration %d usec\\n\", pulse, duration * 20);\n\t\t\t}\n\n\t\t\tif (output_binary) {\n\t\t\t\tfor (j = 0; j < duration; ++j) {\n\t\t\t\t\tprintf(\"%d\", pulse);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (output_packed) {\n\t\t\t\tputchar(buf[i]);\n\t\t\t}\n\t\t}\n\t\tif (r != 0) printf(\"\\n\");\n\t\tfflush(stdout);\n\n\t\tif (max_count != 0 && ++iteration_count >= max_count) do_exit = 1;\n\t}\n\n\tif (do_exit) {\n\t\tfprintf(stderr, \"\\nUser cancel, exiting...\\n\");}\n\telse {\n\t\tfprintf(stderr, \"\\nLibrary error %d, exiting...\\n\", r);}\n\n\trtlsdr_cancel_async(dongle.dev);\n\n\trtlsdr_close(dongle.dev);\n\treturn r >= 0 ? r : -r;\n\n\treturn 0;\n}\n"
  },
  {
    "path": "src/rtl_power.c",
    "content": "/*\n * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver\n * Copyright (C) 2012 by Steve Markgraf <steve@steve-m.de>\n * Copyright (C) 2012 by Hoernchen <la@tfc-server.de>\n * Copyright (C) 2012 by Kyle Keen <keenerd@gmail.com>\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n\n/*\n * rtl_power: general purpose FFT integrator\n * -f low_freq:high_freq:max_bin_size\n * -i seconds\n * outputs CSV\n * time, low, high, step, db, db, db ...\n * db optional?  raw output might be better for noise correction\n * todo:\n *\tthreading\n *\trandomized hopping\n *\tnoise correction\n *\tcontinuous IIR\n *\tgeneral astronomy usefulness\n *\tmultiple dongles\n *\tmultiple FFT workers\n *\tcheck edge cropping for off-by-one and rounding errors\n *\t1.8MS/s for hiding xtal harmonics\n */\n\n#include <errno.h>\n#include <signal.h>\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <time.h>\n\n#ifndef _WIN32\n#include <unistd.h>\n#else\n#include <windows.h>\n#include <fcntl.h>\n#include <io.h>\n#include \"getopt/getopt.h\"\n#define usleep(x) Sleep(x/1000)\n#if defined(_MSC_VER) && (_MSC_VER < 1800)\n#define round(x) (x > 0.0 ? floor(x + 0.5): ceil(x - 0.5))\n#endif\n#define _USE_MATH_DEFINES\n#endif\n\n#include <math.h>\n#ifdef NEED_PTHREADS_WORKARROUND\n#define HAVE_STRUCT_TIMESPEC\n#endif\n#include <pthread.h>\n#include <libusb.h>\n\n#include <rtl-sdr.h>\n#include <rtl_app_ver.h>\n#include \"convenience/convenience.h\"\n#include \"convenience/rtl_convenience.h\"\n\n#define MAX(x, y) (((x) > (y)) ? (x) : (y))\n\n#define DEFAULT_BUF_LENGTH\t\t(1 * 16384)\n#define AUTO_GAIN\t\t\t\t-100\n#define BUFFER_DUMP\t\t\t\t(1<<12)\n\n#define MAXIMUM_RATE\t\t\t2800000\n#define MINIMUM_RATE\t\t\t1000000\n\nstatic volatile int do_exit = 0;\nstatic rtlsdr_dev_t *dev = NULL;\nFILE *file;\n\nint16_t* Sinewave;\ndouble* power_table;\nint N_WAVE, LOG2_N_WAVE;\nint next_power;\nint16_t *fft_buf;\nint *window_coefs;\n\nstruct tuning_state\n/* one per tuning range */\n{\n\tuint64_t freq;\n\tint rate;\n\tint bin_e;\n\tint64_t *avg;  /* length == 2^bin_e */\n\tint samples;\n\tint downsample;\n\tint downsample_passes;  /* for the recursive filter */\n\tdouble crop;\n\t//pthread_rwlock_t avg_lock;\n\t//pthread_mutex_t avg_mutex;\n\t/* having the iq buffer here is wasteful, but will avoid contention */\n\tuint8_t *buf8;\n\tint buf_len;\n\t//int *comp_fir;\n\t//pthread_rwlock_t buf_lock;\n\t//pthread_mutex_t buf_mutex;\n};\n\nenum time_modes { VERBOSE_TIME, EPOCH_TIME };\n\n/* 3000 is enough for 3GHz b/w worst case */\n#define MAX_TUNES\t3000\nstruct tuning_state tunes[MAX_TUNES];\nint tune_count = 0;\n\nint boxcar = 1;\nint comp_fir_size = 0;\nint peak_hold = 0;\nstatic enum time_modes time_mode = VERBOSE_TIME;\n\nvoid usage(void)\n{\n\tfprintf(stderr,\n\t\t\"rtl_power, a simple FFT logger for RTL2832 based SDR-receivers\\n\"\n\t\t\"rtl_power version %d.%d %s (%s)\\n\"\n\t\t\"rtl-sdr   library %d.%d %s\\n\\n\",\n\t\tAPP_VER_MAJOR, APP_VER_MINOR, APP_VER_ID, __DATE__,\n\t\trtlsdr_get_version() >>16, rtlsdr_get_version() & 0xFFFF,\n\t\trtlsdr_get_ver_id() );\n\tfprintf(stderr,\n\t\t\"Usage:\\trtl_power -f freq_range [-options] [filename]\\n\"\n\t\t\"\\t-f lower:upper:bin_size [Hz]\\n\"\n\t\t\"\\t (bin size is a maximum, smaller more convenient bins\\n\"\n\t\t\"\\t  will be used.  valid range 1Hz - 2.8MHz)\\n\"\n\t\t\"\\t[-i integration_interval (default: 10 seconds)]\\n\"\n\t\t\"\\t (buggy if a full sweep takes longer than the interval)\\n\"\n\t\t\"\\t[-1 enables single-shot mode (default: off)]\\n\"\n\t\t\"\\t[-e exit_timer (default: off/0)]\\n\"\n\t\t//\"\\t[-s avg/iir smoothing (default: avg)]\\n\"\n\t\t//\"\\t[-t threads (default: 1)]\\n\"\n\t\t\"\\t[-d device_index or serial (default: 0)]\\n\"\n\t\t\"\\t[-g tuner_gain (default: automatic)]\\n\"\n\t\t\"\\t[-p ppm_error (default: 0)]\\n\"\n\t\t\"\\t[-T enable bias-T on GPIO PIN 0 (works for rtl-sdr.com v3 dongles)]\\n\"\n\t\t\"\\t[-D direct_sampling_mode (default: 0, 1 = I, 2 = Q, 3 = I below threshold, 4 = Q below threshold)]\\n\"\n\t\t\"\\t[-D direct_sampling_threshold_frequency (default: 0 use tuner specific frequency threshold for 3 and 4)]\\n\"\n\t\t\"\\tfilename (a '-' dumps samples to stdout)\\n\"\n\t\t\"\\t (omitting the filename also uses stdout)\\n\"\n\t\t\"\\n\"\n\t\t\"Experimental options:\\n\"\n\t\t\"\\t[-w window (default: rectangle)]\\n\"\n\t\t\"\\t (hamming, blackman, blackman-harris, hann-poisson, bartlett, youssef)\\n\"\n\t\t// kaiser\n\t\t\"\\t[-c crop_percent (default: 0%%, recommended: 20%%-50%%)]\\n\"\n\t\t\"\\t (discards data at the edges, 100%% discards everything)\\n\"\n\t\t\"\\t (has no effect for bins larger than 1MHz)\\n\"\n\t\t\"\\t[-F fir_size (default: disabled)]\\n\"\n\t\t\"\\t (enables low-leakage downsample filter,\\n\"\n\t\t\"\\t  fir_size can be 0 or 9.  0 has bad roll off,\\n\"\n\t\t\"\\t  try with '-c 50%%')\\n\"\n\t\t\"\\t[-P enables peak hold (default: off)]\\n\"\n\t\t\"\\t[-D enable direct sampling (default: off)]\\n\"\n\t\t\"\\t[-O enable offset tuning (default: off)]\\n\"\n\t\t\"\\n\"\n\t\t\"CSV FFT output columns:\\n\"\n\t\t\"\\tdate, time, Hz low, Hz high, Hz step, samples, dbm, dbm, ...\\n\\n\"\n\t\t\"Examples:\\n\"\n\t\t\"\\trtl_power -f 88M:108M:125k fm_stations.csv\\n\"\n\t\t\"\\t (creates 160 bins across the FM band,\\n\"\n\t\t\"\\t  individual stations should be visible)\\n\"\n\t\t\"\\trtl_power -f 100M:1G:1M -i 5m -1 survey.csv\\n\"\n\t\t\"\\t (a five minute low res scan of nearly everything)\\n\"\n\t\t\"\\trtl_power -f ... -i 15m -1 log.csv\\n\"\n\t\t\"\\t (integrate for 15 minutes and exit afterwards)\\n\"\n\t\t\"\\trtl_power -f ... -e 1h | gzip > log.csv.gz\\n\"\n\t\t\"\\t (collect data for one hour and compress it on the fly)\\n\\n\"\n\t\t\"Convert CSV to a waterfall graphic with:\\n\"\n\t\t\"\\t http://kmkeen.com/tmp/heatmap.py.txt \\n\");\n\texit(1);\n}\n\nvoid multi_bail(void)\n{\n\tif (do_exit == 1)\n\t{\n\t\tfprintf(stderr, \"Signal caught, finishing scan pass.\\n\");\n\t}\n\tif (do_exit >= 2)\n\t{\n\t\tfprintf(stderr, \"Signal caught, aborting immediately.\\n\");\n\t}\n}\n\n#ifdef _WIN32\nBOOL WINAPI\nsighandler(int signum)\n{\n\tif (CTRL_C_EVENT == signum) {\n\t\tdo_exit++;\n\t\tmulti_bail();\n\t\treturn TRUE;\n\t}\n\treturn FALSE;\n}\n#else\nstatic void sighandler(int signum)\n{\n\tdo_exit++;\n\tmulti_bail();\n}\n#endif\n\n/* more cond dumbness */\n#define safe_cond_signal(n, m) pthread_mutex_lock(m); pthread_cond_signal(n); pthread_mutex_unlock(m)\n#define safe_cond_wait(n, m) pthread_mutex_lock(m); pthread_cond_wait(n, m); pthread_mutex_unlock(m)\n\n/* {length, coef, coef, coef}  and scaled by 2^15\n   for now, only length 9, optimal way to get +85% bandwidth */\n#define CIC_TABLE_MAX 10\nint cic_9_tables[][10] = {\n\t{0,},\n\t{9, -156,  -97, 2798, -15489, 61019, -15489, 2798,  -97, -156},\n\t{9, -128, -568, 5593, -24125, 74126, -24125, 5593, -568, -128},\n\t{9, -129, -639, 6187, -26281, 77511, -26281, 6187, -639, -129},\n\t{9, -122, -612, 6082, -26353, 77818, -26353, 6082, -612, -122},\n\t{9, -120, -602, 6015, -26269, 77757, -26269, 6015, -602, -120},\n\t{9, -120, -582, 5951, -26128, 77542, -26128, 5951, -582, -120},\n\t{9, -119, -580, 5931, -26094, 77505, -26094, 5931, -580, -119},\n\t{9, -119, -578, 5921, -26077, 77484, -26077, 5921, -578, -119},\n\t{9, -119, -577, 5917, -26067, 77473, -26067, 5917, -577, -119},\n\t{9, -199, -362, 5303, -25505, 77489, -25505, 5303, -362, -199},\n};\n\n#if defined(_MSC_VER) && (_MSC_VER < 1800)\ndouble log2(double n)\n{\n\treturn log(n) / log(2.0);\n}\n#endif\n\n/* FFT based on fix_fft.c by Roberts, Slaney and Bouras\n   http://www.jjj.de/fft/fftpage.html\n   16 bit ints for everything\n   -32768..+32768 maps to -1.0..+1.0\n*/\n\nvoid sine_table(int size)\n{\n\tint i;\n\tdouble d;\n\tLOG2_N_WAVE = size;\n\tN_WAVE = 1 << LOG2_N_WAVE;\n\tSinewave = malloc(sizeof(int16_t) * N_WAVE*3/4);\n\tpower_table = malloc(sizeof(double) * N_WAVE);\n\tfor (i=0; i<N_WAVE*3/4; i++)\n\t{\n\t\td = (double)i * 2.0 * M_PI / N_WAVE;\n\t\tSinewave[i] = (int)round(32767*sin(d));\n\t\t//printf(\"%i\\n\", Sinewave[i]);\n\t}\n}\n\nstatic inline int16_t FIX_MPY(int16_t a, int16_t b)\n/* fixed point multiply and scale */\n{\n\tint c = ((int)a * (int)b) >> 14;\n\tb = c & 0x01;\n\treturn (c >> 1) + b;\n}\n\nint fix_fft(int16_t iq[], int m)\n/* interleaved iq[], 0 <= n < 2**m, changes in place */\n{\n\tint mr, nn, i, j, l, k, istep, n, shift;\n\tint16_t qr, qi, tr, ti, wr, wi;\n\tn = 1 << m;\n\tif (n > N_WAVE)\n\t\t{return -1;}\n\tmr = 0;\n\tnn = n - 1;\n\t/* decimation in time - re-order data */\n\tfor (m=1; m<=nn; ++m) {\n\t\tl = n;\n\t\tdo\n\t\t\t{l >>= 1;}\n\t\twhile (mr+l > nn);\n\t\tmr = (mr & (l-1)) + l;\n\t\tif (mr <= m)\n\t\t\t{continue;}\n\t\t// real = 2*m, imag = 2*m+1\n\t\ttr = iq[2*m];\n\t\tiq[2*m] = iq[2*mr];\n\t\tiq[2*mr] = tr;\n\t\tti = iq[2*m+1];\n\t\tiq[2*m+1] = iq[2*mr+1];\n\t\tiq[2*mr+1] = ti;\n\t}\n\tl = 1;\n\tk = LOG2_N_WAVE-1;\n\twhile (l < n) {\n\t\tshift = 1;\n\t\tistep = l << 1;\n\t\tfor (m=0; m<l; ++m) {\n\t\t\tj = m << k;\n\t\t\twr =  Sinewave[j+N_WAVE/4];\n\t\t\twi = -Sinewave[j];\n\t\t\tif (shift) {\n\t\t\t\twr >>= 1; wi >>= 1;}\n\t\t\tfor (i=m; i<n; i+=istep) {\n\t\t\t\tj = i + l;\n\t\t\t\ttr = FIX_MPY(wr,iq[2*j]) - FIX_MPY(wi,iq[2*j+1]);\n\t\t\t\tti = FIX_MPY(wr,iq[2*j+1]) + FIX_MPY(wi,iq[2*j]);\n\t\t\t\tqr = iq[2*i];\n\t\t\t\tqi = iq[2*i+1];\n\t\t\t\tif (shift) {\n\t\t\t\t\tqr >>= 1; qi >>= 1;}\n\t\t\t\tiq[2*j] = qr - tr;\n\t\t\t\tiq[2*j+1] = qi - ti;\n\t\t\t\tiq[2*i] = qr + tr;\n\t\t\t\tiq[2*i+1] = qi + ti;\n\t\t\t}\n\t\t}\n\t\t--k;\n\t\tl = istep;\n\t}\n\treturn 0;\n}\n\ndouble rectangle(int i, int length)\n{\n\treturn 1.0;\n}\n\ndouble hamming(int i, int length)\n{\n\tdouble a, b, w, N1;\n\ta = 25.0/46.0;\n\tb = 21.0/46.0;\n\tN1 = (double)(length-1);\n\tw = a - b*cos(2*i*M_PI/N1);\n\treturn w;\n}\n\ndouble blackman(int i, int length)\n{\n\tdouble a0, a1, a2, w, N1;\n\ta0 = 7938.0/18608.0;\n\ta1 = 9240.0/18608.0;\n\ta2 = 1430.0/18608.0;\n\tN1 = (double)(length-1);\n\tw = a0 - a1*cos(2*i*M_PI/N1) + a2*cos(4*i*M_PI/N1);\n\treturn w;\n}\n\ndouble blackman_harris(int i, int length)\n{\n\tdouble a0, a1, a2, a3, w, N1;\n\ta0 = 0.35875;\n\ta1 = 0.48829;\n\ta2 = 0.14128;\n\ta3 = 0.01168;\n\tN1 = (double)(length-1);\n\tw = a0 - a1*cos(2*i*M_PI/N1) + a2*cos(4*i*M_PI/N1) - a3*cos(6*i*M_PI/N1);\n\treturn w;\n}\n\ndouble hann_poisson(int i, int length)\n{\n\tdouble a, N1, w;\n\ta = 2.0;\n\tN1 = (double)(length-1);\n\tw = 0.5 * (1 - cos(2*M_PI*i/N1)) * \\\n\t    pow(M_E, (-a*(double)abs((int)(N1-1-2*i)))/N1);\n\treturn w;\n}\n\ndouble youssef(int i, int length)\n/* really a blackman-harris-poisson window, but that is a mouthful */\n{\n\tdouble a, a0, a1, a2, a3, w, N1;\n\ta0 = 0.35875;\n\ta1 = 0.48829;\n\ta2 = 0.14128;\n\ta3 = 0.01168;\n\tN1 = (double)(length-1);\n\tw = a0 - a1*cos(2*i*M_PI/N1) + a2*cos(4*i*M_PI/N1) - a3*cos(6*i*M_PI/N1);\n\ta = 0.0025;\n\tw *= pow(M_E, (-a*(double)abs((int)(N1-1-2*i)))/N1);\n\treturn w;\n}\n\ndouble kaiser(int i, int length)\n// todo, become more smart\n{\n\treturn 1.0;\n}\n\ndouble bartlett(int i, int length)\n{\n\tdouble N1, L, w;\n\tL = (double)length;\n\tN1 = L - 1;\n\tw = (i - N1/2) / (L/2);\n\tif (w < 0) {\n\t\tw = -w;}\n\tw = 1 - w;\n\treturn w;\n}\n\nvoid rms_power(struct tuning_state *ts)\n/* for bins between 1MHz and 2MHz */\n{\n\tint i, s;\n\tuint8_t *buf = ts->buf8;\n\tint buf_len = ts->buf_len;\n\tint64_t p, t;\n\tdouble dc, err;\n\n\tp = t = 0L;\n\tfor (i=0; i<buf_len; i++) {\n\t\ts = (int)buf[i] - 127;\n\t\tt += (int64_t)s;\n\t\tp += (int64_t)(s * s);\n\t}\n\t/* correct for dc offset in squares */\n\tdc = (double)t / (double)buf_len;\n\terr = t * 2 * dc - dc * dc * buf_len;\n\tp -= (int64_t)round(err);\n\n\tif (!peak_hold) {\n\t\tts->avg[0] += p;\n\t} else {\n\t\tts->avg[0] = MAX(ts->avg[0], p);\n\t}\n\tts->samples += 1;\n}\n\nvoid frequency_range(char *arg, double crop)\n/* flesh out the tunes[] for scanning */\n// do we want the fewest ranges (easy) or the fewest bins (harder)?\n{\n\tchar *start, *stop, *step;\n\tuint64_t upper, lower;\n\tint i, j, max_size, bw_seen, bw_used, bin_e, buf_len;\n\tint downsample, downsample_passes;\n\tdouble bin_size;\n\tstruct tuning_state *ts;\n\t/* hacky string parsing */\n\tstart = arg;\n\tstop = strchr(start, ':') + 1;\n\tstop[-1] = '\\0';\n\tstep = strchr(stop, ':') + 1;\n\tstep[-1] = '\\0';\n\tlower = (uint64_t)(atofs(start) + 0.5);\n\tupper = (uint64_t)(atofs(stop) + 0.5);\n\tmax_size = (int)atofs(step);\n\tstop[-1] = ':';\n\tstep[-1] = ':';\n\tdownsample = 1;\n\tdownsample_passes = 0;\n\t/* evenly sized ranges, as close to MAXIMUM_RATE as possible */\n\t// todo, replace loop with algebra\n\tfor (i=1; i<1500; i++) {\n\t\tbw_seen = (upper - lower) / i;\n\t\tbw_used = (int)((double)(bw_seen) / (1.0 - crop));\n\t\tif (bw_used > MAXIMUM_RATE) {\n\t\t\tcontinue;}\n\t\ttune_count = i;\n\t\tbreak;\n\t}\n\t/* unless small bandwidth */\n\tif (bw_used < MINIMUM_RATE) {\n\t\ttune_count = 1;\n\t\tdownsample = MAXIMUM_RATE / bw_used;\n\t\tbw_used = bw_used * downsample;\n\t}\n\tif (!boxcar && downsample > 1) {\n\t\tdownsample_passes = (int)log2(downsample);\n\t\tdownsample = 1 << downsample_passes;\n\t\tbw_used = (int)((double)(bw_seen * downsample) / (1.0 - crop));\n\t}\n\t/* number of bins is power-of-two, bin size is under limit */\n\t// todo, replace loop with log2\n\tfor (i=1; i<=21; i++) {\n\t\tbin_e = i;\n\t\tbin_size = (double)bw_used / (double)((1<<i) * downsample);\n\t\tif (bin_size <= (double)max_size) {\n\t\t\tbreak;}\n\t}\n\t/* unless giant bins */\n\tif (max_size >= MINIMUM_RATE) {\n\t\tbw_seen = max_size;\n\t\tbw_used = max_size;\n\t\ttune_count = (upper - lower) / bw_seen;\n\t\tbin_e = 0;\n\t\tcrop = 0;\n\t}\n\tif (tune_count > MAX_TUNES) {\n\t\tfprintf(stderr, \"Error: bandwidth too wide.\\n\");\n\t\texit(1);\n\t}\n\tbuf_len = 2 * (1<<bin_e) * downsample;\n\tif (buf_len < DEFAULT_BUF_LENGTH) {\n\t\tbuf_len = DEFAULT_BUF_LENGTH;\n\t}\n\t/* build the array */\n\tfor (i=0; i<tune_count; i++) {\n\t\tts = &tunes[i];\n\t\tts->freq = lower + i*bw_seen + bw_seen/2;\n\t\tts->rate = bw_used;\n\t\tts->bin_e = bin_e;\n\t\tts->samples = 0;\n\t\tts->crop = crop;\n\t\tts->downsample = downsample;\n\t\tts->downsample_passes = downsample_passes;\n\t\tts->avg = (int64_t*)malloc((1<<bin_e) * sizeof(int64_t));\n\t\tif (!ts->avg) {\n\t\t\tfprintf(stderr, \"Error: malloc.\\n\");\n\t\t\texit(1);\n\t\t}\n\t\tfor (j=0; j<(1<<bin_e); j++) {\n\t\t\tts->avg[j] = 0L;\n\t\t}\n\t\tts->buf8 = (uint8_t*)malloc(buf_len * sizeof(uint8_t));\n\t\tif (!ts->buf8) {\n\t\t\tfprintf(stderr, \"Error: malloc.\\n\");\n\t\t\texit(1);\n\t\t}\n\t\tts->buf_len = buf_len;\n\t}\n\t/* report */\n\tfprintf(stderr, \"Number of frequency hops: %i\\n\", tune_count);\n\tfprintf(stderr, \"Dongle bandwidth: %iHz\\n\", bw_used);\n\tfprintf(stderr, \"Downsampling by: %ix\\n\", downsample);\n\tfprintf(stderr, \"Cropping by: %0.2f%%\\n\", crop*100);\n\tfprintf(stderr, \"Total FFT bins: %i\\n\", tune_count * (1<<bin_e));\n\tfprintf(stderr, \"Logged FFT bins: %i\\n\", \\\n\t  (int)((double)(tune_count * (1<<bin_e)) * (1.0-crop)));\n\tfprintf(stderr, \"FFT bin size: %0.2fHz\\n\", bin_size);\n\tfprintf(stderr, \"Buffer size: %i bytes (%0.2fms)\\n\", buf_len, 1000 * 0.5 * (float)buf_len / (float)bw_used);\n}\n\nvoid retune(rtlsdr_dev_t *d, uint64_t freq)\n{\n\tuint8_t dump[BUFFER_DUMP];\n\tint n_read;\n\trtlsdr_set_center_freq64(d, freq);\n\t/* wait for settling and flush buffer */\n\tusleep(5000);\n\trtlsdr_read_sync(d, &dump, BUFFER_DUMP, &n_read);\n\tif (n_read != BUFFER_DUMP) {\n\t\tfprintf(stderr, \"Error: bad retune.\\n\");}\n}\n\nvoid fifth_order(int16_t *data, int length)\n/* for half of interleaved data */\n{\n\tint i;\n\tint a, b, c, d, e, f;\n\ta = data[0];\n\tb = data[2];\n\tc = data[4];\n\td = data[6];\n\te = data[8];\n\tf = data[10];\n\t/* a downsample should improve resolution, so don't fully shift */\n\t/* ease in instead of being stateful */\n\tdata[0] = ((a+b)*10 + (c+d)*5 + d + f) >> 4;\n\tdata[2] = ((b+c)*10 + (a+d)*5 + e + f) >> 4;\n\tdata[4] = (a + (b+e)*5 + (c+d)*10 + f) >> 4;\n\tfor (i=12; i<length; i+=4) {\n\t\ta = c;\n\t\tb = d;\n\t\tc = e;\n\t\td = f;\n\t\te = data[i-2];\n\t\tf = data[i];\n\t\tdata[i/2] = (a + (b+e)*5 + (c+d)*10 + f) >> 4;\n\t}\n}\n\nvoid remove_dc(int16_t *data, int length)\n/* works on interleaved data */\n{\n\tint i;\n\tint16_t ave;\n\tint64_t sum = 0L;\n\tfor (i=0; i < length; i+=2) {\n\t\tsum += data[i];\n\t}\n\tave = (int16_t)(sum / (int64_t)(length));\n\tif (ave == 0) {\n\t\treturn;}\n\tfor (i=0; i < length; i+=2) {\n\t\tdata[i] -= ave;\n\t}\n}\n\nvoid generic_fir(int16_t *data, int length, int *fir)\n/* Okay, not at all generic.  Assumes length 9, fix that eventually. */\n{\n\tint d, temp, sum;\n\tint hist[9] = {0,};\n\t/* cheat on the beginning, let it go unfiltered */\n\tfor (d=0; d<18; d+=2) {\n\t\thist[d/2] = data[d];\n\t}\n\tfor (d=18; d<length; d+=2) {\n\t\ttemp = data[d];\n\t\tsum = 0;\n\t\tsum += (hist[0] + hist[8]) * fir[1];\n\t\tsum += (hist[1] + hist[7]) * fir[2];\n\t\tsum += (hist[2] + hist[6]) * fir[3];\n\t\tsum += (hist[3] + hist[5]) * fir[4];\n\t\tsum +=            hist[4]  * fir[5];\n\t\tdata[d] = (int16_t)(sum >> 15) ;\n\t\thist[0] = hist[1];\n\t\thist[1] = hist[2];\n\t\thist[2] = hist[3];\n\t\thist[3] = hist[4];\n\t\thist[4] = hist[5];\n\t\thist[5] = hist[6];\n\t\thist[6] = hist[7];\n\t\thist[7] = hist[8];\n\t\thist[8] = temp;\n\t}\n}\n\nvoid downsample_iq(int16_t *data, int length)\n{\n\tfifth_order(data, length);\n\t//remove_dc(data, length);\n\tfifth_order(data+1, length-1);\n\t//remove_dc(data+1, length-1);\n}\n\nint64_t real_conj(int16_t real, int16_t imag)\n/* real(n * conj(n)) */\n{\n\treturn ((int64_t)real*(int64_t)real + (int64_t)imag*(int64_t)imag);\n}\n\nvoid scanner(void)\n{\n\tint i, j, j2, n_read, offset, bin_e, bin_len, buf_len, ds, ds_p;\n\tuint64_t f;\n\tint32_t w;\n\tstruct tuning_state *ts;\n\tbin_e = tunes[0].bin_e;\n\tbin_len = 1 << bin_e;\n\tbuf_len = tunes[0].buf_len;\n\tfor (i=0; i<tune_count; i++) {\n\t\tif (do_exit >= 2)\n\t\t\t{return;}\n\t\tts = &tunes[i];\n\t\tf = rtlsdr_get_center_freq64(dev);\n\t\tif (f != ts->freq) {\n\t\t\tretune(dev, ts->freq);}\n\t\trtlsdr_read_sync(dev, ts->buf8, buf_len, &n_read);\n\t\tif (n_read != buf_len) {\n\t\t\tfprintf(stderr, \"Error: dropped samples.\\n\");}\n\t\t/* rms */\n\t\tif (bin_len == 1) {\n\t\t\trms_power(ts);\n\t\t\tcontinue;\n\t\t}\n\t\t/* prep for fft */\n\t\tfor (j=0; j<buf_len; j++) {\n\t\t\tfft_buf[j] = (int16_t)ts->buf8[j] - 127;\n\t\t}\n\t\tds = ts->downsample;\n\t\tds_p = ts->downsample_passes;\n\t\tif (boxcar && ds > 1) {\n\t\t\tj=2, j2=0;\n\t\t\twhile (j < buf_len) {\n\t\t\t\tfft_buf[j2]   += fft_buf[j];\n\t\t\t\tfft_buf[j2+1] += fft_buf[j+1];\n\t\t\t\tfft_buf[j] = 0;\n\t\t\t\tfft_buf[j+1] = 0;\n\t\t\t\tj += 2;\n\t\t\t\tif (j % (ds*2) == 0) {\n\t\t\t\t\tj2 += 2;}\n\t\t\t}\n\t\t} else if (ds_p) {  /* recursive */\n\t\t\tfor (j=0; j < ds_p; j++) {\n\t\t\t\tdownsample_iq(fft_buf, buf_len >> j);\n\t\t\t}\n\t\t\t/* droop compensation */\n\t\t\tif (comp_fir_size == 9 && ds_p <= CIC_TABLE_MAX) {\n\t\t\t\tgeneric_fir(fft_buf, buf_len >> j, cic_9_tables[ds_p]);\n\t\t\t\tgeneric_fir(fft_buf+1, (buf_len >> j)-1, cic_9_tables[ds_p]);\n\t\t\t}\n\t\t}\n\t\tremove_dc(fft_buf, buf_len / ds);\n\t\tremove_dc(fft_buf+1, (buf_len / ds) - 1);\n\t\t/* window function and fft */\n\t\tfor (offset=0; offset<(buf_len/ds); offset+=(2*bin_len)) {\n\t\t\t// todo, let rect skip this\n\t\t\tfor (j=0; j<bin_len; j++) {\n\t\t\t\tw =  (int32_t)fft_buf[offset+j*2];\n\t\t\t\tw *= (int32_t)(window_coefs[j]);\n\t\t\t\t//w /= (int32_t)(ds);\n\t\t\t\tfft_buf[offset+j*2]   = (int16_t)w;\n\t\t\t\tw =  (int32_t)fft_buf[offset+j*2+1];\n\t\t\t\tw *= (int32_t)(window_coefs[j]);\n\t\t\t\t//w /= (int32_t)(ds);\n\t\t\t\tfft_buf[offset+j*2+1] = (int16_t)w;\n\t\t\t}\n\t\t\tfix_fft(fft_buf+offset, bin_e);\n\t\t\tif (!peak_hold) {\n\t\t\t\tfor (j=0; j<bin_len; j++) {\n\t\t\t\t\tts->avg[j] += real_conj(fft_buf[offset+j*2], fft_buf[offset+j*2+1]);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor (j=0; j<bin_len; j++) {\n\t\t\t\t\tts->avg[j] = MAX(real_conj(fft_buf[offset+j*2], fft_buf[offset+j*2+1]), ts->avg[j]);\n\t\t\t\t}\n\t\t\t}\n\t\t\tts->samples += ds;\n\t\t}\n\t}\n}\n\nvoid csv_dbm(struct tuning_state *ts)\n{\n\tint i, len, ds, i1, i2, bw2, bin_count;\n\tint64_t tmp;\n\tdouble dbm;\n\tlen = 1 << ts->bin_e;\n\tds = ts->downsample;\n\t/* fix FFT stuff quirks */\n\tif (ts->bin_e > 0) {\n\t\t/* nuke DC component (not effective for all windows) */\n\t\tts->avg[0] = ts->avg[1];\n\t\t/* FFT is translated by 180 degrees */\n\t\tfor (i=0; i<len/2; i++) {\n\t\t\ttmp = ts->avg[i];\n\t\t\tts->avg[i] = ts->avg[i+len/2];\n\t\t\tts->avg[i+len/2] = tmp;\n\t\t}\n\t}\n\t/* Hz low, Hz high, Hz step, samples, dbm, dbm, ... */\n\tbin_count = (int)((double)len * (1.0 - ts->crop));\n\tbw2 = (int)(((double)ts->rate * (double)bin_count) / (len * 2 * ds));\n\tfprintf(file, \"%.0f, %.0f, %.2f, %i, \", (double)(ts->freq - bw2), (double)(ts->freq + bw2),\n\t\t(double)ts->rate / (double)(len*ds), ts->samples);\n\t// something seems off with the dbm math\n\ti1 = 0 + (int)((double)len * ts->crop * 0.5);\n\ti2 = (len-1) - (int)((double)len * ts->crop * 0.5);\n\tfor (i=i1; i<=i2; i++) {\n\t\tdbm  = (double)ts->avg[i];\n\t\tdbm /= (double)ts->rate;\n\t\tdbm /= (double)ts->samples;\n\t\tdbm  = 10 * log10(dbm);\n\t\tfprintf(file, \"%.2f, \", dbm);\n\t}\n\tdbm = (double)ts->avg[i2] / ((double)ts->rate * (double)ts->samples);\n\tif (ts->bin_e == 0) {\n\t\tdbm = ((double)ts->avg[0] / \\\n\t\t((double)ts->rate * (double)ts->samples));}\n\tdbm  = 10 * log10(dbm);\n\tfprintf(file, \"%.2f\\n\", dbm);\n\tfor (i=0; i<len; i++) {\n\t\tts->avg[i] = 0L;\n\t}\n\tts->samples = 0;\n}\n\nint main(int argc, char **argv)\n{\n#ifndef _WIN32\n\tstruct sigaction sigact;\n#endif\n\tchar *filename = NULL;\n\tint i, length, r, opt, wb_mode = 0;\n\tint f_set = 0;\n\tint gain = AUTO_GAIN; // tenths of a dB\n\tint dev_index = 0;\n\tchar dev_label[256];\n\tint dev_given = 0;\n\tint ppm_error = 0;\n\tint interval = 10;\n\tint fft_threads = 1;\n\tint smoothing = 0;\n\tint single = 0;\n\tint direct_sampling = 0;\n\tint offset_tuning = 0;\n\tint enable_biastee = 0;\n\tenum rtlsdr_ds_mode ds_mode = RTLSDR_DS_IQ;\n\tuint32_t ds_temp, ds_threshold = 0;\n\tdouble crop = 0.0;\n\tchar *freq_optarg;\n\ttime_t next_tick;\n\ttime_t time_now;\n\ttime_t exit_time = 0;\n\tchar t_str[512];\n\tstruct tm *cal_time;\n\tdouble (*window_fn)(int, int) = rectangle;\n\tfreq_optarg = \"\";\n\n\twhile ((opt = getopt(argc, argv, \"f:i:s:t:d:g:p:e:w:c:F:1EPOhTD:\")) != -1) {\n\t\tswitch (opt) {\n\t\tcase 'f': // lower:upper:bin_size\n\t\t\tfreq_optarg = strdup(optarg);\n\t\t\tf_set = 1;\n\t\t\tbreak;\n\t\tcase 'd':\n\t\t\tdev_index = verbose_device_search(optarg);\n\t\t\tstrncpy(dev_label, optarg, 255);\n\t\t\tdev_label[255] = 0;\n\t\t\tdev_given = 1;\n\t\t\tbreak;\n\t\tcase 'g':\n\t\t\tgain = (int)(atof(optarg) * 10);\n\t\t\tbreak;\n\t\tcase 'c':\n\t\t\tcrop = atofp(optarg);\n\t\t\tbreak;\n\t\tcase 'i':\n\t\t\tinterval = (int)round(atoft(optarg));\n\t\t\tbreak;\n\t\tcase 'e':\n\t\t\texit_time = (time_t)((int)round(atoft(optarg)));\n\t\t\tbreak;\n\t\tcase 's':\n\t\t\tif (strcmp(\"avg\",  optarg) == 0) {\n\t\t\t\tsmoothing = 0;}\n\t\t\tif (strcmp(\"iir\",  optarg) == 0) {\n\t\t\t\tsmoothing = 1;}\n\t\t\tbreak;\n\t\tcase 'w':\n\t\t\tif (strcmp(\"rectangle\",  optarg) == 0) {\n\t\t\t\twindow_fn = rectangle;}\n\t\t\tif (strcmp(\"hamming\",  optarg) == 0) {\n\t\t\t\twindow_fn = hamming;}\n\t\t\tif (strcmp(\"blackman\",  optarg) == 0) {\n\t\t\t\twindow_fn = blackman;}\n\t\t\tif (strcmp(\"blackman-harris\",  optarg) == 0) {\n\t\t\t\twindow_fn = blackman_harris;}\n\t\t\tif (strcmp(\"hann-poisson\",  optarg) == 0) {\n\t\t\t\twindow_fn = hann_poisson;}\n\t\t\tif (strcmp(\"youssef\",  optarg) == 0) {\n\t\t\t\twindow_fn = youssef;}\n\t\t\tif (strcmp(\"kaiser\",  optarg) == 0) {\n\t\t\t\twindow_fn = kaiser;}\n\t\t\tif (strcmp(\"bartlett\",  optarg) == 0) {\n\t\t\t\twindow_fn = bartlett;}\n\t\t\tbreak;\n\t\tcase 't':\n\t\t\tfft_threads = atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'p':\n\t\t\tppm_error = atoi(optarg);\n\t\t\tbreak;\n\t\tcase '1':\n\t\t\tsingle = 1;\n\t\t\tbreak;\n\t\tcase 'E':\n\t\t\ttime_mode = EPOCH_TIME;\n\t\t\tbreak;\n\t\tcase 'P':\n\t\t\tpeak_hold = 1;\n\t\t\tbreak;\n\t\tcase 'D':\n\t\t\tif(!optarg) {\n\t\t\t\tdirect_sampling = 1;\n\t\t\t} else {\n\t\t\t\tds_temp = (uint32_t)( atofs(optarg) + 0.5 );\n\t\t\t\tif (ds_temp <= RTLSDR_DS_Q_BELOW)\n\t\t\t\t\tds_mode = (enum rtlsdr_ds_mode)ds_temp;\n\t\t\t\telse\n\t\t\t\t\tds_threshold = ds_temp;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'O':\n\t\t\toffset_tuning = 1;\n\t\t\tbreak;\n\t\tcase 'F':\n\t\t\tboxcar = 0;\n\t\t\tcomp_fir_size = atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'T':\n\t\t\tenable_biastee = 1;\n\t\t\tbreak;\n\t\tcase 'h':\n\t\tdefault:\n\t\t\tusage();\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (!f_set) {\n\t\tfprintf(stderr, \"No frequency range provided.\\n\");\n\t\texit(1);\n\t}\n\n\tif ((crop < 0.0) || (crop > 1.0)) {\n\t\tfprintf(stderr, \"Crop value outside of 0 to 1.\\n\");\n\t\texit(1);\n\t}\n\n\tfrequency_range(freq_optarg, crop);\n\n\tif (tune_count == 0) {\n\t\tusage();}\n\n\tif (argc <= optind) {\n\t\tfilename = \"-\";\n\t} else {\n\t\tfilename = argv[optind];\n\t}\n\n\tif (interval < 1) {\n\t\tinterval = 1;}\n\n\tfprintf(stderr, \"Reporting every %i seconds\\n\", interval);\n\n\tif (!dev_given) {\n\t\tdev_index = verbose_device_search(\"0\");\n\t}\n\n\tif (dev_index < 0) {\n\t\texit(1);\n\t}\n\n\tr = rtlsdr_open(&dev, (uint32_t)dev_index);\n\tif (r < 0) {\n\t\tfprintf(stderr, \"Failed to open rtlsdr device #%d.\\n\", dev_index);\n\t\texit(1);\n\t}\n#ifndef _WIN32\n\tsigact.sa_handler = sighandler;\n\tsigemptyset(&sigact.sa_mask);\n\tsigact.sa_flags = 0;\n\tsigaction(SIGINT, &sigact, NULL);\n\tsigaction(SIGTERM, &sigact, NULL);\n\tsigaction(SIGQUIT, &sigact, NULL);\n\tsigaction(SIGPIPE, &sigact, NULL);\n#else\n\tSetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE );\n#endif\n\n\tif (direct_sampling) {\n\t\tverbose_direct_sampling(dev, 1);\n\t}\n\n\t/* Set direct sampling with threshold */\n\trtlsdr_set_ds_mode(dev, ds_mode, ds_threshold);\n\n\tif (offset_tuning) {\n\t\tverbose_offset_tuning(dev);\n\t}\n\n\t/* Set the tuner gain */\n\tif (gain == AUTO_GAIN) {\n\t\tverbose_auto_gain(dev);\n\t} else {\n\t\tgain = nearest_gain(dev, gain);\n\t\tverbose_gain_set(dev, gain);\n\t}\n\n\tverbose_ppm_set(dev, ppm_error);\n\n\trtlsdr_set_bias_tee(dev, enable_biastee);\n\tif (enable_biastee)\n\t\tfprintf(stderr, \"activated bias-T on GPIO PIN 0\\n\");\n\n\tif (strcmp(filename, \"-\") == 0) { /* Write log to stdout */\n\t\tfile = stdout;\n#ifdef _WIN32\n\t\t// Is this necessary?  Output is ascii.\n\t\t_setmode(_fileno(file), _O_BINARY);\n#endif\n\t} else {\n\t\tfile = fopen(filename, \"wb\");\n\t\tif (!file) {\n\t\t\tfprintf(stderr, \"Failed to open %s\\n\", filename);\n\t\t\texit(1);\n\t\t}\n\t}\n\n\t/* Reset endpoint before we start reading from it (mandatory) */\n\tverbose_reset_buffer(dev);\n\n\t/* actually do stuff */\n\trtlsdr_set_sample_rate(dev, (uint32_t)tunes[0].rate);\n\tsine_table(tunes[0].bin_e);\n\tnext_tick = time(NULL) + interval;\n\tif (exit_time) {\n\t\texit_time = time(NULL) + exit_time;}\n\tfft_buf = malloc(tunes[0].buf_len * sizeof(int16_t));\n\tlength = 1 << tunes[0].bin_e;\n\twindow_coefs = malloc(length * sizeof(int));\n\tfor (i=0; i<length; i++) {\n\t\twindow_coefs[i] = (int)(256*window_fn(i, length));\n\t}\n\twhile (!do_exit) {\n\t\tscanner();\n\t\ttime_now = time(NULL);\n\t\tif (time_now < next_tick) {\n\t\t\tcontinue;}\n\t\t// time, Hz low, Hz high, Hz step, samples, dbm, dbm, ...\n\t\tcal_time = localtime(&time_now);\n\t\tif (time_mode == VERBOSE_TIME) {\n\t\t\tstrftime(t_str, 512, \"%Y-%m-%d, %H:%M:%S\", cal_time);\n\t\t}\n\t\tif (time_mode == EPOCH_TIME) {\n\t\t\tsnprintf(t_str, 512, \"%u, %s\", (unsigned)time_now, dev_label);\n\t\t}\n\t\tfor (i=0; i<tune_count; i++) {\n\t\t\tfprintf(file, \"%s, \", t_str);\n\t\t\tcsv_dbm(&tunes[i]);\n\t\t}\n\t\tfflush(file);\n\t\twhile (time(NULL) >= next_tick) {\n\t\t\tnext_tick += interval;}\n\t\tif (single) {\n\t\t\tdo_exit = 1;}\n\t\tif (exit_time && time(NULL) >= exit_time) {\n\t\t\tdo_exit = 1;}\n\t}\n\n\t/* clean up */\n\n\tif (do_exit) {\n\t\tfprintf(stderr, \"\\nUser cancel, exiting...\\n\");}\n\telse {\n\t\tfprintf(stderr, \"\\nLibrary error %d, exiting...\\n\", r);}\n\n\tif (file != stdout) {\n\t\tfclose(file);}\n\n\trtlsdr_close(dev);\n\tfree(fft_buf);\n\tfree(window_coefs);\n\tif (freq_optarg[0])\n\t\tfree(freq_optarg);\n\t//for (i=0; i<tune_count; i++) {\n\t//\tfree(tunes[i].avg);\n\t//\tfree(tunes[i].buf8);\n\t//}\n\treturn r >= 0 ? r : -r;\n}\n\n// vim: tabstop=8:softtabstop=8:shiftwidth=8:noexpandtab\n"
  },
  {
    "path": "src/rtl_raw2wav.c",
    "content": "/*\n * rtl-raw2wav, converts binary/raw data into wave files - including frequency\n * Copyright (C) 2019 by Hayati Ayguen <h_ayguen@web.de>\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <errno.h>\n#include <signal.h>\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <math.h>\n\n#ifndef _WIN32\n  #include <unistd.h>\n  #include <sys/types.h>\n  #include <sys/stat.h>\n\n#else\n  #include <windows.h>\n  #include <fcntl.h>\n  #include <io.h>\n  #include <sys/types.h>\n  #include <sys/stat.h>\n\n  #include \"getopt/getopt.h\"\n\n  #if defined(_MSC_VER) && (_MSC_VER < 1900)\n    #define snprintf _snprintf\n  #endif\n#endif\n\n#include <rtl_app_ver.h>\n#include \"convenience/convenience.h\"\n#include \"convenience/wavewrite.h\"\n\n\nstatic volatile int do_exit = 0;\nstatic int verbosity = 0;\n\n\nvoid usage(void)\n{\n\tfprintf(stderr,\n\t\t\"rtl_raw2wav, a raw (binary sampledata) to wave file converter\\n\"\n\t\t\"rtl_raw2wav version %d.%d %s (%s)\\n\\n\",\n\t\tAPP_VER_MAJOR, APP_VER_MINOR, APP_VER_ID, __DATE__ );\n\tfprintf(stderr,\n\t\t\"Usage:\\trtl_raw2wav -w <output_wave_filename> [-options] [input_raw_filename]\\n\"\n\t\t\"\\t-w filename     output filename\\n\"\n\t\t\"\\t-f frequency    frequency, to write into output filename\\n\"\n\t\t\"\\t-s samplerate   samplerate, of raw input\\n\"\n\t\t\"\\t-c #channels    number of channels, default: 2 - for I and Q\\n\"\n\t\t\"\\t-b #bits        number of bits per sample, default: 8 - 8 or 16 allowed\\n\"\n\t\t\"\\t-u time         set start time in UTC:       'yyy-mm-ddThh:mm:dd.zzz'\\n\"\n\t\t\"\\t-t time         set start time in localtime: 'yyy-mm-ddThh:mm:dd.zzz'\\n\"\n\t\t\"\\t-v              verbose output\\n\"\n\t\t\"\\t-r filename     input filename for raw samples, default: - for stdin\\n\\n\" );\n}\n\n#ifdef _WIN32\nBOOL WINAPI\nsighandler(int signum)\n{\n\tif (CTRL_C_EVENT == signum) {\n\t\tfprintf(stderr, \"Signal caught, exiting!\\n\");\n\t\tdo_exit = 1;\n\t\treturn TRUE;\n\t}\n\treturn FALSE;\n}\n#else\nstatic void sighandler(int signum)\n{\n\tfprintf(stderr, \"Signal caught, exiting!\\n\");\n\tdo_exit = 1;\n}\n#endif\n\n\nint main(int argc, char **argv)\n{\n#ifndef _WIN32\n\tstruct sigaction sigact;\n#endif\n\tint r, opt;\n\tconst char * rawfilename = NULL;\n\tconst char * wavfilename = NULL;\n\tchar *tempfilename = NULL;\n\tFILE * outfile = NULL;\n\tFILE * inpfile = NULL;\n\tuint32_t freq = 0;\n\tuint32_t srate = 0;\n\tint nChan = 2;\n\tint nBits = 8;\n\tchar acBuf[ 65536 * sizeof(int16_t) * 2 ];  /* 64 K frames with 2 channels and 16 Bit */\n\tsize_t smpSize;\n\tsize_t nRead;\n\ttime_t tim = 0;\n\tdouble fraction = 0.0;\n\tint haveTime = 0;\n\n\twhile ((opt = getopt(argc, argv, \"f:s:c:b:r:u:t:w:vh\")) != -1) {\n\t\tswitch (opt) {\n\t\tcase 'f':\tfreq = (uint32_t)atofs(optarg);\t\tbreak;\n\t\tcase 's':\tsrate = (uint32_t)atofs(optarg);\tbreak;\n\t\tcase 'c':\tnChan = atoi(optarg);\tbreak;\n\t\tcase 'b':\tnBits = atoi(optarg);\n\t\t\t\tif (nBits <= 4) /* assume intention was: bytes per sample */\n\t\t\t\t\tnBits *= 8;\n\t\t\t\tbreak;\n\t\tcase 'v':\t++verbosity;\tbreak;\n\t\tcase 'r':\trawfilename = optarg;\tbreak;\n\t\tcase 'u':\ttim = utctimestr_to_time(optarg, &fraction);\n\t\t\tif (tim)\thaveTime = 1;\n\t\t\tbreak;\n\t\tcase 't':\ttim = localtimestr_to_time(optarg, &fraction);\n\t\t\tif (tim)\thaveTime = 1;\n\t\t\tbreak;\n\t\tcase 'w':\twavfilename = optarg;\tbreak;\n\t\tcase 'h':\n\t\tcase '?':\n\t\tdefault:\n\t\t\tusage();\n\t\t\texit(1);\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (verbosity)\n\t\tfprintf(stderr, \"verbosity set to %d\\n\", verbosity);\n\n\tif (optind < argc) {\n\t\trawfilename = argv[optind];\n\t}\n\n\twhile (!wavfilename) {\n\t\tif (rawfilename) {\n\t\t\tint slen = strlen(rawfilename);\n\t\t\tconst char * rawEnd = rawfilename + slen;\n\t\t\tif (slen > 4 && (!strcmp(rawEnd - 4, \".bin\") || !strcmp(rawEnd - 4, \".raw\"))) {\n\t\t\t\tchar * wfn = strdup(rawfilename);\n\t\t\t\tstrcpy(wfn+slen-4, \".wav\");\n\t\t\t\twavfilename = wfn;\n\t\t\t\tif (verbosity)\n\t\t\t\t\tfprintf(stderr, \"Warning: deduced .wav filename '%s' from rawfilename '%s'\\n\", wavfilename, rawfilename);\n\t\t\t\tbreak;  /* the while() */\n\t\t\t}\n\t\t}\n\t\tusage();\n\t\tfprintf(stderr, \"Error: missing output wave filename!\\n\");\n\t\texit(1);\n\t}\n\n\tif (nChan < 1 || nChan > 2) {\n\t\tusage();\n\t\tfprintf(stderr, \"Error: number of channels must be 1 or 2!\\n\");\n\t\texit(1);\n\t}\n\tif (nBits != 8 && nBits != 16) {\n\t\tusage();\n\t\tfprintf(stderr, \"Error: number of bits per sample must be 8 or 16!\\n\");\n\t\texit(1);\n\t}\n\n#ifndef _WIN32\n\tsigact.sa_handler = sighandler;\n\tsigemptyset(&sigact.sa_mask);\n\tsigact.sa_flags = 0;\n\tsigaction(SIGINT, &sigact, NULL);\n\tsigaction(SIGTERM, &sigact, NULL);\n\tsigaction(SIGQUIT, &sigact, NULL);\n\tsigaction(SIGPIPE, &sigact, NULL);\n#else\n\tSetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE );\n#endif\n\n\tsmpSize = nChan * ( nBits == 16 ? sizeof(int16_t) : sizeof(uint8_t) );\n\tif (verbosity >= 2)\n\t\tfprintf(stderr, \"Frame size = %d channels * %d bits = %d bytes\\n\", nChan, nBits, (int)smpSize);\n\n\tif (!rawfilename || !strcmp(rawfilename, \"-\")) {\n#ifdef _WIN32\n\t\t_setmode(_fileno(stdin), _O_BINARY);\n#endif\n\t\tinpfile = stdin;\n\t\tif (verbosity)\n\t\t\tfprintf(stderr, \"Using stdin as input\\n\");\n\t} else {\n\t\tif (verbosity >= 2)\n\t\t\tfprintf(stderr, \"Opening input '%s'\\n\", rawfilename);\n\t\tinpfile = fopen(rawfilename, \"rb\");\n\t\tif (!inpfile) {\n\t\t\tfprintf(stderr, \"Error: Failed to open input %s\\n\", rawfilename);\n\t\t\texit(1);\n\t\t}\n\t\tif (verbosity)\n\t\t\tfprintf(stderr, \"Opened '%s' for input\\n\", rawfilename);\n\t\tif (!haveTime) {\n\t\t\tint gotmodtim = 0;\n#if defined(_WIN32)\n\t\t\tstruct _stat attr;\n\t\t\tif (!_stat(rawfilename, &attr)) {\n\t\t\t\ttim = attr.st_mtime;\n\t\t\t\tfraction = 0.0;\n\t\t\t\tgotmodtim = 1;\n\t\t\t}\n#elif defined(__APPLE__)\n\t\t\tstruct stat attr;\n\t\t\tif (!stat(rawfilename, &attr)) {\n\t\t\t\ttim = attr.st_mtime;\n\t\t\t\tfraction = attr.st_mtimespec.tv_nsec / 1E9;\n\t\t\t\tgotmodtim = 1;\n\t\t\t}\n#else\n\t\t\tstruct stat attr;\n\t\t\tif (!stat(rawfilename, &attr)) {\n\t\t\t\ttim = attr.st_mtime;\n\t\t\t\tfraction = attr.st_mtim.tv_nsec / 1E9;\n\t\t\t\tgotmodtim = 1;\n\t\t\t}\n#endif\n\t\t\tif (gotmodtim) {\n\t\t\t\tlong fs = 0;\n\t\t\t\tif (verbosity >= 2)\n\t\t\t\t\tfprintf(stderr, \"Got 'last modified' from input file '%s'\\n\", rawfilename);\n\t\t\t\tif (!fseek(inpfile, 0, SEEK_END)) {\n\t\t\t\t\tfs = ftell(inpfile);\n\t\t\t\t\tif (fs > 0) {\n\t\t\t\t\t\tdouble dur = (double)(fs) / ( (double)srate * smpSize );\n\t\t\t\t\t\tdouble di = floor(dur);\n\t\t\t\t\t\tdouble df = dur - di;\n\t\t\t\t\t\ttim -= (time_t)di;\n\t\t\t\t\t\tfraction -= df;\n\t\t\t\t\t\tif (fraction < 0.0) {\n\t\t\t\t\t\t\tfraction += 1.0;\n\t\t\t\t\t\t\ttim -= 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (verbosity)\n\t\t\t\t\t\t\tfprintf(stderr, \"Set output's timestamp from input files 'last modified' minus duration of %f seconds\\n\", dur);\n\t\t\t\t\t\thaveTime = 1;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfseek(inpfile, 0, SEEK_SET);\n\t\t\t}\n\t\t}\n\t}\n\n\ttempfilename = malloc( strlen(wavfilename)+8 );\n\tstrcpy(tempfilename, wavfilename);\n\tstrcat(tempfilename, \".tmp\");\n\n\tif (verbosity >= 2)\n\t\tfprintf(stderr, \"Opening output '%s'\\n\", tempfilename);\n\toutfile = fopen(tempfilename, \"wb\");\n\tif (!outfile) {\n\t\tfprintf(stderr, \"Error: Failed to open output '%s'\\n\", tempfilename);\n\t\texit(1);\n\t} else {\n\t\tif (verbosity)\n\t\t\tfprintf(stderr, \"Opened '%s' for output\\n\", tempfilename);\n\t\twaveWriteHeader(srate, freq, nBits, nChan, outfile);\n\t\tif (haveTime) {\n\t\t\tif (verbosity >= 2)\n\t\t\t\tfprintf(stderr, \"Setting start time of output file\\n\");\n\t\t\twaveSetStartTime(tim, fraction);\n\t\t}\n\t}\n\n\twhile ( !feof(inpfile) ) {\n\t\tif (do_exit) {\n\t\t\tfprintf(stderr, \"\\nUser cancel, exiting...\\n\");\n\t\t\tbreak;\n\t\t}\n\t\tnRead = fread(acBuf, smpSize, 65536, inpfile);\n\t\tif (nRead > 0)\n\t\t\twaveWriteFrames(outfile, acBuf, nRead, 0);\n\t\tif (verbosity >= 2)\n\t\t\tfprintf(stderr, \".\");\n\t}\n\n\tif (verbosity >= 2)\n\t\tfprintf(stderr, \"\\nWriting output header\\n\");\n\twaveFinalizeHeader(outfile);\n\tfclose(outfile);\n\tif (verbosity)\n\t\tfprintf(stderr, \"Closed output file.\\n\");\n\tif (verbosity >= 2)\n\t\tfprintf(stderr, \"Deleting '%s' - in case it exists\\n\", wavfilename);\n\tremove(wavfilename);\t/* delete, in case file already exists */\n\tif (verbosity >= 2)\n\t\tfprintf(stderr, \"Renaming '%s' into '%s'\\n\", tempfilename, wavfilename);\n\tr = rename( tempfilename, wavfilename );\t/* #include <stdio.h> */\n\tif ( r )\n\t\tfprintf( stderr, \"%s: Error %d '%s' renaming'%s' to '%s'\\n\"\n\t\t\t, argv[0], errno, strerror(errno), tempfilename, wavfilename );\n\telse if (verbosity)\n\t\tfprintf( stderr, \"Renamed output file into '%s'\\n\", wavfilename );\n\n\tif (inpfile != stdin)\n\t\tfclose(inpfile);\n\n\treturn 0;\n}\n\n/* vim: tabstop=8:softtabstop=8:shiftwidth=8:noexpandtab */\n"
  },
  {
    "path": "src/rtl_rpcd.c",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <unistd.h>\n#include <stddef.h>\n#include <string.h>\n#include <errno.h>\n#include <time.h>\n#include <sys/types.h>\n#include <sys/select.h>\n#include <sys/socket.h>\n#include <sys/fcntl.h>\n#include <sys/time.h>\n#include <arpa/inet.h>\n#include <netinet/in.h>\n#include <netdb.h>\n#include <pthread.h>\n\n#include <rtl-sdr.h>\n#include <rtl_app_ver.h>\n#include \"rtlsdr_rpc_msg.h\"\n\n\n#if 1\n#include <stdio.h>\n#define PRINTF(__s, ...)\t\t\t\\\ndo {\t\t\t\t\t\t\\\n  fprintf(stderr, __s, ##__VA_ARGS__);\t\t\\\n  fflush(stderr);\t\t\t\t\\\n} while (0)\n#define TRACE() PRINTF(\"[t] %s,%u\\n\", __FILE__, __LINE__)\n#define ERROR() PRINTF(\"[e] %s,%u\\n\", __FILE__, __LINE__)\n#else\n#define TRACE()\n#define ERROR()\n#define PRINTF(...)\n#endif\n\n\ntypedef struct\n{\n  int listen_sock;\n  int cli_sock;\n\n  rtlsdr_dev_t* dev;\n  uint32_t did;\n\n  rtlsdr_rpc_msg_t query_msg;\n  rtlsdr_rpc_msg_t reply_msg;\n  rtlsdr_rpc_msg_t event_msg;\n\n  unsigned int async_replied;\n  uint8_t async_id;\n\n  int port_ir;\n  const char *addr_ir;\n  int wait_ir;\n} rpcd_t;\n\nstatic int resolve_ip_addr\n(\n struct sockaddr_storage saddr_both[2], size_t size_both[2],\n const char* addr, const char* port\n)\n{\n  struct addrinfo ai;\n  struct addrinfo* aip = NULL;\n  int err = -1;\n  size_t i;\n\n  memset(&ai, 0, sizeof(ai));\n  ai.ai_family = AF_UNSPEC;\n  ai.ai_socktype = SOCK_STREAM;\n  ai.ai_flags = AI_PASSIVE;\n\n  if (getaddrinfo(addr, port, &ai, &aip)) goto on_error;\n\n  size_both[0] = 0;\n  size_both[1] = 0;\n  i = 0;\n  for (; (i != 2) && (aip != NULL); aip = aip->ai_next)\n  {\n    if ((aip->ai_family != AF_INET) && (aip->ai_family != AF_INET6)) continue ;\n    if (aip->ai_addrlen == 0) continue ;\n    memcpy(&saddr_both[i], aip->ai_addr, aip->ai_addrlen);\n    size_both[i] = aip->ai_addrlen;\n    ++i;\n  }\n\n  if (i == 0) goto on_error;\n\n  err = 0;\n on_error:\n  if (aip != NULL) freeaddrinfo(aip);\n  return err;\n}\n\nstatic int open_nonblock_socket\n(\n struct sockaddr_storage saddr_both[2], size_t size_both[2],\n int type, int proto,\n struct sockaddr_storage** saddr_used, size_t* size_used\n)\n{\n  size_t i;\n  int fd = -1;\n\n  for (i = 0; (i != 2) && (size_both[i]); ++i)\n  {\n    const struct sockaddr* const sa = (const struct sockaddr*)&saddr_both[i];\n    fd = socket(sa->sa_family, type, proto);\n    if (fd != -1) break ;\n  }\n\n  if ((i == 2) || (size_both[i] == 0)) return -1;\n\n  *saddr_used = &saddr_both[i];\n  *size_used = size_both[i];\n\n  if (fcntl(fd, F_SETFL, O_NONBLOCK))\n  {\n    close(fd);\n    return -1;\n  }\n\n  return fd;\n}\n\nstatic int init_rpcd(rpcd_t* rpcd, const char* addr, const char* port)\n{\n  struct sockaddr_storage saddrs[2];\n  struct sockaddr_storage* saddr;\n  size_t sizes[2];\n  size_t size;\n  int err;\n  int enable = 1;\n\n  /* TODO: handle errors */\n  rtlsdr_rpc_msg_init(&rpcd->query_msg, 0);\n  rtlsdr_rpc_msg_init(&rpcd->reply_msg, 0);\n  rtlsdr_rpc_msg_init(&rpcd->event_msg, 0);\n\n  if (resolve_ip_addr(saddrs, sizes, addr, port))\n  {\n    ERROR();\n    goto on_error_0;\n  }\n\n  rpcd->listen_sock = open_nonblock_socket\n    (saddrs, sizes, SOCK_STREAM, IPPROTO_TCP, &saddr, &size);\n  if (rpcd->listen_sock == -1)\n  {\n    ERROR();\n    goto on_error_0;\n  }\n\n  err = setsockopt\n    (rpcd->listen_sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));\n  if (err)\n  {\n    ERROR();\n    goto on_error_1;\n  }\n\n  err = bind\n    (rpcd->listen_sock, (const struct sockaddr*)saddr, (socklen_t)size);\n  if (err)\n  {\n    ERROR();\n    goto on_error_1;\n  }\n\n  if (listen(rpcd->listen_sock, 5))\n  {\n    ERROR();\n    goto on_error_1;\n  }\n\n  rpcd->cli_sock = -1;\n  rpcd->dev = NULL;\n\n  return 0;\n\n on_error_1:\n  close(rpcd->listen_sock);\n on_error_0:\n  return -1;\n}\n\nstatic int fini_rpcd(rpcd_t* rpcd)\n{\n  if (rpcd->cli_sock != -1)\n  {\n    shutdown(rpcd->cli_sock, SHUT_RDWR);\n    close(rpcd->cli_sock);\n  }\n\n  shutdown(rpcd->listen_sock, SHUT_RDWR);\n  close(rpcd->listen_sock);\n\n  rtlsdr_rpc_msg_fini(&rpcd->query_msg);\n  rtlsdr_rpc_msg_fini(&rpcd->reply_msg);\n  rtlsdr_rpc_msg_fini(&rpcd->event_msg);\n\n  return 0;\n}\n\nstatic int recv_all(int fd, uint8_t* buf, size_t size)\n{\n  ssize_t n;\n  fd_set rset;\n\n  while (1)\n  {\n    errno = 0;\n    n = recv(fd, buf, size, 0);\n    if (n <= 0)\n    {\n      if ((errno != EWOULDBLOCK) || (errno != EAGAIN))\n\treturn -1;\n    }\n    else\n    {\n      size -= (size_t)n;\n      buf += (size_t)n;\n      if (size == 0) break ;\n    }\n\n    FD_ZERO(&rset);\n    FD_SET(fd, &rset);\n    if (select(fd + 1, &rset, NULL, NULL, NULL) <= 0)\n    {\n      return -1;\n    }\n  }\n\n  return 0;\n}\n\nstatic int send_all_check_recv\n(int fd, const uint8_t* buf, size_t size, unsigned int* is_recv)\n{\n  ssize_t n;\n  fd_set wset;\n  fd_set rset;\n  fd_set* rsetp;\n\n  rsetp = NULL;\n  if (is_recv != NULL) *is_recv = 0;\n\n  while (1)\n  {\n    FD_ZERO(&wset);\n    FD_SET(fd, &wset);\n\n    rsetp = NULL;\n    if ((is_recv != NULL) && (*is_recv == 0))\n    {\n      FD_ZERO(&rset);\n      FD_SET(fd, &rset);\n      rsetp = &rset;\n    }\n\n    if (select(fd + 1, rsetp, &wset, NULL, NULL) <= 0)\n    {\n      return -1;\n    }\n\n    if ((rsetp != NULL) && FD_ISSET(fd, rsetp))\n    {\n      *is_recv = 1;\n    }\n\n    if (FD_ISSET(fd, &wset))\n    {\n      errno = 0;\n      n = send(fd, buf, size, 0);\n      if (n <= 0)\n      {\n\tif ((errno != EWOULDBLOCK) || (errno != EAGAIN))\n\t  return -1;\n      }\n      else\n      {\n\tsize -= (size_t)n;\n\tbuf += (size_t)n;\n\tif (size == 0) break ;\n      }\n    }\n  }\n\n  return 0;\n}\n\nstatic int send_all(int fd, const uint8_t* buf, size_t size)\n{\n  return send_all_check_recv(fd, buf, size, NULL);\n}\n\nstatic int recv_msg(int fd, rtlsdr_rpc_msg_t* m)\n{\n  uint32_t size;\n\n  if (recv_all(fd, (uint8_t*)&size, sizeof(uint32_t)))\n  {\n    ERROR();\n    return -1;\n  }\n\n  rtlsdr_rpc_msg_set_size(m, size);\n  size = rtlsdr_rpc_msg_get_size(m);\n\n  if (rtlsdr_rpc_msg_realloc(m, size))\n  {\n    ERROR();\n    return -1;\n  }\n\n  if (recv_all(fd, m->fmt + sizeof(uint32_t), size - sizeof(uint32_t)))\n  {\n    ERROR();\n    return -1;\n  }\n\n  return 0;\n}\n\nstatic int send_msg(int fd, rtlsdr_rpc_msg_t* m)\n{\n  return send_all(fd, m->fmt, m->off);\n}\n\nstatic int recv_query(rpcd_t* rpcd, rtlsdr_rpc_msg_t** q)\n{\n  *q = NULL;\n  rtlsdr_rpc_msg_reset(&rpcd->query_msg);\n  if (recv_msg(rpcd->cli_sock, &rpcd->query_msg)) return -1;\n  *q = &rpcd->query_msg;\n  return 0;\n}\n\nstatic int send_reply(rpcd_t* rpcd, rtlsdr_rpc_msg_t* r)\n{\n  return send_msg(rpcd->cli_sock, r);\n}\n\nstatic void read_async_cb\n(unsigned char* buf, uint32_t len, void* ctx)\n{\n  const size_t off = offsetof(rtlsdr_rpc_fmt_t, data);\n\n  rpcd_t* const rpcd = ctx;\n  uint8_t fmt[offsetof(rtlsdr_rpc_fmt_t, data)];\n  rtlsdr_rpc_msg_t msg;\n  unsigned int is_recv;\n\n  if (rpcd->async_replied == 0)\n  {\n    send_reply(rpcd, &rpcd->reply_msg);\n    rpcd->async_replied = 1;\n  }\n\n  msg.off = off;\n  msg.size = off + len;\n  msg.fmt = fmt;\n  rtlsdr_rpc_msg_set_size(&msg, msg.size);\n  rtlsdr_rpc_msg_set_op(&msg, RTLSDR_RPC_OP_READ_ASYNC);\n  rtlsdr_rpc_msg_set_id(&msg, rpcd->async_id);\n  rtlsdr_rpc_msg_set_err(&msg, 0);\n\n  send_all(rpcd->cli_sock, fmt, off);\n  send_all_check_recv(rpcd->cli_sock, buf, len, &is_recv);\n\n  if (is_recv) rtlsdr_cancel_async(rpcd->dev);\n}\n\n__attribute__((unused))\nstatic const char* op_to_string(rtlsdr_rpc_op_t op)\n{\n  const char* const s[] =\n  {\n    \"RTLSDR_RPC_OP_GET_DEVICE_COUNT\",\n    \"RTLSDR_RPC_OP_GET_DEVICE_NAME\",\n    \"RTLSDR_RPC_OP_GET_DEVICE_USB_STRINGS\",\n    \"RTLSDR_RPC_OP_GET_INDEX_BY_SERIAL\",\n    \"RTLSDR_RPC_OP_OPEN\",\n    \"RTLSDR_RPC_OP_CLOSE\",\n    \"RTLSDR_RPC_OP_SET_XTAL_FREQ\",\n    \"RTLSDR_RPC_OP_GET_XTAL_FREQ\",\n    \"RTLSDR_RPC_OP_GET_USB_STRINGS\",\n    \"RTLSDR_RPC_OP_WRITE_EEPROM\",\n    \"RTLSDR_RPC_OP_READ_EEPROM\",\n    \"RTLSDR_RPC_OP_SET_CENTER_FREQ\",\n    \"RTLSDR_RPC_OP_GET_CENTER_FREQ\",\n    \"RTLSDR_RPC_OP_SET_FREQ_CORRECTION\",\n    \"RTLSDR_RPC_OP_GET_FREQ_CORRECTION\",\n    \"RTLSDR_RPC_OP_GET_TUNER_TYPE\",\n    \"RTLSDR_RPC_OP_GET_TUNER_GAINS\",\n    \"RTLSDR_RPC_OP_SET_TUNER_GAIN\",\n    \"RTLSDR_RPC_OP_GET_TUNER_GAIN\",\n    \"RTLSDR_RPC_OP_SET_TUNER_IF_GAIN\",\n    \"RTLSDR_RPC_OP_SET_TUNER_GAIN_MODE\",\n    \"RTLSDR_RPC_OP_SET_GET_TUNER_BW\",\n    \"RTLSDR_RPC_OP_SET_SAMPLE_RATE\",\n    \"RTLSDR_RPC_OP_GET_SAMPLE_RATE\",\n    \"RTLSDR_RPC_OP_SET_TESTMODE\",\n    \"RTLSDR_RPC_OP_SET_AGC_MODE\",\n    \"RTLSDR_RPC_OP_SET_DIRECT_SAMPLING\",\n    \"RTLSDR_RPC_OP_GET_DIRECT_SAMPLING\",\n    \"RTLSDR_RPC_OP_SET_OFFSET_TUNING\",\n    \"RTLSDR_RPC_OP_GET_OFFSET_TUNING\",\n    \"RTLSDR_RPC_OP_RESET_BUFFER\",\n    \"RTLSDR_RPC_OP_READ_SYNC\",\n    \"RTLSDR_RPC_OP_WAIT_ASYNC\",\n    \"RTLSDR_RPC_OP_READ_ASYNC\",\n    \"RTLSDR_RPC_OP_CANCEL_ASYNC\",\n    \"RTLSDR_RPC_OP_EVENT_STATE\",\n    \"RTLSDR_RPC_OP_INVALID\"\n  };\n  if (op >= RTLSDR_RPC_OP_INVALID) op = RTLSDR_RPC_OP_INVALID;\n  return s[op];\n}\n\nstatic int handle_query\n(rpcd_t* rpcd, rtlsdr_rpc_msg_t* q, rtlsdr_rpc_msg_t** rr)\n{\n  rtlsdr_rpc_msg_t* const r = &rpcd->reply_msg;\n  rtlsdr_rpc_op_t op;\n  int err = -1;\n\n  *rr = NULL;\n\n  rtlsdr_rpc_msg_reset(r);\n\n  op = rtlsdr_rpc_msg_get_op(q);\n  switch (op)\n  {\n  case RTLSDR_RPC_OP_GET_DEVICE_COUNT:\n    {\n      uint32_t n;\n\n      n = rtlsdr_get_device_count();\n      if (rtlsdr_rpc_msg_push_uint32(r, n)) goto on_error;\n      err = 0;\n      break ;\n    }\n\n  case RTLSDR_RPC_OP_GET_DEVICE_NAME:\n    {\n      const char* s;\n      uint32_t i;\n\n      if (rtlsdr_rpc_msg_pop_uint32(q, &i)) goto on_error;\n\n      s = rtlsdr_get_device_name(i);\n      if (s == NULL) s = \"\";\n\n      if (rtlsdr_rpc_msg_push_str(r, s)) goto on_error;\n\n      err = 0;\n\n      break ;\n    }\n\n  case RTLSDR_RPC_OP_GET_DEVICE_USB_STRINGS:\n    {\n      char manuf[256];\n      char product[256];\n      char serial[256];\n      uint32_t i;\n\n      if (rtlsdr_rpc_msg_pop_uint32(q, &i)) goto on_error;\n\n      err = rtlsdr_get_device_usb_strings(i, manuf, product, serial);\n      if (err) goto on_error;\n\n      if (rtlsdr_rpc_msg_push_str(r, manuf))\n      {\n\terr = -1;\n\tgoto on_error;\n      }\n\n      if (rtlsdr_rpc_msg_push_str(r, product))\n      {\n\terr = -1;\n\tgoto on_error;\n      }\n\n      if (rtlsdr_rpc_msg_push_str(r, serial))\n      {\n\terr = -1;\n\tgoto on_error;\n      }\n\n      break ;\n    }\n\n  case RTLSDR_RPC_OP_GET_INDEX_BY_SERIAL:\n    {\n      const char* serial;\n\n      if (rtlsdr_rpc_msg_pop_str(q, &serial)) goto on_error;\n      err = rtlsdr_get_index_by_serial(serial);\n      if (err < 0) goto on_error;\n\n      break ;\n    }\n\n  case RTLSDR_RPC_OP_OPEN:\n    {\n      if (rpcd->dev != NULL)\n      {\n\t/* already opened */\n\terr = 0;\n\tgoto on_error;\n      }\n\n      if (rtlsdr_rpc_msg_pop_uint32(q, &rpcd->did)) goto on_error;\n      err = rtlsdr_open(&rpcd->dev, rpcd->did);\n      if (err)\n      {\n\trpcd->dev = NULL;\n\tgoto on_error;\n      }\n\n      break ;\n    }\n\n  case RTLSDR_RPC_OP_CLOSE:\n    {\n      uint32_t did;\n\n      if (rtlsdr_rpc_msg_pop_uint32(q, &did)) goto on_error;\n      if ((rpcd->dev == NULL) || (rpcd->did != did)) goto on_error;\n      err = rtlsdr_close(rpcd->dev);\n      rpcd->dev = NULL;\n\n      break ;\n    }\n\n  case RTLSDR_RPC_OP_SET_XTAL_FREQ:\n    {\n      uint32_t did;\n      uint32_t rtl_freq;\n      uint32_t tuner_freq;\n\n      if (rtlsdr_rpc_msg_pop_uint32(q, &did)) goto on_error;\n      if (rtlsdr_rpc_msg_pop_uint32(q, &rtl_freq)) goto on_error;\n      if (rtlsdr_rpc_msg_pop_uint32(q, &tuner_freq)) goto on_error;\n\n      if ((rpcd->dev == NULL) || (rpcd->did != did)) goto on_error;\n\n      err = rtlsdr_set_xtal_freq(rpcd->dev, rtl_freq, tuner_freq);\n      if (err) goto on_error;\n\n      break ;\n    }\n\n  case RTLSDR_RPC_OP_GET_XTAL_FREQ:\n    {\n      uint32_t did;\n      uint32_t rtl_freq;\n      uint32_t tuner_freq;\n\n      if (rtlsdr_rpc_msg_pop_uint32(q, &did)) goto on_error;\n\n      if ((rpcd->dev == NULL) || (rpcd->did != did)) goto on_error;\n\n      err = rtlsdr_get_xtal_freq(rpcd->dev, &rtl_freq, &tuner_freq);\n      if (err) goto on_error;\n\n      if (rtlsdr_rpc_msg_push_uint32(r, rtl_freq))\n      {\n\terr = -1;\n\tgoto on_error;\n      }\n\n      if (rtlsdr_rpc_msg_push_uint32(r, tuner_freq))\n      {\n\terr = -1;\n\tgoto on_error;\n      }\n\n      break ;\n    }\n\n  case RTLSDR_RPC_OP_GET_USB_STRINGS:\n    {\n      uint32_t did;\n      char manuf[256];\n      char product[256];\n      char serial[256];\n\n      if (rtlsdr_rpc_msg_pop_uint32(q, &did)) goto on_error;\n\n      if ((rpcd->dev == NULL) || (rpcd->did != did)) goto on_error;\n\n      err = rtlsdr_get_usb_strings(rpcd->dev, manuf, product, serial);\n      if (err) goto on_error;\n\n      if (rtlsdr_rpc_msg_push_str(r, manuf))\n      {\n\terr = -1;\n\tgoto on_error;\n      }\n\n      if (rtlsdr_rpc_msg_push_str(r, product))\n      {\n\terr = -1;\n\tgoto on_error;\n      }\n\n      if (rtlsdr_rpc_msg_push_str(r, serial))\n      {\n\terr = -1;\n\tgoto on_error;\n      }\n\n      break ;\n    }\n\n  case RTLSDR_RPC_OP_SET_CENTER_FREQ:\n    {\n      uint32_t did;\n      uint32_t freq;\n\n      if (rtlsdr_rpc_msg_pop_uint32(q, &did)) goto on_error;\n      if (rtlsdr_rpc_msg_pop_uint32(q, &freq)) goto on_error;\n\n      if ((rpcd->dev == NULL) || (rpcd->did != did)) goto on_error;\n\n      err = rtlsdr_set_center_freq(rpcd->dev, freq);\n      if (err) goto on_error;\n\n      break ;\n    }\n\n  case RTLSDR_RPC_OP_GET_CENTER_FREQ:\n    {\n      uint32_t did;\n      uint32_t freq;\n\n      if (rtlsdr_rpc_msg_pop_uint32(q, &did)) goto on_error;\n\n      if ((rpcd->dev == NULL) || (rpcd->did != did)) goto on_error;\n\n      freq = rtlsdr_get_center_freq(rpcd->dev);\n      if (freq == 0) goto on_error;\n      if (rtlsdr_rpc_msg_push_uint32(r, freq)) goto on_error;\n      err = 0;\n\n      break ;\n    }\n\n  case RTLSDR_RPC_OP_SET_FREQ_CORRECTION:\n    {\n      uint32_t did;\n      uint32_t ppm;\n\n      if (rtlsdr_rpc_msg_pop_uint32(q, &did)) goto on_error;\n      if (rtlsdr_rpc_msg_pop_uint32(q, &ppm)) goto on_error;\n\n      if ((rpcd->dev == NULL) || (rpcd->did != did)) goto on_error;\n\n      err = rtlsdr_set_freq_correction(rpcd->dev, (int)ppm);\n      if (err) goto on_error;\n\n      break ;\n    }\n\n  case RTLSDR_RPC_OP_GET_FREQ_CORRECTION:\n    {\n      uint32_t did;\n\n      if (rtlsdr_rpc_msg_pop_uint32(q, &did)) goto on_error;\n\n      if ((rpcd->dev == NULL) || (rpcd->did != did)) goto on_error;\n\n      err = rtlsdr_get_freq_correction(rpcd->dev);\n\n      break ;\n    }\n\n  case RTLSDR_RPC_OP_GET_TUNER_TYPE:\n    {\n      uint32_t did;\n\n      if (rtlsdr_rpc_msg_pop_uint32(q, &did)) goto on_error;\n\n      if ((rpcd->dev == NULL) || (rpcd->did != did)) goto on_error;\n\n      err = rtlsdr_get_tuner_type(rpcd->dev);\n\n      break ;\n    }\n\n  case RTLSDR_RPC_OP_GET_TUNER_GAINS:\n    {\n      uint32_t did;\n      uint32_t is_null;\n      uint32_t gain_size;\n      size_t new_size;\n      uint8_t* buf;\n\n      if (rtlsdr_rpc_msg_pop_uint32(q, &did)) goto on_error;\n      if (rtlsdr_rpc_msg_pop_uint32(q, &is_null)) goto on_error;\n      if (rtlsdr_rpc_msg_pop_uint32(q, &gain_size)) goto on_error;\n\n      if ((rpcd->dev == NULL) || (rpcd->did != did)) goto on_error;\n\n      if (is_null)\n      {\n\terr = rtlsdr_get_tuner_gains(rpcd->dev, NULL);\n\tif (err <= 0) goto on_error;\n      }\n      else\n      {\n\tnew_size = r->off + sizeof(uint32_t) + gain_size;\n\tif (rtlsdr_rpc_msg_realloc(r, new_size)) goto on_error;\n\tbuf = r->fmt + r->off + sizeof(uint32_t);\n\n\terr = rtlsdr_get_tuner_gains(rpcd->dev, (int*)buf);\n\tif (err <= 0) goto on_error;\n\n\trtlsdr_rpc_msg_push_uint32_safe(r, gain_size);\n\trtlsdr_rpc_msg_skip_safe(r, gain_size);\n      }\n\n      break ;\n    }\n\n  case RTLSDR_RPC_OP_SET_TUNER_GAIN:\n    {\n      uint32_t did;\n      uint32_t gain;\n\n      if (rtlsdr_rpc_msg_pop_uint32(q, &did)) goto on_error;\n      if (rtlsdr_rpc_msg_pop_uint32(q, &gain)) goto on_error;\n\n      if ((rpcd->dev == NULL) || (rpcd->did != did)) goto on_error;\n\n      err = rtlsdr_set_tuner_gain(rpcd->dev, (int)gain);\n      if (err) goto on_error;\n\n      break ;\n    }\n\n  case RTLSDR_RPC_OP_GET_TUNER_GAIN:\n    {\n      uint32_t did;\n\n      if (rtlsdr_rpc_msg_pop_uint32(q, &did)) goto on_error;\n\n      if ((rpcd->dev == NULL) || (rpcd->did != did)) goto on_error;\n\n      err = rtlsdr_get_tuner_gain(rpcd->dev);\n\n      break ;\n    }\n\n  case RTLSDR_RPC_OP_SET_TUNER_IF_GAIN:\n    {\n      uint32_t did;\n      uint32_t stage;\n      uint32_t gain;\n\n      if (rtlsdr_rpc_msg_pop_uint32(q, &did)) goto on_error;\n      if (rtlsdr_rpc_msg_pop_uint32(q, &stage)) goto on_error;\n      if (rtlsdr_rpc_msg_pop_uint32(q, &gain)) goto on_error;\n\n      if ((rpcd->dev == NULL) || (rpcd->did != did)) goto on_error;\n\n      err = rtlsdr_set_tuner_if_gain(rpcd->dev, (int)stage, (int)gain);\n      if (err) goto on_error;\n\n      break ;\n    }\n\n  case RTLSDR_RPC_OP_SET_TUNER_GAIN_MODE:\n    {\n      uint32_t did;\n      uint32_t manual;\n\n      if (rtlsdr_rpc_msg_pop_uint32(q, &did)) goto on_error;\n      if (rtlsdr_rpc_msg_pop_uint32(q, &manual)) goto on_error;\n\n      if ((rpcd->dev == NULL) || (rpcd->did != did)) goto on_error;\n\n      err = rtlsdr_set_tuner_gain_mode(rpcd->dev, (int)manual);\n      if (err) goto on_error;\n\n      break ;\n    }\n\n  case RTLSDR_RPC_OP_SET_GET_TUNER_BW:\n    {\n      uint32_t did;\n      uint32_t bw;\n      uint32_t applied_bw;\n      int32_t apply_bw;\n\n      if (rtlsdr_rpc_msg_pop_uint32(q, &did)) goto on_error;\n      if (rtlsdr_rpc_msg_pop_uint32(q, &bw)) goto on_error;\n      if (rtlsdr_rpc_msg_pop_int32(q, &apply_bw)) goto on_error;\n\n      if ((rpcd->dev == NULL) || (rpcd->did != did)) goto on_error;\n\n      err = rtlsdr_set_and_get_tuner_bandwidth(rpcd->dev, bw, &applied_bw, (int)apply_bw);\n      if (err) goto on_error;\n      if (rtlsdr_rpc_msg_push_uint32(r, applied_bw)) goto on_error;\n\n      break ;\n    }\n\n  case RTLSDR_RPC_OP_SET_SAMPLE_RATE:\n    {\n      uint32_t did;\n      uint32_t rate;\n\n      if (rtlsdr_rpc_msg_pop_uint32(q, &did)) goto on_error;\n      if (rtlsdr_rpc_msg_pop_uint32(q, &rate)) goto on_error;\n\n      if ((rpcd->dev == NULL) || (rpcd->did != did)) goto on_error;\n\n      err = rtlsdr_set_sample_rate(rpcd->dev, rate);\n      if (err) goto on_error;\n\n      break ;\n    }\n\n  case RTLSDR_RPC_OP_GET_SAMPLE_RATE:\n    {\n      uint32_t did;\n      uint32_t rate;\n\n      if (rtlsdr_rpc_msg_pop_uint32(q, &did)) goto on_error;\n\n      if ((rpcd->dev == NULL) || (rpcd->did != did)) goto on_error;\n\n      rate = rtlsdr_get_sample_rate(rpcd->dev);\n      if (rate == 0) goto on_error;\n      if (rtlsdr_rpc_msg_push_uint32(r, rate)) goto on_error;\n      err = 0;\n\n      break ;\n    }\n\n  case RTLSDR_RPC_OP_SET_TESTMODE:\n    {\n      uint32_t did;\n      uint32_t on;\n\n      if (rtlsdr_rpc_msg_pop_uint32(q, &did)) goto on_error;\n      if (rtlsdr_rpc_msg_pop_uint32(q, &on)) goto on_error;\n\n      if ((rpcd->dev == NULL) || (rpcd->did != did)) goto on_error;\n\n      err = rtlsdr_set_testmode(rpcd->dev, (int)on);\n      if (err) goto on_error;\n\n      break ;\n    }\n\n  case RTLSDR_RPC_OP_SET_AGC_MODE:\n    {\n      uint32_t did;\n      uint32_t on;\n\n      if (rtlsdr_rpc_msg_pop_uint32(q, &did)) goto on_error;\n      if (rtlsdr_rpc_msg_pop_uint32(q, &on)) goto on_error;\n\n      if ((rpcd->dev == NULL) || (rpcd->did != did)) goto on_error;\n\n      err = rtlsdr_set_agc_mode(rpcd->dev, (int)on);\n      if (err) goto on_error;\n\n      break ;\n    }\n\n  case RTLSDR_RPC_OP_SET_DIRECT_SAMPLING:\n    {\n      uint32_t did;\n      uint32_t on;\n\n      if (rtlsdr_rpc_msg_pop_uint32(q, &did)) goto on_error;\n      if (rtlsdr_rpc_msg_pop_uint32(q, &on)) goto on_error;\n\n      if ((rpcd->dev == NULL) || (rpcd->did != did)) goto on_error;\n\n      err = rtlsdr_set_direct_sampling(rpcd->dev, (int)on);\n      if (err) goto on_error;\n\n      break ;\n    }\n\n  case RTLSDR_RPC_OP_GET_DIRECT_SAMPLING:\n    {\n      uint32_t did;\n\n      if (rtlsdr_rpc_msg_pop_uint32(q, &did)) goto on_error;\n\n      if ((rpcd->dev == NULL) || (rpcd->did != did)) goto on_error;\n\n      err = rtlsdr_get_direct_sampling(rpcd->dev);\n\n      break ;\n    }\n\n  case RTLSDR_RPC_OP_SET_OFFSET_TUNING:\n    {\n      uint32_t did;\n      uint32_t on;\n\n      if (rtlsdr_rpc_msg_pop_uint32(q, &did)) goto on_error;\n      if (rtlsdr_rpc_msg_pop_uint32(q, &on)) goto on_error;\n\n      if ((rpcd->dev == NULL) || (rpcd->did != did)) goto on_error;\n\n      err = rtlsdr_set_offset_tuning(rpcd->dev, (int)on);\n      if (err) goto on_error;\n\n      break ;\n    }\n\n  case RTLSDR_RPC_OP_GET_OFFSET_TUNING:\n    {\n      uint32_t did;\n\n      if (rtlsdr_rpc_msg_pop_uint32(q, &did)) goto on_error;\n\n      if ((rpcd->dev == NULL) || (rpcd->did != did)) goto on_error;\n\n      err = rtlsdr_get_offset_tuning(rpcd->dev);\n\n      break ;\n    }\n\n  case RTLSDR_RPC_OP_RESET_BUFFER:\n    {\n      uint32_t did;\n\n      if (rtlsdr_rpc_msg_pop_uint32(q, &did)) goto on_error;\n\n      if ((rpcd->dev == NULL) || (rpcd->did != did)) goto on_error;\n\n      err = rtlsdr_reset_buffer(rpcd->dev);\n      if (err) goto on_error;\n\n      break ;\n    }\n\n  case RTLSDR_RPC_OP_READ_ASYNC:\n    {\n      uint32_t did;\n      uint32_t buf_num;\n      uint32_t buf_len;\n      rtlsdr_rpc_op_t new_op;\n      rtlsdr_rpc_msg_t* new_q;\n      rtlsdr_rpc_msg_t* new_r;\n      uint8_t id;\n\n      if (rtlsdr_rpc_msg_pop_uint32(q, &did)) goto on_error;\n      if (rtlsdr_rpc_msg_pop_uint32(q, &buf_num)) goto on_error;\n      if (rtlsdr_rpc_msg_pop_uint32(q, &buf_len)) goto on_error;\n\n      if ((rpcd->dev == NULL) || (rpcd->did != did)) goto on_error;\n\n      /* prepare the reply here */\n      id = rtlsdr_rpc_msg_get_id(q);\n      rtlsdr_rpc_msg_set_size(r, r->off);\n      rtlsdr_rpc_msg_set_op(r, op);\n      rtlsdr_rpc_msg_set_id(r, id);\n      rtlsdr_rpc_msg_set_err(r, 0);\n      \n      rpcd->async_id = id;\n      rpcd->async_replied = 0;\n      while (1)\n      {\n\trtlsdr_read_async\n\t  (rpcd->dev, read_async_cb, rpcd, buf_num, buf_len);\n\n\tif (rpcd->async_replied == 0) goto on_error;\n\n\tif (recv_query(rpcd, &new_q)) goto on_error;\n\n\tnew_op = rtlsdr_rpc_msg_get_op(new_q);\n\n\t/* do not reply is cancel_async */\n\tif (new_op == RTLSDR_RPC_OP_CANCEL_ASYNC) return 0;\n\thandle_query(rpcd, new_q, &new_r);\n\n\tif (new_r != NULL) send_reply(rpcd, new_r);\n      }\n\n      /* do not resend reply */\n      if (rpcd->async_replied) return 0;\n      goto on_error;\n      break ;\n    }\n\n  case RTLSDR_RPC_OP_CANCEL_ASYNC:\n    {\n      uint32_t did;\n\n      if (rtlsdr_rpc_msg_pop_uint32(q, &did)) goto on_error;\n\n      if ((rpcd->dev == NULL) || (rpcd->did != did)) goto on_error;\n\n      /* already cancelled if here */\n      err = 0;\n\n      break ;\n    }\n\n  case RTLSDR_RPC_OP_READ_SYNC:\n    {\n      uint32_t did;\n      uint32_t len;\n      int n_read;\n      uint8_t* buf;\n      size_t new_size;\n\n      if (rtlsdr_rpc_msg_pop_uint32(q, &did)) goto on_error;\n      if (rtlsdr_rpc_msg_pop_uint32(q, &len)) goto on_error;\n\n      if ((rpcd->dev == NULL) || (rpcd->did != did)) goto on_error;\n\n      new_size = r->off + sizeof(uint32_t) + len;\n      if (rtlsdr_rpc_msg_realloc(r, new_size)) goto on_error;\n      buf = r->fmt + r->off + sizeof(uint32_t);\n\n      err = rtlsdr_read_sync(rpcd->dev, buf, (int)len, &n_read);\n      if (err) goto on_error;\n\n      rtlsdr_rpc_msg_push_uint32_safe(r, (uint32_t)n_read);\n      rtlsdr_rpc_msg_skip_safe(r, (size_t)n_read);\n\n      break ;\n    }\n\n  default:\n    {\n      PRINTF(\"invalid op: %u\\n\", op);\n      break ;\n    }\n  }\n\n on_error:\n  rtlsdr_rpc_msg_set_size(r, r->off);\n  rtlsdr_rpc_msg_set_op(r, op);\n  rtlsdr_rpc_msg_set_id(r, rtlsdr_rpc_msg_get_id(q));\n  rtlsdr_rpc_msg_set_err(r, err);\n  *rr = r;\n  return 0;\n}\n\nstatic int do_rpcd(rpcd_t* rpcd)\n{\n  fd_set rset;\n  int max_fd;\n\n  while (1)\n  {\n    FD_ZERO(&rset);\n\n    if (rpcd->cli_sock != -1)\n    {\n      FD_SET(rpcd->cli_sock, &rset);\n      max_fd = rpcd->cli_sock;\n    }\n    else\n    {\n      FD_SET(rpcd->listen_sock, &rset);\n      max_fd = rpcd->listen_sock;\n    }\n\n    if (select(max_fd + 1, &rset, NULL, NULL, NULL) <= 0)\n    {\n      ERROR();\n      return -1;\n    }\n\n    if (FD_ISSET(rpcd->listen_sock, &rset))\n    {\n      PRINTF(\"new client\\n\");\n\n      rpcd->cli_sock = accept(rpcd->listen_sock, NULL, NULL);\n      if (rpcd->cli_sock == -1)\n      {\n\tif ((errno == EWOULDBLOCK) || (errno == EAGAIN))\n\t  continue ;\n\tERROR();\n\tbreak ;\n      }\n\n      if (fcntl(rpcd->cli_sock, F_SETFL, O_NONBLOCK))\n      {\n\tERROR();\n\tbreak ;\n      }\n    }\n    else if (FD_ISSET(rpcd->cli_sock, &rset))\n    {\n      rtlsdr_rpc_msg_t* q;\n      rtlsdr_rpc_msg_t* r;\n\n      if (recv_query(rpcd, &q))\n      {\n\tPRINTF(\"cli closed\\n\");\n\tshutdown(rpcd->cli_sock, SHUT_RDWR);\n\tclose(rpcd->cli_sock);\n\trpcd->cli_sock = -1;\n      }\n      else if (q != NULL)\n      {\n\thandle_query(rpcd, q, &r);\n\tif (r != NULL) send_reply(rpcd, r);\n      }\n    }\n  }\n\n  return 0;\n}\n\nvoid usage(void)\n{\n\tfprintf(stderr,\n\t\t\"rtl_rpcd, a Remote Procedure Call server for RTL2832 based SDR-receivers\\n\"\n\t\t\"rtl_rpcd version %d.%d %s (%s)\\n\"\n\t\t\"rtl-sdr  library %d.%d %s\\n\\n\",\n\t\tAPP_VER_MAJOR, APP_VER_MINOR, APP_VER_ID, __DATE__,\n\t\trtlsdr_get_version() >>16, rtlsdr_get_version() & 0xFFFF,\n\t\trtlsdr_get_ver_id() );\n  fprintf(stderr,\n    \"Usage:\\trtl_rpcd [-options]\\n\"\n    \"\\t[-a address]\\tAddress to listen on (default: 0.0.0.0 for all), or RTLSDR_RPC_SERV_ADDR\\n\"\n    \"\\t[-p port]\\tPort number to listen on (default: 40000), or RTLSDR_RPC_SERV_PORT\\n\"\n    \"\\t[-I port_ir]\\tinfrared sensor listen port (default: 0=none)\\n\"\n    \"\\t[-w wait_ir]\\tinfrared sensor query wait interval usec (default: 10000)\\n\"\n    \"\\t[-h]\\t\\tHelp\\n\"\n    \"\\n\"\n    \"On the remote client, set RTLSDR_RPC_IS_ENABLED and matching address/port\\n\"\n  );\n  exit(1);\n}\n\nvoid *ir_thread_fn(void *arg)\n{\n  int r = 1;\n  struct linger ling = {1,0};\n  int listensocket;\n  int irsocket;\n  struct sockaddr_in local, remote;\n  socklen_t rlen;\n  uint8_t buf[128];\n  int ret = 0, len;\n  struct timeval tv;\n  fd_set writefds, errorfds;\n\n  rpcd_t *rpcd = (rpcd_t *)arg;\n\n  rtlsdr_dev_t *dev = rpcd->dev;\n  const char *addr = rpcd->addr_ir;\n  int port = rpcd->port_ir;\n  int wait = rpcd->wait_ir;\n\n\n  memset(&local,0,sizeof(local));\n  local.sin_family = AF_INET;\n  local.sin_port = htons(port);\n  local.sin_addr.s_addr = inet_addr(addr);\n\n  listensocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);\n  r = 1;\n  setsockopt(listensocket, SOL_SOCKET, SO_REUSEADDR, (char *)&r, sizeof(int));\n  setsockopt(listensocket, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling));\n  bind(listensocket,(struct sockaddr *)&local,sizeof(local));\n\n\n  while(1) {\n    printf(\"listening on IR port %d...\\n\", port);\n    listen(listensocket,1);\n\n    irsocket = accept(listensocket,(struct sockaddr *)&remote, &rlen);\n    setsockopt(irsocket, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling));\n\n    printf(\"IR client accepted!\\n\");\n\n    while(1) {\n      dev = rpcd->dev;\n      if (!dev) {\n        printf(\"no device available yet\\n\");\n        // Keep waiting until RPC connects and opens device\n        usleep(1000000);\n        continue;\n      }\n\n      ret = rtlsdr_ir_query(dev, buf, sizeof(buf));\n      if (ret < 0) {\n        printf(\"rtlsdr_ir_query error %d\\n\", ret);\n        break;\n      }\n\n      len = ret;\n\n      FD_ZERO(&writefds);\n      FD_SET(irsocket, &writefds);\n\n      FD_ZERO(&errorfds);\n      FD_SET(irsocket, &errorfds);\n\n      tv.tv_sec = 1;\n      tv.tv_usec = 0;\n      select(irsocket+1, NULL, &writefds, &errorfds, &tv);\n\n      if (FD_ISSET(irsocket, &errorfds)) {\n        printf(\"error condition from irsocket, breaking\\n\");\n        break;\n      }\n\n      if (FD_ISSET(irsocket, &writefds)) {\n        ret = send(irsocket, buf, len, 0);\n        if (ret != len){\n          printf(\"incomplete write to ir client: %d != %d\\n\", ret,len);\n          break;\n        }\n      } else {\n        printf(\"irsocket not ready to write, breaking\\n\");\n        break;\n      }\n\n      usleep(wait);\n    }\n\n    close(irsocket);\n  }\n\n  return 0;\n}\n\n\nint main(int ac, char** av)\n{\n  rpcd_t rpcd;\n  const char* addr = NULL;\n  const char* port = NULL;\n\n  int opt;\n  int port_ir = 0, wait_ir = 10000;\n  pthread_t thread_ir;\n\n  while ((opt = getopt(ac, av, \"a:p:I:w:h\")) != -1) {\n    switch (opt) {\n    case 'a':\n        addr = optarg;\n        break;\n    case 'p':\n        port = optarg;\n        break;\n    case 'I':\n        port_ir = atoi(optarg);\n        break;\n    case 'w':\n        wait_ir = atoi(optarg);\n        break;\n    case 'h':\n    default:\n        usage();\n    }\n  }\n\n  if (addr == NULL) addr = getenv(\"RTLSDR_RPC_SERV_ADDR\");\n  if (addr == NULL) addr = \"0.0.0.0\";\n\n  if (port == NULL) port = getenv(\"RTLSDR_RPC_SERV_PORT\");\n  if (port == NULL) port = \"40000\";\n\n  if (init_rpcd(&rpcd, addr, port)) return -1;\n  if (port_ir) {\n    rpcd.port_ir = port_ir;\n    rpcd.addr_ir = addr;\n    rpcd.wait_ir = wait_ir;\n    pthread_create(&thread_ir, NULL, &ir_thread_fn, (void *)(&rpcd));\n  }\n\n  do_rpcd(&rpcd);\n  fini_rpcd(&rpcd);\n\n  return 0;\n}\n"
  },
  {
    "path": "src/rtl_sdr.c",
    "content": "/*\n * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver\n * Copyright (C) 2012 by Steve Markgraf <steve@steve-m.de>\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <errno.h>\n#include <signal.h>\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#ifndef _WIN32\n#include <unistd.h>\n#else\n#include <windows.h>\n#include <io.h>\n#include <fcntl.h>\n#include \"getopt/getopt.h\"\n#endif\n\n#include <rtl-sdr.h>\n#include <rtl_app_ver.h>\n#include \"convenience/convenience.h\"\n#include \"convenience/rtl_convenience.h\"\n#include \"convenience/wavewrite.h\"\n\n#define DEFAULT_SAMPLE_RATE\t\t2048000\n#define DEFAULT_BANDWIDTH\t\t0\t/* automatic bandwidth */\n#define DEFAULT_BUF_LENGTH\t\t(16 * 16384)\n#define MINIMAL_BUF_LENGTH\t\t512\n#define MAXIMAL_BUF_LENGTH\t\t(256 * 16384)\n\n\nstatic int do_exit = 0;\nstatic uint32_t iq_frames_to_read = 0;\nstatic rtlsdr_dev_t *dev = NULL;\n\nvoid usage(void)\n{\n\tfprintf(stderr,\n\t\t\"rtl_sdr, an I/Q recorder for RTL2832 based SDR-receivers\\n\"\n\t\t\"rtl_sdr version %d.%d %s (%s)\\n\"\n\t\t\"rtl-sdr library %d.%d %s\\n\\n\",\n\t\tAPP_VER_MAJOR, APP_VER_MINOR, APP_VER_ID, __DATE__,\n\t\trtlsdr_get_version() >>16, rtlsdr_get_version() & 0xFFFF,\n\t\trtlsdr_get_ver_id() );\n\tfprintf(stderr,\n\t\t\"Usage:\\trtl_sdr -f frequency_to_tune_to [Hz]\\n\"\n\t\t\"\\t[-s samplerate (default: 2048000 Hz)]\\n\"\n\t\t\"\\t[-w tuner_bandwidth (default: automatic)]\\n\"\n\t\t\"\\t[-d device_index or serial (default: 0)]\\n\"\n\t\t\"\\t[-g gain (default: 0 for auto)]\\n\"\n\t\t\"\\t[-p ppm_error (default: 0)]\\n\"\n\t\t\"%s\"\n\t\t\"\\t[-b output_block_size (default: 16 * 16384)]\\n\"\n\t\t\"\\t[-n number of samples to read (default: 0, infinite)]\\n\"\n\t\t\"\\t[-S force sync output (default: async)]\\n\"\n\t\t\"\\t[-N no dithering (default: use dithering)]\\n\"\n\t\t\"\\t[-H write wave Header to file (default: off)]\\n\"\n\t\t\"\\tfilename (a '-' dumps samples to stdout)\\n\\n\"\n\t\t, rtlsdr_get_opt_help(1) );\n\texit(1);\n}\n\n#ifdef _WIN32\nBOOL WINAPI\nsighandler(int signum)\n{\n\tif (CTRL_C_EVENT == signum) {\n\t\tfprintf(stderr, \"Signal caught, exiting!\\n\");\n\t\tdo_exit = 1;\n\t\trtlsdr_cancel_async(dev);\n\t\treturn TRUE;\n\t}\n\treturn FALSE;\n}\n#else\nstatic void sighandler(int signum)\n{\n\tfprintf(stderr, \"Signal caught, exiting!\\n\");\n\tdo_exit = 1;\n\trtlsdr_cancel_async(dev);\n}\n#endif\n\nstatic void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)\n{\n\tif (ctx) {\n\t\tif (do_exit)\n\t\t\treturn;\n\n\t\tif ((iq_frames_to_read) && (iq_frames_to_read < len/2)) {\n\t\t\tlen = 2U * iq_frames_to_read;\n\t\t\tiq_frames_to_read = 0;\n\t\t\tdo_exit = 1;\n\t\t\trtlsdr_cancel_async(dev);\n\t\t}\n\n\t\tif (!waveHdrStarted) {\n\t\t\tsize_t wr = fwrite(buf, 1, len, (FILE*)ctx);\n\t\t\tif ( wr != len) {\n\t\t\t\tfprintf(stderr, \"Short write (wrote %ld of %ld bytes), samples lost, exiting!\\n\"\n\t\t\t\t\t\t, (long)wr, (long)len );\n\t\t\t\trtlsdr_cancel_async(dev);\n\t\t\t}\n\t\t} else {\n\t\t\tif ( waveWriteFrames((FILE*)ctx, buf, len/2, 0) ) {\n\t\t\t\tfprintf(stderr, \"Short write, samples lost, exiting!\\n\");\n\t\t\t\trtlsdr_cancel_async(dev);\n\t\t\t}\n\t\t}\n\n\t\tif (iq_frames_to_read) {\n\t\t\tif (iq_frames_to_read > len/2)\n\t\t\t\tiq_frames_to_read -= len/2;\n\t\t\telse {\n\t\t\t\tdo_exit = 1;\n\t\t\t\trtlsdr_cancel_async(dev);\n\t\t\t}\n\t\t}\n\t}\n}\n\nint main(int argc, char **argv)\n{\n#ifndef _WIN32\n\tstruct sigaction sigact;\n#endif\n\tchar *filename = NULL;\n\tchar *tempfilename = NULL;\n\tint n_read;\n\tint r, opt;\n\tint gain = 0;\n\tint ppm_error = 0;\n\tint sync_mode = 0;\n\tint dithering = 1;\n\tFILE *file;\n\tuint8_t *buffer;\n\tconst char * rtlOpts = NULL;\n\tint dev_index = 0;\n\tint dev_given = 0;\n\tint writeWav = 0;\n\tuint64_t frequency = 100000000;\n\tuint32_t bandwidth = DEFAULT_BANDWIDTH;\n\tuint32_t samp_rate = DEFAULT_SAMPLE_RATE;\n\tuint32_t out_block_size = DEFAULT_BUF_LENGTH;\n\tint verbosity = 0;\n\n\twhile ((opt = getopt(argc, argv, \"d:f:g:s:w:b:n:p:O:SNHv\")) != -1) {\n\t\tswitch (opt) {\n\t\tcase 'd':\n\t\t\tdev_index = verbose_device_search(optarg);\n\t\t\tdev_given = 1;\n\t\t\tbreak;\n\t\tcase 'f':\n\t\t\tfrequency = (uint64_t)atofs(optarg);\n\t\t\tbreak;\n\t\tcase 'g':\n\t\t\tgain = (int)(atof(optarg) * 10); /* tenths of a dB */\n\t\t\tbreak;\n\t\tcase 's':\n\t\t\tsamp_rate = (uint32_t)atofs(optarg);\n\t\t\tbreak;\n\t\tcase 'w':\n\t\t\tbandwidth = (uint32_t)atofs(optarg);\n\t\t\tbreak;\n\t\tcase 'p':\n\t\t\tppm_error = atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'O':\n\t\t\trtlOpts = optarg;\n\t\t\tbreak;\n\t\tcase 'b':\n\t\t\tout_block_size = (uint32_t)atof(optarg);\n\t\t\tbreak;\n\t\tcase 'n':\n\t\t\tiq_frames_to_read = (uint32_t)atof(optarg);\n\t\t\tbreak;\n\t\tcase 'S':\n\t\t\tsync_mode = 1;\n\t\t\tbreak;\n\t\tcase 'N':\n\t\t\tdithering = 0;\n\t\t\tbreak;\n\t\tcase 'H':\n\t\t\twriteWav = 1;\n\t\t\tbreak;\n\t\tcase 'v':\n\t\t\t++verbosity;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tusage();\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (argc <= optind) {\n\t\tusage();\n\t} else {\n\t\tfilename = argv[optind];\n\t}\n\n\tif(out_block_size < MINIMAL_BUF_LENGTH ||\n\t   out_block_size > MAXIMAL_BUF_LENGTH ){\n\t\tfprintf(stderr,\n\t\t\t\"Output block size wrong value, falling back to default\\n\");\n\t\tfprintf(stderr,\n\t\t\t\"Minimal length: %u\\n\", MINIMAL_BUF_LENGTH);\n\t\tfprintf(stderr,\n\t\t\t\"Maximal length: %u\\n\", MAXIMAL_BUF_LENGTH);\n\t\tout_block_size = DEFAULT_BUF_LENGTH;\n\t}\n\n\tbuffer = malloc(out_block_size * sizeof(uint8_t));\n\n\tif (!dev_given) {\n\t\tdev_index = verbose_device_search(\"0\");\n\t}\n\n\tif (dev_index < 0) {\n\t\texit(1);\n\t}\n\n\tr = rtlsdr_open(&dev, (uint32_t)dev_index);\n\tif (r < 0) {\n\t\tfprintf(stderr, \"Failed to open rtlsdr device #%d.\\n\", dev_index);\n\t\texit(1);\n\t}\n#ifndef _WIN32\n\tsigact.sa_handler = sighandler;\n\tsigemptyset(&sigact.sa_mask);\n\tsigact.sa_flags = 0;\n\tsigaction(SIGINT, &sigact, NULL);\n\tsigaction(SIGTERM, &sigact, NULL);\n\tsigaction(SIGQUIT, &sigact, NULL);\n\tsigaction(SIGPIPE, &sigact, NULL);\n#else\n\tSetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE );\n#endif\n\n\tif (!dithering) {\n\t\tfprintf(stderr, \"Disabling dithering...  \");\n\t\tr = rtlsdr_set_dithering(dev, dithering);\n\t\tif (r) {\n\t\t\tfprintf(stderr, \"failure\\n\");\n\t\t} else {\n\t\t\tfprintf(stderr, \"success\\n\");\n\t\t}\n\t}\n\n\t/* Set the sample rate */\n\tverbose_set_sample_rate(dev, samp_rate);\n\n\t/* Set the tuner bandwidth */\n\tverbose_set_bandwidth(dev, bandwidth);\n\n\t/* Set the frequency */\n\tverbose_set_frequency(dev, frequency);\n\n\tif (0 == gain) {\n\t\t /* Enable automatic gain */\n\t\tverbose_auto_gain(dev);\n\t} else {\n\t\t/* Enable manual gain */\n\t\tgain = nearest_gain(dev, gain);\n\t\tverbose_gain_set(dev, gain);\n\t}\n\n\tif (rtlOpts) {\n\t\trtlsdr_set_opt_string(dev, rtlOpts, verbosity);\n\t}\n\n\tverbose_ppm_set(dev, ppm_error);\n\n\tif(strcmp(filename, \"-\") == 0) { /* Write samples to stdout */\n\t\tfile = stdout;\n#ifdef _WIN32\n\t\t_setmode(_fileno(stdout), _O_BINARY);\n#endif\n\t} else {\n\t\tconst char * filename_to_open = filename;\n\t\tif (writeWav) {\n\t\t\ttempfilename = malloc( strlen(filename)+8 );\n\t\t\tstrcpy(tempfilename, filename);\n\t\t\tstrcat(tempfilename, \".tmp\");\n\t\t\tfilename_to_open = tempfilename;\n\t\t}\n\t\tfile = fopen(filename_to_open, \"wb\");\n\t\tif (!file) {\n\t\t\tfprintf(stderr, \"Failed to open %s\\n\", filename_to_open);\n\t\t\tgoto out;\n\t\t}\n\t\tif (writeWav) {\n\t\t\twaveWriteHeader(samp_rate, frequency, 8, 2, file);\n\t\t}\n\t}\n\n\t/* Reset endpoint before we start reading from it (mandatory) */\n\tverbose_reset_buffer(dev);\n\n\tif (sync_mode) {\n\t\tfprintf(stderr, \"Reading samples in sync mode...\\n\");\n\t\twhile (!do_exit) {\n\t\t\tr = rtlsdr_read_sync(dev, buffer, out_block_size, &n_read);\n\t\t\tif (r < 0) {\n\t\t\t\tfprintf(stderr, \"WARNING: sync read failed.\\n\");\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif ((iq_frames_to_read) && (iq_frames_to_read < ((uint32_t)n_read /2))) {\n\t\t\t\tn_read = 2U * iq_frames_to_read;\n\t\t\t\tdo_exit = 1;\n\t\t\t}\n\n\t\t\tif (!waveHdrStarted) {\n\t\t\t\tsize_t wr = fwrite(buffer, 1, n_read, file);\n\t\t\t\tif (wr != (size_t)n_read) {\n\t\t\t\t\tfprintf(stderr, \"Short write (wrote %ld of %ld bytes), samples lost, exiting!\\n\"\n\t\t\t\t\t\t\t, (long)wr, (long)n_read );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif ( waveWriteSamples(file, buffer, n_read/2, 0) ) {\n\t\t\t\t\tfprintf(stderr, \"Short write, samples lost, exiting!\\n\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ((uint32_t)n_read < out_block_size) {\n\t\t\t\tfprintf(stderr, \"Short read, samples lost, exiting!\\n\");\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (iq_frames_to_read) {\n\t\t\t\tif (iq_frames_to_read > ((uint32_t)n_read /2))\n\t\t\t\t\tiq_frames_to_read -= n_read/2;\n\t\t\t\telse\n\t\t\t\t\tdo_exit = 1;\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfprintf(stderr, \"Reading samples in async mode...\\n\");\n\t\tr = rtlsdr_read_async(dev, rtlsdr_callback, (void *)file,\n\t\t\t\t      0, out_block_size);\n\t}\n\n\tif (file != stdout) {\n\t\tif (writeWav) {\n\t\t\twaveFinalizeHeader(file);\n\t\t\tfclose(file);\n\t\t\tremove(filename);\t/* delete, in case file already exists */\n\t\t\tr = rename( tempfilename, filename );\t/* #include <stdio.h> */\n\t\t\tif ( r )\n\t\t\t\tfprintf( stderr, \"%s: error %d '%s' renaming'%s' to '%s'\\n\"\n\t\t\t\t\t, argv[0], errno, strerror(errno), tempfilename, filename );\n\t\t} else {\n\t\t\tfclose(file);\n\t\t}\n\n\t}\n\n\tif (do_exit)\n\t\tfprintf(stderr, \"\\nUser cancel, exiting...\\n\");\n\telse\n\t\tfprintf(stderr, \"\\nLibrary error %d, exiting...\\n\", r);\n\n\trtlsdr_close(dev);\n\tfree (buffer);\nout:\n\treturn r >= 0 ? r : -r;\n}\n"
  },
  {
    "path": "src/rtl_tcp.c",
    "content": "/*\n * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver\n * Copyright (C) 2012 by Steve Markgraf <steve@steve-m.de>\n * Copyright (C) 2012-2013 by Hoernchen <la@tfc-server.de>\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <errno.h>\n#include <signal.h>\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#ifndef _WIN32\n#include <unistd.h>\n#include <arpa/inet.h>\n#include <sys/socket.h>\n#include <sys/types.h>\n#include <sys/time.h>\n#include <netinet/in.h>\n#include <fcntl.h>\n#else\n#include <winsock2.h>\n#include \"getopt/getopt.h\"\n#define usleep(x) Sleep(x/1000)\n#endif\n\n#ifdef NEED_PTHREADS_WORKARROUND\n#define HAVE_STRUCT_TIMESPEC\n#endif\n#include <pthread.h>\n\n#include <rtl-sdr.h>\n#include <rtl_app_ver.h>\n#include <rtl_tcp.h>\n#include \"convenience/convenience.h\"\n#include \"convenience/rtl_convenience.h\"\n\n#ifdef _WIN32\n#pragma comment(lib, \"ws2_32.lib\")\n\ntypedef int socklen_t;\n\n#else\n#define closesocket close\n#define SOCKADDR struct sockaddr\n#define SOCKET int\n#define SOCKET_ERROR -1\n#endif\n\n#include \"controlThread.h\"\n\nstatic ctrl_thread_data_t ctrldata;\n\nstatic SOCKET s;\n\nstatic pthread_t tcp_worker_thread;\nstatic pthread_t command_thread;\nstatic pthread_cond_t exit_cond;\nstatic pthread_mutex_t exit_cond_lock;\n\nstatic pthread_mutex_t ll_mutex;\nstatic pthread_cond_t cond;\n\nstruct llist {\n\tchar *data;\n\tsize_t len;\n\tstruct llist *next;\n};\n\ntypedef struct { /* structure size must be multiple of 2 bytes */\n\tchar magic[4];\n\tuint32_t tuner_type;\n\tuint32_t tuner_gain_count;\n} dongle_info_t;\n\nstatic rtlsdr_dev_t *dev = NULL;\n\nstatic int verbosity = 0;\nstatic uint32_t bandwidth = 0;\n\nstatic int enable_biastee = 0;\nstatic int global_numq = 0;\nstatic struct llist *ll_buffers = 0;\nstatic int llbuf_num = 500;\n\nstatic volatile int do_exit = 0;\n\nvoid usage(void)\n{\n\tfprintf(stderr,\n\t\t\"rtl_tcp, an I/Q spectrum server for RTL2832 based SDR-receivers\\n\"\n\t\t\"rtl_tcp version %d.%d %s (%s)\\n\"\n\t\t\"rtl-sdr library %d.%d %s\\n\\n\",\n\t\tAPP_VER_MAJOR, APP_VER_MINOR, APP_VER_ID, __DATE__,\n\t\trtlsdr_get_version() >>16, rtlsdr_get_version() & 0xFFFF,\n\t\trtlsdr_get_ver_id() );\n\tfprintf(stderr, \"Usage:\\trtl_tcp [-a listen address]\\n\"\n\t\t\"\\t[-p control listen port (default: 1234)]\\n\"\n\t\t\"\\t[-r response listen port: 0 = off; 1 (=default) for On at control listen port +1; or port]\\n\"\n\t\t\"\\t[-I infrared sensor listen port (default: 0=none)]\\n\"\n\t\t\"\\t[-W infrared sensor query wait interval usec (default: 10000)]\\n\"\n\t\t\"\\t[-f frequency to tune to [Hz]]\\n\"\n\t\t\"\\t[-g gain in dB (default: 0 for auto)]\\n\"\n\t\t\"\\t[-s samplerate in Hz (default: 2048000 Hz)]\\n\"\n\t\t\"\\t[-b number of buffers (default: 15, set by library)]\\n\"\n\t\t\"\\t[-l length of single buffer in units of 512 samples (default: 32 was 256)]\\n\"\n\t\t\"\\t[-n max number of linked list buffers to keep (default: 500)]\\n\"\n\t\t\"\\t[-w rtlsdr tuner bandwidth [Hz] (for R820T/2 and E4000 tuners)]\\n\"\n\t\t\"\\t[-d device index or serial (default: 0)]\\n\"\n\t\t\"\\t[-P ppm_error (default: 0)]\\n\"\n\t\t\"%s\"\n\t\t\"\\t[-T enable bias-T on GPIO PIN 0 (works for rtl-sdr.com v3 dongles)]\\n\"\n\n\t\t\"\\t[-D direct_sampling_mode (default: 0, 1 = I, 2 = Q, 3 = I below threshold, 4 = Q below threshold)]\\n\"\n\t\t\"\\t[-D direct_sampling_threshold_frequency (default: 0 use tuner specific frequency threshold for 3 and 4)]\\n\"\n\t\t\"\\t[-v increase verbosity (default: 0)]\\n\"\n\t\t, rtlsdr_get_opt_help(1) );\n\texit(1);\n}\n\n#ifdef _WIN32\nint gettimeofday(struct timeval *tv, void* ignored)\n{\n\tFILETIME ft;\n\tunsigned __int64 tmp = 0;\n\tif (NULL != tv) {\n\t\tGetSystemTimeAsFileTime(&ft);\n\t\ttmp |= ft.dwHighDateTime;\n\t\ttmp <<= 32;\n\t\ttmp |= ft.dwLowDateTime;\n\t\ttmp /= 10;\n#ifdef _MSC_VER\n\t\ttmp -= 11644473600000000Ui64;\n#else\n\t\ttmp -= 11644473600000000ULL;\n#endif\n\t\ttv->tv_sec = (long)(tmp / 1000000UL);\n\t\ttv->tv_usec = (long)(tmp % 1000000UL);\n\t}\n\treturn 0;\n}\n\nBOOL WINAPI\nsighandler(int signum)\n{\n\tif (CTRL_C_EVENT == signum) {\n\t\tfprintf(stderr, \"Signal caught, exiting!\\n\");\n\t\tdo_exit = 1;\n\t\trtlsdr_cancel_async(dev);\n\t\treturn TRUE;\n\t}\n\treturn FALSE;\n}\n#else\nstatic void sighandler(int signum)\n{\n\tfprintf(stderr, \"Signal caught, exiting!\\n\");\n\trtlsdr_cancel_async(dev);\n\tdo_exit = 1;\n}\n#endif\n\nvoid rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)\n{\n\tif(!do_exit) {\n\t\tstruct llist *rpt = (struct llist*)malloc(sizeof(struct llist));\n\t\trpt->data = (char*)malloc(len);\n\t\tmemcpy(rpt->data, buf, len);\n\t\trpt->len = len;\n\t\trpt->next = NULL;\n\n\t\tpthread_mutex_lock(&ll_mutex);\n\n\t\tif (ll_buffers == NULL) {\n\t\t\tll_buffers = rpt;\n\t\t} else {\n\t\t\tstruct llist *cur = ll_buffers;\n\t\t\tint num_queued = 0;\n\n\t\t\twhile (cur->next != NULL) {\n\t\t\t\tcur = cur->next;\n\t\t\t\tnum_queued++;\n\t\t\t}\n\n\t\t\tif(llbuf_num && llbuf_num == num_queued-2){\n\t\t\t\tstruct llist *curelem;\n\n\t\t\t\tfree(ll_buffers->data);\n\t\t\t\tcurelem = ll_buffers->next;\n\t\t\t\tfree(ll_buffers);\n\t\t\t\tll_buffers = curelem;\n\t\t\t}\n\n\t\t\tcur->next = rpt;\n\n\t\t\tif ( verbosity )\n\t\t\t{\n\t\t\t\tif (num_queued > global_numq)\n\t\t\t\t\tprintf(\"ll+, now %d\\n\", num_queued);\n\t\t\t\telse if (num_queued < global_numq)\n\t\t\t\t\tprintf(\"ll-, now %d\\n\", num_queued);\n\t\t\t}\n\n\t\t\tglobal_numq = num_queued;\n\t\t}\n\t\tpthread_cond_signal(&cond);\n\t\tpthread_mutex_unlock(&ll_mutex);\n\t}\n}\n\nstatic void *tcp_worker(void *arg)\n{\n\tstruct llist *curelem,*prev;\n\tint bytesleft,bytessent, index;\n\tstruct timeval tv= {1,0};\n\tstruct timespec ts;\n\tstruct timeval tp;\n\tfd_set writefds;\n\tint r = 0;\n\n\twhile(1) {\n\t\tif(do_exit)\n\t\t\tpthread_exit(0);\n\n\t\tpthread_mutex_lock(&ll_mutex);\n\t\tgettimeofday(&tp, NULL);\n\t\tts.tv_sec  = tp.tv_sec+1;\n\t\tts.tv_nsec = tp.tv_usec * 1000;\n\t\tr = pthread_cond_timedwait(&cond, &ll_mutex, &ts);\n\t\tif(r == ETIMEDOUT) {\n\t\t\tpthread_mutex_unlock(&ll_mutex);\n\t\t\tprintf(\"worker cond timeout\\n\");\n\t\t\tsighandler(0);\n\t\t\tpthread_exit(NULL);\n\t\t}\n\n\t\tcurelem = ll_buffers;\n\t\tll_buffers = 0;\n\t\tpthread_mutex_unlock(&ll_mutex);\n\n\t\twhile(curelem != 0) {\n\t\t\tbytesleft = curelem->len;\n\t\t\tindex = 0;\n\t\t\tbytessent = 0;\n\t\t\twhile(bytesleft > 0) {\n\t\t\t\tFD_ZERO(&writefds);\n\t\t\t\tFD_SET(s, &writefds);\n\t\t\t\ttv.tv_sec = 1;\n\t\t\t\ttv.tv_usec = 0;\n\t\t\t\tr = select(s+1, NULL, &writefds, NULL, &tv);\n\t\t\t\tif(r) {\n\t\t\t\t\tbytessent = send(s,  &curelem->data[index], bytesleft, 0);\n\t\t\t\t\tbytesleft -= bytessent;\n\t\t\t\t\tindex += bytessent;\n\t\t\t\t}\n\t\t\t\tif(bytessent == SOCKET_ERROR || do_exit) {\n\t\t\t\t\t\tprintf(\"worker socket bye\\n\");\n\t\t\t\t\t\tsighandler(0);\n\t\t\t\t\t\tpthread_exit(NULL);\n\t\t\t\t}\n\t\t\t}\n\t\t\tprev = curelem;\n\t\t\tcurelem = curelem->next;\n\t\t\tfree(prev->data);\n\t\t\tfree(prev);\n\t\t}\n\t}\n}\n\nstatic int set_gain_by_index(rtlsdr_dev_t *_dev, unsigned int index)\n{\n\tint res = 0;\n\tint* gains;\n\tint count = rtlsdr_get_tuner_gains(_dev, NULL);\n\n\tif (count > 0 && index < (unsigned int)count) {\n\t\tgains = malloc(sizeof(int) * count);\n\t\tcount = rtlsdr_get_tuner_gains(_dev, gains);\n\n\t\tif (verbosity)\n\t\t\tprintf(\"set tuner gain to %.1f dB\\n\", gains[index] / 10.0);\n\t\tres = rtlsdr_set_tuner_gain(_dev, gains[index]);\n\t\tif (res < 0)\n\t\tprintf(\"  setting tuner gain index failed\\n\");\n\n\t\tfree(gains);\n\t}\n\telse\n\t{\n\t\tprintf(\"set tuner gain index to %u\\n\", index);\n\t\tprintf(\"  error setting tuner gain index failed: valid range: 0 .. %d\\n\", count-1);\n\t}\n\n\treturn res;\n}\n\nstatic void check_tuner_pll(rtlsdr_dev_t *dev, int *tuner_unsupported, int *last_lock_report)\n{\n\tint r = rtlsdr_is_tuner_PLL_locked(dev);\n\t/* printf(\"performed lock check:\\n\"); */\n\tif (r == 1) {\n\t\tif (*last_lock_report != r)\n\t\t\tprintf(\"tuner PLL is unlocked!\\n\");\n\t\t*last_lock_report = r;\n\t}\n\telse if (r == 0) {\n\t\tif (*last_lock_report != r)\n\t\t\tprintf(\"tuner PLL is locked.\\n\");\n\t\t*last_lock_report = r;\n\t}\n\telse if (r == -2) {\n\t\tprintf(\"error at PLL-locked check: tuner not supported! No further tests.\\n\");\n\t\t*tuner_unsupported = 1;\n\t}\n\telse if (r < 0)\n\t\tprintf(\"error checking tuner PLL!\\n\");\n\telse\n\t\tprintf(\"unknown error at tuner PLL check!\\n\");\n\tfflush(stdout);\n}\n\n\n\n\n#ifdef _WIN32\n#define __attribute__(x)\n#pragma pack(push, 1)\n#endif\nstruct command{\n\tunsigned char cmd;\n\tunsigned int param;\n}__attribute__((packed));\n#ifdef _WIN32\n#pragma pack(pop)\n#endif\nstatic void *command_worker(void *arg)\n{\n\tint left, received = 0;\n\tfd_set readfds;\n\tstruct command cmd={0, 0};\n\tstruct timeval tv= {1, 0};\n\tunsigned tuner_check_timeout = 0;\n\tint last_lock_report = -1;\n\tint tuner_unsupported = 0;\n\tint r = 0;\n\tuint32_t freqhi = 0;\n\tuint64_t tmp64;\n\tuint32_t tmp;\n\tint32_t itmp;\n\tint32_t if_band_center_freq;\n\tint iitmp;\n\n\twhile(1) {\n\t\tleft=sizeof(cmd);\n\t\twhile(left >0) {\n\t\t\tFD_ZERO(&readfds);\n\t\t\tFD_SET(s, &readfds);\n\t\t\ttv.tv_sec = 1;\n\t\t\ttv.tv_usec = 0;\n\t\t\tr = select(s+1, &readfds, NULL, NULL, &tv);\n\t\t\tif(r) {\n\t\t\t\treceived = recv(s, (char*)&cmd+(sizeof(cmd)-left), left, 0);\n\t\t\t\tleft -= received;\n\t\t\t\t/* printf(\"received %d bytes\\n\", received); */\n\t\t\t}\n\t\t\telse if (!tuner_unsupported)\n\t\t\t{\n\t\t\t\t/* timeout: nothing happend */\n\t\t\t\t++tuner_check_timeout;\n\t\t\t\tif (tuner_check_timeout >= 3)\n\t\t\t\t{\n\t\t\t\t\t/* automatic check every 3 seconds */\n\t\t\t\t\tcheck_tuner_pll(dev, &tuner_unsupported, &last_lock_report);\n\t\t\t\t\ttuner_check_timeout = 0;\n\t\t\t\t}\n\t\t\t\tfflush(stdout);\n\t\t\t}\n\t\t\tif(received == SOCKET_ERROR || do_exit) {\n\t\t\t\tprintf(\"comm recv bye\\n\");\n\t\t\t\tsighandler(0);\n\t\t\t\tpthread_exit(NULL);\n\t\t\t}\n\t\t}\n\t\tswitch(cmd.cmd) {\n\t\tcase SET_FREQUENCY:\n\t\t\ttmp = ntohl(cmd.param);\n\t\t\tif (!freqhi)\n\t\t\t{\n\t\t\t\tprintf(\"set freq %f MHz\\n\", tmp * 1E-6);\n\t\t\t\tr = rtlsdr_set_center_freq(dev, tmp);\n\t\t\t\tif (r < 0) {\n\t\t\t\t\tprintf(\"  error setting frequency!\\n\");\n\t\t\t\t\tlast_lock_report = -1;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmp64 = ( ((uint64_t)freqhi) << 32 ) | (uint64_t)tmp;\n\t\t\t\tprintf(\"set freq64 %f MHz\\n\", tmp64 * 1E-6);\n\t\t\t\tr = rtlsdr_set_center_freq64(dev, tmp64);\n\t\t\t\tif (r < 0) {\n\t\t\t\t\tprintf(\"  error setting frequency!\\n\");\n\t\t\t\t\tlast_lock_report = -1;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfreqhi = 0;\n\t\t\tbreak;\n\t\tcase SET_FREQ_HI32:\n\t\t\tfreqhi = ntohl(cmd.param);\n\t\t\tbreak;\n\t\tcase SET_SAMPLE_RATE:\n\t\t\ttmp = ntohl(cmd.param);\n\t\t\tprintf(\"set sample rate %u\\n\", tmp);\n\t\t\tr = rtlsdr_set_sample_rate(dev, tmp);\n\t\t\tif (r < 0)\n\t\t\t\tprintf(\"  error setting sample rate! sample rate is %u\\n\", rtlsdr_get_sample_rate(dev));\n\t\t\tbreak;\n\t\tcase SET_GAIN_MODE:\n\t\t\ttmp = ntohl(cmd.param);\n\t\t\tprintf(\"set gain mode %u (=%s)\\n\", tmp, tmp?\"manual\":\"automatic\");\n\t\t\tr = rtlsdr_set_tuner_gain_mode(dev, tmp);\n\t\t\tif (r < 0)\n\t\t\t\tprintf(\"  error setting gain mode!\\n\");\n\t\t\tbreak;\n\t\tcase SET_GAIN:\n\t\t\ttmp = ntohl(cmd.param);\n\t\t\tprintf(\"set manual tuner gain %.1f dB\\n\", tmp/10.0);\n\t\t\tr = rtlsdr_set_tuner_gain(dev, tmp);\n\t\t\tif (r < 0)\n\t\t\t\tprintf(\"  error setting tuner gain!\\n\");\n\t\t\tbreak;\n\t\tcase SET_FREQUENCY_CORRECTION:\n\t\t\titmp = ntohl(cmd.param);\n\t\t\tprintf(\"set freq correction %d ppm\\n\", itmp);\n\t\t\tr = rtlsdr_set_freq_correction(dev, itmp);\n\t\t\tif (r < 0) {\n\t\t\t\tprintf(\"  error setting frequency correction!\\n\");\n\t\t\t\tlast_lock_report = -1;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase SET_IF_STAGE:\n\t\t\ttmp = ntohl(cmd.param);\n\t\t\tprintf(\"set if stage %d gain %.1f dB\\n\", tmp >> 16, ((short)(tmp & 0xffff))/10.0);\n\t\t\tr = rtlsdr_set_tuner_if_gain(dev, tmp >> 16, (short)(tmp & 0xffff));\n\t\t\tif (r < 0)\n\t\t\t\tprintf(\"  error setting gain for stage!\\n\");\n\t\t\tbreak;\n\t\tcase SET_TEST_MODE:\n\t\t\ttmp = ntohl(cmd.param);\n\t\t\tprintf(\"set test mode %d (=%s)\\n\", tmp, tmp?\"active\":\"inactive\");\n\t\t\tr = rtlsdr_set_testmode(dev, tmp);\n\t\t\tif (r < 0)\n\t\t\t\tprintf(\"  error setting test mode!\\n\");\n\t\t\tbreak;\n\t\tcase SET_AGC_MODE:\n\t\t\ttmp = ntohl(cmd.param);\n\t\t\tprintf(\"set rtl2832's digital agc mode %d (=%s)\\n\", tmp, tmp?\"enabled\":\"disabled\");\n\t\t\tr = rtlsdr_set_agc_mode(dev, tmp);\n\t\t\tif (r < 0)\n\t\t\t\tprintf(\"  error setting digital agc mode!\\n\");\n\t\t\tbreak;\n\t\tcase SET_DIRECT_SAMPLING:\n\t\t\ttmp = ntohl(cmd.param);\n\t\t\tprintf(\"set direct sampling %u (=%s)\\n\", tmp, (!tmp) ? \"disabled\": (tmp==1)?\"pin I-ADC\": (tmp==2)? \"pin Q-ADC\":\"unknown!\");\n\t\t\tr = rtlsdr_set_direct_sampling(dev, tmp);\n\t\t\tif (r < 0)\n\t\t\t\tprintf(\"  error setting direct sampling!\\n\");\n\t\t\tbreak;\n\t\tcase SET_OFFSET_TUNING:\n\t\t\titmp = ntohl(cmd.param);\n\t\t\tprintf(\"set offset tuning %d\\n\", itmp);\n\t\t\tr = rtlsdr_set_offset_tuning(dev, itmp);\n\t\t\tif (r < 0) {\n\t\t\t\tprintf(\"  error setting offset tuning!\\n\");\n\t\t\t\tlast_lock_report = -1;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase SET_RTL_CRYSTAL:\n\t\t\tprintf(\"set rtl xtal frequency %d\\n\", ntohl(cmd.param));\n\t\t\tr = rtlsdr_set_xtal_freq(dev, ntohl(cmd.param), 0);\n\t\t\tif (r < 0)\n\t\t\t\tprintf(\"  error setting rtl xtal frequency!\\n\");\n\t\t\tbreak;\n\t\tcase SET_TUNER_CRYSTAL:\n\t\t\tprintf(\"set tuner xtal %d\\n\", ntohl(cmd.param));\n\t\t\tr = rtlsdr_set_xtal_freq(dev, 0, ntohl(cmd.param));\n\t\t\tif (r < 0)\n\t\t\t\tprintf(\"  error setting tuner xtal frequency!\\n\");\n\t\t\tbreak;\n\t\tcase SET_TUNER_GAIN_BY_INDEX:\n\t\t\ttmp = ntohl(cmd.param);\n\t\t\tprintf(\"set tuner gain by index %u\\n\", tmp);\n\t\t\tset_gain_by_index(dev, tmp);\n\t\t\tbreak;\n\t\tcase SET_BIAS_TEE:\n\t\t\ttmp = ntohl(cmd.param);\n\t\t\tprintf(\"set bias T %u (%s)\\n\", tmp, tmp?\"on\":\"off\");\n\t\t\tr = rtlsdr_set_bias_tee(dev, tmp);\n\t\t\tif (r < 0)\n\t\t\t\tprintf(\"  error setting bias tee!\\n\");\n\t\t\tbreak;\n\t\tcase SET_TUNER_BANDWIDTH:\n\t\t\tbandwidth = ntohl(cmd.param);\n\t\t\tprintf(\"set tuner bandwidth to %i Hz\\n\", bandwidth);\n\t\t\tverbose_set_bandwidth(dev, bandwidth);\n\t\t\tbreak;\n\t\tcase SET_I2C_TUNER_REGISTER:\n\t\t\ttmp = ntohl(cmd.param);\n\t\t\tprintf(\"set i2c register x%03X to x%03X with mask x%02X\\n\", (tmp >> 20) & 0xfff, tmp & 0xfff, (tmp >> 12) & 0xff );\n\t\t\tr = rtlsdr_set_tuner_i2c_register(dev, (tmp >> 20) & 0xfff, (tmp >> 12) & 0xff, tmp & 0xfff);\n\t\t\tif (r < 0)\n\t\t\t\tprintf(\"  error setting i2c register!\\n\");\n\t\t\tbreak;\n\t\tcase SET_I2C_TUNER_OVERRIDE:\n\t\t\ttmp = ntohl(cmd.param);\n\t\t\tprintf(\"set i2c override register x%03X to x%03X with mask x%02X\\n\", (tmp >> 20) & 0xfff, tmp & 0xfff, (tmp >> 12) & 0xff );\n\t\t\tr = rtlsdr_set_tuner_i2c_override(dev, (tmp >> 20) & 0xfff, (tmp >> 12) & 0xff, tmp & 0xfff);\n\t\t\tif (r < 0)\n\t\t\t\tprintf(\"  error setting i2c register!\\n\");\n\t\t\tbreak;\n\t\tcase UDP_TERMINATE:\n\t\t\tprintf(\"comm recv bye\\n\");\n\t\t\tsighandler(0);\n\t\t\tpthread_exit(NULL);\n\t\t\tbreak;\n\t\tcase SET_TUNER_BW_IF_CENTER:\n\t\t\tif_band_center_freq = ntohl(cmd.param);\n\t\t\tprintf(\"set tuner band to IF frequency %i Hz from center\\n\", if_band_center_freq);\n\t\t\tr = rtlsdr_set_tuner_band_center(dev, if_band_center_freq );\n\t\t\tif (r < 0)\n\t\t\t\tprintf(\"  error setting tuner band's IF center frequency!\\n\");\n\t\t\tbreak;\n\t\tcase SET_TUNER_IF_MODE:\n\t\t\titmp = ntohl(cmd.param);\n\t\t\tprintf(\"set tuner IF mode to %i: \", itmp);\n\t\t\tif (!itmp)\n\t\t\t\tprintf(\"automatic gain of VGA controlled from RTL2832\\n\");\n\t\t\telse if (-2500 <= itmp && itmp <= 2500)\n\t\t\t\tprintf(\"VGA nearest to %.1f dB)\\n\", itmp/10.0);\n\t\t\telse if (10000 <=itmp && itmp <= 10015)\n\t\t\t\tprintf(\"VGA gain idx %d\\n\", itmp - 10000);\n\t\t\telse if (10016 <= itmp && itmp <= 10031)\n\t\t\t\tprintf(\"VGA gain idx %d - but with automatic gain of VGA controlled from RTL2832\\n\", itmp-10016);\n\t\t\telse\n\t\t\t\tprintf(\"unknown!\\n\");\n\t\t\tr = rtlsdr_set_tuner_if_mode(dev, itmp);\n\t\t\tif (r < 0)\n\t\t\t\tprintf(\"  error setting tuner IF mode!\\n\");\n\t\t\tbreak;\n\t\tcase SET_SIDEBAND:\n\t\t\ttmp = ntohl(cmd.param);\n\t\t\tif(tmp)\n\t\t\t\ttmp = 1;\n\t\t\tprintf(\"set tuner sideband %d: %s sideband\\n\", tmp, (tmp ? \"upper\" : \"lower\") );\n\t\t\tr = rtlsdr_set_tuner_sideband(dev, tmp);\n\t\t\tif (r < 0) {\n\t\t\t\tprintf(\"  error setting tuner sideband!\\n\");\n\t\t\t\tlast_lock_report = -1;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase REPORT_I2C_REGS:\n\t\t\ttmp = ntohl(cmd.param);\n\t\t\tif(tmp)\n\t\t\t\ttmp = 1;\n\t\t\tctrldata.report_i2c = tmp;  /* (de)activate reporting */\n\t\t\tbreak;\n\t\tcase GPIO_SET_OUTPUT_MODE:\t/* rtlsdr_set_gpio_output() */\n\t\t\titmp = ntohl(cmd.param);\n\t\t\tif ( 0 <= itmp && itmp < 8 )\n\t\t\t{\n\t\t\t\tprintf(\"set gpio pin %d to output\\n\", itmp);\n\t\t\t\tr = rtlsdr_set_gpio_output(dev, (uint8_t)itmp);\n\t\t\t\tif (r < 0)\n\t\t\t\t\tprintf(\"  error setting gpio pin to output mode!\\n\");\n\t\t\t}\n\t\t\telse\n\t\t\t\tprintf(\"set gpio pin %d to output: error: pin has to be in 0 .. 7\\n\", itmp);\n\t\t\tbreak;\n\t\tcase GPIO_SET_INPUT_MODE:\t/* rtlsdr_set_gpio_input() */\n\t\t\titmp = ntohl(cmd.param);\n\t\t\tif ( 0 <= itmp && itmp < 8 )\n\t\t\t{\n\t\t\t\tprintf(\"set gpio pin %d to input\\n\", itmp);\n\t\t\t\tr = rtlsdr_set_gpio_input(dev, (uint8_t)itmp);\n\t\t\t\tif (r < 0)\n\t\t\t\t\tprintf(\"  error setting gpio pin to input mode!\\n\");\n\t\t\t}\n\t\t\telse\n\t\t\t\tprintf(\"set gpio pin %d to input: error: pin has to be in 0 .. 7\\n\", itmp);\n\t\t\tbreak;\n\t\tcase GPIO_GET_IO_STATUS:\t/* rtlsdr_set_gpio_status() */\n\t\t\tr = rtlsdr_set_gpio_status(dev, &iitmp );\n\t\t\tif (r < 0)\n\t\t\t\tprintf(\"error at requesting gpio io status!\\n\");\n\t\t\telse\n\t\t\t\tprintf(\"request for gpio io status: 0x%02x = %d%d%d%d %d%d%d%d for bits 7 .. 0\\n\",\n\t\t\t\t\tiitmp & 0xff,\n\t\t\t\t\t(iitmp >>7) & 1, (iitmp >>6) & 1, (iitmp >>5) & 1, (iitmp >>4) & 1,\n\t\t\t\t\t(iitmp >>3) & 1, (iitmp >>2) & 1, (iitmp >>1) & 1, iitmp & 1 );\n\t\t\tbreak;\n\t\tcase GPIO_WRITE_PIN:\t\t/* rtlsdr_set_gpio_bit() */\n\t\t\titmp = ntohl(cmd.param);\n\t\t\tif ( 0 <= ((itmp >> 16) & 0xffff) && ((itmp >> 16) & 0xffff) < 8 )\n\t\t\t{\n\t\t\t\tprintf(\"write %d to gpio %d\\n\", itmp & 0xffff, (itmp >> 16) & 0xffff);\n\t\t\t\trtlsdr_set_gpio_output(dev, (uint8_t)((itmp >> 16) & 0xffff));\n\t\t\t\trtlsdr_set_gpio_bit(dev, (uint8_t)((itmp >> 16) & 0xffff), itmp & 0xffff);\n\t\t\t}\n\t\t\telse\n\t\t\t\tprintf(\"write %d to gpio %d: error: pin has to be in 0 .. 7\\n\", itmp & 0xffff, (itmp >> 16) & 0xffff);\n\t\t\tbreak;\n\t\tcase GPIO_READ_PIN:\n\t\t\titmp = ntohl(cmd.param);\n\t\t\tif ( 0 <= itmp && itmp < 8 )\n\t\t\t{\n\t\t\t\tr = rtlsdr_get_gpio_bit(dev, itmp, &iitmp);\n\t\t\t\tif (r < 0)\n\t\t\t\t\tprintf(\"  error reading gpio pin!\\n\");\n\t\t\t\telse\n\t\t\t\t\tprintf(\"read gpio pin %d: %d\\n\", itmp, iitmp);\n\t\t\t}\n\t\t\telse\n\t\t\t\tprintf(\"read gpio pin %d out of range: pin has to be in 0 .. 7\\n\", itmp);\n\t\t\tbreak;\n\t\tcase GPIO_GET_BYTE:\n\t\t\tr = rtlsdr_get_gpio_byte(dev, &iitmp);\n\t\t\tif (r < 0)\n\t\t\t\tprintf(\"error reading gpio byte!\\n\");\n\t\t\telse\n\t\t\t\tprintf(\"read gpio byte: 0x%02x = %d%d%d%d %d%d%d%d for bits 7 .. 0\\n\",\n\t\t\t\t\tiitmp & 0xff,\n\t\t\t\t\t(iitmp >>7) & 1, (iitmp >>6) & 1, (iitmp >>5) & 1, (iitmp >>4) & 1,\n\t\t\t\t\t(iitmp >>3) & 1, (iitmp >>2) & 1, (iitmp >>1) & 1, iitmp & 1 );\n\t\t\tbreak;\n\t\tcase IS_TUNER_PLL_LOCKED:\n\t\t\titmp = -1; /* always print lock status */\n\t\t\tcheck_tuner_pll(dev, &tuner_unsupported, &itmp);\n\t\t\tif (itmp != -1)\n\t\t\t\tlast_lock_report = itmp;\n\t\t\ttuner_check_timeout = 0;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tprintf(\"unknown command 0x%02x\\n\", cmd.cmd);\n\t\t\tbreak;\n\t\t}\n\t\tcmd.cmd = 0xff;\n\t}\n}\n\nstruct ir_thread_data\n{\n\trtlsdr_dev_t *dev;\n\tint port;\n\tint wait;\n\tchar *addr;\n};\n\nvoid *ir_thread_fn(void *arg)\n{\n\tint r = 1;\n\tstruct linger ling = {1,0};\n\tSOCKET listensocket;\n\tSOCKET irsocket;\n\tstruct sockaddr_in local, remote;\n\tsocklen_t rlen;\n\tuint8_t buf[128];\n\tint ret = 0, len;\n\n\tstruct ir_thread_data *data = (struct ir_thread_data *)arg;\n\n\trtlsdr_dev_t *dev = data->dev;\n\tint port = data->port;\n\tint wait = data->wait;\n\tchar *addr = data->addr;\n\n\n\tmemset(&local,0,sizeof(local));\n\tlocal.sin_family = AF_INET;\n\tlocal.sin_port = htons(port);\n\tlocal.sin_addr.s_addr = inet_addr(addr);\n\n\tlistensocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);\n\tr = 1;\n\tsetsockopt(listensocket, SOL_SOCKET, SO_REUSEADDR, (char *)&r, sizeof(int));\n\tsetsockopt(listensocket, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling));\n\tbind(listensocket,(struct sockaddr *)&local,sizeof(local));\n\n\n\twhile(1) {\n\t\tprintf(\"listening on IR port %d...\\n\", port);\n\t\tlisten(listensocket,1);\n\n\t\tirsocket = accept(listensocket,(struct sockaddr *)&remote, &rlen);\n\t\tsetsockopt(irsocket, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling));\n\n\t\tprintf(\"IR client accepted!\\n\");\n\n\t\twhile(1) {\n\t\t    ret = rtlsdr_ir_query(dev, buf, sizeof(buf));\n\t\t    if (ret < 0) {\n\t\t\tprintf(\"rtlsdr_ir_query error %d\\n\", ret);\n\t\t\tbreak;\n\t\t    }\n\n\t\t    len = ret;\n\n\t\t    ret = send(irsocket, buf, len, 0);\n\t\t    if (ret != len){\n\t\t\tprintf(\"incomplete write to ir client: %d != %d\\n\", ret,len);\n\t\t\tbreak;\n\t\t    }\n\n\t\t    usleep(wait);\n\t\t}\n\n\t\tclosesocket(irsocket);\n\t}\n\n\treturn 0;\n}\n\nint main(int argc, char **argv)\n{\n\tint r, opt, i;\n\tchar* addr = \"127.0.0.1\";\n\tint port = 1234;\n\tint port_ir = 0;\n\tint wait_ir = 10000;\n\tpthread_t thread_ir;\n\tpthread_t thread_ctrl; /* -cs- for periodically reading the register values */\n\tint port_resp = 1;\n\tint report_i2c = 0;\n\tint do_exit_thrd_ctrl = 0;\n\n\tuint64_t frequency = 100000000;\n\tuint32_t samp_rate = 2048000;\n\tenum rtlsdr_ds_mode ds_mode = RTLSDR_DS_IQ;\n\tuint32_t ds_temp, ds_threshold = 0;\n\tstruct sockaddr_in local, remote;\n\tuint32_t buf_num = 0;\n\t/* buf_len:\n\t * must be multiple of 512 - else it will be overwritten\n\t * in rtlsdr_read_async() in librtlsdr.c with DEFAULT_BUF_LENGTH (= 16*32 *512 = 512 *512)\n\t *\n\t * -> 512*512 -> 1048 ms @ 250 kS  or  81.92 ms @ 3.2 MS (internal default)\n\t * ->  32*512 ->   65 ms @ 250 kS  or   5.12 ms @ 3.2 MS (new default)\n\t *\n\t * usual soundcard as reference:\n\t *   512 samples @ 48 kHz ~= 10.6 ms\n\t *   512 samples @  8 kHz  = 64 ms\n\t */\n\tuint32_t buf_len = 32 * 512;\n\tconst char * rtlOpts = NULL;\n\tint dev_index = 0;\n\tint dev_given = 0;\n\tint gain = 0;\n\tint ppm_error = 0;\n\tstruct llist *curelem,*prev;\n\tpthread_attr_t attr;\n\tvoid *status;\n\tstruct timeval tv = {1,0};\n\tstruct linger ling = {1,0};\n\tSOCKET listensocket;\n\tsocklen_t rlen;\n\tfd_set readfds;\n\tu_long blockmode = 1;\n\tdongle_info_t dongle_info;\n\tint gains[100];\n\tconst char * opt_str = NULL;\n#ifdef _WIN32\n\tWSADATA wsd;\n\ti = WSAStartup(MAKEWORD(2,2), &wsd);\n#else\n\tstruct sigaction sigact, sigign;\n#endif\n\n\topt_str = \"a:p:f:g:s:b:n:d:P:O:TI:W:l:w:D:vr:\";\n\twhile ((opt = getopt(argc, argv, opt_str)) != -1) {\n\t\tswitch (opt) {\n\t\tcase 'd':\n\t\t\tdev_index = verbose_device_search(optarg);\n\t\t\tdev_given = 1;\n\t\t\tbreak;\n\t\tcase 'f':\n\t\t\tfrequency = (uint64_t)( atofs(optarg) + 0.5 );\n\t\t\tbreak;\n\t\tcase 'g':\n\t\t\tgain = (int)(atof(optarg) * 10); /* tenths of a dB */\n\t\t\tbreak;\n\t\tcase 's':\n\t\t\tsamp_rate = (uint32_t)atofs(optarg);\n\t\t\tbreak;\n\t\tcase 'a':\n\t\t\taddr = optarg;\n\t\t\tbreak;\n\t\tcase 'p':\n\t\t\tport = atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'r':\n\t\t\tport_resp = atoi(optarg);\n\t\t\treport_i2c = 0;\n\t\t\tbreak;\n\t\tcase 'I':\n\t\t\tport_ir = atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'W':\n\t\t\twait_ir = atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'b':\n\t\t\tbuf_num = atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'l':\n\t\t\tbuf_len = 512 * atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'n':\n\t\t\tllbuf_num = atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'P':\n\t\t\tppm_error = atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'O':\n\t\t\trtlOpts = optarg;\n\t\t\tbreak;\n\t\tcase 'T':\n\t\t\tenable_biastee = 1;\n\t\t\tbreak;\n\t\tcase 'w':\n\t\t\tbandwidth = (uint32_t)atofs(optarg);\n\t\t\tbreak;\n\t\tcase 'v':\n\t\t\t++verbosity;\n\t\t\tbreak;\n\t\tcase 'D':\n\t\t\tds_temp = (uint32_t)( atofs(optarg) + 0.5 );\n\t\t\tif (ds_temp <= RTLSDR_DS_Q_BELOW)\n\t\t\t\tds_mode = (enum rtlsdr_ds_mode)ds_temp;\n\t\t\telse\n\t\t\t\tds_threshold = ds_temp;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tusage();\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (argc < optind)\n\t\tusage();\n\n\tif (verbosity)\n\t\tfprintf(stderr, \"verbosity set to %d\\n\", verbosity);\n\n\tif (!dev_given) {\n\t\tdev_index = verbose_device_search(\"0\");\n\t}\n\n\tif (dev_index < 0) {\n\t    exit(1);\n\t}\n\n\trtlsdr_open(&dev, (uint32_t)dev_index);\n\tif (NULL == dev) {\n\tfprintf(stderr, \"Failed to open rtlsdr device #%d.\\n\", dev_index);\n\t\texit(1);\n\t}\n\n#ifndef _WIN32\n\tsigact.sa_handler = sighandler;\n\tsigemptyset(&sigact.sa_mask);\n\tsigact.sa_flags = 0;\n\tsigign.sa_handler = SIG_IGN;\n\tsigaction(SIGINT, &sigact, NULL);\n\tsigaction(SIGTERM, &sigact, NULL);\n\tsigaction(SIGQUIT, &sigact, NULL);\n\tsigaction(SIGPIPE, &sigign, NULL);\n#else\n\tSetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE );\n#endif\n\n\t/* Set the tuner error */\n\tverbose_ppm_set(dev, ppm_error);\n\n\t/* Set the sample rate */\n\tr = rtlsdr_set_sample_rate(dev, samp_rate);\n\tif (r < 0)\n\t\tfprintf(stderr, \"WARNING: Failed to set sample rate.\\n\");\n\n\tif (rtlOpts) {\n\t\trtlsdr_set_opt_string(dev, rtlOpts, verbosity);\n\t}\n\n\t/* Set direct sampling with threshold */\n\trtlsdr_set_ds_mode(dev, ds_mode, ds_threshold);\n\n\t/* Set the frequency */\n\tr = rtlsdr_set_center_freq64(dev, frequency);\n\tif (r < 0)\n\t\tfprintf(stderr, \"WARNING: Failed to set center freq.\\n\");\n\telse\n\t\tfprintf(stderr, \"Tuned to %f MHz.\\n\", frequency * 1E-6);\n\n\tif (0 == gain) {\n\t\t /* Enable automatic gain */\n\t\tr = rtlsdr_set_tuner_gain_mode(dev, 0);\n\t\tif (r < 0)\n\t\t\tfprintf(stderr, \"WARNING: Failed to enable automatic gain.\\n\");\n\t} else {\n\t\t/* Enable manual gain */\n\t\tr = rtlsdr_set_tuner_gain_mode(dev, 1);\n\t\tif (r < 0)\n\t\t\tfprintf(stderr, \"WARNING: Failed to enable manual gain.\\n\");\n\n\t\t/* Set the tuner gain */\n\t\tr = rtlsdr_set_tuner_gain(dev, gain);\n\t\tif (r < 0)\n\t\t\tfprintf(stderr, \"WARNING: Failed to set tuner gain.\\n\");\n\t\telse\n\t\t\tfprintf(stderr, \"Tuner gain set to %f dB.\\n\", gain/10.0);\n\t}\n\tverbose_set_bandwidth(dev, bandwidth);\n\n\trtlsdr_set_bias_tee(dev, enable_biastee);\n\tif (enable_biastee)\n\t\tfprintf(stderr, \"activated bias-T on GPIO PIN 0\\n\");\n\n\t/* Reset endpoint before we start reading from it (mandatory) */\n\tr = rtlsdr_reset_buffer(dev);\n\tif (r < 0)\n\t\tfprintf(stderr, \"WARNING: Failed to reset buffers.\\n\");\n\n\tpthread_mutex_init(&exit_cond_lock, NULL);\n\tpthread_mutex_init(&ll_mutex, NULL);\n\tpthread_mutex_init(&exit_cond_lock, NULL);\n\tpthread_cond_init(&cond, NULL);\n\tpthread_cond_init(&exit_cond, NULL);\n\n\tif (port_ir) {\n\t\tstruct ir_thread_data data = {.dev = dev, .port = port_ir, .wait = wait_ir, .addr = addr};\n\n\t\tpthread_create(&thread_ir, NULL, &ir_thread_fn, (void *)(&data));\n\t}\n\n#if 0\n\tfprintf(stderr, \"enabling Response channel with I2C reporting\\n\");\n\tport_resp = 1;\n\treport_i2c = 1;\n#endif\n\tif ( port_resp == 1 )\n\t\tport_resp = port + 1;\n\tctrldata.port = port_resp;\n\tctrldata.dev = dev;\n\tctrldata.addr = addr;\n\tctrldata.wait = 500000; /* = 0.5 sec */\n\tctrldata.report_i2c = report_i2c;\n\tctrldata.pDoExit = &do_exit_thrd_ctrl;\n\tif ( port_resp ) {\n\t\tfprintf(stderr, \"activating Response channel on port %d with %s I2C reporting\\n\"\n\t\t\t, port_resp, (report_i2c ? \"active\" : \"inactive\") );\n\t\tpthread_create(&thread_ctrl, NULL, &ctrl_thread_fn, &ctrldata);\n\t}\n\n\tmemset(&local,0,sizeof(local));\n\tlocal.sin_family = AF_INET;\n\tlocal.sin_port = htons(port);\n\tlocal.sin_addr.s_addr = inet_addr(addr);\n\n\tlistensocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);\n\tr = 1;\n\tsetsockopt(listensocket, SOL_SOCKET, SO_REUSEADDR, (char *)&r, sizeof(int));\n\tsetsockopt(listensocket, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling));\n\tbind(listensocket,(struct sockaddr *)&local,sizeof(local));\n\n#ifdef _WIN32\n\tioctlsocket(listensocket, FIONBIO, &blockmode);\n#else\n\tr = fcntl(listensocket, F_GETFL, 0);\n\tr = fcntl(listensocket, F_SETFL, r | O_NONBLOCK);\n#endif\n\n\twhile(1) {\n\t\tprintf(\"listening...\\n\");\n\t\tprintf(\"Use the device argument 'rtl_tcp=%s:%d' in OsmoSDR \"\n\t\t       \"(gr-osmosdr) source\\n\"\n\t\t       \"to receive samples in GRC and control \"\n\t\t       \"rtl_tcp parameters (frequency, gain, ...).\\n\",\n\t\t       addr, port);\n\t\tlisten(listensocket,1);\n\n\t\twhile(1) {\n\t\t\tFD_ZERO(&readfds);\n\t\t\tFD_SET(listensocket, &readfds);\n\t\t\ttv.tv_sec = 1;\n\t\t\ttv.tv_usec = 0;\n\t\t\tr = select(listensocket+1, &readfds, NULL, NULL, &tv);\n\t\t\tif(do_exit) {\n\t\t\t\tgoto out;\n\t\t\t} else if(r) {\n\t\t\t\trlen = sizeof(remote);\n\t\t\t\ts = accept(listensocket,(struct sockaddr *)&remote, &rlen);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tsetsockopt(s, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling));\n\n\t\tprintf(\"client accepted!\\n\");\n\n\t\tmemset(&dongle_info, 0, sizeof(dongle_info));\n\t\tmemcpy(&dongle_info.magic, \"RTL0\", 4);\n\n\t\tr = rtlsdr_get_tuner_type(dev);\n\t\tif (r >= 0)\n\t\t\tdongle_info.tuner_type = htonl(r);\n\n\t\tr = rtlsdr_get_tuner_gains(dev, gains);\n\t\tif (r >= 0)\n\t\t\tdongle_info.tuner_gain_count = htonl(r);\n\t\tif (verbosity)\n\t\t{\n\t\t\tfprintf(stderr, \"Supported gain values (%d): \", r);\n\t\t\tfor (i = 0; i < r; i++)\n\t\t\t\tfprintf(stderr, \"%.1f \", gains[i] / 10.0);\n\t\t\tfprintf(stderr, \"\\n\");\n\t\t}\n\n\t\tr = send(s, (const char *)&dongle_info, sizeof(dongle_info), 0);\n\t\tif (sizeof(dongle_info) != r)\n\t\t\tprintf(\"failed to send dongle information\\n\");\n\n\t\tpthread_attr_init(&attr);\n\t\tpthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);\n\t\tr = pthread_create(&tcp_worker_thread, &attr, tcp_worker, NULL);\n\t\tr = pthread_create(&command_thread, &attr, command_worker, NULL);\n\t\tpthread_attr_destroy(&attr);\n\n\t\tr = rtlsdr_read_async(dev, rtlsdr_callback, NULL, buf_num, buf_len);\n\n\t\tpthread_join(tcp_worker_thread, &status);\n\t\tpthread_join(command_thread, &status);\n\n\t\tclosesocket(s);\n\n\t\tprintf(\"all threads dead..\\n\");\n\t\tcurelem = ll_buffers;\n\t\tll_buffers = 0;\n\n\t\twhile(curelem != 0) {\n\t\t\tprev = curelem;\n\t\t\tcurelem = curelem->next;\n\t\t\tfree(prev->data);\n\t\t\tfree(prev);\n\t\t}\n\n\t\tdo_exit = 0;\n\t\tglobal_numq = 0;\n\t}\n\nout:\n\trtlsdr_close(dev);\n\tclosesocket(listensocket);\n\t/* if (port_ir) pthread_join(thread_ir, &status); */\n\n\tif ( port_resp ) {\n\t\tdo_exit_thrd_ctrl = 1;\n\t\tpthread_join(thread_ctrl, &status);\n\t}\n\n\tclosesocket(s);\n#ifdef _WIN32\n\tWSACleanup();\n#endif\n\tprintf(\"bye!\\n\");\n\treturn r >= 0 ? r : -r;\n}\n"
  },
  {
    "path": "src/rtl_test.c",
    "content": "/*\n * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver\n * rtl_test, test and benchmark tool\n *\n * Copyright (C) 2012-2014 by Steve Markgraf <steve@steve-m.de>\n * Copyright (C) 2012-2014 by Kyle Keen <keenerd@gmail.com>\n * Copyright (C) 2014 by Michael Tatarinov <kukabu@gmail.com>\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <errno.h>\n#include <signal.h>\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <math.h>\n\n#include <libusb.h>\n\n#ifdef __APPLE__\n#include <sys/time.h>\n#else\n#include <time.h>\n#endif\n\n#ifndef _WIN32\n#include <unistd.h>\n#else\n#include <windows.h>\n#include \"getopt/getopt.h\"\n#endif\n\n#include <rtl-sdr.h>\n#include <rtl_app_ver.h>\n#include \"convenience/convenience.h\"\n#include \"convenience/rtl_convenience.h\"\n\n#define DEFAULT_SAMPLE_RATE\t\t2048000\n#define DEFAULT_BUF_LENGTH\t\t(16 * 16384)\n#define MINIMAL_BUF_LENGTH\t\t512\n#define MAXIMAL_BUF_LENGTH\t\t(256 * 16384)\n\n#define MHZ(x)\t\t\t\t\t((x)*1000*1000)\n\n#define PPM_DURATION\t\t\t10\n#define PPM_DUMP_TIME\t\t\t5\n\n#define DETAILED_LOST_MSG\t\t0\n\n\nstruct time_generic\n/* holds all the platform specific values */\n{\n#ifndef _WIN32\n\ttime_t tv_sec;\n\tlong tv_nsec;\n#else\n\tlong tv_sec;\n\tlong tv_nsec;\n\tint init;\n\tLARGE_INTEGER frequency;\n\tLARGE_INTEGER ticks;\n#endif\n};\n\nstatic enum {\n\tNO_BENCHMARK,\n\tTUNER_BENCHMARK,\n\tPPM_BENCHMARK\n} test_mode = NO_BENCHMARK;\n\nstatic int do_exit = 0;\nstatic rtlsdr_dev_t *dev = NULL;\n\nstatic uint32_t samp_rate = DEFAULT_SAMPLE_RATE;\n\nstatic uint32_t bufferNo = 0;\nstatic uint32_t total_samples = 0;\nstatic uint32_t dropped_samples = 0;\n\nstatic unsigned int ppm_duration = PPM_DURATION;\n\nvoid usage(void)\n{\n\tfprintf(stderr,\n\t\t\"rtl_test, a benchmark tool for RTL2832 based SDR-receivers\\n\"\n\t\t\"rtl_test version %d.%d %s (%s)\\n\"\n\t\t\"rtl-sdr  library %d.%d %s\\n\\n\",\n\t\tAPP_VER_MAJOR, APP_VER_MINOR, APP_VER_ID, __DATE__,\n\t\trtlsdr_get_version() >>16, rtlsdr_get_version() & 0xFFFF,\n\t\trtlsdr_get_ver_id() );\n\tfprintf(stderr,\n\t\t\"Usage:\\trtl_test [-options]\\n\"\n\t\t\"\\t[-s samplerate (default: 2048000 Hz)]\\n\"\n\t\t\"\\t[-d device_index or serial (default: 0)]\\n\"\n\t\t\"%s\"\n\t\t\"\\t[-t enable tuner range benchmark]\\n\"\n\t\t\"\\t[-f first/begin frequency for tuner range benchmark, default: 0]\\n\"\n\t\t\"\\t[-e end frequency for tuner range benchmark, default: 3e9 = 3G ]\\n\"\n#ifndef _WIN32\n\t\t\"\\t[-p[seconds] enable PPM error measurement (default: 10 seconds)]\\n\"\n#endif\n\t\t\"\\t[-b output_block_size (default: 16 * 16384)]\\n\"\n\t\t\"\\t[-S force sync output (default: async)]\\n\"\n\t\t, rtlsdr_get_opt_help(1) );\n\texit(1);\n}\n\n#ifdef _WIN32\nBOOL WINAPI\nsighandler(int signum)\n{\n\tif (CTRL_C_EVENT == signum) {\n\t\tfprintf(stderr, \"\\nSignal caught, exiting!\\n\");\n\t\tdo_exit = 1;\n\t\trtlsdr_cancel_async(dev);\n\t\treturn TRUE;\n\t}\n\treturn FALSE;\n}\n#else\nstatic void sighandler(int signum)\n{\n\tfprintf(stderr, \"\\nSignal caught, exiting!\\n\");\n\tdo_exit = 1;\n\trtlsdr_cancel_async(dev);\n}\n#endif\n\nstatic void underrun_test(unsigned char *buf, uint32_t len, int mute)\n{\n\tuint32_t i, lost = 0;\n\tstatic uint8_t bcnt, uninit = 1;\n#if DETAILED_LOST_MSG\n\tuint32_t n_incont = 0, first_incont_sample = 0;\n\tuint8_t err_from, err_to;\n#endif\n\n\tif (uninit) {\n\t\tbcnt = buf[0];\n\t\tuninit = 0;\n\t}\n\tfor (i = 0; i < len; i++) {\n\t\tif(bcnt != buf[i]) {\n#if DETAILED_LOST_MSG\n\t\t\tif (!first_incont_sample) {\n\t\t\t\tfirst_incont_sample = 1 + i;\n\t\t\t\terr_from = bcnt;\n\t\t\t\terr_to = buf[i];\n\t\t\t}\n\t\t\t++n_incont;\n#endif\n\t\t\tlost += (buf[i] > bcnt) ? (buf[i] - bcnt) : (bcnt - buf[i]);\n\t\t\tbcnt = buf[i];\n\t\t}\n\t\tbcnt++;\n\t}\n\n\ttotal_samples += len;\n\tdropped_samples += lost;\n\tif (mute)\n\t\treturn;\n\tif (lost)\n\t\tprintf(\"lost at least %3u bytes in buffer %u\"\n#if DETAILED_LOST_MSG\n\t\t\t\" in %u incontinuities at byte %4u switching from %3u to %3u\"\n#endif\n\t\t\t\"\\n\", (unsigned)lost, (unsigned)bufferNo\n#if DETAILED_LOST_MSG\n\t\t\t, (unsigned)n_incont, (unsigned)(first_incont_sample-1)\n\t\t\t, (unsigned)err_from, (unsigned)err_to\n#endif\n\t\t\t);\n\t++bufferNo;\n}\n\n#ifndef _WIN32\nstatic int ppm_gettime(struct time_generic *tg)\n{\n\tint rv = ENOSYS;\n\tstruct timespec ts;\n\n#ifdef __unix__\n\trv = clock_gettime(CLOCK_MONOTONIC, &ts);\n\ttg->tv_sec = ts.tv_sec;\n\ttg->tv_nsec = ts.tv_nsec;\n#elif __APPLE__\n\tstruct timeval tv;\n\n\trv = gettimeofday(&tv, NULL);\n\ttg->tv_sec = tv.tv_sec;\n\ttg->tv_nsec = tv.tv_usec * 1000;\n#endif\n\treturn rv;\n}\n#endif\n\n#ifdef _WIN32\nstatic int ppm_gettime(struct time_generic *tg)\n{\n\tint rv;\n\tint64_t frac;\n\tif (!tg->init) {\n\t\tQueryPerformanceFrequency(&tg->frequency);\n\t\ttg->init = 1;\n\t}\n\trv = QueryPerformanceCounter(&tg->ticks);\n\ttg->tv_sec = tg->ticks.QuadPart / tg->frequency.QuadPart;\n\tfrac = (int64_t)(tg->ticks.QuadPart - (tg->tv_sec * tg->frequency.QuadPart));\n\ttg->tv_nsec = (long)(frac * 1000000000L / (int64_t)tg->frequency.QuadPart);\n\treturn !rv;\n}\n#endif\n\nstatic int ppm_report(uint64_t nsamples, uint64_t interval)\n{\n\tdouble real_rate, ppm;\n\n\treal_rate = nsamples * 1e9 / interval;\n\tppm = 1e6 * (real_rate / (double)samp_rate - 1.);\n\treturn (int)round(ppm);\n}\n\nstatic void ppm_test(uint32_t len)\n{\n\tstatic uint64_t nsamples = 0;\n\tstatic uint64_t interval = 0;\n\tstatic uint64_t nsamples_total = 0;\n\tstatic uint64_t interval_total = 0;\n\tstruct time_generic ppm_now;\n\tstatic struct time_generic ppm_recent;\n\tstatic enum {\n\t\tPPM_INIT_NO,\n\t\tPPM_INIT_DUMP,\n\t\tPPM_INIT_RUN\n\t} ppm_init = PPM_INIT_NO;\n\n\tppm_gettime(&ppm_now);\n\n\tif (ppm_init != PPM_INIT_RUN) {\n\t\t/*\n\t\t * Kyle Keen wrote:\n\t\t * PPM_DUMP_TIME throws out the first N seconds of data.\n\t\t * The dongle's PPM is usually very bad when first starting up,\n\t\t * typically incorrect by more than twice the final value.\n\t\t * Discarding the first few seconds allows the value to stabilize much faster.\n\t\t*/\n\t\tif (ppm_init == PPM_INIT_NO) {\n\t\t\tppm_recent.tv_sec = ppm_now.tv_sec + PPM_DUMP_TIME;\n\t\t\tppm_init = PPM_INIT_DUMP;\n\t\t\treturn;\n\t\t}\n\t\tif (ppm_init == PPM_INIT_DUMP && ppm_recent.tv_sec < ppm_now.tv_sec)\n\t\t\treturn;\n\t\tppm_recent = ppm_now;\n\t\tppm_init = PPM_INIT_RUN;\n\t\treturn;\n\t}\n\n\tnsamples += (uint64_t)(len / 2UL);\n\tinterval = (uint64_t)(ppm_now.tv_sec - ppm_recent.tv_sec);\n\tif (interval < ppm_duration)\n\t\treturn;\n\tinterval *= 1000000000UL;\n\tinterval += (int64_t)(ppm_now.tv_nsec - ppm_recent.tv_nsec);\n\tnsamples_total += nsamples;\n\tinterval_total += interval;\n\tprintf(\"real sample rate: %i current PPM: %i cumulative PPM: %i\\n\",\n\t\t(int)((1000000000UL * nsamples) / interval),\n\t\tppm_report(nsamples, interval),\n\t\tppm_report(nsamples_total, interval_total));\n\tppm_recent = ppm_now;\n\tnsamples = 0;\n}\n\nstatic void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)\n{\n\tunderrun_test(buf, len, 0);\n\n\tif (test_mode == PPM_BENCHMARK)\n\t\tppm_test(len);\n}\n\n/* smallest band or band gap that tuner_benchmark() will notice */\nstatic uint32_t max_step(uint32_t freq) {\n\tif (freq < 1e6)\n\t\treturn 1e4;\n\tif (freq > 1e8)\n\t\treturn 1e6;\n\treturn freq / 1e2;\n}\n\n/* precision with which tuner_benchmark() will measure the edges of bands */\nstatic uint32_t min_step(uint32_t freq) {\n\treturn 100;\n}\n\nstatic void report_band_start(uint32_t start) {\n\tif (start)\n\t\tfprintf(stderr, \"Found a new band starting at %u Hz\\n\", start);\n}\n\nstatic void report_band(uint32_t low, uint32_t high) {\n\tif ( low != high && low )\n\t\tfprintf(stderr, \"Tuning band: %u - %u Hz\\n\\n\", low, high);\n}\n\n\nstatic int set_center_freq_wait(rtlsdr_dev_t *dev, uint32_t freq, const char * state_text) {\n\tint rcA, rcB;\n\trcA = rtlsdr_set_center_freq(dev, freq);\n\tif ( rcA == LIBUSB_ERROR_NO_DEVICE ) {\n\t\tfprintf(stderr, \"%s: Got Error -4 for frequency %u .. retry after wait ..\\n\", state_text, (unsigned)freq);\n#ifdef _WIN32\n\t\tSleep(5);\n#else\n\t\tusleep(5000);\n#endif\n\t\trcB = rtlsdr_set_center_freq(dev, freq);\n\t\tif ( rcB == LIBUSB_ERROR_NO_DEVICE ) {\n\t\t\tfprintf(stderr, \"%s: Got Error -4 .. again. Giving Up!\\n\", state_text);\n\t\t\treturn rcB;\n\t\t}\n\t\tfprintf(stderr, \"%s: Now return code %d at retry.\\n\", state_text, rcB);\n\t\treturn rcB;\n\t}\n\treturn rcA;\n}\n\n\nvoid tuner_benchmark(uint32_t beg_freq, uint32_t end_freq)\n{\n\tuint32_t current = beg_freq; /* max_step(0); */\n\tuint32_t band_start = 0;\n\tuint32_t low_bound = 0, high_bound = 0;\n\tint rc;\n\tchar buf[20];\n\tenum { FIND_START, REFINE_START, FIND_END, REFINE_END } state;\n\n\tfprintf(stderr, \"Testing tuner range. This may take a couple of minutes..\\n\");\n\n\t/* deactivate harmonic reception - in case switched on with cli options */\n\trtlsdr_set_harmonic_rx(dev, 0);\n\n\t/* Scan for tuneable frequencies coarsely. When we find something,\n\t * do a binary search to narrow down the exact edge of the band.\n\t *\n\t * This can potentially miss bands/gaps smaller than max_step(freq)\n\t * but it is a lot faster than exhaustively scanning everything.\n\t */\n\n\t/* handle bands starting at 0Hz */\n\trc = set_center_freq_wait(dev, current, \"FIND_START\");\n\tif (rc < 0)\n\t\tstate = FIND_START;\n\telse {\n\t\tband_start = current;\n\t\treport_band_start(band_start);\n\t\tstate = FIND_END;\n\t}\n\n\twhile (current < end_freq && !do_exit) {\n\t\tswitch (state) {\n\t\tcase FIND_START:\n\t\t\t/* scanning for the start of a new band */\n\t\t\trc = set_center_freq_wait(dev, current, \"FIND_START\");\n\t\t\tif (rc < 0) {\n\t\t\t\tif ( rc == LIBUSB_ERROR_NO_DEVICE ) {\n\t\t\t\t\tdo_exit = 1;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t/* still looking for a band */\n\t\t\t\tlow_bound = current;\n\t\t\t\tcurrent += max_step(current);\n\t\t\t} else {\n\t\t\t\t/* new band, starting somewhere at or before current */\n\t\t\t\t/* low_bound < start <= current */\n\t\t\t\thigh_bound = current;\n\t\t\t\tstate = REFINE_START;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase REFINE_START:\n\t\t\t/* refining the start of a band */\n\t\t\t/* low_bound < bandstart <= high_bound */\n\t\t\trc = set_center_freq_wait(dev, current, \"REFINE_START\");\n\t\t\tif (rc == 0) {\n\t\t\t\t/* current is inside the band */\n\t\t\t\t/* low_bound < bandstart <= current */\n\t\t\t\tif (current - low_bound <= min_step(current)) {\n\t\t\t\t\t/* start found at low_bound */\n\t\t\t\t\tband_start = current;\n\t\t\t\t\treport_band_start(band_start);\n\t\t\t\t\tlow_bound = current;\n\t\t\t\t\tcurrent = band_start + max_step(band_start);\n\t\t\t\t\tstate = FIND_END;\n\t\t\t\t} else {\n\t\t\t\t\t/* binary search */\n\t\t\t\t\thigh_bound = current;\n\t\t\t\t\tcurrent = (current + low_bound) / 2;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif ( rc == LIBUSB_ERROR_NO_DEVICE ) {\n\t\t\t\t\tdo_exit = 1;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t/* current is outside the band */\n\t\t\t\t/* current < bandstart <= high_bound */\n\t\t\t\tif (high_bound - current <= min_step(current)) {\n\t\t\t\t\t/* start found at high_bound */\n\t\t\t\t\tlow_bound = band_start = high_bound;\n\t\t\t\t\treport_band_start(band_start);\n\t\t\t\t\tcurrent = band_start + max_step(band_start);\n\t\t\t\t\tstate = FIND_END;\n\t\t\t\t} else {\n\t\t\t\t\t/* binary search */\n\t\t\t\t\tlow_bound = current;\n\t\t\t\t\tcurrent = (current + high_bound) / 2;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase FIND_END:\n\t\t\t/* scanning for the end of the current band */\n\t\t\trc = set_center_freq_wait(dev, current, \"FIND_END\");\n\t\t\tif (rc == 0) {\n\t\t\t\t/* still looking for the end of the band */\n\t\t\t\tlow_bound = current;\n\t\t\t\tcurrent += max_step(current);\n\t\t\t} else {\n\t\t\t\tif ( rc == LIBUSB_ERROR_NO_DEVICE ) {\n\t\t\t\t\tdo_exit = 1;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t/* end found, coarsely */\n\t\t\t\t/* low_bound <= bandend < current, refine it */\n\t\t\t\thigh_bound = current;\n\t\t\t\tstate = REFINE_END;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase REFINE_END:\n\t\t\t/* refining the end of a band */\n\t\t\t/* low_bound <= bandend < high_bound */\n\t\t\trc = set_center_freq_wait(dev, current, \"REFINE_END\");\n\t\t\tif (rc < 0) {\n\t\t\t\tif ( rc == LIBUSB_ERROR_NO_DEVICE ) {\n\t\t\t\t\tdo_exit = 1;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t/* current is outside the band */\n\t\t\t\t/* low_bound <= bandend < current */\n\t\t\t\tif (current - low_bound <= min_step(current)) {\n\t\t\t\t\t/* band ends at low_bound */\n\t\t\t\t\treport_band(band_start, low_bound);\n\t\t\t\t\tlow_bound = current;\n\t\t\t\t\tcurrent = low_bound + max_step(low_bound);\n\t\t\t\t\tstate = FIND_START;\n\t\t\t\t} else {\n\t\t\t\t\t/* binary search */\n\t\t\t\t\thigh_bound = current;\n\t\t\t\t\tcurrent = (current + low_bound) / 2;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t/* current is inside the band */\n\t\t\t\t/* current <= bandend < high_bound */\n\t\t\t\tif (high_bound - current <= min_step(current)) {\n\t\t\t\t\t/* band ends at high_bound */\n\t\t\t\t\treport_band(band_start, current);\n\t\t\t\t\tlow_bound = high_bound;\n\t\t\t\t\tcurrent = low_bound + max_step(low_bound);\n\t\t\t\t\tstate = FIND_START;\n\t\t\t\t} else {\n\t\t\t\t\t/* binary search */\n\t\t\t\t\tlow_bound = current;\n\t\t\t\t\tcurrent = (current + high_bound) / 2;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif ( rc == LIBUSB_ERROR_NO_DEVICE )\n\t\treturn;\n\n\tif (state == FIND_END)\n\t\treport_band(band_start, current);\n\telse if (state == REFINE_END)\n\t\treport_band(band_start, low_bound);\n}\n\nint main(int argc, char **argv)\n{\n#ifndef _WIN32\n\tstruct sigaction sigact;\n#endif\n\tint n_read, r, opt, i;\n\tint sync_mode = 0;\n\tconst char * rtlOpts = NULL;\n\tuint8_t *buffer;\n\tint dev_index = 0;\n\tint dev_given = 0;\n\tuint32_t out_block_size = DEFAULT_BUF_LENGTH;\n\tuint32_t tuner_bench_beg_freq = 0;\n\tuint32_t tuner_bench_end_freq = 0;\n\tint count;\n\tint gains[100];\n\n\twhile ((opt = getopt(argc, argv, \"d:s:b:O:tf:e:p::Sh\")) != -1) {\n\t\tswitch (opt) {\n\t\tcase 'd':\n\t\t\tdev_index = verbose_device_search(optarg);\n\t\t\tdev_given = 1;\n\t\t\tbreak;\n\t\tcase 's':\n\t\t\tsamp_rate = (uint32_t)atofs(optarg);\n\t\t\tbreak;\n\t\tcase 'b':\n\t\t\tout_block_size = (uint32_t)atof(optarg);\n\t\t\tbreak;\n\t\tcase 'O':\n\t\t\trtlOpts = optarg;\n\t\t\tbreak;\n\t\tcase 't':\n\t\t\ttest_mode = TUNER_BENCHMARK;\n\t\t\tbreak;\n\t\tcase 'f':\n\t\t\ttuner_bench_beg_freq = (uint32_t)atofs(optarg);\n\t\t\tbreak;\n\t\tcase 'e':\n\t\t\ttuner_bench_end_freq = (uint32_t)atofs(optarg);\n\t\t\tbreak;\n\t\tcase 'p':\n\t\t\ttest_mode = PPM_BENCHMARK;\n\t\t\tif (optarg)\n\t\t\t\tppm_duration = atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'S':\n\t\t\tsync_mode = 1;\n\t\t\tbreak;\n\t\tcase 'h':\n\t\tdefault:\n\t\t\tusage();\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif(out_block_size < MINIMAL_BUF_LENGTH ||\n\t   out_block_size > MAXIMAL_BUF_LENGTH ){\n\t\tfprintf(stderr,\n\t\t\t\"Output block size wrong value, falling back to default\\n\");\n\t\tfprintf(stderr,\n\t\t\t\"Minimal length: %u\\n\", MINIMAL_BUF_LENGTH);\n\t\tfprintf(stderr,\n\t\t\t\"Maximal length: %u\\n\", MAXIMAL_BUF_LENGTH);\n\t\tout_block_size = DEFAULT_BUF_LENGTH;\n\t}\n\n\tbuffer = malloc(out_block_size * sizeof(uint8_t));\n\n\tif (!dev_given) {\n\t\tdev_index = verbose_device_search(\"0\");\n\t}\n\n\tif (dev_index < 0) {\n\t\texit(1);\n\t}\n\n\tr = rtlsdr_open(&dev, (uint32_t)dev_index);\n\tif (r < 0) {\n\t\tfprintf(stderr, \"Failed to open rtlsdr device #%d.\\n\", dev_index);\n\t\texit(1);\n\t}\n#ifndef _WIN32\n\tsigact.sa_handler = sighandler;\n\tsigemptyset(&sigact.sa_mask);\n\tsigact.sa_flags = 0;\n\tsigaction(SIGINT, &sigact, NULL);\n\tsigaction(SIGTERM, &sigact, NULL);\n\tsigaction(SIGQUIT, &sigact, NULL);\n\tsigaction(SIGPIPE, &sigact, NULL);\n#else\n\tSetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE );\n#endif\n\tcount = rtlsdr_get_tuner_gains(dev, NULL);\n\tfprintf(stderr, \"Supported gain values (%d): \", count);\n\n\tcount = rtlsdr_get_tuner_gains(dev, gains);\n\tfor (i = 0; i < count; i++)\n\t\tfprintf(stderr, \"%.1f \", gains[i] / 10.0);\n\tfprintf(stderr, \"\\n\");\n\n\t/* Set the sample rate */\n\tverbose_set_sample_rate(dev, samp_rate);\n\n\t/* set - especially sideband - before testing tuning range */\n\tif (rtlOpts) {\n\t\trtlsdr_set_opt_string(dev, rtlOpts, 1);\n\t}\n\n\tif (test_mode == TUNER_BENCHMARK) {\n\t\ttuner_benchmark(tuner_bench_beg_freq, tuner_bench_end_freq);\n\t\tgoto exit;\n\t}\n\n\t/* Enable test mode */\n\tr = rtlsdr_set_testmode(dev, 1);\n\n\t/* Reset endpoint before we start reading from it (mandatory) */\n\tverbose_reset_buffer(dev);\n\n\tif ((test_mode == PPM_BENCHMARK) && !sync_mode) {\n\t\tfprintf(stderr, \"Reporting PPM error measurement every %u seconds...\\n\", ppm_duration);\n\t\tfprintf(stderr, \"Press ^C after a few minutes.\\n\");\n\t}\n\n\tif (test_mode == NO_BENCHMARK) {\n\t\tfprintf(stderr, \"\\nInfo: This tool will continuously\"\n\t\t\t\t\" read from the device, and report if\\n\"\n\t\t\t\t\"samples get lost. If you observe no \"\n\t\t\t\t\"further output, everything is fine.\\n\\n\");\n\t}\n\n\tif (sync_mode) {\n\t\tfprintf(stderr, \"Reading samples in sync mode...\\n\");\n\t\tfprintf(stderr, \"(Samples are being lost but not reported.)\\n\");\n\t\twhile (!do_exit) {\n\t\t\tr = rtlsdr_read_sync(dev, buffer, out_block_size, &n_read);\n\t\t\tif (r < 0) {\n\t\t\t\tfprintf(stderr, \"WARNING: sync read failed.\\n\");\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif ((uint32_t)n_read < out_block_size) {\n\t\t\t\tfprintf(stderr, \"Short read, samples lost, exiting!\\n\");\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tunderrun_test(buffer, n_read, 1);\n\t\t}\n\t} else {\n\t\tfprintf(stderr, \"Reading samples in async mode...\\n\");\n\t\tr = rtlsdr_read_async(dev, rtlsdr_callback, NULL,\n\t\t\t\t      0, out_block_size);\n\t}\n\n\tif (do_exit) {\n\t\tfprintf(stderr, \"\\nUser cancel after %u buffers, exiting...\\n\", (unsigned)bufferNo );\n\t\tfprintf(stderr, \"Samples per million lost (minimum): %i\\n\", (int)(1000000L * dropped_samples / total_samples));\n\t}\n\telse\n\t\tfprintf(stderr, \"\\nLibrary error %d after %u buffers, exiting...\\n\", r, (unsigned)bufferNo);\n\nexit:\n\trtlsdr_close(dev);\n\tfree (buffer);\n\n\treturn r >= 0 ? r : -r;\n}\n"
  },
  {
    "path": "src/rtl_udp.c",
    "content": "/*\n * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver\n * Copyright (C) 2012 by Steve Markgraf <steve@steve-m.de>\n * Copyright (C) 2012-2013 by Hoernchen <la@tfc-server.de>\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <errno.h>\n#include <signal.h>\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#ifndef _WIN32\n#include <unistd.h>\n#include <arpa/inet.h>\n#include <sys/socket.h>\n#include <sys/types.h>\n#include <sys/time.h>\n#include <netinet/in.h>\n#include <fcntl.h>\n#else\n#include <winsock2.h>\n#include \"getopt/getopt.h\"\n#define usleep(x) Sleep(x/1000)\n#endif\n\n#ifdef NEED_PTHREADS_WORKARROUND\n#define HAVE_STRUCT_TIMESPEC\n#endif\n#include <pthread.h>\n\n#include <rtl-sdr.h>\n#include <rtl_app_ver.h>\n#include <rtl_tcp.h>\n#include \"convenience/convenience.h\"\n#include \"convenience/rtl_convenience.h\"\n\n#ifdef _WIN32\n#pragma comment(lib, \"ws2_32.lib\")\n\ntypedef int socklen_t;\n\n#else\n#define closesocket close\n#define SOCKADDR struct sockaddr\n#define SOCKET int\n#define SOCKET_ERROR -1\n#endif\n\nstatic SOCKET s;\nstruct sockaddr_in remote;\n\nstatic pthread_t tcp_worker_thread;\nstatic pthread_t command_thread;\nstatic pthread_cond_t exit_cond;\nstatic pthread_mutex_t exit_cond_lock;\n\nstatic pthread_mutex_t ll_mutex;\nstatic pthread_cond_t cond;\n\nstruct llist {\n\tchar *data;\n\tsize_t len;\n\tstruct llist *next;\n};\n\ntypedef struct { /* structure size must be multiple of 2 bytes */\n\tchar magic[4];\n\tuint32_t tuner_type;\n\tuint32_t tuner_gain_count;\n} dongle_info_t;\n\nstatic rtlsdr_dev_t *dev = NULL;\n\nstatic int verbosity = 0;\nstatic uint32_t bandwidth = 0;\n\nstatic int enable_biastee = 0;\nstatic int global_numq = 0;\nstatic struct llist *ll_buffers = 0;\nstatic int llbuf_num = 500;\n\nstatic volatile int do_exit = 0;\n\nvoid usage(void)\n{\n\tfprintf(stderr,\n\t\t\"rtl_udp, an I/Q spectrum server for RTL2832 based SDR-receivers\\n\"\n\t\t\"rtl_udp version %d.%d %s (%s)\\n\"\n\t\t\"rtl-sdr library %d.%d %s\\n\\n\",\n\t\tAPP_VER_MAJOR, APP_VER_MINOR, APP_VER_ID, __DATE__,\n\t\trtlsdr_get_version() >>16, rtlsdr_get_version() & 0xFFFF,\n\t\trtlsdr_get_ver_id() );\n\tfprintf(stderr, \"Usage:\\trtl_udp [-a listen address]\\n\"\n\t\t\"\\t[-p listen port (default: 1234)]\\n\"\n\t\t\"\\t[-I infrared sensor listen port (default: 0=none)]\\n\"\n\t\t\"\\t[-W infrared sensor query wait interval usec (default: 10000)]\\n\"\n\t\t\"\\t[-f frequency to tune to [Hz]]\\n\"\n\t\t\"\\t[-g gain in dB (default: 0 for auto)]\\n\"\n\t\t\"\\t[-s samplerate in Hz (default: 2048000 Hz)]\\n\"\n\t\t\"\\t[-b number of buffers (default: 15, set by library)]\\n\"\n\t\t\"\\t[-l length of single buffer in units of 512 samples (default: 32 was 256)]\\n\"\n\t\t\"\\t[-n max number of linked list buffers to keep (default: 500)]\\n\"\n\t\t\"\\t[-w rtlsdr tuner bandwidth [Hz] (for R820T/2 and E4000 tuners)]\\n\"\n\t\t\"\\t[-d device index or serial (default: 0)]\\n\"\n\t\t\"\\t[-P ppm_error (default: 0)]\\n\"\n\t\t\"%s\"\n\t\t\"\\t[-T enable bias-T on GPIO PIN 0 (works for rtl-sdr.com v3 dongles)]\\n\"\n\n\t\t\"\\t[-D direct_sampling_mode (default: 0, 1 = I, 2 = Q, 3 = I below threshold, 4 = Q below threshold)]\\n\"\n\t\t\"\\t[-D direct_sampling_threshold_frequency (default: 0 use tuner specific frequency threshold for 3 and 4)]\\n\"\n\t\t\"\\t[-v increase verbosity (default: 0)]\\n\"\n\t\t, rtlsdr_get_opt_help(1) );\n\texit(1);\n}\n\n#ifdef _WIN32\nint gettimeofday(struct timeval *tv, void* ignored)\n{\n\tFILETIME ft;\n\tunsigned __int64 tmp = 0;\n\tif (NULL != tv) {\n\t\tGetSystemTimeAsFileTime(&ft);\n\t\ttmp |= ft.dwHighDateTime;\n\t\ttmp <<= 32;\n\t\ttmp |= ft.dwLowDateTime;\n\t\ttmp /= 10;\n#ifdef _MSC_VER\n\t\ttmp -= 11644473600000000Ui64;\n#else\n\t\ttmp -= 11644473600000000ULL;\n#endif\n\t\ttv->tv_sec = (long)(tmp / 1000000UL);\n\t\ttv->tv_usec = (long)(tmp % 1000000UL);\n\t}\n\treturn 0;\n}\n\nBOOL WINAPI\nsighandler(int signum)\n{\n\tif (CTRL_C_EVENT == signum) {\n\t\tfprintf(stderr, \"Signal caught, exiting!\\n\");\n\t\tdo_exit = 1;\n\t\trtlsdr_cancel_async(dev);\n\t\treturn TRUE;\n\t}\n\treturn FALSE;\n}\n#else\nstatic void sighandler(int signum)\n{\n\tfprintf(stderr, \"Signal caught, exiting!\\n\");\n\trtlsdr_cancel_async(dev);\n\tdo_exit = 1;\n}\n#endif\n\nvoid rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)\n{\n\tif(!do_exit) {\n\t\tstruct llist *rpt = (struct llist*)malloc(sizeof(struct llist));\n\t\trpt->data = (char*)malloc(len);\n\t\tmemcpy(rpt->data, buf, len);\n\t\trpt->len = len;\n\t\trpt->next = NULL;\n\n\t\tpthread_mutex_lock(&ll_mutex);\n\n\t\tif (ll_buffers == NULL) {\n\t\t\tll_buffers = rpt;\n\t\t} else {\n\t\t\tstruct llist *cur = ll_buffers;\n\t\t\tint num_queued = 0;\n\n\t\t\twhile (cur->next != NULL) {\n\t\t\t\tcur = cur->next;\n\t\t\t\tnum_queued++;\n\t\t\t}\n\n\t\t\tif(llbuf_num && llbuf_num == num_queued-2){\n\t\t\t\tstruct llist *curelem;\n\n\t\t\t\tfree(ll_buffers->data);\n\t\t\t\tcurelem = ll_buffers->next;\n\t\t\t\tfree(ll_buffers);\n\t\t\t\tll_buffers = curelem;\n\t\t\t}\n\n\t\t\tcur->next = rpt;\n\n\t\t\tif ( verbosity )\n\t\t\t{\n\t\t\t\tif (num_queued > global_numq)\n\t\t\t\t\tprintf(\"ll+, now %d\\n\", num_queued);\n\t\t\t\telse if (num_queued < global_numq)\n\t\t\t\t\tprintf(\"ll-, now %d\\n\", num_queued);\n\t\t\t}\n\n\t\t\tglobal_numq = num_queued;\n\t\t}\n\t\tpthread_cond_signal(&cond);\n\t\tpthread_mutex_unlock(&ll_mutex);\n\t}\n}\n\nstatic void *udp_worker(void *arg)\n{\n\tstruct llist *curelem,*prev;\n\tint bytesleft,bytessent, index;\n\tstruct timeval tv= {1,0};\n\tstruct timespec ts;\n\tstruct timeval tp;\n\tfd_set writefds;\n\tint r = 0;\n\n\twhile(1) {\n\t\tif(do_exit)\n\t\t\tpthread_exit(0);\n\n\t\tpthread_mutex_lock(&ll_mutex);\n\t\tgettimeofday(&tp, NULL);\n\t\tts.tv_sec  = tp.tv_sec+1;\n\t\tts.tv_nsec = tp.tv_usec * 1000;\n\t\tr = pthread_cond_timedwait(&cond, &ll_mutex, &ts);\n\t\tif(r == ETIMEDOUT) {\n\t\t\tpthread_mutex_unlock(&ll_mutex);\n\t\t\tprintf(\"worker cond timeout\\n\");\n\t\t\tsighandler(0);\n\t\t\tpthread_exit(NULL);\n\t\t}\n\n\t\tcurelem = ll_buffers;\n\t\tll_buffers = 0;\n\t\tpthread_mutex_unlock(&ll_mutex);\n\n\t\twhile(curelem != 0) {\n\t\t\tbytesleft = curelem->len;\n\t\t\tindex = 0;\n\t\t\tbytessent = 0;\n\t\t\twhile(bytesleft > 0) {\n\t\t\t\tFD_ZERO(&writefds);\n\t\t\t\tFD_SET(s, &writefds);\n\t\t\t\ttv.tv_sec = 1;\n\t\t\t\ttv.tv_usec = 0;\n\t\t\t\tr = select(s+1, NULL, &writefds, NULL, &tv);\n\t\t\t\tif(r) {\n\t\t\t\t\tbytessent = sendto(s,  &curelem->data[index], bytesleft, 0, (struct sockaddr *)&remote, sizeof(remote));\n\t\t\t\t\tbytesleft -= bytessent;\n\t\t\t\t\tindex += bytessent;\n\t\t\t\t}\n\t\t\t\tif(bytessent == SOCKET_ERROR || do_exit) {\n\t\t\t\t\t\tprintf(\"worker socket bye\\n\");\n\t\t\t\t\t\tsighandler(0);\n\t\t\t\t\t\tpthread_exit(NULL);\n\t\t\t\t}\n\t\t\t}\n\t\t\tprev = curelem;\n\t\t\tcurelem = curelem->next;\n\t\t\tfree(prev->data);\n\t\t\tfree(prev);\n\t\t}\n\t}\n}\n\nstatic int set_gain_by_index(rtlsdr_dev_t *_dev, unsigned int index)\n{\n\tint res = 0;\n\tint* gains;\n\tint count = rtlsdr_get_tuner_gains(_dev, NULL);\n\n\tif (count > 0 && index < (unsigned int)count) {\n\t\tgains = malloc(sizeof(int) * count);\n\t\tcount = rtlsdr_get_tuner_gains(_dev, gains);\n\n\t\tif (verbosity)\n\t\t\tprintf(\"set tuner gain to %.1f dB\\n\", gains[index] / 10.0);\n\t\tres = rtlsdr_set_tuner_gain(_dev, gains[index]);\n\t\tif (res < 0)\n\t\tprintf(\"  setting tuner gain index failed\\n\");\n\n\t\tfree(gains);\n\t}\n\telse\n\t{\n\t\tprintf(\"set tuner gain index to %u\\n\", index);\n\t\tprintf(\"  error setting tuner gain index failed: valid range: 0 .. %d\\n\", count-1);\n\t}\n\n\treturn res;\n}\n\nstatic void check_tuner_pll(rtlsdr_dev_t *dev, int *tuner_unsupported, int *last_lock_report)\n{\n\tint r = rtlsdr_is_tuner_PLL_locked(dev);\n\t/* printf(\"performed lock check:\\n\"); */\n\tif (r == 1) {\n\t\tif (*last_lock_report != r)\n\t\t\tprintf(\"tuner PLL is unlocked!\\n\");\n\t\t*last_lock_report = r;\n\t}\n\telse if (r == 0) {\n\t\tif (*last_lock_report != r)\n\t\t\tprintf(\"tuner PLL is locked.\\n\");\n\t\t*last_lock_report = r;\n\t}\n\telse if (r == -2) {\n\t\tprintf(\"error at PLL-locked check: tuner not supported! No further tests.\\n\");\n\t\t*tuner_unsupported = 1;\n\t}\n\telse if (r < 0)\n\t\tprintf(\"error checking tuner PLL!\\n\");\n\telse\n\t\tprintf(\"unknown error at tuner PLL check!\\n\");\n\tfflush(stdout);\n}\n\n\n\n\n#ifdef _WIN32\n#define __attribute__(x)\n#pragma pack(push, 1)\n#endif\nstruct command{\n\tunsigned char cmd;\n\tunsigned int param;\n}__attribute__((packed));\n#ifdef _WIN32\n#pragma pack(pop)\n#endif\nstatic void *command_worker(void *arg)\n{\n\tint left, received = 0;\n\tfd_set readfds;\n\tstruct command cmd={0, 0};\n\tstruct timeval tv= {1, 0};\n\tunsigned tuner_check_timeout = 0;\n\tint last_lock_report = -1;\n\tint tuner_unsupported = 0;\n\tint r = 0;\n\tuint32_t freqhi = 0;\n\tuint64_t tmp64;\n\tuint32_t tmp;\n\tint32_t itmp;\n\tint32_t if_band_center_freq;\n\tint iitmp;\n\n\twhile(1) {\n\t\tleft=sizeof(cmd);\n\t\twhile(left >0) {\n\t\t\tFD_ZERO(&readfds);\n\t\t\tFD_SET(s, &readfds);\n\t\t\ttv.tv_sec = 1;\n\t\t\ttv.tv_usec = 0;\n\t\t\tr = select(s+1, &readfds, NULL, NULL, &tv);\n\t\t\tif(r) {\n\t\t\t\treceived = recv(s, (char*)&cmd+(sizeof(cmd)-left), left, 0);\n\t\t\t\tleft -= received;\n\t\t\t\t/* printf(\"received %d bytes\\n\", received); */\n\t\t\t}\n\t\t\telse if (!tuner_unsupported)\n\t\t\t{\n\t\t\t\t/* timeout: nothing happend */\n\t\t\t\t++tuner_check_timeout;\n\t\t\t\tif (tuner_check_timeout >= 3)\n\t\t\t\t{\n\t\t\t\t\t/* automatic check every 3 seconds */\n\t\t\t\t\tcheck_tuner_pll(dev, &tuner_unsupported, &last_lock_report);\n\t\t\t\t\ttuner_check_timeout = 0;\n\t\t\t\t}\n\t\t\t\tfflush(stdout);\n\t\t\t}\n\t\t\tif(received == SOCKET_ERROR || do_exit) {\n\t\t\t\tprintf(\"comm recv bye\\n\");\n\t\t\t\tsighandler(0);\n\t\t\t\tpthread_exit(NULL);\n\t\t\t}\n\t\t}\n\t\tswitch(cmd.cmd) {\n\t\tcase SET_FREQUENCY:\n\t\t\ttmp = ntohl(cmd.param);\n\t\t\tif (!freqhi)\n\t\t\t{\n\t\t\t\tprintf(\"set freq %f MHz\\n\", tmp * 1E-6);\n\t\t\t\tr = rtlsdr_set_center_freq(dev, tmp);\n\t\t\t\tif (r < 0) {\n\t\t\t\t\tprintf(\"  error setting frequency!\\n\");\n\t\t\t\t\tlast_lock_report = -1;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmp64 = ( ((uint64_t)freqhi) << 32 ) | (uint64_t)tmp;\n\t\t\t\tprintf(\"set freq64 %f MHz\\n\", tmp64 * 1E-6);\n\t\t\t\tr = rtlsdr_set_center_freq64(dev, tmp64);\n\t\t\t\tif (r < 0) {\n\t\t\t\t\tprintf(\"  error setting frequency!\\n\");\n\t\t\t\t\tlast_lock_report = -1;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfreqhi = 0;\n\t\t\tbreak;\n\t\tcase SET_FREQ_HI32:\n\t\t\tfreqhi = ntohl(cmd.param);\n\t\t\tbreak;\n\t\tcase SET_SAMPLE_RATE:\n\t\t\ttmp = ntohl(cmd.param);\n\t\t\tprintf(\"set sample rate %u\\n\", tmp);\n\t\t\tr = rtlsdr_set_sample_rate(dev, tmp);\n\t\t\tif (r < 0)\n\t\t\t\tprintf(\"  error setting sample rate! sample rate is %u\\n\", rtlsdr_get_sample_rate(dev));\n\t\t\tbreak;\n\t\tcase SET_GAIN_MODE:\n\t\t\ttmp = ntohl(cmd.param);\n\t\t\tprintf(\"set gain mode %u (=%s)\\n\", tmp, tmp?\"manual\":\"automatic\");\n\t\t\tr = rtlsdr_set_tuner_gain_mode(dev, tmp);\n\t\t\tif (r < 0)\n\t\t\t\tprintf(\"  error setting gain mode!\\n\");\n\t\t\tbreak;\n\t\tcase SET_GAIN:\n\t\t\ttmp = ntohl(cmd.param);\n\t\t\tprintf(\"set manual tuner gain %.1f dB\\n\", tmp/10.0);\n\t\t\tr = rtlsdr_set_tuner_gain(dev, tmp);\n\t\t\tif (r < 0)\n\t\t\t\tprintf(\"  error setting tuner gain!\\n\");\n\t\t\tbreak;\n\t\tcase SET_FREQUENCY_CORRECTION:\n\t\t\titmp = ntohl(cmd.param);\n\t\t\tprintf(\"set freq correction %d ppm\\n\", itmp);\n\t\t\tr = rtlsdr_set_freq_correction(dev, itmp);\n\t\t\tif (r < 0) {\n\t\t\t\tprintf(\"  error setting frequency correction!\\n\");\n\t\t\t\tlast_lock_report = -1;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase SET_IF_STAGE:\n\t\t\ttmp = ntohl(cmd.param);\n\t\t\tprintf(\"set if stage %d gain %.1f dB\\n\", tmp >> 16, ((short)(tmp & 0xffff))/10.0);\n\t\t\tr = rtlsdr_set_tuner_if_gain(dev, tmp >> 16, (short)(tmp & 0xffff));\n\t\t\tif (r < 0)\n\t\t\t\tprintf(\"  error setting gain for stage!\\n\");\n\t\t\tbreak;\n\t\tcase SET_TEST_MODE:\n\t\t\ttmp = ntohl(cmd.param);\n\t\t\tprintf(\"set test mode %d (=%s)\\n\", tmp, tmp?\"active\":\"inactive\");\n\t\t\tr = rtlsdr_set_testmode(dev, tmp);\n\t\t\tif (r < 0)\n\t\t\t\tprintf(\"  error setting test mode!\\n\");\n\t\t\tbreak;\n\t\tcase SET_AGC_MODE:\n\t\t\ttmp = ntohl(cmd.param);\n\t\t\tprintf(\"set rtl2832's digital agc mode %d (=%s)\\n\", tmp, tmp?\"enabled\":\"disabled\");\n\t\t\tr = rtlsdr_set_agc_mode(dev, tmp);\n\t\t\tif (r < 0)\n\t\t\t\tprintf(\"  error setting digital agc mode!\\n\");\n\t\t\tbreak;\n\t\tcase SET_DIRECT_SAMPLING:\n\t\t\ttmp = ntohl(cmd.param);\n\t\t\tprintf(\"set direct sampling %u (=%s)\\n\", tmp, (!tmp) ? \"disabled\": (tmp==1)?\"pin I-ADC\": (tmp==2)? \"pin Q-ADC\":\"unknown!\");\n\t\t\tr = rtlsdr_set_direct_sampling(dev, tmp);\n\t\t\tif (r < 0)\n\t\t\t\tprintf(\"  error setting direct sampling!\\n\");\n\t\t\tbreak;\n\t\tcase SET_OFFSET_TUNING:\n\t\t\titmp = ntohl(cmd.param);\n\t\t\tprintf(\"set offset tuning %d\\n\", itmp);\n\t\t\tr = rtlsdr_set_offset_tuning(dev, itmp);\n\t\t\tif (r < 0) {\n\t\t\t\tprintf(\"  error setting offset tuning!\\n\");\n\t\t\t\tlast_lock_report = -1;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase SET_RTL_CRYSTAL:\n\t\t\tprintf(\"set rtl xtal frequency %d\\n\", ntohl(cmd.param));\n\t\t\tr = rtlsdr_set_xtal_freq(dev, ntohl(cmd.param), 0);\n\t\t\tif (r < 0)\n\t\t\t\tprintf(\"  error setting rtl xtal frequency!\\n\");\n\t\t\tbreak;\n\t\tcase SET_TUNER_CRYSTAL:\n\t\t\tprintf(\"set tuner xtal %d\\n\", ntohl(cmd.param));\n\t\t\tr = rtlsdr_set_xtal_freq(dev, 0, ntohl(cmd.param));\n\t\t\tif (r < 0)\n\t\t\t\tprintf(\"  error setting tuner xtal frequency!\\n\");\n\t\t\tbreak;\n\t\tcase SET_TUNER_GAIN_BY_INDEX:\n\t\t\ttmp = ntohl(cmd.param);\n\t\t\tprintf(\"set tuner gain by index %u\\n\", tmp);\n\t\t\tset_gain_by_index(dev, tmp);\n\t\t\tbreak;\n\t\tcase SET_BIAS_TEE:\n\t\t\ttmp = ntohl(cmd.param);\n\t\t\tprintf(\"set bias T %u (%s)\\n\", tmp, tmp?\"on\":\"off\");\n\t\t\tr = rtlsdr_set_bias_tee(dev, tmp);\n\t\t\tif (r < 0)\n\t\t\t\tprintf(\"  error setting bias tee!\\n\");\n\t\t\tbreak;\n\t\tcase SET_TUNER_BANDWIDTH:\n\t\t\tbandwidth = ntohl(cmd.param);\n\t\t\tprintf(\"set tuner bandwidth to %i Hz\\n\", bandwidth);\n\t\t\tverbose_set_bandwidth(dev, bandwidth);\n\t\t\tbreak;\n\t\tcase SET_I2C_TUNER_REGISTER:\n\t\t\ttmp = ntohl(cmd.param);\n\t\t\tprintf(\"set i2c register x%03X to x%03X with mask x%02X\\n\", (tmp >> 20) & 0xfff, tmp & 0xfff, (tmp >> 12) & 0xff );\n\t\t\tr = rtlsdr_set_tuner_i2c_register(dev, (tmp >> 20) & 0xfff, (tmp >> 12) & 0xff, tmp & 0xfff);\n\t\t\tif (r < 0)\n\t\t\t\tprintf(\"  error setting i2c register!\\n\");\n\t\t\tbreak;\n\t\tcase SET_I2C_TUNER_OVERRIDE:\n\t\t\ttmp = ntohl(cmd.param);\n\t\t\tprintf(\"set i2c override register x%03X to x%03X with mask x%02X\\n\", (tmp >> 20) & 0xfff, tmp & 0xfff, (tmp >> 12) & 0xff );\n\t\t\tr = rtlsdr_set_tuner_i2c_override(dev, (tmp >> 20) & 0xfff, (tmp >> 12) & 0xff, tmp & 0xfff);\n\t\t\tif (r < 0)\n\t\t\t\tprintf(\"  error setting i2c register!\\n\");\n\t\t\tbreak;\n\t\tcase UDP_TERMINATE:\n\t\t\tprintf(\"comm recv bye\\n\");\n\t\t\tsighandler(0);\n\t\t\tpthread_exit(NULL);\n\t\t\tbreak;\n\t\tcase SET_TUNER_BW_IF_CENTER:\n\t\t\tif_band_center_freq = ntohl(cmd.param);\n\t\t\tprintf(\"set tuner band to IF frequency %i Hz from center\\n\", if_band_center_freq);\n\t\t\tr = rtlsdr_set_tuner_band_center(dev, if_band_center_freq );\n\t\t\tif (r < 0)\n\t\t\t\tprintf(\"  error setting tuner band's IF center frequency!\\n\");\n\t\t\tbreak;\n\t\tcase SET_TUNER_IF_MODE:\n\t\t\titmp = ntohl(cmd.param);\n\t\t\tprintf(\"set tuner IF mode to %i: \", itmp);\n\t\t\tif (!itmp)\n\t\t\t\tprintf(\"automatic gain of VGA controlled from RTL2832\\n\");\n\t\t\telse if (-2500 <= itmp && itmp <= 2500)\n\t\t\t\tprintf(\"VGA nearest to %.1f dB)\\n\", itmp/10.0);\n\t\t\telse if (10000 <=itmp && itmp <= 10015)\n\t\t\t\tprintf(\"VGA gain idx %d\\n\", itmp - 10000);\n\t\t\telse if (10016 <= itmp && itmp <= 10031)\n\t\t\t\tprintf(\"VGA gain idx %d - but with automatic gain of VGA controlled from RTL2832\\n\", itmp-10016);\n\t\t\telse\n\t\t\t\tprintf(\"unknown!\\n\");\n\t\t\tr = rtlsdr_set_tuner_if_mode(dev, itmp);\n\t\t\tif (r < 0)\n\t\t\t\tprintf(\"  error setting tuner IF mode!\\n\");\n\t\t\tbreak;\n\t\tcase SET_SIDEBAND:\n\t\t\ttmp = ntohl(cmd.param);\n\t\t\tif(tmp)\n\t\t\t\ttmp = 1;\n\t\t\tprintf(\"set tuner sideband %d: %s sideband\\n\", tmp, (tmp ? \"upper\" : \"lower\") );\n\t\t\tr = rtlsdr_set_tuner_sideband(dev, tmp);\n\t\t\tif (r < 0) {\n\t\t\t\tprintf(\"  error setting tuner sideband!\\n\");\n\t\t\t\tlast_lock_report = -1;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase REPORT_I2C_REGS:\n\t\t\tprintf(\"unsupported command REPORT_I2C_REGS (0x%02x)\\n\", cmd.cmd);\n\t\t\tbreak;\n\t\tcase GPIO_SET_OUTPUT_MODE:\t/* rtlsdr_set_gpio_output() */\n\t\t\titmp = ntohl(cmd.param);\n\t\t\tif ( 0 <= itmp && itmp < 8 )\n\t\t\t{\n\t\t\t\tprintf(\"set gpio pin %d to output\\n\", itmp);\n\t\t\t\tr = rtlsdr_set_gpio_output(dev, (uint8_t)itmp);\n\t\t\t\tif (r < 0)\n\t\t\t\t\tprintf(\"  error setting gpio pin to output mode!\\n\");\n\t\t\t}\n\t\t\telse\n\t\t\t\tprintf(\"set gpio pin %d to output: error: pin has to be in 0 .. 7\\n\", itmp);\n\t\t\tbreak;\n\t\tcase GPIO_SET_INPUT_MODE:\t/* rtlsdr_set_gpio_input() */\n\t\t\titmp = ntohl(cmd.param);\n\t\t\tif ( 0 <= itmp && itmp < 8 )\n\t\t\t{\n\t\t\t\tprintf(\"set gpio pin %d to input\\n\", itmp);\n\t\t\t\tr = rtlsdr_set_gpio_input(dev, (uint8_t)itmp);\n\t\t\t\tif (r < 0)\n\t\t\t\t\tprintf(\"  error setting gpio pin to input mode!\\n\");\n\t\t\t}\n\t\t\telse\n\t\t\t\tprintf(\"set gpio pin %d to input: error: pin has to be in 0 .. 7\\n\", itmp);\n\t\t\tbreak;\n\t\tcase GPIO_GET_IO_STATUS:\t/* rtlsdr_set_gpio_status() */\n\t\t\tr = rtlsdr_set_gpio_status(dev, &iitmp );\n\t\t\tif (r < 0)\n\t\t\t\tprintf(\"error at requesting gpio io status!\\n\");\n\t\t\telse\n\t\t\t\tprintf(\"request for gpio io status: 0x%02x = %d%d%d%d %d%d%d%d for bits 7 .. 0\\n\",\n\t\t\t\t\tiitmp & 0xff,\n\t\t\t\t\t(iitmp >>7) & 1, (iitmp >>6) & 1, (iitmp >>5) & 1, (iitmp >>4) & 1,\n\t\t\t\t\t(iitmp >>3) & 1, (iitmp >>2) & 1, (iitmp >>1) & 1, iitmp & 1 );\n\t\t\tbreak;\n\t\tcase GPIO_WRITE_PIN:\t\t/* rtlsdr_set_gpio_bit() */\n\t\t\titmp = ntohl(cmd.param);\n\t\t\tif ( 0 <= ((itmp >> 16) & 0xffff) && ((itmp >> 16) & 0xffff) < 8 )\n\t\t\t{\n\t\t\t\tprintf(\"write %d to gpio %d\\n\", itmp & 0xffff, (itmp >> 16) & 0xffff);\n\t\t\t\trtlsdr_set_gpio_output(dev, (uint8_t)((itmp >> 16) & 0xffff));\n\t\t\t\trtlsdr_set_gpio_bit(dev, (uint8_t)((itmp >> 16) & 0xffff), itmp & 0xffff);\n\t\t\t}\n\t\t\telse\n\t\t\t\tprintf(\"write %d to gpio %d: error: pin has to be in 0 .. 7\\n\", itmp & 0xffff, (itmp >> 16) & 0xffff);\n\t\t\tbreak;\n\t\tcase GPIO_READ_PIN:\n\t\t\titmp = ntohl(cmd.param);\n\t\t\tif ( 0 <= itmp && itmp < 8 )\n\t\t\t{\n\t\t\t\tr = rtlsdr_get_gpio_bit(dev, itmp, &iitmp);\n\t\t\t\tif (r < 0)\n\t\t\t\t\tprintf(\"  error reading gpio pin!\\n\");\n\t\t\t\telse\n\t\t\t\t\tprintf(\"read gpio pin %d: %d\\n\", itmp, iitmp);\n\t\t\t}\n\t\t\telse\n\t\t\t\tprintf(\"read gpio pin %d out of range: pin has to be in 0 .. 7\\n\", itmp);\n\t\t\tbreak;\n\t\tcase GPIO_GET_BYTE:\n\t\t\tr = rtlsdr_get_gpio_byte(dev, &iitmp);\n\t\t\tif (r < 0)\n\t\t\t\tprintf(\"error reading gpio byte!\\n\");\n\t\t\telse\n\t\t\t\tprintf(\"read gpio byte: 0x%02x = %d%d%d%d %d%d%d%d for bits 7 .. 0\\n\",\n\t\t\t\t\tiitmp & 0xff,\n\t\t\t\t\t(iitmp >>7) & 1, (iitmp >>6) & 1, (iitmp >>5) & 1, (iitmp >>4) & 1,\n\t\t\t\t\t(iitmp >>3) & 1, (iitmp >>2) & 1, (iitmp >>1) & 1, iitmp & 1 );\n\t\t\tbreak;\n\t\tcase IS_TUNER_PLL_LOCKED:\n\t\t\titmp = -1; /* always print lock status */\n\t\t\tcheck_tuner_pll(dev, &tuner_unsupported, &itmp);\n\t\t\tif (itmp != -1)\n\t\t\t\tlast_lock_report = itmp;\n\t\t\ttuner_check_timeout = 0;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tprintf(\"unknown command 0x%02x\\n\", cmd.cmd);\n\t\t\tbreak;\n\t\t}\n\t\tcmd.cmd = 0xff;\n\t}\n}\n\nstruct ir_thread_data\n{\n\trtlsdr_dev_t *dev;\n\tSOCKET port;\n\tint wait;\n\tchar *addr;\n};\n\nvoid *ir_thread_fn(void *arg)\n{\n\tint r = 1;\n\tstruct linger ling = {1,0};\n\tSOCKET listensocket;\n\tSOCKET irsocket;\n\tstruct sockaddr_in local, remote;\n\tsocklen_t rlen;\n\tuint8_t buf[128];\n\tint ret = 0, len;\n\n\tstruct ir_thread_data *data = (struct ir_thread_data *)arg;\n\n\trtlsdr_dev_t *dev = data->dev;\n\tint port = data->port;\n\tint wait = data->wait;\n\tchar *addr = data->addr;\n\n\n\tmemset(&local,0,sizeof(local));\n\tlocal.sin_family = AF_INET;\n\tlocal.sin_port = htons(port);\n\tlocal.sin_addr.s_addr = inet_addr(addr);\n\n\tlistensocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);\n\tr = 1;\n\tsetsockopt(listensocket, SOL_SOCKET, SO_REUSEADDR, (char *)&r, sizeof(int));\n\tsetsockopt(listensocket, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling));\n\tbind(listensocket,(struct sockaddr *)&local,sizeof(local));\n\n\n\twhile(1) {\n\t\tprintf(\"listening on IR port %d...\\n\", port);\n\t\tlisten(listensocket,1);\n\n\t\tirsocket = accept(listensocket,(struct sockaddr *)&remote, &rlen);\n\t\tsetsockopt(irsocket, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling));\n\n\t\tprintf(\"IR client accepted!\\n\");\n\n\t\twhile(1) {\n\t\t    ret = rtlsdr_ir_query(dev, buf, sizeof(buf));\n\t\t    if (ret < 0) {\n\t\t\tprintf(\"rtlsdr_ir_query error %d\\n\", ret);\n\t\t\tbreak;\n\t\t    }\n\n\t\t    len = ret;\n\n\t\t    ret = send(irsocket, buf, len, 0);\n\t\t    if (ret != len){\n\t\t\tprintf(\"incomplete write to ir client: %d != %d\\n\", ret,len);\n\t\t\tbreak;\n\t\t    }\n\n\t\t    usleep(wait);\n\t\t}\n\n\t\tclosesocket(irsocket);\n\t}\n\n\treturn 0;\n}\n\nint main(int argc, char **argv)\n{\n\tint r, opt, i;\n\tchar* addr = \"127.0.0.1\";\n\tint port = 1234;\n\tint port_ir = 0;\n\tint wait_ir = 10000;\n\tpthread_t thread_ir;\n\tuint32_t frequency = 100000000, samp_rate = 2048000;\n\tenum rtlsdr_ds_mode ds_mode = RTLSDR_DS_IQ;\n\tuint32_t ds_temp, ds_threshold = 0;\n\tstruct sockaddr_in local;\n\tuint32_t buf_num = 0;\n\t/* buf_len:\n\t * must be multiple of 512 - else it will be overwritten\n\t * in rtlsdr_read_async() in librtlsdr.c with DEFAULT_BUF_LENGTH (= 16*32 *512 = 512 *512)\n\t *\n\t * -> 512*512 -> 1048 ms @ 250 kS  or  81.92 ms @ 3.2 MS (internal default)\n\t * ->  32*512 ->   65 ms @ 250 kS  or   5.12 ms @ 3.2 MS (new default)\n\t *\n\t * usual soundcard as reference:\n\t *   512 samples @ 48 kHz ~= 10.6 ms\n\t *   512 samples @  8 kHz  = 64 ms\n\t */\n\tuint32_t buf_len = 32 * 512;\n\tconst char * rtlOpts = NULL;\n\tint dev_index = 0;\n\tint dev_given = 0;\n\tint gain = 0;\n\tint ppm_error = 0;\n\tstruct llist *curelem,*prev;\n\tpthread_attr_t attr;\n\tvoid *status;\n\tstruct timeval tv = {1,0};\n//\tstruct linger ling = {1,0};\n//\tSOCKET listensocket;\n\tsocklen_t rlen;\n\tfd_set readfds;\n\tu_long blockmode = 1;\n\tdongle_info_t dongle_info;\n\tint gains[100];\n\tconst char * opt_str = NULL;\n#ifdef _WIN32\n\tWSADATA wsd;\n\ti = WSAStartup(MAKEWORD(2,2), &wsd);\n#else\n\tstruct sigaction sigact, sigign;\n#endif\n\n\topt_str = \"a:p:f:g:s:b:n:d:P:O:TI:W:l:w:D:v\";\n\twhile ((opt = getopt(argc, argv, opt_str)) != -1) {\n\t\tswitch (opt) {\n\t\tcase 'd':\n\t\t\tdev_index = verbose_device_search(optarg);\n\t\t\tdev_given = 1;\n\t\t\tbreak;\n\t\tcase 'f':\n\t\t\tfrequency = (uint32_t)atofs(optarg);\n\t\t\tbreak;\n\t\tcase 'g':\n\t\t\tgain = (int)(atof(optarg) * 10); /* tenths of a dB */\n\t\t\tbreak;\n\t\tcase 's':\n\t\t\tsamp_rate = (uint32_t)atofs(optarg);\n\t\t\tbreak;\n\t\tcase 'a':\n\t\t\taddr = optarg;\n\t\t\tbreak;\n\t\tcase 'p':\n\t\t\tport = atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'I':\n\t\t\tport_ir = atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'W':\n\t\t\twait_ir = atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'b':\n\t\t\tbuf_num = atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'l':\n\t\t\tbuf_len = 512 * atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'n':\n\t\t\tllbuf_num = atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'P':\n\t\t\tppm_error = atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'O':\n\t\t\trtlOpts = optarg;\n\t\t\tbreak;\n\t\tcase 'T':\n\t\t\tenable_biastee = 1;\n\t\t\tbreak;\n\t\tcase 'w':\n\t\t\tbandwidth = (uint32_t)atofs(optarg);\n\t\t\tbreak;\n\t\tcase 'v':\n\t\t\t++verbosity;\n\t\t\tbreak;\n\t\tcase 'D':\n\t\t\tds_temp = (uint32_t)( atofs(optarg) + 0.5 );\n\t\t\tif (ds_temp <= RTLSDR_DS_Q_BELOW)\n\t\t\t\tds_mode = (enum rtlsdr_ds_mode)ds_temp;\n\t\t\telse\n\t\t\t\tds_threshold = ds_temp;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tusage();\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (argc < optind)\n\t\tusage();\n\n\tif (verbosity)\n\t\tfprintf(stderr, \"verbosity set to %d\\n\", verbosity);\n\n\tif (!dev_given) {\n\t\tdev_index = verbose_device_search(\"0\");\n\t}\n\n\tif (dev_index < 0) {\n\t    exit(1);\n\t}\n\n\trtlsdr_open(&dev, (uint32_t)dev_index);\n\tif (NULL == dev) {\n\tfprintf(stderr, \"Failed to open rtlsdr device #%d.\\n\", dev_index);\n\t\texit(1);\n\t}\n\n#ifndef _WIN32\n\tsigact.sa_handler = sighandler;\n\tsigemptyset(&sigact.sa_mask);\n\tsigact.sa_flags = 0;\n\tsigign.sa_handler = SIG_IGN;\n\tsigaction(SIGINT, &sigact, NULL);\n\tsigaction(SIGTERM, &sigact, NULL);\n\tsigaction(SIGQUIT, &sigact, NULL);\n\tsigaction(SIGPIPE, &sigign, NULL);\n#else\n\tSetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE );\n#endif\n\n\t/* Set the tuner error */\n\tverbose_ppm_set(dev, ppm_error);\n\n\t/* Set the sample rate */\n\tr = rtlsdr_set_sample_rate(dev, samp_rate);\n\tif (r < 0)\n\t\tfprintf(stderr, \"WARNING: Failed to set sample rate.\\n\");\n\n\tif (rtlOpts) {\n\t\trtlsdr_set_opt_string(dev, rtlOpts, verbosity);\n\t}\n\n\t/* Set direct sampling with threshold */\n\trtlsdr_set_ds_mode(dev, ds_mode, ds_threshold);\n\n\t/* Set the frequency */\n\tr = rtlsdr_set_center_freq(dev, frequency);\n\tif (r < 0)\n\t\tfprintf(stderr, \"WARNING: Failed to set center freq.\\n\");\n\telse\n\t\tfprintf(stderr, \"Tuned to %i Hz.\\n\", frequency);\n\n\tif (0 == gain) {\n\t\t /* Enable automatic gain */\n\t\tr = rtlsdr_set_tuner_gain_mode(dev, 0);\n\t\tif (r < 0)\n\t\t\tfprintf(stderr, \"WARNING: Failed to enable automatic gain.\\n\");\n\t} else {\n\t\t/* Enable manual gain */\n\t\tr = rtlsdr_set_tuner_gain_mode(dev, 1);\n\t\tif (r < 0)\n\t\t\tfprintf(stderr, \"WARNING: Failed to enable manual gain.\\n\");\n\n\t\t/* Set the tuner gain */\n\t\tr = rtlsdr_set_tuner_gain(dev, gain);\n\t\tif (r < 0)\n\t\t\tfprintf(stderr, \"WARNING: Failed to set tuner gain.\\n\");\n\t\telse\n\t\t\tfprintf(stderr, \"Tuner gain set to %f dB.\\n\", gain/10.0);\n\t}\n\tverbose_set_bandwidth(dev, bandwidth);\n\n\trtlsdr_set_bias_tee(dev, enable_biastee);\n\tif (enable_biastee)\n\t\tfprintf(stderr, \"activated bias-T on GPIO PIN 0\\n\");\n\n\t/* Reset endpoint before we start reading from it (mandatory) */\n\tr = rtlsdr_reset_buffer(dev);\n\tif (r < 0)\n\t\tfprintf(stderr, \"WARNING: Failed to reset buffers.\\n\");\n\n\tpthread_mutex_init(&exit_cond_lock, NULL);\n\tpthread_mutex_init(&ll_mutex, NULL);\n\tpthread_mutex_init(&exit_cond_lock, NULL);\n\tpthread_cond_init(&cond, NULL);\n\tpthread_cond_init(&exit_cond, NULL);\n\n\tif (port_ir) {\n\t\tstruct ir_thread_data data = {.dev = dev, .port = port_ir, .wait = wait_ir, .addr = addr};\n\n\t\tpthread_create(&thread_ir, NULL, &ir_thread_fn, (void *)(&data));\n\t}\n\n\n\tmemset(&local,0,sizeof(local));\n\tlocal.sin_family = AF_INET;\n\tlocal.sin_port = htons(port);\n\tlocal.sin_addr.s_addr = inet_addr(addr);\n\n\ts = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);\n\tr = 1;\n\tbind(s,(struct sockaddr *)&local,sizeof(local));\n\n#ifdef _WIN32\n\tioctlsocket(s, FIONBIO, &blockmode);\n#else\n\tr = fcntl(s, F_GETFL, 0);\n\tr = fcntl(s, F_SETFL, r | O_NONBLOCK);\n#endif\n\n\twhile(1) {\n\t\tprintf(\"listening...\\n\");\n\t\tprintf(\"Use the device argument 'rtl_tcp=%s:%d' in OsmoSDR \"\n\t\t       \"(gr-osmosdr) source\\n\"\n\t\t       \"to receive samples in GRC and control \"\n\t\t       \"rtl_udp parameters (frequency, gain, ...).\\n\",\n\t\t       addr, port);\n\n\t\twhile(1) {\n\t\t\tFD_ZERO(&readfds);\n\t\t\tFD_SET(s, &readfds);\n\t\t\ttv.tv_sec = 1;\n\t\t\ttv.tv_usec = 0;\n\t\t\tr = select(s+1, &readfds, NULL, NULL, &tv);\n\t\t\tif(do_exit) {\n\t\t\t\tgoto out;\n\t\t\t} else if(r) {\n\t\t\t\tchar buff = 0;\n\t\t\t\tsocklen_t blen = sizeof(buff);\n\t\t\t\trlen = sizeof(remote);\n\t\t\t\tr = recvfrom(s, &buff, blen, 0, (struct sockaddr *)&remote, &rlen);\n\t\t\t\tif(buff == UDP_ESTABLISH)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tprintf(\"client accepted!\\n\");\n\n\t\tmemset(&dongle_info, 0, sizeof(dongle_info));\n\t\tmemcpy(&dongle_info.magic, \"RTL0\", 4);\n\n\t\tr = rtlsdr_get_tuner_type(dev);\n\t\tif (r >= 0)\n\t\t\tdongle_info.tuner_type = htonl(r);\n\n\t\tr = rtlsdr_get_tuner_gains(dev, gains);\n\t\tif (r >= 0)\n\t\t\tdongle_info.tuner_gain_count = htonl(r);\n\t\tif (verbosity)\n\t\t{\n\t\t\tfprintf(stderr, \"Supported gain values (%d): \", r);\n\t\t\tfor (i = 0; i < r; i++)\n\t\t\t\tfprintf(stderr, \"%.1f \", gains[i] / 10.0);\n\t\t\tfprintf(stderr, \"\\n\");\n\t\t}\n\n\t\tr = sendto(s, (const char *)&dongle_info, sizeof(dongle_info), 0, (struct sockaddr *)&remote, sizeof(remote));\n\t\tif (sizeof(dongle_info) != r)\n\t\t\tprintf(\"failed to send dongle information\\n\");\n\n\t\tpthread_attr_init(&attr);\n\t\tpthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);\n\t\tr = pthread_create(&tcp_worker_thread, &attr, udp_worker, NULL);\n\t\tr = pthread_create(&command_thread, &attr, command_worker, NULL);\n\t\tpthread_attr_destroy(&attr);\n\n\t\tr = rtlsdr_read_async(dev, rtlsdr_callback, NULL, buf_num, buf_len);\n\n\t\tpthread_join(tcp_worker_thread, &status);\n\t\tpthread_join(command_thread, &status);\n\n\t\tprintf(\"all threads dead..\\n\");\n\t\tcurelem = ll_buffers;\n\t\tll_buffers = 0;\n\n\t\twhile(curelem != 0) {\n\t\t\tprev = curelem;\n\t\t\tcurelem = curelem->next;\n\t\t\tfree(prev->data);\n\t\t\tfree(prev);\n\t\t}\n\n\t\tdo_exit = 0;\n\t\tglobal_numq = 0;\n\t}\n\nout:\n\trtlsdr_close(dev);\n\t/* if (port_ir) pthread_join(thread_ir, &status); */\n\tclosesocket(s);\n#ifdef _WIN32\n\tWSACleanup();\n#endif\n\tprintf(\"bye!\\n\");\n\treturn r >= 0 ? r : -r;\n}\n"
  },
  {
    "path": "src/rtl_wavestat.c",
    "content": "/*\n * rtl-wavestat, display wave file meta information\n * Copyright (C) 2019 by Hayati Ayguen <h_ayguen@web.de>\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <errno.h>\n#include <signal.h>\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <math.h>\n\n#ifndef _WIN32\n  #include <unistd.h>\n  #include <sys/types.h>\n  #include <sys/stat.h>\n\n#else\n  #include <windows.h>\n  #include <fcntl.h>\n  #include <io.h>\n  #include <sys/types.h>\n  #include <sys/stat.h>\n\n  #include \"getopt/getopt.h\"\n\n  #if defined(_MSC_VER) && (_MSC_VER < 1900)\n    #define snprintf _snprintf\n  #endif\n#endif\n\n#include <rtl_app_ver.h>\n#include \"convenience/convenience.h\"\n#include \"convenience/waveread.h\"\n\n\nstatic volatile int do_exit = 0;\nstatic int verbosity = 0;\n\n\nvoid usage(void)\n{\n\tfprintf(stderr,\n\t\t\"rtl_wavestat, display wave file meta information\\n\"\n\t\t\"rtl_wavestat version %d.%d %s (%s)\\n\\n\",\n\t\tAPP_VER_MAJOR, APP_VER_MINOR, APP_VER_ID, __DATE__ );\n\tfprintf(stderr,\n\t\t\"Use:\\trtl_wavestat [-options] <input_wave_filename>\\n\"\n\t\t\"\\t-a  print all information\\n\"\n\t\t\"\\t-r  print without field name\\n\"\n\t\t\"\\t-f  print center frequency in Hz\\n\"\n\t\t\"\\t-s  print samplerate in Hz\\n\"\n\t\t\"\\t-c  print number of channels\\n\"\n\t\t\"\\t-b  print number of bits per sample\\n\"\n\t\t\"\\t-F  print sample Format\\n\"\n\t\t\"\\t-u  print start time in UTC:       'yyy-mm-ddThh:mm:dd.zzz'\\n\"\n\t\t\"\\t-t  print start time in localtime: 'yyy-mm-ddThh:mm:dd.zzz'\\n\"\n\t\t\"\\t-z  print start time in seconds since 1970-01-01T00:00:00.000\\n\"\n\t\t\"\\t-d  print file duration in frames (= num samples per channel)\\n\"\n\t\t\"\\t-D  print file duration in seconds\\n\"\n\t\t\"\\t-w  input file\\n\"\n\t\t\"\\t-v  verbose output\\n\" );\n}\n\n#ifdef _WIN32\nBOOL WINAPI\nsighandler(int signum)\n{\n\tif (CTRL_C_EVENT == signum) {\n\t\tfprintf(stderr, \"Signal caught, exiting!\\n\");\n\t\tdo_exit = 1;\n\t\treturn TRUE;\n\t}\n\treturn FALSE;\n}\n#else\nstatic void sighandler(int signum)\n{\n\tfprintf(stderr, \"Signal caught, exiting!\\n\");\n\tdo_exit = 1;\n}\n#endif\n\n\nint main(int argc, char **argv)\n{\n#ifndef _WIN32\n\tstruct sigaction sigact;\n#endif\n\tint r, opt;\n\tconst char * wavfilename = NULL;\n\tFILE * inpfile = stdin;\n\tuint32_t freq = 0;\n\tuint32_t srate = 0;\n\tint nChan = 0;\n\tint nBits = 0;\n\tint16_t formatTag;\n\tuint32_t numFrames;\n\ttime_t tim = 0;\n\tdouble fraction = 0.0;\n\tstruct tm *ptm = NULL;\n\tint printAll = 0;\n\tint printFieldName = 1;\n\tint printFreq = 0;\n\tint printSRate = 0;\n\tint printNchan = 0;\n\tint printNbits = 0;\n\tint printSmpFmt = 0;\n\tint printStartZ = 0;\n\tint printStartL = 0;\n\tint printStartUnix = 0;\n\tint printDurationSmp = 0;\n\tint printDurationTim = 0;\n\n\twhile ((opt = getopt(argc, argv, \"arfscbFutzdDvhw:\")) != -1) {\n\t\tswitch (opt) {\n\t\tcase 'a':\tprintAll = 1;\tbreak;\n\t\tcase 'r':\tprintFieldName = 0;\tbreak;\n\t\tcase 'f':\tprintFreq = 1;\tbreak;\n\t\tcase 's':\tprintSRate = 1;\tbreak;\n\t\tcase 'c':\tprintNchan = 1;\tbreak;\n\t\tcase 'b':\tprintNbits = 1;\tbreak;\n\t\tcase 'F':\tprintSmpFmt = 1;\tbreak;\n\t\tcase 'u':\tprintStartZ = 1;\tbreak;\n\t\tcase 't':\tprintStartL = 1;\tbreak;\n\t\tcase 'z':\tprintStartUnix = 1;\tbreak;\n\t\tcase 'd':\tprintDurationSmp = 1;\tbreak;\n\t\tcase 'D':\tprintDurationTim = 1;\tbreak;\n\t\tcase 'w':\twavfilename = optarg;\tbreak;\n\t\tcase 'v':\t++verbosity;\tbreak;\n\t\tcase 'h':\n\t\tcase '?':\n\t\tdefault:\n\t\t\tusage();\n\t\t\texit(1);\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (verbosity)\n\t\tfprintf(stderr, \"verbosity set to %d\\n\", verbosity);\n\n\tif (optind < argc) {\n\t\twavfilename = argv[optind];\n\t}\n\n#ifndef _WIN32\n\tsigact.sa_handler = sighandler;\n\tsigemptyset(&sigact.sa_mask);\n\tsigact.sa_flags = 0;\n\tsigaction(SIGINT, &sigact, NULL);\n\tsigaction(SIGTERM, &sigact, NULL);\n\tsigaction(SIGQUIT, &sigact, NULL);\n\tsigaction(SIGPIPE, &sigact, NULL);\n#else\n\tSetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE );\n#endif\n\n\tif (!wavfilename || !strcmp(wavfilename, \"-\")) {\n#ifdef _WIN32\n\t\t_setmode(_fileno(stdin), _O_BINARY);\n#endif\n\t\tinpfile = stdin;\n\t\tif (verbosity)\n\t\t\tfprintf(stderr, \"Using stdin as input\\n\");\n\t} else {\n\t\tif (verbosity >= 2)\n\t\t\tfprintf(stderr, \"Opening input '%s'\\n\", wavfilename);\n\t\tinpfile = fopen(wavfilename, \"rb\");\n\t\tif (!inpfile) {\n\t\t\tfprintf(stderr, \"Error: Failed to open input %s\\n\", wavfilename);\n\t\t\texit(1);\n\t\t}\n\t\tif (verbosity)\n\t\t\tfprintf(stderr, \"Opened '%s' for input\\n\", wavfilename);\n\t}\n\n\tr = waveReadHeader(inpfile, &srate, &freq, &nBits, &nChan, &numFrames, &formatTag, verbosity);\n\tif ( r >= 10 ) {\n\t\tfprintf(stderr, \"Error %d reading/evaluating wave file header\\n\", r);\n\t\texit(1);\n\t} else if ( verbosity >= 2 ) {\n\t\tfprintf(stderr, \"Success reading/evaluating wave file header\\n\");\n\t}\n\n\tif ( !printFreq && !printSRate && !printNchan && !printNbits && !printSmpFmt && !printStartZ && !printStartL\n\t\t&& !printDurationSmp && !printDurationTim ) {\n\t\tprintAll = 1;\n\t}\n\n\tif ( printAll || printFreq ) {\n\t\tif ( printFieldName )\n\t\t\tfprintf(stdout, \"frequency/Hz:\\t\");\n\t\tfprintf(stdout, \"%lu\\n\", (unsigned long)freq);\n\t}\n\tif ( printAll || printSRate ) {\n\t\tif ( printFieldName )\n\t\t\tfprintf(stdout, \"samplerate/Hz:\\t\");\n\t\tfprintf(stdout, \"%lu\\n\", (unsigned long)srate);\n\t}\n\tif ( printAll || printNchan ) {\n\t\tif ( printFieldName )\n\t\t\tfprintf(stdout, \"num_channels:\\t\");\n\t\tfprintf(stdout, \"%d\\n\", nChan);\n\t}\n\tif ( printAll || printNbits ) {\n\t\tif ( printFieldName )\n\t\t\tfprintf(stdout, \"bits_per_sample:\\t\");\n\t\tfprintf(stdout, \"%d\\n\", nBits);\n\t}\n\tif ( printAll || printSmpFmt ) {\n\t\tif ( printFieldName )\n\t\t\tfprintf(stdout, \"sample_format:\\t\");\n\t\tif (formatTag == 0x0001)\n\t\t\tfprintf(stdout, \"0x%04X\\tPCM\\n\", (unsigned)formatTag);\n\t\telse if (formatTag == 0x0003)\n\t\t\tfprintf(stdout, \"0x%04X\\tIEEE_FLOAT\\n\", (unsigned)formatTag);\n\t\telse\n\t\t\tfprintf(stdout, \"0x%04X\\n\", (unsigned)formatTag);\n\t}\n\tif ( printAll || printStartZ ) {\n\t\twaveGetStartTime(&tim, &fraction);\n\t\tptm = gmtime(&tim);\n\t\tif (ptm) {\n\t\t\tif ( printFieldName )\n\t\t\t\tfprintf(stdout, \"time_start/Z:\\t\");\n\t\t\tfprintf(stdout, \"%04d-%02d-%02dT%02d:%02d:%02d.%03d\\n\"\n\t\t\t\t, ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday\n\t\t\t\t, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, (int)(fraction*1000.0) );\n\t\t}\n\t}\n\tif ( printAll || printStartL ) {\n\t\twaveGetStartTime(&tim, &fraction);\n\t\tptm = localtime(&tim);\n\t\tif (ptm) {\n\t\t\tif ( printFieldName )\n\t\t\t\tfprintf(stdout, \"time_start/L:\\t\");\n\t\t\tfprintf(stdout, \"%04d-%02d-%02dT%02d:%02d:%02d.%03d\\n\"\n\t\t\t\t, ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday\n\t\t\t\t, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, (int)(fraction*1000.0) );\n\t\t}\n\t}\n\tif ( printAll || printStartUnix ) {\n\t\ttim = 0;\n\t\tfraction = 0;\n\t\twaveGetStartTime(&tim, &fraction);\n\t\tif ( printFieldName )\n\t\t\tfprintf(stdout, \"time_start/secs (unix):\\t\");\n\t\tfraction += (double)tim;\n\t\tfprintf(stdout, \"%f\\n\", fraction );\n\t}\n\tif ( printAll || printDurationSmp ) {\n\t\tif ( printFieldName )\n\t\t\tfprintf(stdout, \"duration/frames:\\t\");\n\t\tfprintf(stdout, \"%lu\\n\", (unsigned long)numFrames);\n\t}\n\tif ( printAll || printDurationTim ) {\n\t\tif ( printFieldName )\n\t\t\tfprintf(stdout, \"duration/secs:\\t\");\n\t\tfprintf(stdout, \"%f\\n\", (double)numFrames/(double)srate);\n\t}\n\n\tif (inpfile != stdin)\n\t\tfclose(inpfile);\n\n\treturn 0;\n}\n\n/* vim: tabstop=8:softtabstop=8:shiftwidth=8:noexpandtab */\n"
  },
  {
    "path": "src/rtl_wavestream.c",
    "content": "/*\n * rtl-wavestream, stream raw data (in specified sample format)\n * Copyright (C) 2019 by Hayati Ayguen <h_ayguen@web.de>\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <errno.h>\n#include <signal.h>\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <math.h>\n\n#ifndef _WIN32\n  #include <unistd.h>\n  #include <sys/types.h>\n  #include <sys/stat.h>\n\n#else\n  #include <windows.h>\n  #include <fcntl.h>\n  #include <io.h>\n  #include <sys/types.h>\n  #include <sys/stat.h>\n\n  #include \"getopt/getopt.h\"\n\n  #if defined(_MSC_VER) && (_MSC_VER < 1900)\n    #define snprintf _snprintf\n  #endif\n#endif\n\n#include <rtl_app_ver.h>\n#include \"convenience/convenience.h\"\n#include \"convenience/waveread.h\"\n\n\nstatic volatile int do_exit = 0;\nstatic int verbosity = 0;\n\n#define BLOCKLEN 65536\n\n/* read up to 64K samples */\nstatic uint8_t inpBuffer[BLOCKLEN * sizeof(int32_t)];\n/* output is max 4 times bigger: uint8_t -> int32_t */\nstatic uint8_t outBuffer[BLOCKLEN * sizeof(int32_t) * sizeof(int32_t)];\n\nvoid usage(void)\n{\n\tfprintf(stderr,\n\t\t\"rtl_wavestream, stream raw data (in specified format)\\n\"\n\t\t\"rtl_wavestream version %d.%d %s (%s)\\n\\n\",\n\t\tAPP_VER_MAJOR, APP_VER_MINOR, APP_VER_ID, __DATE__ );\n\tfprintf(stderr,\n\t\t\"Usage:\\trtl_wavestream [-options] <input_wave_filename>\\n\"\n\t\t\"\\t-f <fmt>  sample format for output. default = input format\\n\"\n\t\t\"\\t            supported formats: 'PCM16'/'PCM' or 'FLOAT32'/'FLOAT'\\n\"\n\t\t\"\\t-w  input file\\n\"\n\t\t\"\\t-v        verbose output\\n\" );\n}\n\n#ifdef _WIN32\nBOOL WINAPI\nsighandler(int signum)\n{\n\tif (CTRL_C_EVENT == signum) {\n\t\tfprintf(stderr, \"Signal caught, exiting!\\n\");\n\t\tdo_exit = 1;\n\t\treturn TRUE;\n\t}\n\treturn FALSE;\n}\n#else\nstatic void sighandler(int signum)\n{\n\tfprintf(stderr, \"Signal caught, exiting!\\n\");\n\tdo_exit = 1;\n}\n#endif\n\n\nint main(int argc, char **argv)\n{\n#ifndef _WIN32\n\tstruct sigaction sigact;\n#endif\n\tint r, opt;\n\tconst char * wavfilename = NULL;\n\tconst char * targetFmtStr = \"pcm16\";\n\tFILE * inpfile = NULL;\n\tuint32_t freq = 0;\n\tuint32_t srate = 0;\n\tint nChan = 0;\n\tint nBits = 0;\n\tint targetFmt = 0;  /* PCM16 = 0, FLOAT32 = 1 */\n\tint inputFmt = 0;   /* PCM16 = 0, FLOAT32 = 1 */\n\tint16_t formatTag;\n\tuint32_t numFrames;\n\n\twhile ((opt = getopt(argc, argv, \"f:w:vh\")) != -1) {\n\t\tswitch (opt) {\n\t\tcase 'f':\ttargetFmtStr = optarg;\t\tbreak;\n\t\tcase 'w':\twavfilename = optarg;\tbreak;\n\t\tcase 'v':\t++verbosity;\tbreak;\n\t\tcase 'h':\n\t\tcase '?':\n\t\tdefault:\n\t\t\tusage();\n\t\t\texit(1);\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (verbosity)\n\t\tfprintf(stderr, \"verbosity set to %d\\n\", verbosity);\n\n\tif (optind < argc) {\n\t\twavfilename = argv[optind];\n\t}\n\n\tif ( !strcmp(targetFmtStr, \"pcm\") || !strcmp(targetFmtStr, \"pcm16\")\n\t\t|| !strcmp(targetFmtStr, \"PCM\") || !strcmp(targetFmtStr, \"PCM16\") )\n\t{\n\t\ttargetFmt = 0;  /* PCM16 = 0, FLOAT32 = 1 */\n\t\tif (verbosity)\n\t\t\tfprintf(stderr, \"target sample format: PCM16\\n\");\n\t}\n\telse if ( !strcmp(targetFmtStr, \"flt32\") || !strcmp(targetFmtStr, \"float32\") || !strcmp(targetFmtStr, \"float\")\n\t\t|| !strcmp(targetFmtStr, \"FLT32\") || !strcmp(targetFmtStr, \"FLOAT32\") || !strcmp(targetFmtStr, \"FLOAT\") )\n\t{\n\t\ttargetFmt = 1;  /* PCM16 = 0, FLOAT32 = 1 */\n\t\tif (verbosity)\n\t\t\tfprintf(stderr, \"target sample format: FLOAT32\\n\");\n\t}\n\telse\n\t{\n\t\tfprintf(stderr, \"Error: unsupported target format. accepting 'PCM16'/'PCM' or 'FLOAT32'/'FLOAT'\\n\");\n\t\texit(1);\n\t}\n\n\n#ifndef _WIN32\n\tsigact.sa_handler = sighandler;\n\tsigemptyset(&sigact.sa_mask);\n\tsigact.sa_flags = 0;\n\tsigaction(SIGINT, &sigact, NULL);\n\tsigaction(SIGTERM, &sigact, NULL);\n\tsigaction(SIGQUIT, &sigact, NULL);\n\tsigaction(SIGPIPE, &sigact, NULL);\n#else\n\tSetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE );\n#endif\n\n#ifdef _WIN32\n\t\t_setmode(_fileno(stdout), _O_BINARY);\n#endif\n\n\tif (!wavfilename) {\n\t\tfprintf(stderr, \"Error: No input file specified!\\n\");\n\t\texit(1);\n\t} else {\n\t\tif (verbosity >= 2)\n\t\t\tfprintf(stderr, \"Opening input '%s'\\n\", wavfilename);\n\t\tinpfile = fopen(wavfilename, \"rb\");\n\t\tif (!inpfile) {\n\t\t\tfprintf(stderr, \"Error: Failed to open input %s\\n\", wavfilename);\n\t\t\texit(1);\n\t\t}\n\t\tif (verbosity)\n\t\t\tfprintf(stderr, \"Opened '%s' for input\\n\", wavfilename);\n\t}\n\n\tr = waveReadHeader(inpfile, &srate, &freq, &nBits, &nChan, &numFrames, &formatTag, verbosity);\n\tif ( r >= 10 ) {\n\t\tfprintf(stderr, \"Error %d reading/evaluating wave file header\\n\", r);\n\t} else if ( verbosity >= 2 ) {\n\t\tfprintf(stderr, \"Success reading/evaluating wave file header\\n\");\n\t}\n\n\tif ( verbosity ) {\n\t\tfprintf(stderr, \"frequency/Hz:\\t%lu\\n\", (unsigned long)freq);\n\t\tfprintf(stderr, \"samplerate/Hz:\\t%lu\\n\", (unsigned long)srate);\n\t\tfprintf(stderr, \"num_channels:\\t%d\\n\", nChan);\n\t\tfprintf(stderr, \"bits_per_sample:\\t%d\\n\", nBits);\n\t\tif (formatTag == 0x0001)\n\t\t\tfprintf(stderr, \"sample_format:\\t0x%04X\\tPCM\\n\", (unsigned)formatTag);\n\t\telse if (formatTag == 0x0003)\n\t\t\tfprintf(stderr, \"sample_format:\\t0x%04X\\tIEEE_FLOAT\\n\", (unsigned)formatTag);\n\t\telse\n\t\t\tfprintf(stderr, \"sample_format:\\t0x%04X\\n\", (unsigned)formatTag);\n\t\tfprintf(stderr, \"duration/frames:\\t%lu\\t0x%lX\\n\", (unsigned long)numFrames, (unsigned long)numFrames);\n\t\tfprintf(stderr, \"duration/secs:\\t%f\\n\", (double)numFrames/(double)srate);\n\t}\n\n\tif ( formatTag == 0x0001 && nBits == 16 ) {\n\t\tinputFmt = 0;\n\t\tif (verbosity)\n\t\t\tfprintf(stderr, \"input sample format: PCM16\\n\");\n\t}\n\telse if ( formatTag == 0x0003 && nBits == 32 ) {\n\t\tinputFmt = 1;\n\t\tif (verbosity)\n\t\t\tfprintf(stderr, \"input sample format: FLOAT32\\n\");\n\t}\n\telse\n\t{\n\t\tfprintf(stderr, \"Error: unsupported input format. only 'PCM16' and 'FLOAT32' supported.\\n\");\n\t\texit(1);\n\t}\n\n\t{\n\t\tvoid * pvInp = &inpBuffer[0];\n\t\tvoid * pvOut = &outBuffer[0];\n\t\tconst size_t numFramesPerRead = BLOCKLEN / nChan;\n\t\tconst size_t numSmpPerRead = numFramesPerRead * nChan;\n\t\tconst size_t inpSmpSize = (inputFmt  == 0) ? sizeof(int16_t) : sizeof(float);\n\t\tconst size_t outSmpSize = (targetFmt == 0) ? sizeof(int16_t) : sizeof(float);\n\t\tsize_t numSamples = numFrames * nChan;\n\t\tsize_t readTotal = 0;\n\t\tsize_t numRead;\n\n\t\tif ( verbosity )\n\t\t{\n\t\t\tfprintf(stderr, \"input  sample size = %u\\n\", (unsigned)inpSmpSize);\n\t\t\tfprintf(stderr, \"output sample size = %u\\n\", (unsigned)outSmpSize);\n\t\t\tfprintf(stderr, \"samples per read = %u smp\\n\", (unsigned)numSmpPerRead);\n\t\t}\n\n\t\twhile ( !do_exit )\n\t\t{\n\t\t\tconst size_t numToRead = numSmpPerRead;\n\t\t\tconst size_t readErr = waveReadSamples(inpfile, pvInp, numToRead, 0, &numRead);\n\t\t\tif ( numRead != numToRead )\n\t\t\t\tfprintf(stderr, \"Error: reading %lu delivered %lu smp after %lu smp - left %lu frames\\n\"\n\t\t\t\t\t, (unsigned long)numToRead, (unsigned long)numRead\n\t\t\t\t\t, (unsigned long)readTotal, (unsigned long)(numSamples / nChan) );\n\t\t\tif ( readErr )\n\t\t\t{\n\t\t\t\tfprintf(stderr, \"Error reading samples after %lu smp - left %lu frames\\n\"\n\t\t\t\t\t, (unsigned long)readTotal, (unsigned long)(numSamples / nChan) );\n\t\t\t}\n\t\t\telse if ( verbosity >= 2 )\n\t\t\t\tfprintf(stderr, \"read %lu samples: left frames: %lu\\n\"\n\t\t\t\t\t, (unsigned long)numToRead, (unsigned long)numSamples);\n\t\t\tif ( !numRead )\n\t\t\t\tbreak;\n\n\t\t\tif ( inputFmt == targetFmt ) {\n\t\t\t\tsize_t w = fwrite(pvInp, inpSmpSize, numRead, stdout);\n\t\t\t\tif ( w != numRead ) {\n\t\t\t\t\tfprintf(stderr, \"Error writing read samples after %lu smp - left %lu frames\\n\"\n\t\t\t\t\t\t, (unsigned long)readTotal, (unsigned long)(numSamples / nChan) );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( inputFmt == 0 && targetFmt == 1 ) {\n\t\t\t\tconst int16_t *ai = (const int16_t*)pvInp;\n\t\t\t\tfloat * ao = (float*)pvOut;\n\t\t\t\tsize_t w, k;\n\t\t\t\tfor ( k = 0; k < numRead; ++k )\n\t\t\t\t\tao[k] = ai[k] * (1.0F / 32768.0F);\n\t\t\t\tw = fwrite(pvOut, outSmpSize, numRead, stdout);\n\t\t\t\tif ( w != numRead ) {\n\t\t\t\t\tfprintf(stderr, \"Error writing converted samples after %lu smp - left %lu frames\\n\"\n\t\t\t\t\t\t, (unsigned long)readTotal, (unsigned long)(numSamples / nChan) );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( inputFmt == 1 && targetFmt == 0 ) {\n\t\t\t\tconst float *ai = (const float*)pvInp;\n\t\t\t\tint16_t * ao = (int16_t*)pvOut;\n\t\t\t\tsize_t w, k;\n\t\t\t\tfor ( k = 0; k < numRead; ++k )\n\t\t\t\t\tao[k] = (int16_t)( ai[k] * 32768.0F );\n\t\t\t\tw = fwrite(pvOut, outSmpSize, numRead, stdout);\n\t\t\t\tif ( w != numRead ) {\n\t\t\t\t\tfprintf(stderr, \"Error writing converted samples after %lu smp - left %lu frames\\n\"\n\t\t\t\t\t\t, (unsigned long)readTotal, (unsigned long)(numSamples / nChan) );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tnumSamples -= numRead;\n\t\t\treadTotal += numRead;\n\t\t}\n\n\t\tif ( verbosity )\n\t\t{\n\t\t\tfprintf(stderr, \"Written %lu samples in total - left %lu of %lu frames\\n\"\n\t\t\t\t, (unsigned long)readTotal, (unsigned long)(numSamples / nChan), (unsigned long)(numFrames * nChan) );\n\t\t}\n\t}\n\n\tfclose(inpfile);\n\n\treturn 0;\n}\n\n/* vim: tabstop=8:softtabstop=8:shiftwidth=8:noexpandtab */\n"
  },
  {
    "path": "src/rtlsdr.rc.in",
    "content": "\n#include <windows.h>\n\nVS_VERSION_INFO VERSIONINFO\n  FILEVERSION 0,0,0,0\n  PRODUCTVERSION 0,0,0,0\n  FILEFLAGSMASK 0x3fL\n#ifndef NDEBUG\n  FILEFLAGS 0x0L\n#else\n  FILEFLAGS 0x1L\n#endif\n  FILEOS VOS__WINDOWS32\n  FILETYPE VFT_DLL\n  FILESUBTYPE VFT2_DRV_INSTALLABLE\n  BEGIN\n    BLOCK \"StringFileInfo\"\n    BEGIN\n      BLOCK \"040904b0\"\n      BEGIN\n        VALUE \"FileDescription\", \"osmocom rtl-sdr\"\n        VALUE \"FileVersion\", \"@VERSION@\"\n        VALUE \"InternalName\", \"rtl-sdr.dll\"\n        VALUE \"LegalCopyright\", \"Licensed under GPLv2\"\n        VALUE \"OriginalFilename\", \"rtl-sdr.dll\"\n        VALUE \"ProductName\", \"github.com/librtlsdr/librtlsdr\"\n        VALUE \"ProductVersion\", \"@VERSION@\"\n      END\n    END\n    BLOCK \"VarFileInfo\"\n    BEGIN\n      VALUE \"Translation\", 0x409, 1200\n    END\n  END\n"
  },
  {
    "path": "src/rtlsdr_rpc.c",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <unistd.h>\n#include <stddef.h>\n#include <string.h>\n#include <errno.h>\n#include <time.h>\n#include <pthread.h>\n#include <sys/types.h>\n#include <sys/select.h>\n#include <sys/socket.h>\n#include <sys/fcntl.h>\n#include <sys/time.h>\n#include <netinet/in.h>\n#include <netdb.h>\n#include \"rtlsdr_rpc_msg.h\"\n\n\n#if 1\n#include <stdio.h>\n#define PRINTF(__s, ...) fprintf(stderr, __s, ##__VA_ARGS__)\n#define TRACE() PRINTF(\"[t] %s,%u\\n\", __FILE__, __LINE__)\n#define ERROR() PRINTF(\"[e] %s,%u\\n\", __FILE__, __LINE__)\n#define UNIMPL() PRINTF(\"[u] %s,%u\\n\", __FILE__, __LINE__)\n#else\n#define PRINTF(...)\n#define TRACE()\n#define ERROR()\n#define UNIMPL()\n#endif\n\n\ntypedef struct\n{\n  volatile unsigned int is_locked;\n  volatile unsigned int is_init;\n  int sock;\n\n#define QR_COUNT 32\n  pthread_mutex_t qr_lock;\n  volatile uint32_t qr_mask;\n  volatile uint32_t qr_box;\n  rtlsdr_rpc_msg_t query[QR_COUNT];\n  rtlsdr_rpc_msg_t reply[QR_COUNT];\n\n  pthread_mutex_t send_lock;\n  pthread_mutex_t recv_lock;\n\n  volatile unsigned int is_async_cancel;\n\n} rtlsdr_rpc_cli_t;\n\nstatic rtlsdr_rpc_cli_t rtlsdr_rpc_cli = { 0, };\n\ntypedef void (*rtlsdr_rpc_read_async_cb_t)\n(unsigned char*, uint32_t, void*);\n\ntypedef struct rtlsdr_rpc_dev\n{\n  uint32_t index;\n  size_t gain_count;\n  rtlsdr_rpc_cli_t* cli;\n} rtlsdr_rpc_dev_t;\n\nstatic int resolve_ip_addr\n(\n struct sockaddr_storage saddr_both[2], size_t size_both[2],\n const char* addr, const char* port\n)\n{\n  struct addrinfo ai;\n  struct addrinfo* aip = NULL;\n  int err = -1;\n  size_t i;\n\n  memset(&ai, 0, sizeof(ai));\n  ai.ai_family = AF_UNSPEC;\n  ai.ai_socktype = SOCK_STREAM;\n  ai.ai_flags = AI_PASSIVE;\n\n  if (getaddrinfo(addr, port, &ai, &aip)) goto on_error;\n\n  size_both[0] = 0;\n  size_both[1] = 0;\n  i = 0;\n  for (; (i != 2) && (aip != NULL); aip = aip->ai_next)\n  {\n    if ((aip->ai_family != AF_INET) && (aip->ai_family != AF_INET6)) continue ;\n    if (aip->ai_addrlen == 0) continue ;\n    memcpy(&saddr_both[i], aip->ai_addr, aip->ai_addrlen);\n    size_both[i] = aip->ai_addrlen;\n    ++i;\n  }\n\n  if (i == 0) goto on_error;\n\n  err = 0;\n on_error:\n  if (aip != NULL) freeaddrinfo(aip);\n  return err;\n}\n\nstatic int open_socket\n(\n struct sockaddr_storage saddr_both[2], size_t size_both[2],\n int type, int proto,\n struct sockaddr_storage** saddr_used, size_t* size_used\n)\n{\n  size_t i;\n  int fd;\n\n  for (i = 0; (i != 2) && (size_both[i]); ++i)\n  {\n    const struct sockaddr* const sa = (const struct sockaddr*)&saddr_both[i];\n    fd = socket(sa->sa_family, type, proto);\n    if (fd != -1) break ;\n  }\n\n  if ((i == 2) || (size_both[i] == 0)) return -1;\n\n  *saddr_used = &saddr_both[i];\n  *size_used = size_both[i];\n\n  return fd;\n}\n\nstatic int init_cli(rtlsdr_rpc_cli_t* cli)\n{\n  struct sockaddr_storage saddrs[2];\n  struct sockaddr_storage* saddr;\n  size_t sizes[2];\n  size_t size;\n  const char* addr;\n  const char* port;\n  size_t i;\n  size_t j;\n  int err = -1;\n\n  /* no better way in this case ... */\n  while (cli->is_locked) usleep(10000);\n  cli->is_locked = 1;\n\n  if (cli->is_init) goto on_success;\n\n  addr = getenv(\"RTLSDR_RPC_SERV_ADDR\");\n  if (addr == NULL) addr = \"127.0.0.1\";\n\n  port = getenv(\"RTLSDR_RPC_SERV_PORT\");\n  if (port == NULL) port = \"40000\";\n\n  if (resolve_ip_addr(saddrs, sizes, addr, port))\n  {\n    ERROR();\n    goto on_error_0;\n  }\n\n  cli->sock = open_socket\n    (saddrs, sizes, SOCK_STREAM, IPPROTO_TCP, &saddr, &size);\n  if (cli->sock == -1)\n  {\n    ERROR();\n    goto on_error_0;\n  }\n\n  if (connect(cli->sock, (const struct sockaddr*)saddr, (socklen_t)size))\n  {\n    ERROR();\n    goto on_error_1;\n  }\n\n  if (fcntl(cli->sock, F_SETFL, O_NONBLOCK))\n  {\n    ERROR();\n    goto on_error_1;\n  }\n\n  for (i = 0; i != QR_COUNT; ++i)\n  {\n    rtlsdr_rpc_msg_t* const q = &cli->query[i];\n    rtlsdr_rpc_msg_t* const r = &cli->reply[i];\n\n    if (rtlsdr_rpc_msg_init(q, 0))\n      goto on_error_2;\n\n    if (rtlsdr_rpc_msg_init(r, 0))\n    {\n      rtlsdr_rpc_msg_fini(q);\n      goto on_error_2;\n    }\n  }\n  pthread_mutex_init(&cli->qr_lock, NULL);\n  cli->qr_mask = 0;\n  cli->qr_box = 0;\n\n  pthread_mutex_init(&cli->send_lock, NULL);\n  pthread_mutex_init(&cli->recv_lock, NULL);\n\n  cli->is_init = 1;\n\n on_success:\n  err = 0;\n  goto on_error_0;\n\n on_error_2:\n  for (j = 0; j != i; ++j)\n  {\n    rtlsdr_rpc_msg_fini(&cli->query[j]);\n    rtlsdr_rpc_msg_fini(&cli->reply[j]);\n  }\n\n on_error_1:\n  shutdown(cli->sock, SHUT_RDWR);\n  close(cli->sock);\n\n on_error_0:\n  cli->is_locked = 0;\n  return err;\n}\n\n__attribute__((unused))\nstatic int fini_cli(rtlsdr_rpc_cli_t* cli)\n{\n  size_t i;\n\n  for (i = 0; i != QR_COUNT; ++i)\n  {\n    rtlsdr_rpc_msg_fini(&cli->query[i]);\n    rtlsdr_rpc_msg_fini(&cli->reply[i]);\n  }\n  pthread_mutex_destroy(&cli->qr_lock);\n\n  pthread_mutex_destroy(&cli->send_lock);\n  pthread_mutex_destroy(&cli->recv_lock);\n\n  shutdown(cli->sock, SHUT_RDWR);\n  close(cli->sock);\n\n  return 0;\n}\n\nstatic int alloc_qr\n(rtlsdr_rpc_cli_t* cli, rtlsdr_rpc_msg_t** q, rtlsdr_rpc_msg_t** r)\n{\n  size_t i;\n\n  pthread_mutex_lock(&cli->qr_lock);\n  for (i = 0; i != QR_COUNT; ++i)\n  {\n    const uint32_t m = 1 << i;\n    if ((cli->qr_mask & m) == 0)\n    {\n      cli->qr_mask |= m;\n      break ;\n    }\n  }\n  pthread_mutex_unlock(&cli->qr_lock);\n\n  if (i == QR_COUNT) return -1;\n\n  *q = &cli->query[i];\n  *r = &cli->reply[i];\n\n  /* set the query id */\n  rtlsdr_rpc_msg_reset(*q);\n  rtlsdr_rpc_msg_set_id(*q, (uint8_t)i);\n\n  return 0;\n}\n\nstatic void free_qr\n(rtlsdr_rpc_cli_t* cli, rtlsdr_rpc_msg_t* q, rtlsdr_rpc_msg_t* r)\n{\n  const uint32_t m = 1 << (uint32_t)rtlsdr_rpc_msg_get_id(q);\n  pthread_mutex_lock(&cli->qr_lock);\n  cli->qr_mask &= ~m;\n  pthread_mutex_unlock(&cli->qr_lock);\n}\n\nstatic int recv_all(int fd, uint8_t* buf, size_t size)\n{\n  ssize_t n;\n  fd_set rset;\n\n  while (1)\n  {\n    errno = 0;\n    n = recv(fd, buf, size, 0);\n    if (n <= 0)\n    {\n      if ((errno != EWOULDBLOCK) || (errno != EAGAIN))\n\treturn -1;\n    }\n    else\n    {\n      size -= (size_t)n;\n      buf += (size_t)n;\n      if (size == 0) break ;\n    }\n\n    FD_ZERO(&rset);\n    FD_SET(fd, &rset);\n    if (select(fd + 1, &rset, NULL, NULL, NULL) <= 0)\n    {\n      return -1;\n    }\n  }\n\n  return 0;\n}\n\nstatic int send_all(int fd, const uint8_t* buf, size_t size)\n{\n  ssize_t n;\n  fd_set wset;\n\n  while (1)\n  {\n    errno = 0;\n    n = send(fd, buf, size, 0);\n    if (n <= 0)\n    {\n      if ((errno != EWOULDBLOCK) || (errno != EAGAIN))\n\treturn -1;\n    }\n    else\n    {\n      size -= (size_t)n;\n      buf += (size_t)n;\n      if (size == 0) break ;\n    }\n\n    FD_ZERO(&wset);\n    FD_SET(fd, &wset);\n    if (select(fd + 1, NULL, &wset, NULL, NULL) <= 0)\n    {\n      return -1;\n    }\n  }\n\n  return 0;\n}\n\nstatic int recv_msg\n(rtlsdr_rpc_cli_t* cli, uint8_t id, rtlsdr_rpc_msg_t* m)\n{\n  static const size_t fmt_size = offsetof(rtlsdr_rpc_fmt_t, data);\n  const uint32_t mask = 1 << (uint32_t)id;\n  const int fd = cli->sock;\n  uint32_t size;\n  uint8_t to_id;\n  int err = -1;\n  rtlsdr_rpc_msg_t* to_m;\n\n  pthread_mutex_lock(&cli->recv_lock);\n\n  if (cli->qr_box & mask)\n  {\n    cli->qr_box &= ~mask;\n    goto on_success;\n  }\n\n  while (1)\n  {\n    /* receive next message */\n    if (recv_all(fd, m->fmt, fmt_size)) goto on_error;\n\n    /* get destination message by id */\n    to_id = rtlsdr_rpc_msg_get_id(m);\n\n    if (to_id >= QR_COUNT) goto on_error;\n    to_m = &cli->reply[to_id];\n    if (to_id != id) memcpy(to_m->fmt, m->fmt, fmt_size);\n\n    size = rtlsdr_rpc_msg_get_size(to_m);\n    if (size < fmt_size) goto on_error;\n\n    if (rtlsdr_rpc_msg_realloc(to_m, size)) goto on_error;\n\n    size -= fmt_size;\n    if (size)\n    {\n      if (recv_all(fd, to_m->fmt + fmt_size, size)) goto on_error;\n    }\n\n    if (to_id == id) goto on_success;\n\n    /* message not for this query, forward */\n    cli->qr_box |= 1 << (uint32_t)to_id;\n  }\n\n on_success:\n  err = 0;\n on_error:\n  pthread_mutex_unlock(&cli->recv_lock);\n  return err;\n}\n\nstatic int send_msg(rtlsdr_rpc_cli_t* cli, rtlsdr_rpc_msg_t* m)\n{\n  int err;\n\n  rtlsdr_rpc_msg_set_size(m, (uint32_t)m->off);\n\n  pthread_mutex_lock(&cli->send_lock);\n  err = send_all(cli->sock, m->fmt, m->off);\n  pthread_mutex_unlock(&cli->send_lock);\n\n  return err;\n}\n\nstatic int send_recv_msg\n(rtlsdr_rpc_cli_t* cli, rtlsdr_rpc_msg_t* q, rtlsdr_rpc_msg_t* r)\n{\n  const uint8_t id = rtlsdr_rpc_msg_get_id(q);\n\n  if (send_msg(cli, q)) return -1;\n  if (recv_msg(cli, id, r)) return -1;\n  rtlsdr_rpc_msg_reset(r);\n\n  return 0;\n}\n\nstatic int send_flush_msgs\n(rtlsdr_rpc_cli_t* cli, rtlsdr_rpc_msg_t* q)\n{\n  struct timeval tm;\n  ssize_t n;\n  fd_set rset;\n  uint8_t buf[256];\n\n  if (send_msg(cli, q)) return -1;\n\n  pthread_mutex_lock(&cli->recv_lock);\n\n  while (1)\n  {\n    FD_ZERO(&rset);\n    FD_SET(cli->sock, &rset);\n    tm.tv_sec = 0;\n    tm.tv_usec = 200000;\n    if (select(cli->sock + 1, &rset, NULL, NULL, &tm) < 0) break ;\n    if (recv(cli->sock, buf, sizeof(buf), 0) <= 0) break ;\n  }\n\n  pthread_mutex_unlock(&cli->recv_lock);\n\n  return 0;\n}\n\nuint32_t rtlsdr_rpc_get_device_count(void)\n{\n  rtlsdr_rpc_cli_t* const cli = &rtlsdr_rpc_cli;\n  rtlsdr_rpc_msg_t* q;\n  rtlsdr_rpc_msg_t* r;\n  uint32_t n = 0;\n\n  if (init_cli(cli)) goto on_error_0;\n\n  if (alloc_qr(cli, &q, &r)) goto on_error_0;\n\n  rtlsdr_rpc_msg_set_op(q, RTLSDR_RPC_OP_GET_DEVICE_COUNT);\n\n  if (send_recv_msg(cli, q, r)) goto on_error_1;\n\n  if (rtlsdr_rpc_msg_pop_uint32(r, &n)) goto on_error_1;\n\n on_error_1:\n  free_qr(cli, q, r);\n on_error_0:\n  return n;\n}\n\nconst char* rtlsdr_rpc_get_device_name\n(\n uint32_t index\n)\n{\n  rtlsdr_rpc_cli_t* const cli = &rtlsdr_rpc_cli;\n  rtlsdr_rpc_msg_t* q;\n  rtlsdr_rpc_msg_t* r;\n  const char* s = NULL;\n\n  if (init_cli(cli)) goto on_error_0;\n\n  if (alloc_qr(cli, &q, &r)) goto on_error_0;\n\n  rtlsdr_rpc_msg_set_op(q, RTLSDR_RPC_OP_GET_DEVICE_NAME);\n  if (rtlsdr_rpc_msg_push_uint32(q, index)) goto on_error_1;\n\n  if (send_recv_msg(cli, q, r)) goto on_error_1;\n\n  if (rtlsdr_rpc_msg_pop_str(r, &s)) goto on_error_1;\n  /* TODO: memory leak here */\n  s = strdup(s);\n\n on_error_1:\n  free_qr(cli, q, r);\n on_error_0:\n  return s;\n}\n\nint rtlsdr_rpc_get_device_usb_strings\n(uint32_t index, char* manufact, char* product, char* serial)\n{\n  rtlsdr_rpc_cli_t* const cli = &rtlsdr_rpc_cli;\n  rtlsdr_rpc_msg_t* q;\n  rtlsdr_rpc_msg_t* r;\n  const char* s;\n  int err = -1;\n\n  if (init_cli(cli)) goto on_error_0;\n\n  if (alloc_qr(cli, &q, &r)) goto on_error_0;\n\n  rtlsdr_rpc_msg_set_op(q, RTLSDR_RPC_OP_GET_DEVICE_USB_STRINGS);\n  if (rtlsdr_rpc_msg_push_uint32(q, index)) goto on_error_1;\n\n  if (send_recv_msg(cli, q, r)) goto on_error_1;\n\n  err = rtlsdr_rpc_msg_get_err(r);\n  if (err) goto on_error_1;\n\n  if (rtlsdr_rpc_msg_pop_str(r, &s)) goto on_error_1;\n  strcpy(manufact, s);\n  if (rtlsdr_rpc_msg_pop_str(r, &s)) goto on_error_1;\n  strcpy(product, s);\n  if (rtlsdr_rpc_msg_pop_str(r, &s)) goto on_error_1;\n  strcpy(serial, s);\n\n on_error_1:\n  free_qr(cli, q, r);\n on_error_0:\n  return err;\n}\n\nint rtlsdr_rpc_get_index_by_serial(const char* serial)\n{\n  rtlsdr_rpc_cli_t* const cli = &rtlsdr_rpc_cli;\n  rtlsdr_rpc_msg_t* q;\n  rtlsdr_rpc_msg_t* r;\n  int err = -1;\n\n  if (init_cli(cli)) goto on_error_0;\n\n  if (alloc_qr(cli, &q, &r)) goto on_error_0;\n\n  rtlsdr_rpc_msg_set_op(q, RTLSDR_RPC_OP_GET_INDEX_BY_SERIAL);\n  if (rtlsdr_rpc_msg_push_str(q, serial)) goto on_error_1;\n\n  if (send_recv_msg(cli, q, r)) goto on_error_1;\n\n  err = rtlsdr_rpc_msg_get_err(r);\n\n on_error_1:\n  free_qr(cli, q, r);\n on_error_0:\n  return err;\n}\n\nint rtlsdr_rpc_open(void** devp, uint32_t index)\n{\n  rtlsdr_rpc_cli_t* const cli = &rtlsdr_rpc_cli;\n  rtlsdr_rpc_msg_t* q;\n  rtlsdr_rpc_msg_t* r;\n  rtlsdr_rpc_dev_t* dev;\n  int err = -1;\n\n  index = (uint32_t) atoi(getenv(\"RTLSDR_RPC_DEVICE_INDEX\"));\n\n  *devp = NULL;\n\n  if (init_cli(cli)) goto on_error_0;\n\n  dev = malloc(sizeof(rtlsdr_rpc_dev_t));\n  if (dev == NULL) goto on_error_0;\n\n  if (alloc_qr(cli, &q, &r)) goto on_error_1;\n\n  rtlsdr_rpc_msg_set_op(q, RTLSDR_RPC_OP_OPEN);\n  if (rtlsdr_rpc_msg_push_uint32(q, index)) goto on_error_2;\n\n  if (send_recv_msg(cli, q, r)) goto on_error_2;\n\n  err = rtlsdr_rpc_msg_get_err(r);\n  if (err) goto on_error_2;\n\n  dev->index = index;\n  dev->gain_count = 32;\n  dev->cli = cli;\n  *devp = dev;\n\n on_error_2:\n  free_qr(cli, q, r);\n on_error_1:\n  if (err) free(dev);\n on_error_0:\n  return err;\n}\n\nint rtlsdr_rpc_close(void* devp)\n{\n  rtlsdr_rpc_dev_t* const dev = devp;\n  rtlsdr_rpc_cli_t* const cli = dev->cli;\n  rtlsdr_rpc_msg_t* q;\n  rtlsdr_rpc_msg_t* r;\n  int err = -1;\n\n  if (alloc_qr(cli, &q, &r)) goto on_error_0;\n\n  rtlsdr_rpc_msg_set_op(q, RTLSDR_RPC_OP_CLOSE);\n  if (rtlsdr_rpc_msg_push_uint32(q, dev->index)) goto on_error_1;\n\n  if (send_recv_msg(cli, q, r)) goto on_error_1;\n\n  err = rtlsdr_rpc_msg_get_err(r);\n  if (err) goto on_error_1;\n\n on_error_1:\n  free_qr(cli, q, r);\n on_error_0:\n  free(dev);\n  return err;\n}\n\nint rtlsdr_rpc_set_xtal_freq\n(void* devp, uint32_t rtl_freq, uint32_t tuner_freq)\n{\n  rtlsdr_rpc_dev_t* const dev = devp;\n  rtlsdr_rpc_cli_t* const cli = dev->cli;\n  rtlsdr_rpc_msg_t* q;\n  rtlsdr_rpc_msg_t* r;\n  int err = -1;\n\n  if (alloc_qr(cli, &q, &r)) goto on_error_0;\n\n  rtlsdr_rpc_msg_set_op(q, RTLSDR_RPC_OP_SET_XTAL_FREQ);\n  if (rtlsdr_rpc_msg_push_uint32(q, dev->index)) goto on_error_1;\n  if (rtlsdr_rpc_msg_push_uint32(q, rtl_freq)) goto on_error_1;\n  if (rtlsdr_rpc_msg_push_uint32(q, tuner_freq)) goto on_error_1;\n\n  if (send_recv_msg(cli, q, r)) goto on_error_1;\n\n  err = rtlsdr_rpc_msg_get_err(r);\n  if (err) goto on_error_1;\n\n on_error_1:\n  free_qr(cli, q, r);\n on_error_0:\n  return err;\n}\n\nint rtlsdr_rpc_get_xtal_freq\n(void* devp, uint32_t* rtl_freq, uint32_t* tuner_freq)\n{\n  rtlsdr_rpc_dev_t* const dev = devp;\n  rtlsdr_rpc_cli_t* const cli = dev->cli;\n  rtlsdr_rpc_msg_t* q;\n  rtlsdr_rpc_msg_t* r;\n  int err = -1;\n\n  if (alloc_qr(cli, &q, &r)) goto on_error_0;\n\n  rtlsdr_rpc_msg_set_op(q, RTLSDR_RPC_OP_GET_XTAL_FREQ);\n  if (rtlsdr_rpc_msg_push_uint32(q, dev->index)) goto on_error_1;\n\n  if (send_recv_msg(cli, q, r)) goto on_error_1;\n\n  err = rtlsdr_rpc_msg_get_err(r);\n  if (err) goto on_error_1;\n\n  if (rtlsdr_rpc_msg_pop_uint32(r, rtl_freq))\n  {\n    err = -1;\n    goto on_error_1;\n  }\n\n  if (rtlsdr_rpc_msg_pop_uint32(r, tuner_freq))\n  {\n    err = -1;\n    goto on_error_1;\n  }\n\n on_error_1:\n  free_qr(cli, q, r);\n on_error_0:\n  return err;\n}\n\nint rtlsdr_rpc_get_usb_strings\n(void* devp, char* manufact, char* product, char* serial)\n{\n  rtlsdr_rpc_dev_t* const dev = devp;\n  rtlsdr_rpc_cli_t* const cli = &rtlsdr_rpc_cli;\n  rtlsdr_rpc_msg_t* q;\n  rtlsdr_rpc_msg_t* r;\n  const char* s;\n  int err = -1;\n\n  if (init_cli(cli)) goto on_error_0;\n\n  if (alloc_qr(cli, &q, &r)) goto on_error_0;\n\n  rtlsdr_rpc_msg_set_op(q, RTLSDR_RPC_OP_GET_USB_STRINGS);\n  if (rtlsdr_rpc_msg_push_uint32(q, dev->index)) goto on_error_1;\n\n  if (send_recv_msg(cli, q, r)) goto on_error_1;\n\n  err = rtlsdr_rpc_msg_get_err(r);\n  if (err) goto on_error_1;\n\n  if (rtlsdr_rpc_msg_pop_str(r, &s)) goto on_error_1;\n  strcpy(manufact, s);\n  if (rtlsdr_rpc_msg_pop_str(r, &s)) goto on_error_1;\n  strcpy(product, s);\n  if (rtlsdr_rpc_msg_pop_str(r, &s)) goto on_error_1;\n  strcpy(serial, s);\n\n on_error_1:\n  free_qr(cli, q, r);\n on_error_0:\n  return err;\n}\n\nint rtlsdr_rpc_write_eeprom\n(void* dev, uint8_t* data, uint8_t offset, uint16_t len)\n{\n  UNIMPL();\n  return -1;\n}\n\nint rtlsdr_rpc_read_eeprom\n(void* dev, uint8_t* data, uint8_t offset, uint16_t len)\n{\n  UNIMPL();\n  return -1;\n}\n\nint rtlsdr_rpc_set_center_freq(void* devp, uint32_t freq)\n{\n  rtlsdr_rpc_dev_t* const dev = devp;\n  rtlsdr_rpc_cli_t* const cli = dev->cli;\n  rtlsdr_rpc_msg_t* q;\n  rtlsdr_rpc_msg_t* r;\n  int err = -1;\n\n  if (alloc_qr(cli, &q, &r)) goto on_error_0;\n\n  rtlsdr_rpc_msg_set_op(q, RTLSDR_RPC_OP_SET_CENTER_FREQ);\n  if (rtlsdr_rpc_msg_push_uint32(q, dev->index)) goto on_error_1;\n  if (rtlsdr_rpc_msg_push_uint32(q, freq)) goto on_error_1;\n\n  if (send_recv_msg(cli, q, r)) goto on_error_1;\n\n  err = rtlsdr_rpc_msg_get_err(r);\n  if (err) goto on_error_1;\n\n on_error_1:\n  free_qr(cli, q, r);\n on_error_0:\n  return err;\n}\n\nuint32_t rtlsdr_rpc_get_center_freq(void* devp)\n{\n  rtlsdr_rpc_dev_t* const dev = devp;\n  rtlsdr_rpc_cli_t* const cli = dev->cli;\n  rtlsdr_rpc_msg_t* q;\n  rtlsdr_rpc_msg_t* r;\n  uint32_t freq = 0;\n\n  if (alloc_qr(cli, &q, &r)) goto on_error_0;\n\n  rtlsdr_rpc_msg_set_op(q, RTLSDR_RPC_OP_GET_CENTER_FREQ);\n  if (rtlsdr_rpc_msg_push_uint32(q, dev->index)) goto on_error_1;\n\n  if (send_recv_msg(cli, q, r)) goto on_error_1;\n\n  if (rtlsdr_rpc_msg_get_err(r)) goto on_error_1;\n  if (rtlsdr_rpc_msg_pop_uint32(r, &freq)) goto on_error_1;\n\n on_error_1:\n  free_qr(cli, q, r);\n on_error_0:\n  return freq;\n}\n\nint rtlsdr_rpc_set_freq_correction(void* devp, int ppm)\n{\n  rtlsdr_rpc_dev_t* const dev = devp;\n  rtlsdr_rpc_cli_t* const cli = dev->cli;\n  rtlsdr_rpc_msg_t* q;\n  rtlsdr_rpc_msg_t* r;\n  int err = -1;\n\n  if (alloc_qr(cli, &q, &r)) goto on_error_0;\n\n  rtlsdr_rpc_msg_set_op(q, RTLSDR_RPC_OP_SET_FREQ_CORRECTION);\n  if (rtlsdr_rpc_msg_push_uint32(q, dev->index)) goto on_error_1;\n  if (rtlsdr_rpc_msg_push_uint32(q, (uint32_t)ppm)) goto on_error_1;\n\n  if (send_recv_msg(cli, q, r)) goto on_error_1;\n\n  err = rtlsdr_rpc_msg_get_err(r);\n  if (err) goto on_error_1;\n\n on_error_1:\n  free_qr(cli, q, r);\n on_error_0:\n  return err;\n}\n\nint rtlsdr_rpc_get_freq_correction(void* devp)\n{\n  rtlsdr_rpc_dev_t* const dev = devp;\n  rtlsdr_rpc_cli_t* const cli = dev->cli;\n  rtlsdr_rpc_msg_t* q;\n  rtlsdr_rpc_msg_t* r;\n  int err = -1;\n\n  if (alloc_qr(cli, &q, &r)) goto on_error_0;\n\n  rtlsdr_rpc_msg_set_op(q, RTLSDR_RPC_OP_GET_FREQ_CORRECTION);\n  if (rtlsdr_rpc_msg_push_uint32(q, dev->index)) goto on_error_1;\n\n  if (send_recv_msg(cli, q, r)) goto on_error_1;\n\n  err = rtlsdr_rpc_msg_get_err(r);\n\n on_error_1:\n  free_qr(cli, q, r);\n on_error_0:\n  return err;\n}\n\nint rtlsdr_rpc_get_tuner_type(void* devp)\n{\n  rtlsdr_rpc_dev_t* const dev = devp;\n  rtlsdr_rpc_cli_t* const cli = dev->cli;\n  rtlsdr_rpc_msg_t* q;\n  rtlsdr_rpc_msg_t* r;\n  int err = -1;\n\n  if (alloc_qr(cli, &q, &r)) goto on_error_0;\n\n  rtlsdr_rpc_msg_set_op(q, RTLSDR_RPC_OP_GET_TUNER_TYPE);\n  if (rtlsdr_rpc_msg_push_uint32(q, dev->index)) goto on_error_1;\n\n  if (send_recv_msg(cli, q, r)) goto on_error_1;\n\n  err = rtlsdr_rpc_msg_get_err(r);\n\n on_error_1:\n  free_qr(cli, q, r);\n on_error_0:\n  return err;\n}\n\nint rtlsdr_rpc_get_tuner_gains(void* devp, int* gainsp)\n{\n  rtlsdr_rpc_dev_t* const dev = devp;\n  rtlsdr_rpc_cli_t* const cli = dev->cli;\n  rtlsdr_rpc_msg_t* q;\n  rtlsdr_rpc_msg_t* r;\n  const uint32_t is_null = (gainsp == NULL);\n  const uint32_t gain_size = (uint32_t)dev->gain_count * sizeof(int);\n  const uint8_t* tmp;\n  size_t size;\n  int err = 0;\n\n  if (alloc_qr(cli, &q, &r)) goto on_error_0;\n\n  rtlsdr_rpc_msg_set_op(q, RTLSDR_RPC_OP_GET_TUNER_GAINS);\n  if (rtlsdr_rpc_msg_push_uint32(q, dev->index)) goto on_error_1;\n  if (rtlsdr_rpc_msg_push_uint32(q, is_null)) goto on_error_1;\n  if (rtlsdr_rpc_msg_push_uint32(q, gain_size)) goto on_error_1;\n\n  if (send_recv_msg(cli, q, r)) goto on_error_1;\n\n  err = rtlsdr_rpc_msg_get_err(r);\n\n  if (err <= 0) goto on_error_1;\n\n  dev->gain_count = (size_t)err;\n\n  if (is_null == 0)\n  {\n    if (rtlsdr_rpc_msg_pop_buf(r, &tmp, &size))\n    {\n      err = 0;\n      goto on_error_1;\n    }\n\n    /* TODO: endianess */\n    memcpy(gainsp, tmp, size);\n  }\n\n on_error_1:\n  free_qr(cli, q, r);\n on_error_0:\n  return err;\n}\n\nint rtlsdr_rpc_set_tuner_gain(void* devp, int gain)\n{\n  rtlsdr_rpc_dev_t* const dev = devp;\n  rtlsdr_rpc_cli_t* const cli = dev->cli;\n  rtlsdr_rpc_msg_t* q;\n  rtlsdr_rpc_msg_t* r;\n  int err = -1;\n\n  if (alloc_qr(cli, &q, &r)) goto on_error_0;\n\n  rtlsdr_rpc_msg_set_op(q, RTLSDR_RPC_OP_SET_TUNER_GAIN);\n  if (rtlsdr_rpc_msg_push_uint32(q, dev->index)) goto on_error_1;\n  if (rtlsdr_rpc_msg_push_uint32(q, (uint32_t)gain)) goto on_error_1;\n\n  if (send_recv_msg(cli, q, r)) goto on_error_1;\n\n  err = rtlsdr_rpc_msg_get_err(r);\n  if (err) goto on_error_1;\n\n on_error_1:\n  free_qr(cli, q, r);\n on_error_0:\n  return err;\n}\n\nint rtlsdr_rpc_set_and_get_tuner_bandwidth(void* devp, uint32_t bw, uint32_t *applied_bw, int apply_bw )\n{\n  rtlsdr_rpc_dev_t* const dev = devp;\n  rtlsdr_rpc_cli_t* const cli = dev->cli;\n  rtlsdr_rpc_msg_t* q;\n  rtlsdr_rpc_msg_t* r;\n  int err = -1;\n\n  if (alloc_qr(cli, &q, &r)) goto on_error_0;\n\n  rtlsdr_rpc_msg_set_op(q, RTLSDR_RPC_OP_SET_GET_TUNER_BW);\n\n  if (rtlsdr_rpc_msg_push_uint32(q, dev->index)) goto on_error_1;\n  if (rtlsdr_rpc_msg_push_uint32(q, (uint32_t)bw)) goto on_error_1;\n  if (rtlsdr_rpc_msg_push_int32(q, (int32_t)apply_bw)) goto on_error_1;\n\n  if (send_recv_msg(cli, q, r)) goto on_error_1;\n\n  if (rtlsdr_rpc_msg_get_err(r)) goto on_error_1;\n  if (rtlsdr_rpc_msg_pop_uint32(r, applied_bw)) goto on_error_1;\n\n on_error_1:\n  free_qr(cli, q, r);\n on_error_0:\n  return err;\n}\n\nint rtlsdr_rpc_get_tuner_gain(void* devp)\n{\n  rtlsdr_rpc_dev_t* const dev = devp;\n  rtlsdr_rpc_cli_t* const cli = dev->cli;\n  rtlsdr_rpc_msg_t* q;\n  rtlsdr_rpc_msg_t* r;\n  int err = -1;\n\n  if (alloc_qr(cli, &q, &r)) goto on_error_0;\n\n  rtlsdr_rpc_msg_set_op(q, RTLSDR_RPC_OP_GET_TUNER_GAIN);\n  if (rtlsdr_rpc_msg_push_uint32(q, dev->index)) goto on_error_1;\n\n  if (send_recv_msg(cli, q, r)) goto on_error_1;\n\n  err = rtlsdr_rpc_msg_get_err(r);\n\n on_error_1:\n  free_qr(cli, q, r);\n on_error_0:\n  return err;\n}\n\nint rtlsdr_rpc_set_tuner_if_gain(void* devp, int stage, int gain)\n{\n  rtlsdr_rpc_dev_t* const dev = devp;\n  rtlsdr_rpc_cli_t* const cli = dev->cli;\n  rtlsdr_rpc_msg_t* q;\n  rtlsdr_rpc_msg_t* r;\n  int err = -1;\n\n  if (alloc_qr(cli, &q, &r)) goto on_error_0;\n\n  rtlsdr_rpc_msg_set_op(q, RTLSDR_RPC_OP_SET_TUNER_IF_GAIN);\n  if (rtlsdr_rpc_msg_push_uint32(q, dev->index)) goto on_error_1;\n  if (rtlsdr_rpc_msg_push_uint32(q, (uint32_t)stage)) goto on_error_1;\n  if (rtlsdr_rpc_msg_push_uint32(q, (uint32_t)gain)) goto on_error_1;\n\n  if (send_recv_msg(cli, q, r)) goto on_error_1;\n\n  err = rtlsdr_rpc_msg_get_err(r);\n  if (err) goto on_error_1;\n\n on_error_1:\n  free_qr(cli, q, r);\n on_error_0:\n  return err;\n}\n\nint rtlsdr_rpc_set_tuner_gain_mode(void* devp, int manual)\n{\n  rtlsdr_rpc_dev_t* const dev = devp;\n  rtlsdr_rpc_cli_t* const cli = dev->cli;\n  rtlsdr_rpc_msg_t* q;\n  rtlsdr_rpc_msg_t* r;\n  int err = -1;\n\n  if (alloc_qr(cli, &q, &r)) goto on_error_0;\n\n  rtlsdr_rpc_msg_set_op(q, RTLSDR_RPC_OP_SET_TUNER_GAIN_MODE);\n  if (rtlsdr_rpc_msg_push_uint32(q, dev->index)) goto on_error_1;\n  if (rtlsdr_rpc_msg_push_uint32(q, manual)) goto on_error_1;\n\n  if (send_recv_msg(cli, q, r)) goto on_error_1;\n\n  err = rtlsdr_rpc_msg_get_err(r);\n  if (err) goto on_error_1;\n\n on_error_1:\n  free_qr(cli, q, r);\n on_error_0:\n  return err;\n}\n\nint rtlsdr_rpc_set_sample_rate(void* devp, uint32_t rate)\n{\n  rtlsdr_rpc_dev_t* const dev = devp;\n  rtlsdr_rpc_cli_t* const cli = dev->cli;\n  rtlsdr_rpc_msg_t* q;\n  rtlsdr_rpc_msg_t* r;\n  int err = -1;\n\n  if (alloc_qr(cli, &q, &r)) goto on_error_0;\n\n  rtlsdr_rpc_msg_set_op(q, RTLSDR_RPC_OP_SET_SAMPLE_RATE);\n  if (rtlsdr_rpc_msg_push_uint32(q, dev->index)) goto on_error_1;\n  if (rtlsdr_rpc_msg_push_uint32(q, rate)) goto on_error_1;\n\n  if (send_recv_msg(cli, q, r)) goto on_error_1;\n\n  err = rtlsdr_rpc_msg_get_err(r);\n  if (err) goto on_error_1;\n\n on_error_1:\n  free_qr(cli, q, r);\n on_error_0:\n  return err;\n}\n\nuint32_t rtlsdr_rpc_get_sample_rate(void* devp)\n{\n  rtlsdr_rpc_dev_t* const dev = devp;\n  rtlsdr_rpc_cli_t* const cli = dev->cli;\n  rtlsdr_rpc_msg_t* q;\n  rtlsdr_rpc_msg_t* r;\n  uint32_t rate = 0;\n\n  if (alloc_qr(cli, &q, &r)) goto on_error_0;\n\n  rtlsdr_rpc_msg_set_op(q, RTLSDR_RPC_OP_GET_SAMPLE_RATE);\n  if (rtlsdr_rpc_msg_push_uint32(q, dev->index)) goto on_error_1;\n\n  if (send_recv_msg(cli, q, r)) goto on_error_1;\n\n  if (rtlsdr_rpc_msg_get_err(r)) goto on_error_1;\n  if (rtlsdr_rpc_msg_pop_uint32(r, &rate)) goto on_error_1;\n\n on_error_1:\n  free_qr(cli, q, r);\n on_error_0:\n  return rate;\n}\n\nint rtlsdr_rpc_set_testmode(void* devp, int on)\n{\n  rtlsdr_rpc_dev_t* const dev = devp;\n  rtlsdr_rpc_cli_t* const cli = dev->cli;\n  rtlsdr_rpc_msg_t* q;\n  rtlsdr_rpc_msg_t* r;\n  int err = -1;\n\n  if (alloc_qr(cli, &q, &r)) goto on_error_0;\n\n  rtlsdr_rpc_msg_set_op(q, RTLSDR_RPC_OP_SET_TESTMODE);\n  if (rtlsdr_rpc_msg_push_uint32(q, dev->index)) goto on_error_1;\n  if (rtlsdr_rpc_msg_push_uint32(q, (uint32_t)on)) goto on_error_1;\n\n  if (send_recv_msg(cli, q, r)) goto on_error_1;\n\n  err = rtlsdr_rpc_msg_get_err(r);\n  if (err) goto on_error_1;\n\n on_error_1:\n  free_qr(cli, q, r);\n on_error_0:\n  return err;\n}\n\nint rtlsdr_rpc_set_agc_mode(void* devp, int on)\n{\n  rtlsdr_rpc_dev_t* const dev = devp;\n  rtlsdr_rpc_cli_t* const cli = dev->cli;\n  rtlsdr_rpc_msg_t* q;\n  rtlsdr_rpc_msg_t* r;\n  int err = -1;\n\n  if (alloc_qr(cli, &q, &r)) goto on_error_0;\n\n  rtlsdr_rpc_msg_set_op(q, RTLSDR_RPC_OP_SET_AGC_MODE);\n  if (rtlsdr_rpc_msg_push_uint32(q, dev->index)) goto on_error_1;\n  if (rtlsdr_rpc_msg_push_uint32(q, (uint32_t)on)) goto on_error_1;\n\n  if (send_recv_msg(cli, q, r)) goto on_error_1;\n\n  err = rtlsdr_rpc_msg_get_err(r);\n  if (err) goto on_error_1;\n\n on_error_1:\n  free_qr(cli, q, r);\n on_error_0:\n  return err;\n}\n\nint rtlsdr_rpc_set_direct_sampling(void* devp, int on)\n{\n  rtlsdr_rpc_dev_t* const dev = devp;\n  rtlsdr_rpc_cli_t* const cli = dev->cli;\n  rtlsdr_rpc_msg_t* q;\n  rtlsdr_rpc_msg_t* r;\n  int err = -1;\n\n  if (alloc_qr(cli, &q, &r)) goto on_error_0;\n\n  rtlsdr_rpc_msg_set_op(q, RTLSDR_RPC_OP_SET_DIRECT_SAMPLING);\n  if (rtlsdr_rpc_msg_push_uint32(q, dev->index)) goto on_error_1;\n  if (rtlsdr_rpc_msg_push_uint32(q, (uint32_t)on)) goto on_error_1;\n\n  if (send_recv_msg(cli, q, r)) goto on_error_1;\n\n  err = rtlsdr_rpc_msg_get_err(r);\n  if (err) goto on_error_1;\n\n on_error_1:\n  free_qr(cli, q, r);\n on_error_0:\n  return err;\n}\n\nint rtlsdr_rpc_get_direct_sampling(void* devp)\n{\n  rtlsdr_rpc_dev_t* const dev = devp;\n  rtlsdr_rpc_cli_t* const cli = dev->cli;\n  rtlsdr_rpc_msg_t* q;\n  rtlsdr_rpc_msg_t* r;\n  int err = -1;\n\n  if (alloc_qr(cli, &q, &r)) goto on_error_0;\n\n  rtlsdr_rpc_msg_set_op(q, RTLSDR_RPC_OP_GET_DIRECT_SAMPLING);\n  if (rtlsdr_rpc_msg_push_uint32(q, dev->index)) goto on_error_1;\n\n  if (send_recv_msg(cli, q, r)) goto on_error_1;\n\n  err = rtlsdr_rpc_msg_get_err(r);\n\n on_error_1:\n  free_qr(cli, q, r);\n on_error_0:\n  return err;\n}\n\nint rtlsdr_rpc_set_offset_tuning(void* devp, int on)\n{\n  rtlsdr_rpc_dev_t* const dev = devp;\n  rtlsdr_rpc_cli_t* const cli = dev->cli;\n  rtlsdr_rpc_msg_t* q;\n  rtlsdr_rpc_msg_t* r;\n  int err = -1;\n\n  if (alloc_qr(cli, &q, &r)) goto on_error_0;\n\n  rtlsdr_rpc_msg_set_op(q, RTLSDR_RPC_OP_SET_OFFSET_TUNING);\n  if (rtlsdr_rpc_msg_push_uint32(q, dev->index)) goto on_error_1;\n  if (rtlsdr_rpc_msg_push_uint32(q, (uint32_t)on)) goto on_error_1;\n\n  if (send_recv_msg(cli, q, r)) goto on_error_1;\n\n  err = rtlsdr_rpc_msg_get_err(r);\n  if (err) goto on_error_1;\n\n on_error_1:\n  free_qr(cli, q, r);\n on_error_0:\n  return err;\n}\n\nint rtlsdr_rpc_get_offset_tuning(void* devp)\n{\n  rtlsdr_rpc_dev_t* const dev = devp;\n  rtlsdr_rpc_cli_t* const cli = dev->cli;\n  rtlsdr_rpc_msg_t* q;\n  rtlsdr_rpc_msg_t* r;\n  int err = -1;\n\n  if (alloc_qr(cli, &q, &r)) goto on_error_0;\n\n  rtlsdr_rpc_msg_set_op(q, RTLSDR_RPC_OP_GET_OFFSET_TUNING);\n  if (rtlsdr_rpc_msg_push_uint32(q, dev->index)) goto on_error_1;\n\n  if (send_recv_msg(cli, q, r)) goto on_error_1;\n\n  err = rtlsdr_rpc_msg_get_err(r);\n\n on_error_1:\n  free_qr(cli, q, r);\n on_error_0:\n  return err;\n}\n\nint rtlsdr_rpc_reset_buffer(void* devp)\n{\n  rtlsdr_rpc_dev_t* const dev = devp;\n  rtlsdr_rpc_cli_t* const cli = dev->cli;\n  rtlsdr_rpc_msg_t* q;\n  rtlsdr_rpc_msg_t* r;\n  int err = -1;\n\n  if (alloc_qr(cli, &q, &r)) goto on_error_0;\n\n  rtlsdr_rpc_msg_set_op(q, RTLSDR_RPC_OP_RESET_BUFFER);\n  if (rtlsdr_rpc_msg_push_uint32(q, dev->index)) goto on_error_1;\n\n  if (send_recv_msg(cli, q, r)) goto on_error_1;\n\n  err = rtlsdr_rpc_msg_get_err(r);\n  if (err) goto on_error_1;\n\n on_error_1:\n  free_qr(cli, q, r);\n on_error_0:\n  return err;\n}\n\nint rtlsdr_rpc_read_sync\n(void* devp, void* buf, int len, int* n_read)\n{\n  rtlsdr_rpc_dev_t* const dev = devp;\n  rtlsdr_rpc_cli_t* const cli = dev->cli;\n  rtlsdr_rpc_msg_t* q;\n  rtlsdr_rpc_msg_t* r;\n  const uint8_t* tmp;\n  size_t size;\n  int err = -1;\n\n  if (alloc_qr(cli, &q, &r)) goto on_error_0;\n\n  rtlsdr_rpc_msg_set_op(q, RTLSDR_RPC_OP_READ_SYNC);\n  if (rtlsdr_rpc_msg_push_uint32(q, dev->index)) goto on_error_1;\n  if (rtlsdr_rpc_msg_push_uint32(q, (uint32_t)len)) goto on_error_1;\n\n  if (send_recv_msg(cli, q, r)) goto on_error_1;\n\n  err = rtlsdr_rpc_msg_get_err(r);\n  if (err) goto on_error_1;\n\n  if (rtlsdr_rpc_msg_pop_buf(r, &tmp, &size))\n  {\n    err = -1;\n    goto on_error_1;\n  }\n\n  if (size > (size_t)len) size = len;\n\n  memcpy(buf, tmp, size);\n\n  *n_read = (int)size;\n\n on_error_1:\n  free_qr(cli, q, r);\n on_error_0:\n  return err;\n}\n\n\nstatic volatile unsigned int is_cancel;\nint rtlsdr_rpc_read_async\n(\n void* devp,\n rtlsdr_rpc_read_async_cb_t cb, void* ctx,\n uint32_t buf_num, uint32_t buf_len\n)\n{\n  rtlsdr_rpc_dev_t* const dev = devp;\n  rtlsdr_rpc_cli_t* const cli = dev->cli;\n  rtlsdr_rpc_msg_t* q;\n  rtlsdr_rpc_msg_t* r;\n  uint8_t id;\n  size_t size;\n  int err = -1;\n\n  if (alloc_qr(cli, &q, &r)) goto on_error_0;\n\n  id = rtlsdr_rpc_msg_get_id(q);\n\n  rtlsdr_rpc_msg_set_op(q, RTLSDR_RPC_OP_READ_ASYNC);\n  if (rtlsdr_rpc_msg_push_uint32(q, dev->index)) goto on_error_1;\n  if (rtlsdr_rpc_msg_push_uint32(q, buf_num)) goto on_error_1;\n  if (rtlsdr_rpc_msg_push_uint32(q, buf_len)) goto on_error_1;\n\n  if (send_recv_msg(cli, q, r)) goto on_error_1;\n\n  err = rtlsdr_rpc_msg_get_err(r);\n  if (err) goto on_error_1;\n\n  cli->is_async_cancel = 0;\n  while (cli->is_async_cancel == 0)\n  {\n    static const size_t off = offsetof(rtlsdr_rpc_fmt_t, data);\n\n    if (recv_msg(cli, id, r))\n    {\n      err = -1;\n      goto on_error_1;\n    }\n\n    size = rtlsdr_rpc_msg_get_size(r);\n    cb(r->fmt + off, size - off, ctx);\n  }\n\n  rtlsdr_rpc_msg_reset(q);\n  rtlsdr_rpc_msg_set_id(q, id);\n  rtlsdr_rpc_msg_set_op(q, RTLSDR_RPC_OP_CANCEL_ASYNC);\n  rtlsdr_rpc_msg_push_uint32(q, dev->index);\n  send_flush_msgs(cli, q);\n\n on_error_1:\n  free_qr(cli, q, r);\n on_error_0:\n  return err;\n}\n\nint rtlsdr_rpc_wait_async\n(\n void* dev,\n rtlsdr_rpc_read_async_cb_t cb, void* ctx\n)\n{\n  return rtlsdr_rpc_read_async(dev, cb, ctx, 0, 0);\n}\n\nint rtlsdr_rpc_cancel_async(void* devp)\n{\n  rtlsdr_rpc_dev_t* const dev = devp;\n  rtlsdr_rpc_cli_t* const cli = dev->cli;\n  cli->is_async_cancel = 1;\n  return 0;\n}\n\nunsigned int rtlsdr_rpc_is_enabled(void)\n{\n  static unsigned int is_enabled = (unsigned int)-1;\n  if (is_enabled == (unsigned int)-1)\n    is_enabled = (getenv(\"RTLSDR_RPC_IS_ENABLED\") != NULL);\n  return is_enabled;\n}\n"
  },
  {
    "path": "src/rtlsdr_rpc_msg.c",
    "content": "#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stddef.h>\n#include \"rtlsdr_rpc_msg.h\"\n\n#if 1\n#include <stdio.h>\n#define PRINTF(__s, ...) fprintf(stderr, __s, ##__VA_ARGS__)\n#define TRACE() PRINTF(\"[t] %s,%u\\n\", __FILE__, __LINE__)\n#define ERROR() PRINTF(\"[e] %s,%u\\n\", __FILE__, __LINE__)\n#else\n#define TRACE()\n#define ERROR()\n#define PRINTF(...)\n#endif\n\n\nint rtlsdr_rpc_msg_init(rtlsdr_rpc_msg_t* msg, size_t data_size)\n{\n  size_t fmt_size;\n\n  if (data_size == 0) data_size = 64;\n\n  fmt_size = offsetof(rtlsdr_rpc_fmt_t, data) + data_size;\n  msg->fmt = malloc(fmt_size);\n  if (msg->fmt == NULL) return -1;\n\n  msg->off = offsetof(rtlsdr_rpc_fmt_t, data);\n  msg->size = fmt_size;\n\n  return 0;\n}\n\nint rtlsdr_rpc_msg_fini(rtlsdr_rpc_msg_t* msg)\n{\n  free(msg->fmt);\n  return 0;\n}\n\nvoid rtlsdr_rpc_msg_reset(rtlsdr_rpc_msg_t* msg)\n{\n  msg->off = offsetof(rtlsdr_rpc_fmt_t, data);\n}\n\nint rtlsdr_rpc_msg_realloc(rtlsdr_rpc_msg_t* msg, size_t size)\n{\n  uint8_t* new_fmt;\n\n  if (msg->size >= size) return 0;\n\n  new_fmt = malloc(size);\n  if (new_fmt == NULL) return -1;\n\n  memcpy(new_fmt, msg->fmt, msg->off);\n  free(msg->fmt);\n  msg->fmt = new_fmt;\n  msg->size = size;\n\n  return 0;\n}\n\nstatic int check_size(const rtlsdr_rpc_msg_t* msg, size_t size)\n{\n  if ((msg->off + size) > msg->size) return -1;\n  return 0;\n}\n\nstatic int check_size_or_realloc(rtlsdr_rpc_msg_t* msg, size_t size)\n{\n  uint8_t* new_fmt;\n  size_t new_size;\n\n  if (check_size(msg, size) == 0) return 0;\n\n  new_size = (msg->off + size + 256) & ~(256 - 1);\n  new_fmt = malloc(new_size);\n  if (new_fmt == NULL) return -1;\n\n  memcpy(new_fmt, msg->fmt, msg->off);\n  free(msg->fmt);\n\n  msg->fmt = new_fmt;\n  msg->size = new_size;\n\n  return 0;\n}\n\nstatic int pop_uint32(rtlsdr_rpc_msg_t* msg, uint32_t* x)\n{\n#if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)\n#error \"unsupported endianness\"\n#endif\n\n  if (check_size(msg, sizeof(uint32_t))) return -1;\n  *x = *(const uint32_t*)(msg->fmt + msg->off);\n  msg->off += sizeof(uint32_t);\n  return 0;\n}\n\nstatic void push_mem_safe(rtlsdr_rpc_msg_t* msg, const uint8_t* x, size_t n)\n{\n  memcpy(msg->fmt + msg->off, x, n);\n  msg->off += n;\n}\n\nstatic void push_uint32_safe(rtlsdr_rpc_msg_t* msg, uint32_t x)\n{\n#if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)\n#error \"unsupported endianness\"\n#endif\n\n  push_mem_safe(msg, (const uint8_t*)&x, sizeof(uint32_t));\n}\n\nint rtlsdr_rpc_msg_push_int32(rtlsdr_rpc_msg_t* msg, int x)\n{\n  if (check_size_or_realloc(msg, sizeof(x))) return -1;\n  push_uint32_safe(msg, (uint32_t)x);\n  return 0;\n}\n\nint rtlsdr_rpc_msg_push_uint32(rtlsdr_rpc_msg_t* msg, uint32_t x)\n{\n  if (check_size_or_realloc(msg, sizeof(x))) return -1;\n  push_uint32_safe(msg, x);\n  return 0;\n}\n\nvoid rtlsdr_rpc_msg_push_uint32_safe(rtlsdr_rpc_msg_t* msg, uint32_t x)\n{\n  push_uint32_safe(msg, x);\n}\n\nint rtlsdr_rpc_msg_push_str(rtlsdr_rpc_msg_t* msg, const char* s)\n{\n  if (check_size_or_realloc(msg, strlen(s) + 1)) return -1;\n  push_mem_safe(msg, (const uint8_t*)s, strlen(s) + 1);\n  return 0;\n}\n\nint rtlsdr_rpc_msg_push_buf(rtlsdr_rpc_msg_t* msg, const uint8_t* buf, size_t size)\n{\n  size_t total_size = sizeof(uint32_t) + size;\n  if (check_size_or_realloc(msg, total_size)) return -1;\n  push_uint32_safe(msg, (uint32_t)size);\n  push_mem_safe(msg, buf, size);\n  return 0;\n}\n\nvoid rtlsdr_rpc_msg_skip_safe(rtlsdr_rpc_msg_t* msg, size_t size)\n{\n  msg->off += size;\n}\n\nint rtlsdr_rpc_msg_pop_int32(rtlsdr_rpc_msg_t* msg, int32_t* x)\n{\n  return pop_uint32(msg, (uint32_t*)x);\n}\n\nint rtlsdr_rpc_msg_pop_uint32(rtlsdr_rpc_msg_t* msg, uint32_t* x)\n{\n  return pop_uint32(msg, x);\n}\n\nint rtlsdr_rpc_msg_pop_str(rtlsdr_rpc_msg_t* msg, const char** s)\n{\n  size_t i;\n\n  *s = (const char*)(msg->fmt + msg->off);\n\n  for (i = msg->off; i != msg->size; ++i)\n  {\n    if (msg->fmt[i] == 0)\n    {\n      msg->off = i + 1;\n      return 0;\n    }\n  }\n\n  return -1;\n}\n\nint rtlsdr_rpc_msg_pop_buf\n(rtlsdr_rpc_msg_t* msg, const uint8_t** buf, size_t* size)\n{\n  uint32_t x;\n\n  if (pop_uint32(msg, &x)) return -1;\n  if ((msg->off + x) > msg->size) return -1;\n\n  *buf = (const uint8_t*)(msg->fmt + msg->off);\n  msg->off += x;\n\n  *size = (size_t)x;\n\n  return 0;\n}\n\nstatic void put_uint8(void* p, uint8_t x)\n{\n  memcpy(p, (const void*)&x, sizeof(x));\n}\n\nstatic void put_uint16(void* p, uint16_t x)\n{\n#if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)\n#error \"unsupported endianness\"\n#endif\n\n  memcpy(p, (const void*)&x, sizeof(x));\n}\n\nstatic void put_uint32(void* p, uint32_t x)\n{\n#if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)\n#error \"unsupported endianness\"\n#endif\n\n  memcpy(p, (const void*)&x, sizeof(x));\n}\n\nstatic uint8_t get_uint8(const void* p)\n{\n  uint8_t x;\n  memcpy((void*)&x, p, sizeof(x));\n  return x;\n}\n\nstatic uint16_t get_uint16(const void* p)\n{\n#if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)\n#error \"unsupported endianness\"\n#endif\n\n  uint16_t x;\n  memcpy((void*)&x, p, sizeof(x));\n  return x;\n}\n\nstatic uint32_t get_uint32(const void* p)\n{\n#if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)\n#error \"unsupported endianness\"\n#endif\n\n  uint32_t x;\n  memcpy((void*)&x, p, sizeof(x));\n  return x;\n}\n\nvoid rtlsdr_rpc_msg_set_size(rtlsdr_rpc_msg_t* msg, size_t size)\n{\n  rtlsdr_rpc_fmt_t* const fmt = (rtlsdr_rpc_fmt_t*)msg->fmt;\n  put_uint32(&fmt->size, (uint32_t)size);\n}\n\nsize_t rtlsdr_rpc_msg_get_size(const rtlsdr_rpc_msg_t* msg)\n{\n  const rtlsdr_rpc_fmt_t* const fmt = (const rtlsdr_rpc_fmt_t*)msg->fmt;\n  return (size_t)get_uint32(&fmt->size);\n}\n\nvoid rtlsdr_rpc_msg_set_op(rtlsdr_rpc_msg_t* msg, rtlsdr_rpc_op_t op)\n{\n  rtlsdr_rpc_fmt_t* const fmt = (rtlsdr_rpc_fmt_t*)msg->fmt;\n  put_uint8(&fmt->op, (uint8_t)op);\n}\n\nrtlsdr_rpc_op_t rtlsdr_rpc_msg_get_op(const rtlsdr_rpc_msg_t* msg)\n{\n  const rtlsdr_rpc_fmt_t* const fmt = (const rtlsdr_rpc_fmt_t*)msg->fmt;\n  return (rtlsdr_rpc_op_t)get_uint8(&fmt->op);\n}\n\nvoid rtlsdr_rpc_msg_set_id(rtlsdr_rpc_msg_t* msg, uint8_t id)\n{\n  rtlsdr_rpc_fmt_t* const fmt = (rtlsdr_rpc_fmt_t*)msg->fmt;\n  put_uint16(&fmt->id, id);\n}\n\nuint8_t rtlsdr_rpc_msg_get_id(const rtlsdr_rpc_msg_t* msg)\n{\n  const rtlsdr_rpc_fmt_t* const fmt = (const rtlsdr_rpc_fmt_t*)msg->fmt;\n  return get_uint8(&fmt->id);\n}\n\nvoid rtlsdr_rpc_msg_set_err(rtlsdr_rpc_msg_t* msg, int err)\n{\n  rtlsdr_rpc_fmt_t* const fmt = (rtlsdr_rpc_fmt_t*)msg->fmt;\n  put_uint32(&fmt->err, (uint32_t)err);\n}\n\nint rtlsdr_rpc_msg_get_err(const rtlsdr_rpc_msg_t* msg)\n{\n  const rtlsdr_rpc_fmt_t* const fmt = (const rtlsdr_rpc_fmt_t*)msg->fmt;\n  return (int)get_uint32(&fmt->err);\n}\n"
  },
  {
    "path": "src/tuner_e4k.c",
    "content": "/*\n * Elonics E4000 tuner driver\n *\n * (C) 2011-2012 by Harald Welte <laforge@gnumonks.org>\n * (C) 2012 by Sylvain Munaut <tnt@246tNt.com>\n * (C) 2012 by Hoernchen <la@tfc-server.de>\n *\n * All Rights Reserved\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <limits.h>\n#include <stdint.h>\n#include <errno.h>\n#include <string.h>\n#include <stdio.h>\n\n#include <reg_field.h>\n#include <tuner_e4k.h>\n#include <rtlsdr_i2c.h>\n\n#define PRINT_PLL_ERRORS\t0\n\n\n#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))\n\n/* If this is defined, the limits are somewhat relaxed compared to what the\n * vendor claims is possible */\n#define OUT_OF_SPEC\n\n#define MHZ(x)\t((x)*1000*1000)\n#define KHZ(x)\t((x)*1000)\n\nuint32_t unsigned_delta(uint32_t a, uint32_t b)\n{\n\tif (a > b)\n\t\treturn a - b;\n\telse\n\t\treturn b - a;\n}\n\n/* look-up table bit-width -> mask */\nstatic const uint8_t width2mask[] = {\n\t0, 1, 3, 7, 0xf, 0x1f, 0x3f, 0x7f, 0xff\n};\n\n/***********************************************************************\n * Register Access */\n\n/*! \\brief Write a register of the tuner chip\n *  \\param[in] e4k reference to the tuner\n *  \\param[in] reg number of the register\n *  \\param[in] val value to be written\n *  \\returns 0 on success, negative in case of error\n */\nstatic int e4k_reg_write(struct e4k_state *e4k, uint8_t reg, uint8_t val)\n{\n\tint r;\n\tuint8_t data[2];\n\tdata[0] = reg;\n\tdata[1] = val;\n\n\tr = rtlsdr_i2c_write_fn(e4k->rtl_dev, e4k->i2c_addr, data, 2);\n\treturn r == 2 ? 0 : -1;\n}\n\n/*! \\brief Read a register of the tuner chip\n *  \\param[in] e4k reference to the tuner\n *  \\param[in] reg number of the register\n *  \\returns positive 8bit register contents on success, negative in case of error\n */\nstatic int e4k_reg_read(struct e4k_state *e4k, uint8_t reg)\n{\n\tuint8_t data = reg;\n\n\tif (rtlsdr_i2c_write_fn(e4k->rtl_dev, e4k->i2c_addr, &data, 1) < 1)\n\t\treturn -1;\n\n\tif (rtlsdr_i2c_read_fn(e4k->rtl_dev, e4k->i2c_addr, &data, 1) < 1)\n\t\treturn -1;\n\n\treturn data;\n}\n\n/*! \\brief Set or clear some (masked) bits inside a register\n *  \\param[in] e4k reference to the tuner\n *  \\param[in] reg number of the register\n *  \\param[in] mask bit-mask of the value\n *  \\param[in] val data value to be written to register\n *  \\returns 0 on success, negative in case of error\n */\nstatic int e4k_reg_set_mask(struct e4k_state *e4k, uint8_t reg,\n\t\t     uint8_t mask, uint8_t val)\n{\n\tuint8_t tmp = e4k_reg_read(e4k, reg);\n\n\tif ((tmp & mask) == val)\n\t\treturn 0;\n\n\treturn e4k_reg_write(e4k, reg, (tmp & ~mask) | (val & mask));\n}\n\n/*! \\brief Write a given field inside a register\n *  \\param[in] e4k reference to the tuner\n *  \\param[in] field structure describing the field\n *  \\param[in] val value to be written\n *  \\returns 0 on success, negative in case of error\n */\nstatic int e4k_field_write(struct e4k_state *e4k, const struct reg_field *field, uint8_t val)\n{\n\tint rc;\n\tuint8_t mask;\n\n\trc = e4k_reg_read(e4k, field->reg);\n\tif (rc < 0)\n\t\treturn rc;\n\n\tmask = width2mask[field->width] << field->shift;\n\n\treturn e4k_reg_set_mask(e4k, field->reg, mask, val << field->shift);\n}\n\n/*! \\brief Read a given field inside a register\n *  \\param[in] e4k reference to the tuner\n *  \\param[in] field structure describing the field\n *  \\returns positive value of the field, negative in case of error\n */\nstatic int e4k_field_read(struct e4k_state *e4k, const struct reg_field *field)\n{\n\tint rc;\n\n\trc = e4k_reg_read(e4k, field->reg);\n\tif (rc < 0)\n\t\treturn rc;\n\n\trc = (rc >> field->shift) & width2mask[field->width];\n\n\treturn rc;\n}\n\n/***********************************************************************\n * Filter Control */\n\nstatic const uint32_t rf_filt_center_uhf[] = {\n\tMHZ(360), MHZ(380), MHZ(405), MHZ(425),\n\tMHZ(450), MHZ(475), MHZ(505), MHZ(540),\n\tMHZ(575), MHZ(615), MHZ(670), MHZ(720),\n\tMHZ(760), MHZ(840), MHZ(890), MHZ(970)\n};\n\nstatic const uint32_t rf_filt_center_l[] = {\n\tMHZ(1300), MHZ(1320), MHZ(1360), MHZ(1410),\n\tMHZ(1445), MHZ(1460), MHZ(1490), MHZ(1530),\n\tMHZ(1560), MHZ(1590), MHZ(1640), MHZ(1660),\n\tMHZ(1680), MHZ(1700), MHZ(1720), MHZ(1750)\n};\n\nstatic int closest_arr_idx(const uint32_t *arr, unsigned int arr_size, uint32_t freq)\n{\n\tunsigned int i, bi = 0;\n\tuint32_t best_delta = 0xffffffff;\n\n\t/* iterate over the array containing a list of the center\n\t * frequencies, selecting the closest one */\n\tfor (i = 0; i < arr_size; i++) {\n\t\tuint32_t delta = unsigned_delta(freq, arr[i]);\n\t\tif (delta < best_delta) {\n\t\t\tbest_delta = delta;\n\t\t\tbi = i;\n\t\t}\n\t}\n\n\treturn bi;\n}\n\n/* return 4-bit index as to which RF filter to select */\nstatic int choose_rf_filter(enum e4k_band band, uint32_t freq)\n{\n\tint rc;\n\n\tswitch (band) {\n\t\tcase E4K_BAND_VHF2:\n\t\tcase E4K_BAND_VHF3:\n\t\t\trc = 0;\n\t\t\tbreak;\n\t\tcase E4K_BAND_UHF:\n\t\t\trc = closest_arr_idx(rf_filt_center_uhf,\n\t\t\t\t\t\t ARRAY_SIZE(rf_filt_center_uhf),\n\t\t\t\t\t\t freq);\n\t\t\tbreak;\n\t\tcase E4K_BAND_L:\n\t\t\trc = closest_arr_idx(rf_filt_center_l,\n\t\t\t\t\t\t ARRAY_SIZE(rf_filt_center_l),\n\t\t\t\t\t\t freq);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\trc = -EINVAL;\n\t\t\tbreak;\n\t}\n\n\treturn rc;\n}\n\n/* \\brief Automatically select apropriate RF filter based on e4k state */\nint e4k_rf_filter_set(struct e4k_state *e4k)\n{\n\tint rc;\n\n\trc = choose_rf_filter(e4k->band, e4k->vco.flo);\n\tif (rc < 0)\n\t\treturn rc;\n\n\treturn e4k_reg_set_mask(e4k, E4K_REG_FILT1, 0xF, rc);\n}\n\n/* Mixer Filter */\nstatic const uint32_t mix_filter_bw[] = {\n\tKHZ(27000), KHZ(27000), KHZ(27000), KHZ(27000),\n\tKHZ(27000), KHZ(27000), KHZ(27000), KHZ(27000),\n\tKHZ(4600), KHZ(4200), KHZ(3800), KHZ(3400),\n\tKHZ(3300), KHZ(2700), KHZ(2300), KHZ(1900)\n};\n\n/* IF RC Filter */\nstatic const uint32_t ifrc_filter_bw[] = {\n\tKHZ(21400), KHZ(21000), KHZ(17600), KHZ(14700),\n\tKHZ(12400), KHZ(10600), KHZ(9000), KHZ(7700),\n\tKHZ(6400), KHZ(5300), KHZ(4400), KHZ(3400),\n\tKHZ(2600), KHZ(1800), KHZ(1200), KHZ(1000)\n};\n\n/* IF Channel Filter */\nstatic const uint32_t ifch_filter_bw[] = {\n\tKHZ(5500), KHZ(5300), KHZ(5000), KHZ(4800),\n\tKHZ(4600), KHZ(4400), KHZ(4300), KHZ(4100),\n\tKHZ(3900), KHZ(3800), KHZ(3700), KHZ(3600),\n\tKHZ(3400), KHZ(3300), KHZ(3200), KHZ(3100),\n\tKHZ(3000), KHZ(2950), KHZ(2900), KHZ(2800),\n\tKHZ(2750), KHZ(2700), KHZ(2600), KHZ(2550),\n\tKHZ(2500), KHZ(2450), KHZ(2400), KHZ(2300),\n\tKHZ(2280), KHZ(2240), KHZ(2200), KHZ(2150)\n};\n\nstatic const uint32_t *if_filter_bw[] = {\n\tmix_filter_bw,\n\tifch_filter_bw,\n\tifrc_filter_bw,\n};\n\nstatic const uint32_t if_filter_bw_len[] = {\n\tARRAY_SIZE(mix_filter_bw),\n\tARRAY_SIZE(ifch_filter_bw),\n\tARRAY_SIZE(ifrc_filter_bw),\n};\n\nstatic const struct reg_field if_filter_fields[] = {\n\t{\n\t\tE4K_REG_FILT2, 4, 4,\n\t},\n\t{\n\t\tE4K_REG_FILT3, 0, 5,\n\t},\n\t{\n\t\tE4K_REG_FILT2, 0, 4,\n\t}\n};\n\nstatic int find_if_bw(enum e4k_if_filter filter, uint32_t bw)\n{\n\tif (filter >= ARRAY_SIZE(if_filter_bw))\n\t\treturn -EINVAL;\n\n\treturn closest_arr_idx(if_filter_bw[filter],\n\t\t\t       if_filter_bw_len[filter], bw);\n}\n\n/*! \\brief Set the filter band-width of any of the IF filters\n *  \\param[in] e4k reference to the tuner chip\n *  \\param[in] filter filter to be configured\n *  \\param[in] bandwidth bandwidth to be configured\n *  \\returns positive actual filter band-width, negative in case of error\n */\nint e4k_if_filter_bw_set(struct e4k_state *e4k, enum e4k_if_filter filter,\n\t\t         uint32_t bandwidth)\n{\n\tint bw_idx;\n\tconst struct reg_field *field;\n\n\tif (filter >= ARRAY_SIZE(if_filter_bw))\n\t\treturn -EINVAL;\n\n\tbw_idx = find_if_bw(filter, bandwidth);\n\n\tfield = &if_filter_fields[filter];\n\n\treturn e4k_field_write(e4k, field, bw_idx);\n}\n\n/*! \\brief Enables / Disables the channel filter\n *  \\param[in] e4k reference to the tuner chip\n *  \\param[in] on 1=filter enabled, 0=filter disabled\n *  \\returns 0 success, negative errors\n */\nint e4k_if_filter_chan_enable(struct e4k_state *e4k, int on)\n{\n\treturn e4k_reg_set_mask(e4k, E4K_REG_FILT3, E4K_FILT3_DISABLE,\n\t                        on ? 0 : E4K_FILT3_DISABLE);\n}\n\nint e4k_if_filter_bw_get(struct e4k_state *e4k, enum e4k_if_filter filter)\n{\n\tconst uint32_t *arr;\n\tint rc;\n\tconst struct reg_field *field;\n\n\tif (filter >= ARRAY_SIZE(if_filter_bw))\n\t\treturn -EINVAL;\n\n\tfield = &if_filter_fields[filter];\n\n\trc = e4k_field_read(e4k, field);\n\tif (rc < 0)\n\t\treturn rc;\n\n\tarr = if_filter_bw[filter];\n\n\treturn arr[rc];\n}\n\n\n/***********************************************************************\n * Frequency Control */\n\n#define E4K_FVCO_MIN_KHZ\t2600000\t/* 2.6 GHz */\n#define E4K_FVCO_MAX_KHZ\t3900000\t/* 3.9 GHz */\n#define E4K_PLL_Y\t\t\t65536\n\n#ifdef OUT_OF_SPEC\n#define E4K_FLO_MIN_MHZ\t\t50\n#define E4K_FLO_MAX_MHZ\t\t2200UL\n#else\n#define E4K_FLO_MIN_MHZ\t\t64\n#define E4K_FLO_MAX_MHZ\t\t1700\n#endif\n\nstruct pll_settings {\n\tuint32_t freq;\n\tuint8_t reg_synth7;\n\tuint8_t mult;\n};\n\nstatic const struct pll_settings pll_vars[] = {\n\t{KHZ(72400),\t(1 << 3) | 7,\t48},\n\t{KHZ(81200),\t(1 << 3) | 6,\t40},\n\t{KHZ(108300),\t(1 << 3) | 5,\t32},\n\t{KHZ(162500),\t(1 << 3) | 4,\t24},\n\t{KHZ(216600),\t(1 << 3) | 3,\t16},\n\t{KHZ(325000),\t(1 << 3) | 2,\t12},\n\t{KHZ(350000),\t(1 << 3) | 1,\t8},\n\t{KHZ(432000),\t(0 << 3) | 3,\t8},\n\t{KHZ(667000),\t(0 << 3) | 2,\t6},\n\t{KHZ(1200000),\t(0 << 3) | 1,\t4}\n};\n\nstatic int is_fvco_valid(uint32_t fvco_z)\n{\n\t/* check if the resulting fosc is valid */\n\tif (fvco_z/1000 < E4K_FVCO_MIN_KHZ ||\n\t    fvco_z/1000 > E4K_FVCO_MAX_KHZ) {\n\t\tfprintf(stderr, \"[E4K] Fvco %u invalid\\n\", fvco_z);\n\t\treturn 0;\n\t}\n\n\treturn 1;\n}\n\nstatic int is_fosc_valid(uint32_t fosc)\n{\n\tif (fosc < MHZ(16) || fosc > MHZ(30)) {\n\t\tfprintf(stderr, \"[E4K] Fosc %u invalid\\n\", fosc);\n\t\treturn 0;\n\t}\n\n\treturn 1;\n}\n\nstatic int is_z_valid(uint32_t z)\n{\n\tif (z > 255) {\n\t\tfprintf(stderr, \"[E4K] Z %u invalid\\n\", z);\n\t\treturn 0;\n\t}\n\n\treturn 1;\n}\n\n/*! \\brief Determine if 3-phase mixing shall be used or not */\nstatic int use_3ph_mixing(uint32_t flo)\n{\n\t/* this is a magic number somewhre between VHF and UHF */\n\tif (flo < MHZ(350))\n\t\treturn 1;\n\n\treturn 0;\n}\n\n/* \\brief compute Fvco based on Fosc, Z and X\n * \\returns positive value (Fvco in Hz), 0 in case of error */\nstatic uint64_t compute_fvco(uint32_t f_osc, uint8_t z, uint16_t x)\n{\n\tuint64_t fvco_z, fvco_x, fvco;\n\n\t/* We use the following transformation in order to\n\t * handle the fractional part with integer arithmetic:\n\t *  Fvco = Fosc * (Z + X/Y) <=> Fvco = Fosc * Z + (Fosc * X)/Y\n\t * This avoids X/Y = 0.  However, then we would overflow a 32bit\n\t * integer, as we cannot hold e.g. 26 MHz * 65536 either.\n\t */\n\tfvco_z = (uint64_t)f_osc * z;\n\n#if 0\n\tif (!is_fvco_valid(fvco_z))\n\t\treturn 0;\n#endif\n\n\tfvco_x = ((uint64_t)f_osc * x) / E4K_PLL_Y;\n\n\tfvco = fvco_z + fvco_x;\n\n\treturn fvco;\n}\n\nstatic uint32_t compute_flo(uint32_t f_osc, uint8_t z, uint16_t x, uint8_t r)\n{\n\tuint64_t fvco = compute_fvco(f_osc, z, x);\n\tif (fvco == 0)\n\t\treturn -EINVAL;\n\n\treturn fvco / r;\n}\n\nstatic int e4k_band_set(struct e4k_state *e4k, enum e4k_band band)\n{\n\tint rc;\n\n\tswitch (band) {\n\tcase E4K_BAND_VHF2:\n\tcase E4K_BAND_VHF3:\n\tcase E4K_BAND_UHF:\n\t\te4k_reg_write(e4k, E4K_REG_BIAS, 3);\n\t\tbreak;\n\tcase E4K_BAND_L:\n\t\te4k_reg_write(e4k, E4K_REG_BIAS, 0);\n\t\tbreak;\n\t}\n\n\t/* workaround: if we don't reset this register before writing to it,\n\t * we get a gap between 325-350 MHz */\n\trc = e4k_reg_set_mask(e4k, E4K_REG_SYNTH1, 0x06, 0);\n\trc = e4k_reg_set_mask(e4k, E4K_REG_SYNTH1, 0x06, band << 1);\n\tif (rc >= 0)\n\t\te4k->band = band;\n\n\treturn rc;\n}\n\n/*! \\brief Compute PLL parameters for givent target frequency\n *  \\param[out] oscp Oscillator parameters, if computation successful\n *  \\param[in] fosc Clock input frequency applied to the chip (Hz)\n *  \\param[in] intended_flo target tuning frequency (Hz)\n *  \\returns actual PLL frequency, as close as possible to intended_flo,\n *\t     0 in case of error\n */\nuint32_t e4k_compute_pll_params(struct e4k_pll_params *oscp, uint32_t fosc, uint32_t intended_flo)\n{\n\tuint32_t i;\n\tuint8_t r = 2;\n\tuint64_t intended_fvco, remainder;\n\tuint64_t z = 0;\n\tuint32_t x;\n\tint flo;\n\tint three_phase_mixing = 0;\n\toscp->r_idx = 0;\n\n\tif (!is_fosc_valid(fosc))\n\t\treturn 0;\n\n\tfor(i = 0; i < ARRAY_SIZE(pll_vars); ++i) {\n\t\tif(intended_flo < pll_vars[i].freq) {\n\t\t\tthree_phase_mixing = (pll_vars[i].reg_synth7 & 0x08) ? 1 : 0;\n\t\t\toscp->r_idx = pll_vars[i].reg_synth7;\n\t\t\tr = pll_vars[i].mult;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t//fprintf(stderr, \"[E4K] Fint=%u, R=%u\\n\", intended_flo, r);\n\n\t/* flo(max) = 1700MHz, R(max) = 48, we need 64bit! */\n\tintended_fvco = (uint64_t)intended_flo * r;\n\n\t/* compute integral component of multiplier */\n\tz = intended_fvco / fosc;\n\n\t/* compute fractional part.  this will not overflow,\n\t* as fosc(max) = 30MHz and z(max) = 255 */\n\tremainder = intended_fvco - (fosc * z);\n\t/* remainder(max) = 30MHz, E4K_PLL_Y = 65536 -> 64bit! */\n\tx = (remainder * E4K_PLL_Y) / fosc;\n\t/* x(max) as result of this computation is 65536 */\n\n\tflo = compute_flo(fosc, z, x, r);\n\n\toscp->fosc = fosc;\n\toscp->flo = flo;\n\toscp->intended_flo = intended_flo;\n\toscp->r = r;\n//\toscp->r_idx = pll_vars[i].reg_synth7 & 0x0;\n\toscp->threephase = three_phase_mixing;\n\toscp->x = x;\n\toscp->z = z;\n\n\treturn flo;\n}\n\nint e4k_tune_params(struct e4k_state *e4k, struct e4k_pll_params *p)\n{\n\t/* program R + 3phase/2phase */\n\te4k_reg_write(e4k, E4K_REG_SYNTH7, p->r_idx);\n\t/* program Z */\n\te4k_reg_write(e4k, E4K_REG_SYNTH3, p->z);\n\t/* program X */\n\te4k_reg_write(e4k, E4K_REG_SYNTH4, p->x & 0xff);\n\te4k_reg_write(e4k, E4K_REG_SYNTH5, p->x >> 8);\n\n\t/* we're in auto calibration mode, so there's no need to trigger it */\n\n\tmemcpy(&e4k->vco, p, sizeof(e4k->vco));\n\n\t/* set the band */\n\tif (e4k->vco.flo < MHZ(140))\n\t\te4k_band_set(e4k, E4K_BAND_VHF2);\n\telse if (e4k->vco.flo < MHZ(350))\n\t\te4k_band_set(e4k, E4K_BAND_VHF3);\n\telse if (e4k->vco.flo < MHZ(1135))\n\t\te4k_band_set(e4k, E4K_BAND_UHF);\n\telse\n\t\te4k_band_set(e4k, E4K_BAND_L);\n\n\t/* select and set proper RF filter */\n\te4k_rf_filter_set(e4k);\n\n\treturn e4k->vco.flo;\n}\n\n/*! \\brief High-level tuning API, just specify frquency\n *\n *  This function will compute matching PLL parameters, program them into the\n *  hardware and set the band as well as RF filter.\n *\n *  \\param[in] e4k reference to tuner\n *  \\param[in] freq frequency in Hz\n *  \\returns actual tuned frequency, negative in case of error\n */\nint e4k_tune_freq(struct e4k_state *e4k, uint32_t freq)\n{\n\tuint32_t rc;\n\tstruct e4k_pll_params p;\n\n\t/* determine PLL parameters */\n\trc = e4k_compute_pll_params(&p, e4k->vco.fosc, freq);\n\tif (!rc)\n\t\treturn -EINVAL;\n\n\t/* actually tune to those parameters */\n\trc = e4k_tune_params(e4k, &p);\n\n\t/* check PLL lock */\n\trc = e4k_reg_read(e4k, E4K_REG_SYNTH1);\n\tif (!(rc & 0x01)) {\n#if PRINT_PLL_ERRORS\n\t\tfprintf(stderr, \"[E4K] PLL not locked for %u Hz!\\n\", freq);\n#endif\n\t\treturn -1;\n\t}\n\n\treturn 0;\n}\n\n/***********************************************************************\n * Gain Control */\n\nstatic const int8_t if_stage1_gain[] = {\n\t-3, 6\n};\n\nstatic const int8_t if_stage23_gain[] = {\n\t0, 3, 6, 9\n};\n\nstatic const int8_t if_stage4_gain[] = {\n\t0, 1, 2, 2\n};\n\nstatic const int8_t if_stage56_gain[] = {\n\t3, 6, 9, 12, 15, 15, 15, 15\n};\n\nstatic const int8_t *if_stage_gain[] = {\n\t0,\n\tif_stage1_gain,\n\tif_stage23_gain,\n\tif_stage23_gain,\n\tif_stage4_gain,\n\tif_stage56_gain,\n\tif_stage56_gain\n};\n\nstatic const uint8_t if_stage_gain_len[] = {\n\t0,\n\tARRAY_SIZE(if_stage1_gain),\n\tARRAY_SIZE(if_stage23_gain),\n\tARRAY_SIZE(if_stage23_gain),\n\tARRAY_SIZE(if_stage4_gain),\n\tARRAY_SIZE(if_stage56_gain),\n\tARRAY_SIZE(if_stage56_gain)\n};\n\nstatic const struct reg_field if_stage_gain_regs[] = {\n\t{ 0, 0, 0 },\n\t{ E4K_REG_GAIN3, 0, 1 },\n\t{ E4K_REG_GAIN3, 1, 2 },\n\t{ E4K_REG_GAIN3, 3, 2 },\n\t{ E4K_REG_GAIN3, 5, 2 },\n\t{ E4K_REG_GAIN4, 0, 3 },\n\t{ E4K_REG_GAIN4, 3, 3 }\n};\n\nstatic const int32_t lnagain[] = {\n\t-50,\t0,\n\t-25,\t1,\n\t0,\t\t4,\n\t25,\t\t5,\n\t50,\t\t6,\n\t75,\t\t7,\n\t100,\t8,\n\t125,\t9,\n\t150,\t10,\n\t175,\t11,\n\t200,\t12,\n\t250,\t13,\n\t300,\t14,\n};\n\nstatic const int32_t enhgain[] = {\n\t10, 30, 50, 70\n};\n\nint e4k_set_lna_gain(struct e4k_state *e4k, int32_t gain)\n{\n\tuint32_t i;\n\tfor(i = 0; i < ARRAY_SIZE(lnagain)/2; ++i) {\n\t\tif(lnagain[i*2] == gain) {\n\t\t\te4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, lnagain[i*2+1]);\n\t\t\treturn gain;\n\t\t}\n\t}\n\treturn -EINVAL;\n}\n\nint e4k_set_enh_gain(struct e4k_state *e4k, int32_t gain)\n{\n\tuint32_t i;\n\tfor(i = 0; i < ARRAY_SIZE(enhgain); ++i) {\n\t\tif(enhgain[i] == gain) {\n\t\t\te4k_reg_set_mask(e4k, E4K_REG_AGC11, 0x7, E4K_AGC11_LNA_GAIN_ENH | (i << 1));\n\t\t\treturn gain;\n\t\t}\n\t}\n\te4k_reg_set_mask(e4k, E4K_REG_AGC11, 0x7, 0);\n\n\t/* special case: 0 = off*/\n\tif(0 == gain)\n\t\treturn 0;\n\telse\n\t\treturn -EINVAL;\n}\n\nint e4k_enable_manual_gain(struct e4k_state *e4k, uint8_t manual)\n{\n\tif (manual) {\n\t\t/* Set LNA mode to manual */\n\t\te4k_reg_set_mask(e4k, E4K_REG_AGC1, E4K_AGC1_MOD_MASK, E4K_AGC_MOD_SERIAL);\n\n\t\t/* Set Mixer Gain Control to manual */\n\t\te4k_reg_set_mask(e4k, E4K_REG_AGC7, E4K_AGC7_MIX_GAIN_AUTO, 0);\n\t} else {\n\t\t/* Set LNA mode to auto */\n\t\te4k_reg_set_mask(e4k, E4K_REG_AGC1, E4K_AGC1_MOD_MASK, E4K_AGC_MOD_IF_SERIAL_LNA_AUTON);\n\t\t/* Set Mixer Gain Control to auto */\n\t\te4k_reg_set_mask(e4k, E4K_REG_AGC7, E4K_AGC7_MIX_GAIN_AUTO, 1);\n\n\t\te4k_reg_set_mask(e4k, E4K_REG_AGC11, 0x7, 0);\n\t}\n\n\treturn 0;\n}\n\nstatic int find_stage_gain(uint8_t stage, int8_t val)\n{\n\tconst int8_t *arr;\n\tint i;\n\n\tif (stage >= ARRAY_SIZE(if_stage_gain))\n\t\treturn -EINVAL;\n\n\tarr = if_stage_gain[stage];\n\n\tfor (i = 0; i < if_stage_gain_len[stage]; i++) {\n\t\tif (arr[i] == val)\n\t\t\treturn i;\n\t}\n\treturn -EINVAL;\n}\n\n/*! \\brief Set the gain of one of the IF gain stages\n *  \\param [e4k] handle to the tuner chip\n *  \\param [stage] number of the stage (1..6)\n *  \\param [value] gain value in dB\n *  \\returns 0 on success, negative in case of error\n */\nint e4k_if_gain_set(struct e4k_state *e4k, uint8_t stage, int8_t value)\n{\n\tint rc;\n\tuint8_t mask;\n\tconst struct reg_field *field;\n\n\trc = find_stage_gain(stage, value);\n\tif (rc < 0)\n\t\treturn rc;\n\n\t/* compute the bit-mask for the given gain field */\n\tfield = &if_stage_gain_regs[stage];\n\tmask = width2mask[field->width] << field->shift;\n\n\treturn e4k_reg_set_mask(e4k, field->reg, mask, rc << field->shift);\n}\n\nint e4k_mixer_gain_set(struct e4k_state *e4k, int8_t value)\n{\n\tuint8_t bit;\n\n\tswitch (value) {\n\tcase 4:\n\t\tbit = 0;\n\t\tbreak;\n\tcase 12:\n\t\tbit = 1;\n\t\tbreak;\n\tdefault:\n\t\treturn -EINVAL;\n\t}\n\n\treturn e4k_reg_set_mask(e4k, E4K_REG_GAIN2, 1, bit);\n}\n\nint e4k_commonmode_set(struct e4k_state *e4k, int8_t value)\n{\n\tif(value < 0)\n\t\treturn -EINVAL;\n\telse if(value > 7)\n\t\treturn -EINVAL;\n\n\treturn e4k_reg_set_mask(e4k, E4K_REG_DC7, 7, value);\n}\n\n/***********************************************************************\n * DC Offset */\n\nint e4k_manual_dc_offset(struct e4k_state *e4k, int8_t iofs, int8_t irange, int8_t qofs, int8_t qrange)\n{\n\tint res;\n\n\tif((iofs < 0x00) || (iofs > 0x3f))\n\t\treturn -EINVAL;\n\tif((irange < 0x00) || (irange > 0x03))\n\t\treturn -EINVAL;\n\tif((qofs < 0x00) || (qofs > 0x3f))\n\t\treturn -EINVAL;\n\tif((qrange < 0x00) || (qrange > 0x03))\n\t\treturn -EINVAL;\n\n\tres = e4k_reg_set_mask(e4k, E4K_REG_DC2, 0x3f, iofs);\n\tif(res < 0)\n\t\treturn res;\n\n\tres = e4k_reg_set_mask(e4k, E4K_REG_DC3, 0x3f, qofs);\n\tif(res < 0)\n\t\treturn res;\n\n\tres = e4k_reg_set_mask(e4k, E4K_REG_DC4, 0x33, (qrange << 4) | irange);\n\treturn res;\n}\n\n/*! \\brief Perform a DC offset calibration right now\n *  \\param [e4k] handle to the tuner chip\n */\nint e4k_dc_offset_calibrate(struct e4k_state *e4k)\n{\n\t/* make sure the DC range detector is enabled */\n\te4k_reg_set_mask(e4k, E4K_REG_DC5, E4K_DC5_RANGE_DET_EN, E4K_DC5_RANGE_DET_EN);\n\n\treturn e4k_reg_write(e4k, E4K_REG_DC1, 0x01);\n}\n\n\nstatic const int8_t if_gains_max[] = {\n\t0, 6, 9, 9, 2, 15, 15\n};\n\nstruct gain_comb {\n\tint8_t mixer_gain;\n\tint8_t if1_gain;\n\tuint8_t reg;\n};\n\nstatic const struct gain_comb dc_gain_comb[] = {\n\t{ 4,  -3, 0x50 },\n\t{ 4,   6, 0x51 },\n\t{ 12, -3, 0x52 },\n\t{ 12,  6, 0x53 },\n};\n\n#define TO_LUT(offset, range)\t(offset | (range << 6))\n\nint e4k_dc_offset_gen_table(struct e4k_state *e4k)\n{\n\tuint32_t i;\n\n\t/* FIXME: read ont current gain values and write them back\n\t * before returning to the caller */\n\n\t/* disable auto mixer gain */\n\te4k_reg_set_mask(e4k, E4K_REG_AGC7, E4K_AGC7_MIX_GAIN_AUTO, 0);\n\n\t/* set LNA/IF gain to full manual */\n\te4k_reg_set_mask(e4k, E4K_REG_AGC1, E4K_AGC1_MOD_MASK,\n\t\t\t E4K_AGC_MOD_SERIAL);\n\n\t/* set all 'other' gains to maximum */\n\tfor (i = 2; i <= 6; i++)\n\t\te4k_if_gain_set(e4k, i, if_gains_max[i]);\n\n\t/* iterate over all mixer + if_stage_1 gain combinations */\n\tfor (i = 0; i < ARRAY_SIZE(dc_gain_comb); i++) {\n\t\tuint8_t offs_i, offs_q, range, range_i, range_q;\n\n\t\t/* set the combination of mixer / if1 gain */\n\t\te4k_mixer_gain_set(e4k, dc_gain_comb[i].mixer_gain);\n\t\te4k_if_gain_set(e4k, 1, dc_gain_comb[i].if1_gain);\n\n\t\t/* perform actual calibration */\n\t\te4k_dc_offset_calibrate(e4k);\n\n\t\t/* extract I/Q offset and range values */\n\t\toffs_i = e4k_reg_read(e4k, E4K_REG_DC2) & 0x3f;\n\t\toffs_q = e4k_reg_read(e4k, E4K_REG_DC3) & 0x3f;\n\t\trange  = e4k_reg_read(e4k, E4K_REG_DC4);\n\t\trange_i = range & 0x3;\n\t\trange_q = (range >> 4) & 0x3;\n\n\t\tfprintf(stderr, \"[E4K] Table %u I=%u/%u, Q=%u/%u\\n\",\n\t\t\ti, range_i, offs_i, range_q, offs_q);\n\n\t\t/* write into the table */\n\t\te4k_reg_write(e4k, dc_gain_comb[i].reg,\n\t\t\t      TO_LUT(offs_q, range_q));\n\t\te4k_reg_write(e4k, dc_gain_comb[i].reg + 0x10,\n\t\t\t      TO_LUT(offs_i, range_i));\n\t}\n\n\treturn 0;\n}\n\n/***********************************************************************\n * Standby */\n\n/*! \\brief Enable/disable standby mode\n */\nint e4k_standby(struct e4k_state *e4k, int enable)\n{\n\te4k_reg_set_mask(e4k, E4K_REG_MASTER1, E4K_MASTER1_NORM_STBY,\n\t\t\t enable ? 0 : E4K_MASTER1_NORM_STBY);\n\n\treturn 0;\n}\n\n/***********************************************************************\n * Initialization */\n\nstatic int magic_init(struct e4k_state *e4k)\n{\n\te4k_reg_write(e4k, 0x7e, 0x01);\n\te4k_reg_write(e4k, 0x7f, 0xfe);\n\te4k_reg_write(e4k, 0x82, 0x00);\n\te4k_reg_write(e4k, 0x86, 0x50);\t/* polarity A */\n\te4k_reg_write(e4k, 0x87, 0x20);\n\te4k_reg_write(e4k, 0x88, 0x01);\n\te4k_reg_write(e4k, 0x9f, 0x7f);\n\te4k_reg_write(e4k, 0xa0, 0x07);\n\n\treturn 0;\n}\n\n/*! \\brief Initialize the E4K tuner\n */\nint e4k_init(struct e4k_state *e4k)\n{\n\t/* make a dummy i2c read or write command, will not be ACKed! */\n\te4k_reg_read(e4k, 0);\n\n\t/* Make sure we reset everything and clear POR indicator */\n\te4k_reg_write(e4k, E4K_REG_MASTER1,\n\t\tE4K_MASTER1_RESET |\n\t\tE4K_MASTER1_NORM_STBY |\n\t\tE4K_MASTER1_POR_DET\n\t);\n\n\t/* Configure clock input */\n\te4k_reg_write(e4k, E4K_REG_CLK_INP, 0x00);\n\n\t/* Disable clock output */\n\te4k_reg_write(e4k, E4K_REG_REF_CLK, 0x00);\n\te4k_reg_write(e4k, E4K_REG_CLKOUT_PWDN, 0x96);\n\n\t/* Write some magic values into registers */\n\tmagic_init(e4k);\n#if 0\n\t/* Set common mode voltage a bit higher for more margin 850 mv */\n\te4k_commonmode_set(e4k, 4);\n\n\t/* Initialize DC offset lookup tables */\n\te4k_dc_offset_gen_table(e4k);\n\n\t/* Enable time variant DC correction */\n\te4k_reg_write(e4k, E4K_REG_DCTIME1, 0x01);\n\te4k_reg_write(e4k, E4K_REG_DCTIME2, 0x01);\n#endif\n\n\t/* Set LNA mode to manual */\n\te4k_reg_write(e4k, E4K_REG_AGC4, 0x10); /* High threshold */\n\te4k_reg_write(e4k, E4K_REG_AGC5, 0x04);\t/* Low threshold */\n\te4k_reg_write(e4k, E4K_REG_AGC6, 0x1a);\t/* LNA calib + loop rate */\n\n\te4k_reg_set_mask(e4k, E4K_REG_AGC1, E4K_AGC1_MOD_MASK,\n\t\tE4K_AGC_MOD_SERIAL);\n\n\t/* Set Mixer Gain Control to manual */\n\te4k_reg_set_mask(e4k, E4K_REG_AGC7, E4K_AGC7_MIX_GAIN_AUTO, 0);\n\n#if 0\n\t/* Enable LNA Gain enhancement */\n\te4k_reg_set_mask(e4k, E4K_REG_AGC11, 0x7,\n\t\t\t E4K_AGC11_LNA_GAIN_ENH | (2 << 1));\n\n\t/* Enable automatic IF gain mode switching */\n\te4k_reg_set_mask(e4k, E4K_REG_AGC8, 0x1, E4K_AGC8_SENS_LIN_AUTO);\n#endif\n\n\t/* Use auto-gain as default */\n\te4k_enable_manual_gain(e4k, 0);\n\n\t/* Select moderate gain levels */\n\te4k_if_gain_set(e4k, 1, 6);\n\te4k_if_gain_set(e4k, 2, 0);\n\te4k_if_gain_set(e4k, 3, 0);\n\te4k_if_gain_set(e4k, 4, 0);\n\te4k_if_gain_set(e4k, 5, 9);\n\te4k_if_gain_set(e4k, 6, 9);\n\n\t/* Set the most narrow filter we can possibly use */\n\te4k_if_filter_bw_set(e4k, E4K_IF_FILTER_MIX, KHZ(1900));\n\te4k_if_filter_bw_set(e4k, E4K_IF_FILTER_RC, KHZ(1000));\n\te4k_if_filter_bw_set(e4k, E4K_IF_FILTER_CHAN, KHZ(2150));\n\te4k_if_filter_chan_enable(e4k, 1);\n\n\t/* Disable time variant DC correction and LUT */\n\te4k_reg_set_mask(e4k, E4K_REG_DC5, 0x03, 0);\n\te4k_reg_set_mask(e4k, E4K_REG_DCTIME1, 0x03, 0);\n\te4k_reg_set_mask(e4k, E4K_REG_DCTIME2, 0x03, 0);\n\n\treturn 0;\n}\n"
  },
  {
    "path": "src/tuner_fc0012.c",
    "content": "/*\n * Fitipower FC0012 tuner driver\n *\n * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net>\n *\n * modified for use in librtlsdr\n * Copyright (C) 2012 Steve Markgraf <steve@steve-m.de>\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n */\n\n#include <stdint.h>\n#include <stdio.h>\n\n#include \"rtlsdr_i2c.h\"\n#include \"tuner_fc0012.h\"\n\n#define PRINT_PLL_ERRORS\t0\n\n\nstatic int fc0012_writereg(void *dev, uint8_t reg, uint8_t val)\n{\n\tuint8_t data[2];\n\tdata[0] = reg;\n\tdata[1] = val;\n\n\tif (rtlsdr_i2c_write_fn(dev, FC0012_I2C_ADDR, data, 2) < 0)\n\t\treturn -1;\n\n\treturn 0;\n}\n\nstatic int fc0012_readreg(void *dev, uint8_t reg, uint8_t *val)\n{\n\tuint8_t data = reg;\n\n\tif (rtlsdr_i2c_write_fn(dev, FC0012_I2C_ADDR, &data, 1) < 0)\n\t\treturn -1;\n\n\tif (rtlsdr_i2c_read_fn(dev, FC0012_I2C_ADDR, &data, 1) < 0)\n\t\treturn -1;\n\n\t*val = data;\n\n\treturn 0;\n}\n\n/* expose/permit tuner specific i2c register hacking! */\nint fc0012_set_i2c_register(void *dev, unsigned i2c_register, unsigned data)\n{\n\tuint8_t reg = i2c_register & 0xFF;\n\tuint8_t reg_val = data & 0xFF;\n\treturn fc0012_writereg(dev, reg, reg_val);\n}\n\nint fc0012_get_i2c_register(void *dev, unsigned char* data, int len)\n{\n\tint len1;\n\n\tdata[0] = 0;\n\t/* The lower 16 I2C registers can be read with the normal read fct,\n\t * the upper ones are read from the cache */\n\tif(len < 16)\n\t\tlen1 = len;\n\telse\n\t\tlen1 = 16;\n\tif (rtlsdr_i2c_write_fn(dev, FC0012_I2C_ADDR, data, 1) < 0)\n\t\treturn -1;\n\tif (rtlsdr_i2c_read_fn(dev, FC0012_I2C_ADDR, data, len1) < 0)\n\t\treturn -1;\n\n\tif(len > 16)\n\t{\n\t\tlen1 = len - 16;\n\t\tdata[16] = 16;\n\t\tif (rtlsdr_i2c_write_fn(dev, FC0012_I2C_ADDR, data+16, 1) < 0)\n\t\t\treturn -1;\n\t\tif (rtlsdr_i2c_read_fn(dev, FC0012_I2C_ADDR, data+16, len1) < 0)\n\t\t\treturn -1;\n\t}\n\n\treturn 0;\n}\n\nstatic int print_registers(void *dev)\n{\n\tuint8_t data[32];\n\tunsigned int i;\n\n\tif (fc0012_get_i2c_register(dev, data, 32) < 0)\n\t\treturn -1;\n\tfor(i=0; i<16; i++)\n\t\tprintf(\"%02x \", data[i]);\n\tprintf(\"\\n\");\n\tfor(i=16; i<32; i++)\n\t\tprintf(\"%02x \", data[i]);\n\tprintf(\"\\n\");\n\treturn 0;\n}\n\n\n/* Incomplete list of register settings:\n *\n * Name\t\t\t\tReg\t\tBitsDesc\n * CHIP_ID\t\t\t0x00\t0-7\tChip ID (constant 0xA1)\n * RF_A\t\t\t\t0x01\t0-3\tNumber of count-to-9 cycles in RF\n *\t\t\t\t\t\t\t\tdivider (suggested: 2..9)\n * RF_M\t\t\t\t0x02\t0-7\tTotal number of cycles (to-8 and to-9)\n *\t\t\t\t\t\t\t\tin RF divider\n * RF_K_HIGH\t\t0x03\t0-6\tBits 8..14 of fractional divider\n * RF_K_LOW\t\t\t0x04\t0-7\tBits 0..7 of fractional RF divider\n * RF_OUTDIV_A\t\t0x05\t3-7\tPower of two required?\n * LNA_POWER_DOWN\t0x06\t0\tSet to 1 to switch off low noise amp\n * RF_OUTDIV_B\t\t0x06\t1\tSet to select 3 instead of 2 for the\n *\t\t\t\t\t\t\t\tRF output divider\n * VCO_SPEED\t\t0x06\t3\tSelect tuning range of VCO:\n *\t\t\t\t\t\t\t\t 0 = Low range, (ca. 1.1 - 1.5GHz)\n *\t\t\t\t\t\t\t\t 1 = High range (ca. 1.4 - 1.8GHz)\n * BANDWIDTH\t\t0x06\t6-7\tSet bandwidth. 6MHz = 0x80, 7MHz=0x40\n *\t\t\t\t\t\t\t\t8MHz=0x00\n * XTAL_SPEED\t\t0x07\t5\tSet to 1 for 28.8MHz Crystal input\n *\t\t\t\t\t\t\t\tor 0 for 36MHz\n * <agc params>\t\t0x08\t0-7\n * EN_CAL_RSSI\t\t0x09\t4 \tEnable calibrate RSSI\n *\t\t\t\t\t\t\t\t(Receive Signal Strength Indicator)\n * LNA_FORCE\t\t0x0d\t0\n * AGC_FORCE\t\t0x0d\t?\n * VCO_CALIB\t\t0x0e\t7\tSet high then low to calibrate VCO\n *\t\t\t\t\t\t\t\t(fast lock?)\n * VCO_VOLTAGE\t\t0x0e\t0-6\tRead Control voltage of VCO\n *\t\t\t\t\t\t\t\t(big value -> low freq)\n * LNA_GAIN\t\t\t0x13\t3-4\tLow noise amp gain\n * LNA_COMPS\t\t0x15\t3\t?\n */\n\nint fc0012_init(void *dev)\n{\n\tint ret = 0;\n\tunsigned int i;\n\tuint8_t reg[] = {\n\t\t0x00,\t/* dummy reg. 0 */\n\t\t0x05,\t/* reg. 0x01 */\n\t\t0x10,\t/* reg. 0x02 */\n\t\t0x00,\t/* reg. 0x03 */\n\t\t0x00,\t/* reg. 0x04 */\n\t\t0x0f,\t/* reg. 0x05: may also be 0x0a */\n\t\t0x00,\t/* reg. 0x06: divider 2, VCO slow */\n\t\t0x00,\t/* reg. 0x07: may also be 0x0f */\n\t\t0xff,\t/* reg. 0x08: AGC Clock divide by 256, AGC gain 1/256,\n\t\t\t   Loop Bw 1/8 */\n\t\t0x6e,\t/* reg. 0x09: Disable LoopThrough, Enable LoopThrough: 0x6f */\n\t\t0xb8,\t/* reg. 0x0a: Disable LO Test Buffer */\n\t\t0x82,\t/* reg. 0x0b: Output Clock is same as clock frequency,\n\t\t\t   may also be 0x83 */\n\t\t0xfc,\t/* reg. 0x0c: depending on AGC Up-Down mode, may need 0xf8 */\n\t\t0x02,\t/* reg. 0x0d: AGC Not Forcing & LNA Forcing, 0x02 for DVB-T */\n\t\t0x00,\t/* reg. 0x0e */\n\t\t0x00,\t/* reg. 0x0f */\n\t\t0x00,\t/* reg. 0x10: may also be 0x0d */\n\t\t0x0a,\t/* reg. 0x11 */\n\t\t0x51,\t/* reg. 0x12: Set to maximum gain */\n\t\t0x08,\t/* reg. 0x13: Set to Middle Gain: 0x08,\n\t\t\t   Low Gain: 0x00, High Gain: 0x10, enable IX2: 0x80 */\n\t\t0x00,\t/* reg. 0x14 */\n\t\t0x04,\t/* reg. 0x15: Enable LNA COMPS */\n\t};\n\n#if 0\n\tswitch (rtlsdr_get_tuner_clock(dev)) {\n\tcase FC_XTAL_27_MHZ:\n\tcase FC_XTAL_28_8_MHZ:\n\t\treg[0x07] |= 0x20;\n\t\tbreak;\n\tcase FC_XTAL_36_MHZ:\n\tdefault:\n\t\tbreak;\n\t}\n#endif\n\treg[0x07] |= 0x20;\n\n/*\tif (priv->dual_master) */\n\treg[0x0c] |= 0x02;\n\n\tfor (i = 1; i < sizeof(reg); i++) {\n\t\tret = fc0012_writereg(dev, i, reg[i]);\n\t\tif (ret)\n\t\t\tbreak;\n\t}\n\n\treturn ret;\n}\n\nint fc0012_set_params(void *dev, uint32_t freq, uint32_t bandwidth)\n{\n\tint i, ret = 0;\n\tuint8_t reg[7], am, pm, multi, tmp;\n\tuint64_t f_vco;\n\tuint32_t xtal_freq_div_2;\n\tuint16_t xin, xdiv;\n\tint vco_select = 0;\n\n\txtal_freq_div_2 = rtlsdr_get_tuner_clock(dev) / 2;\n\n\t/* select frequency divider and the frequency of VCO */\n\tif (freq < 37084000) {\t\t/* freq * 96 < 3560000000 */\n\t\tmulti = 96;\n\t\treg[5] = 0x82;\n\t\treg[6] = 0x00;\n\t} else if (freq < 55625000) {\t/* freq * 64 < 3560000000 */\n\t\tmulti = 64;\n\t\treg[5] = 0x82;\n\t\treg[6] = 0x02;\n\t} else if (freq < 74167000) {\t/* freq * 48 < 3560000000 */\n\t\tmulti = 48;\n\t\treg[5] = 0x42;\n\t\treg[6] = 0x00;\n\t} else if (freq < 111250000) {\t/* freq * 32 < 3560000000 */\n\t\tmulti = 32;\n\t\treg[5] = 0x42;\n\t\treg[6] = 0x02;\n\t} else if (freq < 148334000) {\t/* freq * 24 < 3560000000 */\n\t\tmulti = 24;\n\t\treg[5] = 0x22;\n\t\treg[6] = 0x00;\n\t} else if (freq < 222500000) {\t/* freq * 16 < 3560000000 */\n\t\tmulti = 16;\n\t\treg[5] = 0x22;\n\t\treg[6] = 0x02;\n\t} else if (freq < 296667000) {\t/* freq * 12 < 3560000000 */\n\t\tmulti = 12;\n\t\treg[5] = 0x12;\n\t\treg[6] = 0x00;\n\t} else if (freq < 445000000) {\t/* freq * 8 < 3560000000 */\n\t\tmulti = 8;\n\t\treg[5] = 0x12;\n\t\treg[6] = 0x02;\n\t} else if (freq < 593334000) {\t/* freq * 6 < 3560000000 */\n\t\tmulti = 6;\n\t\treg[5] = 0x0a;\n\t\treg[6] = 0x00;\n\t} else {\n\t\tmulti = 4;\n\t\treg[5] = 0x0a;\n\t\treg[6] = 0x02;\n\t}\n\n\tf_vco = freq * multi;\n\n\tif (f_vco >= 3060000000U) {\n\t\treg[6] |= 0x08;\n\t\tvco_select = 1;\n\t}\n\n\t/* From divided value (XDIV) determined the FA and FP value */\n\txdiv = (uint16_t)(f_vco / xtal_freq_div_2);\n\tif ((f_vco - xdiv * xtal_freq_div_2) >= (xtal_freq_div_2 / 2))\n\t\txdiv++;\n\n\tpm = (uint8_t)(xdiv / 8);\n\tam = (uint8_t)(xdiv - (8 * pm));\n\n\tif (am < 2) {\n\t\tam += 8;\n\t\tpm--;\n\t}\n\n\tif (pm > 31) {\n\t\treg[1] = am + (8 * (pm - 31));\n\t\treg[2] = 31;\n\t} else {\n\t\treg[1] = am;\n\t\treg[2] = pm;\n\t}\n\n\tif ((reg[1] > 15) || (reg[2] < 0x0b)) {\n#if PRINT_PLL_ERRORS\n\t\tfprintf(stderr, \"[FC0012] no valid PLL combination \"\n\t\t\t\t\"found for %u Hz!\\n\", freq);\n#endif\n\t\treturn -1;\n\t}\n\n\t/* fix clock out */\n\treg[6] |= 0x20;\n\n\t/* From VCO frequency determines the XIN ( fractional part of Delta\n\t   Sigma PLL) and divided value (XDIV) */\n\txin = (uint16_t)((f_vco - (f_vco / xtal_freq_div_2) * xtal_freq_div_2) / 1000);\n\txin = (xin << 15) / (xtal_freq_div_2 / 1000);\n\tif (xin >= 16384)\n\t\txin += 32768;\n\n\treg[3] = xin >> 8;\t/* xin with 9 bit resolution */\n\treg[4] = xin & 0xff;\n\n\treg[6] &= 0x3f; /* bits 6 and 7 describe the bandwidth */\n\tswitch (bandwidth) {\n\tcase 6000000:\n\t\treg[6] |= 0x80;\n\t\tbreak;\n\tcase 7000000:\n\t\treg[6] |= 0x40;\n\t\tbreak;\n\tcase 8000000:\n\tdefault:\n\t\tbreak;\n\t}\n\n\t/* modified for Realtek demod */\n\treg[5] |= 0x07;\n\n\tfor (i = 1; i <= 6; i++) {\n\t\tret = fc0012_writereg(dev, i, reg[i]);\n\t\tif (ret)\n\t\t\tgoto exit;\n\t}\n\n\t/* VCO Calibration */\n\tret = fc0012_writereg(dev, 0x0e, 0x80);\n\tif (!ret)\n\t\tret = fc0012_writereg(dev, 0x0e, 0x00);\n\n\t/* VCO Re-Calibration if needed */\n\tif (!ret)\n\t\tret = fc0012_writereg(dev, 0x0e, 0x00);\n\n\tif (!ret) {\n\t\t/*\tmsleep(10); */\n\t\tret = fc0012_readreg(dev, 0x0e, &tmp);\n\t}\n\tif (ret)\n\t\tgoto exit;\n\n\t/* vco selection */\n\ttmp &= 0x3f;\n\n\tif (vco_select) {\n\t\tif (tmp > 0x3c) {\n\t\t\treg[6] &= ~0x08;\n\t\t\tret = fc0012_writereg(dev, 0x06, reg[6]);\n\t\t\tif (!ret)\n\t\t\t\tret = fc0012_writereg(dev, 0x0e, 0x80);\n\t\t\tif (!ret)\n\t\t\t\tret = fc0012_writereg(dev, 0x0e, 0x00);\n\t\t}\n\t} else {\n\t\tif (tmp < 0x02) {\n\t\t\treg[6] |= 0x08;\n\t\t\tret = fc0012_writereg(dev, 0x06, reg[6]);\n\t\t\tif (!ret)\n\t\t\t\tret = fc0012_writereg(dev, 0x0e, 0x80);\n\t\t\tif (!ret)\n\t\t\t\tret = fc0012_writereg(dev, 0x0e, 0x00);\n\t\t}\n\t}\n\nexit:\n\treturn ret;\n}\n\nint fc0012_set_gain(void *dev, int gain)\n{\n\tint ret;\n\tuint8_t tmp = 0;\n\n\tret = fc0012_readreg(dev, 0x13, &tmp);\n\n\t/* mask bits off */\n\ttmp &= 0xe0;\n\n\tswitch (gain) {\n\tcase -99:\t\t/* -9.9 dB */\n\t\ttmp |= 0x02;\n\t\tbreak;\n\tcase -40:\t\t/* -4 dB */\n\t\tbreak;\n\tcase 71:\n\t\ttmp |= 0x08;\t/* 7.1 dB */\n\t\tbreak;\n\tcase 179:\n\t\ttmp |= 0x17;\t/* 17.9 dB */\n\t\tbreak;\n\tcase 192:\n\tdefault:\n\t\ttmp |= 0x10;\t/* 19.2 dB */\n\t\tbreak;\n\t}\n\n\tret = fc0012_writereg(dev, 0x13, tmp);\n\t/* print_registers(dev); */\n\treturn ret;\n}\n"
  },
  {
    "path": "src/tuner_fc0013.c",
    "content": "/*\n * Fitipower FC0013 tuner driver\n *\n * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net>\n * partially based on driver code from Fitipower\n * Copyright (C) 2010 Fitipower Integrated Technology Inc\n *\n * modified for use in librtlsdr\n * Copyright (C) 2012 Steve Markgraf <steve@steve-m.de>\n *\n *    This program is free software; you can redistribute it and/or modify\n *    it under the terms of the GNU General Public License as published by\n *    the Free Software Foundation; either version 2 of the License, or\n *    (at your option) any later version.\n *\n *    This program is distributed in the hope that it will be useful,\n *    but WITHOUT ANY WARRANTY; without even the implied warranty of\n *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *    GNU General Public License for more details.\n *\n *    You should have received a copy of the GNU General Public License\n *    along with this program; if not, write to the Free Software\n *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n */\n\n#include <stdint.h>\n#include <stdio.h>\n\n#include \"rtlsdr_i2c.h\"\n#include \"tuner_fc0013.h\"\n\n#define PRINT_PLL_ERRORS\t0\n\n\nstatic int fc0013_writereg(void *dev, uint8_t reg, uint8_t val)\n{\n\tuint8_t data[2];\n\tdata[0] = reg;\n\tdata[1] = val;\n\n\tif (rtlsdr_i2c_write_fn(dev, FC0013_I2C_ADDR, data, 2) < 0)\n\t\treturn -1;\n\n\treturn 0;\n}\n\nstatic int fc0013_readreg(void *dev, uint8_t reg, uint8_t *val)\n{\n\tuint8_t data = reg;\n\n\tif (rtlsdr_i2c_write_fn(dev, FC0013_I2C_ADDR, &data, 1) < 0)\n\t\treturn -1;\n\n\tif (rtlsdr_i2c_read_fn(dev, FC0013_I2C_ADDR, &data, 1) < 0)\n\t\treturn -1;\n\n\t*val = data;\n\n\treturn 0;\n}\n\nint fc0013_init(void *dev)\n{\n\tint ret = 0;\n\tunsigned int i;\n\tuint8_t reg[] = {\n\t\t0x00,\t/* reg. 0x00: dummy */\n\t\t0x09,\t/* reg. 0x01 */\n\t\t0x16,\t/* reg. 0x02 */\n\t\t0x00,\t/* reg. 0x03 */\n\t\t0x00,\t/* reg. 0x04 */\n\t\t0x17,\t/* reg. 0x05 */\n\t\t0x02,\t/* reg. 0x06: LPF bandwidth */\n\t\t0x0a,\t/* reg. 0x07: CHECK */\n\t\t0xff,\t/* reg. 0x08: AGC Clock divide by 256, AGC gain 1/256,\n\t\t\t   Loop Bw 1/8 */\n\t\t0x6e,\t/* reg. 0x09: Disable LoopThrough, Enable LoopThrough: 0x6f */\n\t\t0xb8,\t/* reg. 0x0a: Disable LO Test Buffer */\n\t\t0x82,\t/* reg. 0x0b: CHECK */\n\t\t0xfc,\t/* reg. 0x0c: depending on AGC Up-Down mode, may need 0xf8 */\n\t\t0x01,\t/* reg. 0x0d: AGC Not Forcing & LNA Forcing, may need 0x02 */\n\t\t0x00,\t/* reg. 0x0e */\n\t\t0x00,\t/* reg. 0x0f */\n\t\t0x00,\t/* reg. 0x10 */\n\t\t0x00,\t/* reg. 0x11 */\n\t\t0x00,\t/* reg. 0x12 */\n\t\t0x00,\t/* reg. 0x13 */\n\t\t0x50,\t/* reg. 0x14: DVB-t High Gain, UHF.\n\t\t\t   Middle Gain: 0x48, Low Gain: 0x40 */\n\t\t0x01,\t/* reg. 0x15 */\n\t};\n#if 0\n\tswitch (rtlsdr_get_tuner_clock(dev)) {\n\tcase FC_XTAL_27_MHZ:\n\tcase FC_XTAL_28_8_MHZ:\n\t\treg[0x07] |= 0x20;\n\t\tbreak;\n\tcase FC_XTAL_36_MHZ:\n\tdefault:\n\t\tbreak;\n\t}\n#endif\n\treg[0x07] |= 0x20;\n\n//\tif (dev->dual_master)\n\treg[0x0c] |= 0x02;\n\n\tfor (i = 1; i < sizeof(reg); i++) {\n\t\tret = fc0013_writereg(dev, i, reg[i]);\n\t\tif (ret < 0)\n\t\t\tbreak;\n\t}\n\n\treturn ret;\n}\n\nint fc0013_rc_cal_add(void *dev, int rc_val)\n{\n\tint ret;\n\tuint8_t rc_cal;\n\tint val;\n\n\t/* push rc_cal value, get rc_cal value */\n\tret = fc0013_writereg(dev, 0x10, 0x00);\n\tif (ret)\n\t\tgoto error_out;\n\n\t/* get rc_cal value */\n\tret = fc0013_readreg(dev, 0x10, &rc_cal);\n\tif (ret)\n\t\tgoto error_out;\n\n\trc_cal &= 0x0f;\n\n\tval = (int)rc_cal + rc_val;\n\n\t/* forcing rc_cal */\n\tret = fc0013_writereg(dev, 0x0d, 0x11);\n\tif (ret)\n\t\tgoto error_out;\n\n\t/* modify rc_cal value */\n\tif (val > 15)\n\t\tret = fc0013_writereg(dev, 0x10, 0x0f);\n\telse if (val < 0)\n\t\tret = fc0013_writereg(dev, 0x10, 0x00);\n\telse\n\t\tret = fc0013_writereg(dev, 0x10, (uint8_t)val);\n\nerror_out:\n\treturn ret;\n}\n\nint fc0013_rc_cal_reset(void *dev)\n{\n\tint ret;\n\n\tret = fc0013_writereg(dev, 0x0d, 0x01);\n\tif (!ret)\n\t\tret = fc0013_writereg(dev, 0x10, 0x00);\n\n\treturn ret;\n}\n\nstatic int fc0013_set_vhf_track(void *dev, uint32_t freq)\n{\n\tint ret;\n\tuint8_t tmp;\n\n\tret = fc0013_readreg(dev, 0x1d, &tmp);\n\tif (ret)\n\t\tgoto error_out;\n\ttmp &= 0xe3;\n\tif (freq <= 177500000) {\t\t/* VHF Track: 7 */\n\t\tret = fc0013_writereg(dev, 0x1d, tmp | 0x1c);\n\t} else if (freq <= 184500000) {\t/* VHF Track: 6 */\n\t\tret = fc0013_writereg(dev, 0x1d, tmp | 0x18);\n\t} else if (freq <= 191500000) {\t/* VHF Track: 5 */\n\t\tret = fc0013_writereg(dev, 0x1d, tmp | 0x14);\n\t} else if (freq <= 198500000) {\t/* VHF Track: 4 */\n\t\tret = fc0013_writereg(dev, 0x1d, tmp | 0x10);\n\t} else if (freq <= 205500000) {\t/* VHF Track: 3 */\n\t\tret = fc0013_writereg(dev, 0x1d, tmp | 0x0c);\n\t} else if (freq <= 219500000) {\t/* VHF Track: 2 */\n\t\tret = fc0013_writereg(dev, 0x1d, tmp | 0x08);\n\t} else if (freq < 300000000) {\t\t/* VHF Track: 1 */\n\t\tret = fc0013_writereg(dev, 0x1d, tmp | 0x04);\n\t} else {\t\t\t\t/* UHF and GPS */\n\t\tret = fc0013_writereg(dev, 0x1d, tmp | 0x1c);\n\t}\n\nerror_out:\n\treturn ret;\n}\n\nint fc0013_set_params(void *dev, uint32_t freq, uint32_t bandwidth)\n{\n\tint i, ret = 0;\n\tuint8_t reg[7], am, pm, multi, tmp;\n\tuint64_t f_vco;\n\tuint32_t xtal_freq_div_2;\n\tuint16_t xin, xdiv;\n\tint vco_select = 0;\n\n\txtal_freq_div_2 = rtlsdr_get_tuner_clock(dev) / 2;\n\n\t/* set VHF track */\n\tret = fc0013_set_vhf_track(dev, freq);\n\tif (ret)\n\t\tgoto exit;\n\n\tif (freq < 300000000) {\n\t\t/* enable VHF filter */\n\t\tret = fc0013_readreg(dev, 0x07, &tmp);\n\t\tif (ret)\n\t\t\tgoto exit;\n\t\tret = fc0013_writereg(dev, 0x07, tmp | 0x10);\n\t\tif (ret)\n\t\t\tgoto exit;\n\n\t\t/* disable UHF & disable GPS */\n\t\tret = fc0013_readreg(dev, 0x14, &tmp);\n\t\tif (ret)\n\t\t\tgoto exit;\n\t\tret = fc0013_writereg(dev, 0x14, tmp & 0x1f);\n\t\tif (ret)\n\t\t\tgoto exit;\n\t} else if (freq <= 862000000) {\n\t\t/* disable VHF filter */\n\t\tret = fc0013_readreg(dev, 0x07, &tmp);\n\t\tif (ret)\n\t\t\tgoto exit;\n\t\tret = fc0013_writereg(dev, 0x07, tmp & 0xef);\n\t\tif (ret)\n\t\t\tgoto exit;\n\n\t\t/* enable UHF & disable GPS */\n\t\tret = fc0013_readreg(dev, 0x14, &tmp);\n\t\tif (ret)\n\t\t\tgoto exit;\n\t\tret = fc0013_writereg(dev, 0x14, (tmp & 0x1f) | 0x40);\n\t\tif (ret)\n\t\t\tgoto exit;\n\t} else {\n\t\t/* disable VHF filter */\n\t\tret = fc0013_readreg(dev, 0x07, &tmp);\n\t\tif (ret)\n\t\t\tgoto exit;\n\t\tret = fc0013_writereg(dev, 0x07, tmp & 0xef);\n\t\tif (ret)\n\t\t\tgoto exit;\n\n\t\t/* disable UHF & enable GPS */\n\t\tret = fc0013_readreg(dev, 0x14, &tmp);\n\t\tif (ret)\n\t\t\tgoto exit;\n\t\tret = fc0013_writereg(dev, 0x14, (tmp & 0x1f) | 0x20);\n\t\tif (ret)\n\t\t\tgoto exit;\n\t}\n\n\t/* select frequency divider and the frequency of VCO */\n\tif (freq < 37084000) {\t\t/* freq * 96 < 3560000000 */\n\t\tmulti = 96;\n\t\treg[5] = 0x82;\n\t\treg[6] = 0x00;\n\t} else if (freq < 55625000) {\t/* freq * 64 < 3560000000 */\n\t\tmulti = 64;\n\t\treg[5] = 0x02;\n\t\treg[6] = 0x02;\n\t} else if (freq < 74167000) {\t/* freq * 48 < 3560000000 */\n\t\tmulti = 48;\n\t\treg[5] = 0x42;\n\t\treg[6] = 0x00;\n\t} else if (freq < 111250000) {\t/* freq * 32 < 3560000000 */\n\t\tmulti = 32;\n\t\treg[5] = 0x82;\n\t\treg[6] = 0x02;\n\t} else if (freq < 148334000) {\t/* freq * 24 < 3560000000 */\n\t\tmulti = 24;\n\t\treg[5] = 0x22;\n\t\treg[6] = 0x00;\n\t} else if (freq < 222500000) {\t/* freq * 16 < 3560000000 */\n\t\tmulti = 16;\n\t\treg[5] = 0x42;\n\t\treg[6] = 0x02;\n\t} else if (freq < 296667000) {\t/* freq * 12 < 3560000000 */\n\t\tmulti = 12;\n\t\treg[5] = 0x12;\n\t\treg[6] = 0x00;\n\t} else if (freq < 445000000) {\t/* freq * 8 < 3560000000 */\n\t\tmulti = 8;\n\t\treg[5] = 0x22;\n\t\treg[6] = 0x02;\n\t} else if (freq < 593334000) {\t/* freq * 6 < 3560000000 */\n\t\tmulti = 6;\n\t\treg[5] = 0x0a;\n\t\treg[6] = 0x00;\n\t} else if (freq < 950000000) {\t/* freq * 4 < 3800000000 */\n\t\tmulti = 4;\n\t\treg[5] = 0x12;\n\t\treg[6] = 0x02;\n\t} else {\n\t\tmulti = 2;\n\t\treg[5] = 0x0a;\n\t\treg[6] = 0x02;\n\t}\n\n\tf_vco = freq * multi;\n\n\tif (f_vco >= 3060000000U) {\n\t\treg[6] |= 0x08;\n\t\tvco_select = 1;\n\t}\n\n\t/* From divided value (XDIV) determined the FA and FP value */\n\txdiv = (uint16_t)(f_vco / xtal_freq_div_2);\n\tif ((f_vco - xdiv * xtal_freq_div_2) >= (xtal_freq_div_2 / 2))\n\t\txdiv++;\n\n\tpm = (uint8_t)(xdiv / 8);\n\tam = (uint8_t)(xdiv - (8 * pm));\n\n\tif (am < 2) {\n\t\tam += 8;\n\t\tpm--;\n\t}\n\n\tif (pm > 31) {\n\t\treg[1] = am + (8 * (pm - 31));\n\t\treg[2] = 31;\n\t} else {\n\t\treg[1] = am;\n\t\treg[2] = pm;\n\t}\n\n\tif ((reg[1] > 15) || (reg[2] < 0x0b)) {\n#if PRINT_PLL_ERRORS\n\t\tfprintf(stderr, \"[FC0013] no valid PLL combination \"\n\t\t\t\t\"found for %u Hz!\\n\", freq);\n#endif\n\t\treturn -1;\n\t}\n\n\t/* fix clock out */\n\treg[6] |= 0x20;\n\n\t/* From VCO frequency determines the XIN ( fractional part of Delta\n\t   Sigma PLL) and divided value (XDIV) */\n\txin = (uint16_t)((f_vco - (f_vco / xtal_freq_div_2) * xtal_freq_div_2) / 1000);\n\txin = (xin << 15) / (xtal_freq_div_2 / 1000);\n\tif (xin >= 16384)\n\t\txin += 32768;\n\n\treg[3] = xin >> 8;\n\treg[4] = xin & 0xff;\n\n\treg[6] &= 0x3f; /* bits 6 and 7 describe the bandwidth */\n\tswitch (bandwidth) {\n\tcase 6000000:\n\t\treg[6] |= 0x80;\n\t\tbreak;\n\tcase 7000000:\n\t\treg[6] |= 0x40;\n\t\tbreak;\n\tcase 8000000:\n\tdefault:\n\t\tbreak;\n\t}\n\n\t/* modified for Realtek demod */\n\treg[5] |= 0x07;\n\n\tfor (i = 1; i <= 6; i++) {\n\t\tret = fc0013_writereg(dev, i, reg[i]);\n\t\tif (ret)\n\t\t\tgoto exit;\n\t}\n\n\tret = fc0013_readreg(dev, 0x11, &tmp);\n\tif (ret)\n\t\tgoto exit;\n\tif (multi == 64)\n\t\tret = fc0013_writereg(dev, 0x11, tmp | 0x04);\n\telse\n\t\tret = fc0013_writereg(dev, 0x11, tmp & 0xfb);\n\tif (ret)\n\t\tgoto exit;\n\n\t/* VCO Calibration */\n\tret = fc0013_writereg(dev, 0x0e, 0x80);\n\tif (!ret)\n\t\tret = fc0013_writereg(dev, 0x0e, 0x00);\n\n\t/* VCO Re-Calibration if needed */\n\tif (!ret)\n\t\tret = fc0013_writereg(dev, 0x0e, 0x00);\n\n\tif (!ret) {\n//\t\tmsleep(10);\n\t\tret = fc0013_readreg(dev, 0x0e, &tmp);\n\t}\n\tif (ret)\n\t\tgoto exit;\n\n\t/* vco selection */\n\ttmp &= 0x3f;\n\n\tif (vco_select) {\n\t\tif (tmp > 0x3c) {\n\t\t\treg[6] &= ~0x08;\n\t\t\tret = fc0013_writereg(dev, 0x06, reg[6]);\n\t\t\tif (!ret)\n\t\t\t\tret = fc0013_writereg(dev, 0x0e, 0x80);\n\t\t\tif (!ret)\n\t\t\t\tret = fc0013_writereg(dev, 0x0e, 0x00);\n\t\t}\n\t} else {\n\t\tif (tmp < 0x02) {\n\t\t\treg[6] |= 0x08;\n\t\t\tret = fc0013_writereg(dev, 0x06, reg[6]);\n\t\t\tif (!ret)\n\t\t\t\tret = fc0013_writereg(dev, 0x0e, 0x80);\n\t\t\tif (!ret)\n\t\t\t\tret = fc0013_writereg(dev, 0x0e, 0x00);\n\t\t}\n\t}\n\nexit:\n\treturn ret;\n}\n\nint fc0013_set_gain_mode(void *dev, int manual)\n{\n\tint ret = 0;\n\tuint8_t tmp = 0;\n\n\tret |= fc0013_readreg(dev, 0x0d, &tmp);\n\n\tif (manual)\n\t\ttmp |= (1 << 3);\n\telse\n\t\ttmp &= ~(1 << 3);\n\n\tret |= fc0013_writereg(dev, 0x0d, tmp);\n\n\t/* set a fixed IF-gain for now */\n\tret |= fc0013_writereg(dev, 0x13, 0x0a);\n\n\treturn ret;\n}\n\nint fc0013_lna_gains[] ={\n\t-99,\t0x02,\n\t-73,\t0x03,\n\t-65,\t0x05,\n\t-63,\t0x04,\n\t-63,\t0x00,\n\t-60,\t0x07,\n\t-58,\t0x01,\n\t-54,\t0x06,\n\t58,\t\t0x0f,\n\t61,\t\t0x0e,\n\t63,\t\t0x0d,\n\t65,\t\t0x0c,\n\t67,\t\t0x0b,\n\t68,\t\t0x0a,\n\t70,\t\t0x09,\n\t71,\t\t0x08,\n\t179,\t0x17,\n\t181,\t0x16,\n\t182,\t0x15,\n\t184,\t0x14,\n\t186,\t0x13,\n\t188,\t0x12,\n\t191,\t0x11,\n\t197,\t0x10\n};\n\n#define GAIN_CNT\t(sizeof(fc0013_lna_gains) / sizeof(int) / 2)\n\nint fc0013_set_lna_gain(void *dev, int gain)\n{\n\tint ret = 0;\n\tunsigned int i;\n\tuint8_t tmp = 0;\n\n\tret |= fc0013_readreg(dev, 0x14, &tmp);\n\n\t/* mask bits off */\n\ttmp &= 0xe0;\n\n\tfor (i = 0; i < GAIN_CNT; i++) {\n\t\tif ((fc0013_lna_gains[i*2] >= gain) || (i+1 == GAIN_CNT)) {\n\t\t\ttmp |= fc0013_lna_gains[i*2 + 1];\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t/* set gain */\n\tret |= fc0013_writereg(dev, 0x14, tmp);\n\n\treturn ret;\n}\n"
  },
  {
    "path": "src/tuner_fc2580.c",
    "content": "/*\n * FCI FC2580 tuner driver, taken from the kernel driver that can be found\n * on http://linux.terratec.de/tv_en.html\n *\n * This driver is a mess, and should be cleaned up/rewritten.\n *\n */\n\n#include <stdint.h>\n\n#include \"rtlsdr_i2c.h\"\n#include \"tuner_fc2580.h\"\n\n/* 16.384 MHz (at least on the Logilink VG0002A) */\n#define CRYSTAL_FREQ\t\t16384000\n\n/* glue functions to rtl-sdr code */\n\nfc2580_fci_result_type fc2580_i2c_write(void *pTuner, unsigned char reg, unsigned char val)\n{\n\tuint8_t data[2];\n\n\tdata[0] = reg;\n\tdata[1] = val;\n\n\tif (rtlsdr_i2c_write_fn(pTuner, FC2580_I2C_ADDR, data, 2) < 0)\n\t\treturn FC2580_FCI_FAIL;\n\n\treturn FC2580_FCI_SUCCESS;\n}\n\nfc2580_fci_result_type fc2580_i2c_read(void *pTuner, unsigned char reg, unsigned char *read_data)\n{\n\tuint8_t data = reg;\n\n\tif (rtlsdr_i2c_write_fn(pTuner, FC2580_I2C_ADDR, &data, 1) < 0)\n\t\treturn FC2580_FCI_FAIL;\n\n\tif (rtlsdr_i2c_read_fn(pTuner, FC2580_I2C_ADDR, &data, 1) < 0)\n\t\treturn FC2580_FCI_FAIL;\n\n\t*read_data = data;\n\n\treturn FC2580_FCI_SUCCESS;\n}\n\nint fc2580_Initialize(void *pTuner)\n{\n\tint AgcMode;\n\tunsigned int CrystalFreqKhz;\n\n\t//TODO set AGC mode\n\tAgcMode = FC2580_AGC_EXTERNAL;\n\n\t// Initialize tuner with AGC mode.\n\t// Note: CrystalFreqKhz = round(CrystalFreqHz / 1000)\n\tCrystalFreqKhz = (unsigned int)((CRYSTAL_FREQ + 500) / 1000);\n\n\tif(fc2580_set_init(pTuner, AgcMode, CrystalFreqKhz) != FC2580_FCI_SUCCESS)\n\t\tgoto error_status_initialize_tuner;\n\n\n\treturn FUNCTION_SUCCESS;\n\n\nerror_status_initialize_tuner:\n\treturn FUNCTION_ERROR;\n}\n\nint fc2580_SetRfFreqHz(void *pTuner, unsigned long RfFreqHz)\n{\n\tunsigned int RfFreqKhz;\n\tunsigned int CrystalFreqKhz;\n\n\t// Set tuner RF frequency in KHz.\n\t// Note: RfFreqKhz = round(RfFreqHz / 1000)\n\t//       CrystalFreqKhz = round(CrystalFreqHz / 1000)\n\tRfFreqKhz = (unsigned int)((RfFreqHz + 500) / 1000);\n\tCrystalFreqKhz = (unsigned int)((CRYSTAL_FREQ + 500) / 1000);\n\n\tif(fc2580_set_freq(pTuner, RfFreqKhz, CrystalFreqKhz) != FC2580_FCI_SUCCESS)\n\t\tgoto error_status_set_tuner_rf_frequency;\n\n\treturn FUNCTION_SUCCESS;\n\nerror_status_set_tuner_rf_frequency:\n\treturn FUNCTION_ERROR;\n}\n\n/**\n\n@brief   Set FC2580 tuner bandwidth mode.\n\n*/\nint fc2580_SetBandwidthMode(void *pTuner, int BandwidthMode)\n{\n\tunsigned int CrystalFreqKhz;\n\n\t// Set tuner bandwidth mode.\n\t// Note: CrystalFreqKhz = round(CrystalFreqHz / 1000)\n\tCrystalFreqKhz = (unsigned int)((CRYSTAL_FREQ + 500) / 1000);\n\n\tif(fc2580_set_filter(pTuner, (unsigned char)BandwidthMode, CrystalFreqKhz) != FC2580_FCI_SUCCESS)\n\t\tgoto error_status_set_tuner_bandwidth_mode;\n\n\treturn FUNCTION_SUCCESS;\n\n\nerror_status_set_tuner_bandwidth_mode:\n\treturn FUNCTION_ERROR;\n}\n\nvoid fc2580_wait_msec(void *pTuner, int a)\n{\n\t/* USB latency is enough for now ;) */\n//\tusleep(a * 1000);\n\treturn;\n}\n\n/*==============================================================================\n       fc2580 initial setting\n\n  This function is a generic function which gets called to initialize\n\n  fc2580 in DVB-H mode or L-Band TDMB mode\n\n  <input parameter>\n\n  ifagc_mode\n    type : integer\n\t1 : Internal AGC\n\t2 : Voltage Control Mode\n\n==============================================================================*/\nfc2580_fci_result_type fc2580_set_init(void *pTuner, int ifagc_mode, unsigned int freq_xtal)\n{\n\tfc2580_fci_result_type result = FC2580_FCI_SUCCESS;\n\n\tresult &= fc2580_i2c_write(pTuner, 0x00, 0x00);\t/*** Confidential ***/\n\tresult &= fc2580_i2c_write(pTuner, 0x12, 0x86);\n\tresult &= fc2580_i2c_write(pTuner, 0x14, 0x5C);\n\tresult &= fc2580_i2c_write(pTuner, 0x16, 0x3C);\n\tresult &= fc2580_i2c_write(pTuner, 0x1F, 0xD2);\n\tresult &= fc2580_i2c_write(pTuner, 0x09, 0xD7);\n\tresult &= fc2580_i2c_write(pTuner, 0x0B, 0xD5);\n\tresult &= fc2580_i2c_write(pTuner, 0x0C, 0x32);\n\tresult &= fc2580_i2c_write(pTuner, 0x0E, 0x43);\n\tresult &= fc2580_i2c_write(pTuner, 0x21, 0x0A);\n\tresult &= fc2580_i2c_write(pTuner, 0x22, 0x82);\n\tif( ifagc_mode == 1 )\n\t{\n\t\tresult &= fc2580_i2c_write(pTuner, 0x45, 0x10);\t//internal AGC\n\t\tresult &= fc2580_i2c_write(pTuner, 0x4C, 0x00);\t//HOLD_AGC polarity\n\t}\n\telse if( ifagc_mode == 2 )\n\t{\n\t\tresult &= fc2580_i2c_write(pTuner, 0x45, 0x20);\t//Voltage Control Mode\n\t\tresult &= fc2580_i2c_write(pTuner, 0x4C, 0x02);\t//HOLD_AGC polarity\n\t}\n\tresult &= fc2580_i2c_write(pTuner, 0x3F, 0x88);\n\tresult &= fc2580_i2c_write(pTuner, 0x02, 0x0E);\n\tresult &= fc2580_i2c_write(pTuner, 0x58, 0x14);\n\tresult &= fc2580_set_filter(pTuner, 8, freq_xtal);\t//BW = 7.8MHz\n\n\treturn result;\n}\n\n\n/*==============================================================================\n       fc2580 frequency setting\n\n  This function is a generic function which gets called to change LO Frequency\n\n  of fc2580 in DVB-H mode or L-Band TDMB mode\n\n  <input parameter>\n  freq_xtal: kHz\n\n  f_lo\n\tValue of target LO Frequency in 'kHz' unit\n\tex) 2.6GHz = 2600000\n\n==============================================================================*/\nfc2580_fci_result_type fc2580_set_freq(void *pTuner, unsigned int f_lo, unsigned int freq_xtal)\n{\n\tunsigned int f_diff, f_diff_shifted, n_val, k_val;\n\tunsigned int f_vco, r_val, f_comp;\n\tunsigned char pre_shift_bits = 4;// number of preshift to prevent overflow in shifting f_diff to f_diff_shifted\n\tunsigned char data_0x18;\n\tunsigned char data_0x02 = (USE_EXT_CLK<<5)|0x0E;\n\n\tfc2580_band_type band = ( f_lo > 1000000 )? FC2580_L_BAND : ( f_lo > 400000 )? FC2580_UHF_BAND : FC2580_VHF_BAND;\n\n\tfc2580_fci_result_type result = FC2580_FCI_SUCCESS;\n\n\tf_vco = ( band == FC2580_UHF_BAND )? f_lo * 4 : (( band == FC2580_L_BAND )? f_lo * 2 : f_lo * 12);\n\tr_val = ( f_vco >= 2*76*freq_xtal )? 1 : ( f_vco >= 76*freq_xtal )? 2 : 4;\n\tf_comp = freq_xtal/r_val;\n\tn_val =\t( f_vco / 2 ) / f_comp;\n\n\tf_diff = f_vco - 2* f_comp * n_val;\n\tf_diff_shifted = f_diff << ( 20 - pre_shift_bits );\n\tk_val = f_diff_shifted / ( ( 2* f_comp ) >> pre_shift_bits );\n\n\tif( f_diff_shifted - k_val * ( ( 2* f_comp ) >> pre_shift_bits ) >= ( f_comp >> pre_shift_bits ) )\n\tk_val = k_val + 1;\n\n\tif( f_vco >= BORDER_FREQ )\t//Select VCO Band\n\t\tdata_0x02 = data_0x02 | 0x08;\t//0x02[3] = 1;\n\telse\n\t\tdata_0x02 = data_0x02 & 0xF7;\t//0x02[3] = 0;\n\n//\tif( band != curr_band ) {\n\t\tswitch(band)\n\t\t{\n\t\t\tcase FC2580_UHF_BAND:\n\t\t\t\tdata_0x02 = (data_0x02 & 0x3F);\n\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x25, 0xF0);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x27, 0x77);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x28, 0x53);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x29, 0x60);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x30, 0x09);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x50, 0x8C);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x53, 0x50);\n\n\t\t\t\tif( f_lo < 538000 )\n\t\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x5F, 0x13);\n\t\t\t\telse\n\t\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x5F, 0x15);\n\n\t\t\t\tif( f_lo < 538000 )\n\t\t\t\t{\n\t\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x61, 0x07);\n\t\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x62, 0x06);\n\t\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x67, 0x06);\n\t\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x68, 0x08);\n\t\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x69, 0x10);\n\t\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x6A, 0x12);\n\t\t\t\t}\n\t\t\t\telse if( f_lo < 794000 )\n\t\t\t\t{\n\t\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x61, 0x03);\n\t\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x62, 0x03);\n\t\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x67, 0x03);  //ACI improve\n\t\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x68, 0x05);  //ACI improve\n\t\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x69, 0x0C);\n\t\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x6A, 0x0E);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x61, 0x07);\n\t\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x62, 0x06);\n\t\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x67, 0x07);\n\t\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x68, 0x09);\n\t\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x69, 0x10);\n\t\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x6A, 0x12);\n\t\t\t\t}\n\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x63, 0x15);\n\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x6B, 0x0B);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x6C, 0x0C);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x6D, 0x78);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x6E, 0x32);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x6F, 0x14);\n\t\t\t\tresult &= fc2580_set_filter(pTuner, 8, freq_xtal);\t//BW = 7.8MHz\n\t\t\t\tbreak;\n\t\t\tcase FC2580_VHF_BAND:\n\t\t\t\tdata_0x02 = (data_0x02 & 0x3F) | 0x80;\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x27, 0x77);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x28, 0x33);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x29, 0x40);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x30, 0x09);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x50, 0x8C);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x53, 0x50);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x5F, 0x0F);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x61, 0x07);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x62, 0x00);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x63, 0x15);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x67, 0x03);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x68, 0x05);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x69, 0x10);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x6A, 0x12);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x6B, 0x08);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x6C, 0x0A);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x6D, 0x78);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x6E, 0x32);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x6F, 0x54);\n\t\t\t\tresult &= fc2580_set_filter(pTuner, 7, freq_xtal);\t//BW = 6.8MHz\n\t\t\t\tbreak;\n\t\t\tcase FC2580_L_BAND:\n\t\t\t\tdata_0x02 = (data_0x02 & 0x3F) | 0x40;\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x2B, 0x70);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x2C, 0x37);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x2D, 0xE7);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x30, 0x09);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x44, 0x20);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x50, 0x8C);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x53, 0x50);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x5F, 0x0F);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x61, 0x0F);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x62, 0x00);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x63, 0x13);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x67, 0x00);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x68, 0x02);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x69, 0x0C);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x6A, 0x0E);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x6B, 0x08);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x6C, 0x0A);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x6D, 0xA0);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x6E, 0x50);\n\t\t\t\tresult &= fc2580_i2c_write(pTuner, 0x6F, 0x14);\n\t\t\t\tresult &= fc2580_set_filter(pTuner, 1, freq_xtal);\t//BW = 1.53MHz\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n//\t\tcurr_band = band;\n//\t}\n\n\t//A command about AGC clock's pre-divide ratio\n\tif( freq_xtal >= 28000 )\n\t\tresult &= fc2580_i2c_write(pTuner, 0x4B, 0x22 );\n\n\t//Commands about VCO Band and PLL setting.\n\tresult &= fc2580_i2c_write(pTuner, 0x02, data_0x02);\n\tdata_0x18 = ( ( r_val == 1 )? 0x00 : ( ( r_val == 2 )? 0x10 : 0x20 ) ) + (unsigned char)(k_val >> 16);\n\tresult &= fc2580_i2c_write(pTuner, 0x18, data_0x18);\t\t\t\t\t\t//Load 'R' value and high part of 'K' values\n\tresult &= fc2580_i2c_write(pTuner, 0x1A, (unsigned char)( k_val >> 8 ) );\t//Load middle part of 'K' value\n\tresult &= fc2580_i2c_write(pTuner, 0x1B, (unsigned char)( k_val ) );\t\t//Load lower part of 'K' value\n\tresult &= fc2580_i2c_write(pTuner, 0x1C, (unsigned char)( n_val ) );\t\t//Load 'N' value\n\n\t//A command about UHF LNA Load Cap\n\tif( band == FC2580_UHF_BAND )\n\t\tresult &= fc2580_i2c_write(pTuner, 0x2D, ( f_lo <= (unsigned int)794000 )? 0x9F : 0x8F );\t//LNA_OUT_CAP\n\n\n\treturn result;\n}\n\n\n/*==============================================================================\n       fc2580 filter BW setting\n\n  This function is a generic function which gets called to change Bandwidth\n\n  frequency of fc2580's channel selection filter\n\n  <input parameter>\n  freq_xtal: kHz\n\n  filter_bw\n    1 : 1.53MHz(TDMB)\n\t6 : 6MHz   (Bandwidth 6MHz)\n\t7 : 6.8MHz (Bandwidth 7MHz)\n\t8 : 7.8MHz (Bandwidth 8MHz)\n\n\n==============================================================================*/\nfc2580_fci_result_type fc2580_set_filter(void *pTuner, unsigned char filter_bw, unsigned int freq_xtal)\n{\n\tunsigned char\tcal_mon = 0, i;\n\tfc2580_fci_result_type result = FC2580_FCI_SUCCESS;\n\n\tif(filter_bw == 1)\n\t{\n\t\tresult &= fc2580_i2c_write(pTuner, 0x36, 0x1C);\n\t\tresult &= fc2580_i2c_write(pTuner, 0x37, (unsigned char)(4151*freq_xtal/1000000) );\n\t\tresult &= fc2580_i2c_write(pTuner, 0x39, 0x00);\n\t\tresult &= fc2580_i2c_write(pTuner, 0x2E, 0x09);\n\t}\n\tif(filter_bw == 6)\n\t{\n\t\tresult &= fc2580_i2c_write(pTuner, 0x36, 0x18);\n\t\tresult &= fc2580_i2c_write(pTuner, 0x37, (unsigned char)(4400*freq_xtal/1000000) );\n\t\tresult &= fc2580_i2c_write(pTuner, 0x39, 0x00);\n\t\tresult &= fc2580_i2c_write(pTuner, 0x2E, 0x09);\n\t}\n\telse if(filter_bw == 7)\n\t{\n\t\tresult &= fc2580_i2c_write(pTuner, 0x36, 0x18);\n\t\tresult &= fc2580_i2c_write(pTuner, 0x37, (unsigned char)(3910*freq_xtal/1000000) );\n\t\tresult &= fc2580_i2c_write(pTuner, 0x39, 0x80);\n\t\tresult &= fc2580_i2c_write(pTuner, 0x2E, 0x09);\n\t}\n\telse if(filter_bw == 8)\n\t{\n\t\tresult &= fc2580_i2c_write(pTuner, 0x36, 0x18);\n\t\tresult &= fc2580_i2c_write(pTuner, 0x37, (unsigned char)(3300*freq_xtal/1000000) );\n\t\tresult &= fc2580_i2c_write(pTuner, 0x39, 0x80);\n\t\tresult &= fc2580_i2c_write(pTuner, 0x2E, 0x09);\n\t}\n\n\n\tfor(i=0; i<5; i++)\n\t{\n\t\tfc2580_wait_msec(pTuner, 5);//wait 5ms\n\t\tresult &= fc2580_i2c_read(pTuner, 0x2F, &cal_mon);\n\t\tif( (cal_mon & 0xC0) != 0xC0)\n\t\t{\n\t\t\tresult &= fc2580_i2c_write(pTuner, 0x2E, 0x01);\n\t\t\tresult &= fc2580_i2c_write(pTuner, 0x2E, 0x09);\n\t\t}\n\t\telse\n\t\t\tbreak;\n\t}\n\n\tresult &= fc2580_i2c_write(pTuner, 0x2E, 0x01);\n\n\treturn result;\n}\n\n/*==============================================================================\n       fc2580 RSSI function\n\n  This function is a generic function which returns fc2580's\n\n  current RSSI value.\n\n  <input parameter>\n\tnone\n\n  <return value>\n  int\n  \trssi : estimated input power.\n\n==============================================================================*/\n//int fc2580_get_rssi(void) {\n//\n//\tunsigned char s_lna, s_rfvga, s_cfs, s_ifvga;\n//\tint ofs_lna, ofs_rfvga, ofs_csf, ofs_ifvga, rssi;\n//\n//\tfc2580_i2c_read(0x71, &s_lna );\n//\tfc2580_i2c_read(0x72, &s_rfvga );\n//\tfc2580_i2c_read(0x73, &s_cfs );\n//\tfc2580_i2c_read(0x74, &s_ifvga );\n//\n//\n//\tofs_lna =\n//\t\t\t(curr_band==FC2580_UHF_BAND)?\n//\t\t\t\t(s_lna==0)? 0 :\n//\t\t\t\t(s_lna==1)? -6 :\n//\t\t\t\t(s_lna==2)? -17 :\n//\t\t\t\t(s_lna==3)? -22 : -30 :\n//\t\t\t(curr_band==FC2580_VHF_BAND)?\n//\t\t\t\t(s_lna==0)? 0 :\n//\t\t\t\t(s_lna==1)? -6 :\n//\t\t\t\t(s_lna==2)? -19 :\n//\t\t\t\t(s_lna==3)? -24 : -32 :\n//\t\t\t(curr_band==FC2580_L_BAND)?\n//\t\t\t\t(s_lna==0)? 0 :\n//\t\t\t\t(s_lna==1)? -6 :\n//\t\t\t\t(s_lna==2)? -11 :\n//\t\t\t\t(s_lna==3)? -16 : -34 :\n//\t\t\t0;//FC2580_NO_BAND\n//\tofs_rfvga = -s_rfvga+((s_rfvga>=11)? 1 : 0) + ((s_rfvga>=18)? 1 : 0);\n//\tofs_csf = -6*s_cfs;\n//\tofs_ifvga = s_ifvga/4;\n//\n//\treturn rssi = ofs_lna+ofs_rfvga+ofs_csf+ofs_ifvga+OFS_RSSI;\n//\n//}\n\n/*==============================================================================\n       fc2580 Xtal frequency Setting\n\n  This function is a generic function which sets\n\n  the frequency of xtal.\n\n  <input parameter>\n\n  frequency\n  \tfrequency value of internal(external) Xtal(clock) in kHz unit.\n\n==============================================================================*/\n//void fc2580_set_freq_xtal(unsigned int frequency) {\n//\n//\tfreq_xtal = frequency;\n//\n//}\n\n"
  },
  {
    "path": "src/tuner_r82xx.c",
    "content": "/*\n * Rafael Micro R820T/R828D driver\n *\n * Copyright (C) 2013 Mauro Carvalho Chehab <mchehab@redhat.com>\n * Copyright (C) 2013 Steve Markgraf <steve@steve-m.de>\n *\n * This driver is a heavily modified version of the driver found in the\n * Linux kernel:\n * http://git.linuxtv.org/linux-2.6.git/history/HEAD:/drivers/media/tuners/r820t.c\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <stdio.h>\n#include <stdint.h>\n#include <string.h>\n#include <stdlib.h>\n\n#include \"rtlsdr_i2c.h\"\n#include \"tuner_r82xx.h\"\n\n#define WITH_ASYM_FILTER\t0\n#define PRINT_PLL_ERRORS\t0\n#define PRINT_VGA_REG\t\t0\n#define PRINT_INITIAL_REGISTERS\t\t0\n#define PRINT_ACTUAL_VCO_AND_ERR\t0\n\n/* use fifth harmonic above this frequency in kHz, when PLL does NOT lock */\n#define FIFTH_HARM_FRQ_THRESH_KHZ\t1770000\n#define RETRY_WITH_FIFTH_HARM_KHZ\t1760000\n#define DEFAULT_HARMONIC\t\t\t5\n#define PRINT_HARMONICS\t\t\t\t0\n\n\n/* #define VGA_FOR_AGC_MODE\t16 */\n#define DEFAULT_IF_VGA_VAL\t11\n\n\n#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))\n#define MHZ(x)\t\t((x)*1000*1000)\n#define KHZ(x)\t\t((x)*1000)\n\n#define HF 1\n#define VHF 2\n#define UHF 3\n\n/*\nRegister Description\nmany updates from https://github.com/old-dab/rtlsdr\n\nReg\t\tBitmap\tSymbol\t\t\tDescription\n------------------------------------------------------------------------------------\nR0\t\t[7:0]\tCHIP_ID\t\t\treference check point for read mode: 0x96\n0x00\n------------------------------------------------------------------------------------\nR1\t\t[7:6]\t\t\t\t\t10\n0x01\t[5:0]\tADC\t\t\t\tAnalog-Digital Converter for detector 3\n------------------------------------------------------------------------------------\nR2\t\t[7]\t\t\t\t\t\t1\n0x02\t[6]\t\tVCO_INDICATOR\t0: PLL has not locked, 1: PLL has locked\n\t\t[5:0]\t\t\t\t\tAnalog-Digital Converter for VCO\n\t \t\t\t\t\t\t\t000000: min (1.75 GHz), 111111: max (3.6 GHz)\n------------------------------------------------------------------------------------\nR3\t\t[7:4]\tRF_INDICATOR\tMixer gain\n0x03\t\t\t\t\t\t\t0: Lowest, 15: Highest\n\t\t[3:0]\t\t\t\t\tLNA gain\n\t\t\t\t\t\t\t\t0: Lowest, 15: Highest\n------------------------------------------------------------------------------------\nR4\t\t[5:4]\t\t\t\t\tvco_fine_tune\n0x04\t[3:0]\t\t\t\t\tfil_cal_code\n------------------------------------------------------------------------------------\nR5\t\t[7] \tLOOP_THROUGH\tLoop through ON/OFF\n0x05\t\t\t\t\t\t\t0: on, 1: off\n\t\t[6:5]\tAIR_CABLE1_IN\t0 (only R828D)\n\t\t[5] \tPWD_LNA1\t\tLNA 1 power control\n\t\t\t\t\t\t\t\t0:on, 1:off\n\t\t[4] \tLNA_GAIN_MODE\tLNA gain mode switch\n\t\t\t\t\t\t\t\t0: auto, 1: manual\n\t\t[3:0] \tLNA_GAIN\t\tLNA manual gain control\n\t\t\t\t\t\t\t\t15: max gain, 0: min gain\n------------------------------------------------------------------------------------\nR6\t\t[7] \tPWD_PDET1\t\tPower detector 1 on/off\n0x06\t\t\t\t\t\t\t0: on, 1: off\n\t\t[6] \tPWD_PDET3\t\tPower detector 3 on/off\n\t\t\t\t\t\t\t\t0: off, 1: on\n\t\t[5] \tFILT_GAIN\t\tFilter gain 3db\n\t\t\t\t\t\t\t\t0:0db, 1:+3db\n\t\t[4]\t\t\t\t\t\t1\n\t\t[3]\t\tCABLE2_IN\t\t0 (only R828D)\n\t\t[2:0]\tPW_LNA\t\t\tLNA power control\n\t\t\t\t\t\t\t\t000: max, 111: min\n------------------------------------------------------------------------------------\nR7\t\t[7]\t\tIMG_R\t\t\tMixer Sideband\n0x07\t\t\t\t\t\t\t0: lower, 1: upper\n\t\t[6] \tPWD_MIX\t\t\tMixer power\n\t\t\t\t\t\t\t\t0:off, 1:on\n\t\t[5] \tPW0_MIX\t\t\tMixer current control\n\t\t\t\t\t\t\t\t0:max current, 1:normal current\n\t\t[4] \tMIXGAIN_MODE\tMixer gain mode\n\t\t\t\t\t\t\t\t0:manual mode, 1:auto mode\n\t\t[3:0] \tMIX_GAIN\t\tMixer manual gain control\n\t\t\t\t\t\t\t\t0000->min, 1111->max\n------------------------------------------------------------------------------------\nR8\t\t[7] \tPWD_AMP\t\t\tMixer buffer power on/off\n0x08\t\t\t\t\t\t\t0: off, 1:on\n\t\t[6] \tPW0_AMP\t\t\tMixer buffer current setting\n\t\t\t\t\t\t\t\t0: high current, 1: low current\n\t\t[5]\t\t\t\t\t\t0: Q, 1: I\n\t\t[4:0] \tIMR_G\t\t\tImage Gain Adjustment\n\t\t\t\t\t\t\t\t0: min, 31: max\n------------------------------------------------------------------------------------\nR9\t\t[7] \tPWD_IFFILT\t\tIF Filter power on/off\n0x09\t\t\t\t\t\t\t0: filter on, 1: off\n\t\t[6] \tPW1_IFFILT\t\tIF Filter current\n\t\t\t\t\t\t\t\t0: high current, 1: low current\n\t\t[5]\t\t\t\t\t\t0: Q, 1: I\n\t\t[4:0] \tIMR_P\t\t\tImage Phase Adjustment\n\t\t\t\t\t\t\t\t0: min, 31: max\n------------------------------------------------------------------------------------\nR10\t\t[7] \tPWD_FILT\t\tFilter power on/off\n0x0A\t\t\t\t\t\t\t0: channel filter off, 1: on\n\t\t[6:5] \tPW_FILT\t\t\tFilter power control\n\t\t\t\t\t\t\t\t00: highest power, 11: lowest power\n\t\t[4]\t\tFILT_Q\t\t\t1\n\t\t[3:0] \tFILT_CODE\t\tFilter bandwidth manual fine tune\n\t\t\t\t\t\t\t\t0000 Widest, 1111 narrowest\n------------------------------------------------------------------------------------\nR11\t\t[7:5] \tFILT_BW\t\t\tFilter bandwidth manual course tunnel\n0x0B\t\t\t\t\t\t\t000: widest\n\t\t\t\t\t\t\t\t010 or 001: middle\n\t\t\t\t\t\t\t\t111: narrowest\n\t\t[4]\t\tCAL_TRIGGER\t\t0\n\t\t[3:0] \tHP_COR\t\t\tHigh pass filter corner control\n\t\t\t\t\t\t\t\t0000: highest\n\t\t\t\t\t\t\t\t1111: lowest\n------------------------------------------------------------------------------------\nR12\t\t[7]\t\tSW_ADC\t\t\tSwitch Analog-Digital Converter for detector 3 (see R1)\n\t\t\t\t\t\t\t\t0: on, 1: off\n0x0C\t[6] \tPWD_VGA\t\t\tVGA power control\n\t\t\t\t\t\t\t\t0: vga power off, 1: vga power on\n\t\t[5]\t\t\t\t\t\t1\n\t\t[4] \tVGA_MODE\t\tVGA GAIN manual / pin selector\n\t\t\t\t\t\t\t\t1: IF vga gain controlled by vagc pin\n\t\t\t\t\t\t\t\t0: IF vga gain controlled by vga_code[3:0]\n\t\t[3:0] \tVGA_CODE\t\tIF vga manual gain control\n\t\t\t\t\t\t\t\t0000: -12.0 dB\n\t\t\t\t\t\t\t\t1111: +40.5 dB; -3.5dB/step\n------------------------------------------------------------------------------------\nR13\t\t[7:4]\tLNA_VTHH\t\tLNA agc power detector voltage threshold high setting\n0x0D\t\t\t\t\t\t\t1111: 1.94 V\n\t\t\t\t\t\t\t\t0000: 0.34 V, ~0.1 V/step\n\t\t[3:0] \tLNA_VTHL\t\tLNA agc power detector voltage threshold low setting\n\t\t\t\t\t\t\t\t1111: 1.94 V\n\t\t\t\t\t\t\t\t0000: 0.34 V, ~0.1 V/step\n------------------------------------------------------------------------------------\nR14 \t[7:4] \tMIX_VTH_H\t\tMIXER agc power detector voltage threshold high setting\n0x0E\t\t\t\t\t\t\t1111: 1.94 V\n\t\t\t\t\t\t\t\t0000: 0.34 V, ~0.1 V/step\n\t\t[3:0] \tMIX_VTH_L\t\tMIXER agc power detector voltage threshold low setting\n\t\t\t\t\t\t\t\t1111: 1.94 V\n\t\t\t\t\t\t\t\t0000: 0.34 V, ~0.1 V/step\n------------------------------------------------------------------------------------\nR15\t\t[7]\t\tFLT_EXT_WIDEST\tfilter extension widest\n0x0F\t\t\t\t\t\t\t0: off, 1: on\n\t\t[4] \tCLK_OUT_ENB\t\tClock out pin control\n\t\t\t\t\t\t\t\t0: clk output on, 1: off\n\t\t[3]\t\t\t\t\t\tring clk\n\t\t\t\t\t\t\t\t1: off, 0: on\n\t\t[2]\t\t\t\t\t\tset cali clk\n\t\t\t\t\t\t\t\t0: off, 1: on\n\t\t[1] \tCLK_AGC_ENB\t\tAGC clk control\n\t\t\t\t\t\t\t\t0: internal agc clock on, 1: off\n\t\t[0]\t\tGPIO\t\t\t0\n------------------------------------------------------------------------------------\nR16\t\t[7:5] \tSEL_DIV\t\t\tPLL to Mixer divider number control\n0x10\t\t\t\t\t\t\t000: mixer in = vco out / 2\n\t\t\t\t\t\t\t\t001: mixer in = vco out / 4\n\t\t\t\t\t\t\t\t010: mixer in = vco out / 8\n\t\t\t\t\t\t\t\t011: mixer in = vco out / 16\n\t\t\t\t\t\t\t\t100: mixer in = vco out / 32\n\t\t\t\t\t\t\t\t101: mixer in = vco out / 64\n\t\t[4] \tREFDIV\t\t\tPLL Reference frequency Divider\n\t\t\t\t\t\t\t\t0 -> fref=xtal_freq\n\t\t\t\t\t\t\t\t1 -> fref=xta_freql / 2 (for Xtal >24MHz)\n\t\t[3]\t\t\t\t\t\tX'tal Drive\n\t\t\t\t\t\t\t\t0: High, 1: Low\n\t\t[2]\t\t\t\t\t\t1\n\t\t[1:0] \tCAPX\t\t\tInternal xtal cap setting\n\t\t\t\t\t\t\t\t00->no cap\n\t\t\t\t\t\t\t\t01->10pF\n\t\t\t\t\t\t\t\t10->20pF\n\t\t\t\t\t\t\t\t11->30pF\n------------------------------------------------------------------------------------\nR17\t\t[7:6] \tPW_LDO_A\t\tPLL analog low drop out regulator switch\n0x11\t\t\t\t\t\t\t00: off\n\t\t\t\t\t\t\t\t01: 2.1V\n\t\t\t\t\t\t\t\t10: 2.0V\n\t\t\t\t\t\t\t\t11: 1.9V\n\t\t[5:3]\tCP_CUR\t\t\tcp_cur\n\t\t\t\t\t\t\t\t101: 0.2, 111: auto\n\t\t[2:0]\t\t\t\t\t011\n------------------------------------------------------------------------------------\nR18\t\t[7:5] \t\t\t\t\tset VCO current\n0x12\t[4]\t\t\t\t\t\t0: enable dithering, 1: disable dithering\n\t\t[3]\t\tPW_SDM\t\t\t0: Enable frac pll, 1: Disable frac pll\n\t\t[2:0]\t\t\t\t\t000\n------------------------------------------------------------------------------------\nR19\t\t[7]\t\t\t\t\t\t0\n0x13\t[6]\t\t\t\t\t\tVCO control mode\n\t\t\t\t\t\t\t\t0: auto mode, VCO controlled by PLL\n\t\t\t\t\t\t\t\t1: manual mode, VCO controlled by DAC code[5:0]\n\t\t[5:0]\tVCO_DAC\t\t\tDAC for VCO\n\t \t\t\t\t\t\t\t000000: min (1.75 GHz), 111111: max (3.6 GHz)\n------------------------------------------------------------------------------------\nR20\t\t[7:6] \tSI2C\t\t\tPLL integer divider number input Si2c\n0x14\t\t\t\t\t\t\tNint=4*Ni2c+Si2c+13\n\t\t\t\t\t\t\t\tPLL divider number Ndiv = (Nint + Nfra)*2\n\t\t[5:0] \tNI2C\t\t\tPLL integer divider number input Ni2c\n------------------------------------------------------------------------------------\nR21\t\t[7:0] \tSDM_IN[8:1]\t\tPLL fractional divider number input SDM[16:1]\n0x15\t\t\t\t\t\t\tNfra=SDM_IN[16]*2^-1+SDM_IN[15]*2^-2+...\nR22\t\t[7:0] \tSDM_IN[16:9]\t+SDM_IN[2]*2^-15+SDM_IN[1]*2^-16\n0x16\n------------------------------------------------------------------------------------\nR23\t\t[7:6] \tPW_LDO_D\t\tPLL digital low drop out regulator supply current switch\n0x17\t\t\t\t\t\t\t00: 1.8V,8mA\n\t\t\t\t\t\t\t\t01: 1.8V,4mA\n\t\t\t\t\t\t\t\t10: 2.0V,8mA\n\t\t\t\t\t\t\t\t11: OFF\n\t\t[5:4]\tDIV_BUF_CUR\t\tdiv_buf_cur\n\t\t\t\t\t\t\t\t10: 200u, 11: 150u\n\t\t[3] \tOPEN_D\t\t\tOpen drain\n\t\t\t\t\t\t\t\t0: High-Z, 1: Low-Z\n\t\t[2:0]\t\t\t\t\t100\n------------------------------------------------------------------------------------\nR24\t\t[7:6]\t\t\t\t\t01\n\t\t[5]\t\tring_div[0]\t\tring_div bit 0, see ring_div[2:1] in R25\n0x18\t[4] \t\t\t\t\tring power\n\t\t\t\t\t\t\t\t0: off, 1:on\n\t\t[3:0]\t\t\t\t\tn_ring\n\t\t\t\t\t\t\t\tring_vco = (16+n_ring)*8*pll_ref, n_ring = 9...14\n------------------------------------------------------------------------------------\nR25\t\t[7] \tPWD_RFFILT\t\tRF Filter power\n0x19\t\t\t\t\t\t\t0: off, 1:on\n\t\t[6:5]\tPOLYFIL_CUR\t\tRF poly filter current\n\t\t\t\t\t\t\t\t00: min\n\t\t[4] \tSW_AGC\t\t\tSwitch agc_pin\n\t\t\t\t\t\t\t\t0:agc=agc_in\n\t\t\t\t\t\t\t\t1:agc=agc_in2\n\t\t[3:2]\t\t\t\t\t11\n\t\t[1:0]\tring_div[2:1]\tcal_freq = ring_vco / divisor; see ring_div[0] in R24\n\t\t\t\t\t\t\t\t000: ring_freq = ring_vco / 4\n\t\t\t\t\t\t\t\t001: ring_freq = ring_vco / 6\n\t\t\t\t\t\t\t\t010: ring_freq = ring_vco / 8\n\t\t\t\t\t\t\t\t011: ring_freq = ring_vco / 12\n\t\t\t\t\t\t\t\t100: ring_freq = ring_vco / 16\n\t\t\t\t\t\t\t\t101: ring_freq = ring_vco / 24\n\t\t\t\t\t\t\t\t110: ring_freq = ring_vco / 32\n\t\t\t\t\t\t\t\t111: ring_freq = ring_vco / 48\n------------------------------------------------------------------------------------\nR26\t\t[7:6] \tRF_MUX_POLY\t\tTracking Filter switch\n0x1A\t\t\t\t\t\t\t00: TF on\n\t\t\t\t\t\t\t\t01: Bypass\n\t\t[5:4]\t\t\t\t\tAGC clk\n\t\t\t\t\t\t\t\t00: 300ms, 01: 300ms, 10: 80ms, 11: 20ms\n\t\t[3:2]\tPLL_AUTO_CLK\tPLL auto tune clock rate\n\t\t\t\t\t\t\t\t00: 128 kHz\n\t\t\t\t\t\t\t\t01: 32 kHz\n\t\t\t\t\t\t\t\t10: 8 kHz\n\t\t[1:0]\tRFFILT\t\t\tRF FILTER band selection\n\t\t\t\t\t\t\t\t00: highest band\n\t\t\t\t\t\t\t\t01: med band\n\t\t\t\t\t\t\t\t10: low band\n------------------------------------------------------------------------------------\nR27\t\t[7:4]\tTF_NCH\t\t\t0000 highest corner for LPNF\n0x1B\t\t\t\t\t\t\t1111 lowest corner for LPNF\n\t\t[3:0]\tTF_LP\t\t\t0000 highest corner for LPF\n\t\t\t\t\t\t\t\t1111 lowest corner for LPF\n------------------------------------------------------------------------------------\nR28\t\t[7:4]\tMIXER_TOP\t\tPower detector 3 (Mixer) TOP(take off point) control\n0x1C\t\t\t\t\t\t\t0: Highest, 15: Lowest\n\t\t[3]\t\t\t\t\t\tdischarge mode\n\t\t\t\t\t\t\t\t0: on\n\t\t[2]\t\t\t\t\t\t1\n\t\t[1]\t\t\t\t\t\t1: from ring = ring pll in\n\t\t[0]\t\t\t\t\t\t0\n------------------------------------------------------------------------------------\nR29\t\t[7:6]\t\t\t\t\t11\n0x1D\t[5:3]\tLNA_TOP\t\t\tPower detector 1 (LNA) TOP(take off point) control\n\t\t\t\t\t\t\t\t0: Highest, 7: Lowest\n\t\t[2:0] \tPDET2_GAIN\t\tPower detector 2 TOP(take off point) control\n\t\t\t\t\t\t\t\t0: Highest, 7: Lowest\n------------------------------------------------------------------------------------\nR30\t\t[7]\t\t\t\t\t\tsw_pdect\n0x1E\t\t\t\t\t\t\t1: sw_pdect = det3\n\t \t[6]\t\tFILTER_EXT\t\tFilter extension under weak signal\n\t\t\t\t\t\t\t\t0: Disable, 1: Enable\n\t\t[5:0]\tPDET_CLK\t\tPower detector timing control (LNA discharge current)\n\t \t\t\t\t\t\t\t111111: max, 000000: min\n------------------------------------------------------------------------------------\nR31\t\t[7]\t\tLT_ATT\t\t\tLoop through attenuation\n0x1F\t\t\t\t\t\t\t0: Enable, 1: Disable\n\t\t[6:2]\t\t\t\t\t10000\n\t\t[1:0]\t\t\t\t\tpw_ring\n\t\t\t\t\t\t\t\t0: -5dB, 1: 0dB, 2: -8dB, 3: -3dB\n------------------------------------------------------------------------------------\nR0...R4 read, R5...R15 read/write, R16..R31 write\n*/\n\n\n/*\n * Static constants\n */\n\n/* Those initial values start from REG_SHADOW_START */\nstatic const uint8_t r82xx_init_array[] = {\n\t0x80,\t/* Reg 0x05 */\n\t0x13,\t/* Reg 0x06 */\n\t0x70,\t/* Reg 0x07 */\n\n\t0xc0,\t/* Reg 0x08 */\n\t0x40,\t/* Reg 0x09 */\n\t0xdb,\t/* Reg 0x0a */\n\t0x6b,\t/* Reg 0x0b */\n\n\t/* Reg 0x0c:\n\t * for manual gain was: set fixed VGA gain for now (16.3 dB): 0x08\n\t * with active agc was: set fixed VGA gain for now (26.5 dB): 0x0b */\n\t0xe0 | DEFAULT_IF_VGA_VAL, /* Reg 0x0c */\n\t0x53,\t/* Reg 0x0d */\n\t0x75,\t/* Reg 0x0e */\n\t0x68,\t/* Reg 0x0f */\n\n\t0x6c,\t/* Reg 0x10 */\n\t0xbb,\t/* Reg 0x11 */\n\t0x80,\t/* Reg 0x12 */\n\tVER_NUM & 0x3f,\t/* Reg 0x13 */\n\n\t0x0f,\t/* Reg 0x14 */\n\t0x00,\t/* Reg 0x15 */\n\t0xc0,\t/* Reg 0x16 */\n\t0x30,\t/* Reg 0x17 */\n\n\t0x48,\t/* Reg 0x18 */\n\t0xec,\t/* Reg 0x19 */\n\t0x60,\t/* Reg 0x1a */\n\t0x00,\t/* Reg 0x1b */\n\n\t0x24,\t/* Reg 0x1c */\n\t0xdd,\t/* Reg 0x1d */\n\t0x0e,\t/* Reg 0x1e */\n\t0x40\t/* Reg 0x1f */\n};\n\n/* Tuner frequency ranges */\nstatic const struct r82xx_freq_range freq_ranges[] = {\n\t{\n\t/* .freq = */\t\t\t0,\t/* Start freq, in MHz */\n\t/* .open_d = */\t\t\t0x08,\t/* low */\n\t/* .rf_mux_ploy = */\t0x02,\t/* R26[7:6]=0 (LPF)  R26[1:0]=2 (low) */\n\t/* .tf_c = */\t\t\t0xdf,\t/* R27[7:0]  band2,band0 */\n\t/* .xtal_cap20p = */\t0x02,\t/* R16[1:0]  20pF (10)   */\n\t/* .xtal_cap10p = */\t0x01,\n\t/* .xtal_cap0p = */\t\t0x00,\n\t}, {\n\t/* .freq = */\t\t\t50,\t/* Start freq, in MHz */\n\t/* .open_d = */\t\t\t0x08,\t/* low */\n\t/* .rf_mux_ploy = */\t0x02,\t/* R26[7:6]=0 (LPF)  R26[1:0]=2 (low) */\n\t/* .tf_c = */\t\t\t0xbe,\t/* R27[7:0]  band4,band1  */\n\t/* .xtal_cap20p = */\t0x02,\t/* R16[1:0]  20pF (10)   */\n\t/* .xtal_cap10p = */\t0x01,\n\t/* .xtal_cap0p = */\t\t0x00,\n\t}, {\n\t/* .freq = */\t\t\t55,\t/* Start freq, in MHz */\n\t/* .open_d = */\t\t\t0x08,\t/* low */\n\t/* .rf_mux_ploy = */\t0x02,\t/* R26[7:6]=0 (LPF)  R26[1:0]=2 (low) */\n\t/* .tf_c = */\t\t\t0x8b,\t/* R27[7:0]  band7,band4 */\n\t/* .xtal_cap20p = */\t0x02,\t/* R16[1:0]  20pF (10)   */\n\t/* .xtal_cap10p = */\t0x01,\n\t/* .xtal_cap0p = */\t\t0x00,\n\t}, {\n\t/* .freq = */\t\t\t60,\t/* Start freq, in MHz */\n\t/* .open_d = */\t\t\t0x08,\t/* low */\n\t/* .rf_mux_ploy = */\t0x02,\t/* R26[7:6]=0 (LPF)  R26[1:0]=2 (low) */\n\t/* .tf_c = */\t\t\t0x7b,\t/* R27[7:0]  band8,band4 */\n\t/* .xtal_cap20p = */\t0x02,\t/* R16[1:0]  20pF (10)   */\n\t/* .xtal_cap10p = */\t0x01,\n\t/* .xtal_cap0p = */\t\t0x00,\n\t}, {\n\t/* .freq = */\t\t\t65,\t/* Start freq, in MHz */\n\t/* .open_d = */\t\t\t0x08,\t/* low */\n\t/* .rf_mux_ploy = */\t0x02,\t/* R26[7:6]=0 (LPF)  R26[1:0]=2 (low) */\n\t/* .tf_c = */\t\t\t0x69,\t/* R27[7:0]  band9,band6 */\n\t/* .xtal_cap20p = */\t0x02,\t/* R16[1:0]  20pF (10)   */\n\t/* .xtal_cap10p = */\t0x01,\n\t/* .xtal_cap0p = */\t\t0x00,\n\t}, {\n\t/* .freq = */\t\t\t70,\t/* Start freq, in MHz */\n\t/* .open_d = */\t\t\t0x08,\t/* low */\n\t/* .rf_mux_ploy = */\t0x02,\t/* R26[7:6]=0 (LPF)  R26[1:0]=2 (low) */\n\t/* .tf_c = */\t\t\t0x58,\t/* R27[7:0]  band10,band7 */\n\t/* .xtal_cap20p = */\t0x02,\t/* R16[1:0]  20pF (10)   */\n\t/* .xtal_cap10p = */\t0x01,\n\t/* .xtal_cap0p = */\t\t0x00,\n\t}, {\n\t/* .freq = */\t\t\t75,\t/* Start freq, in MHz */\n\t/* .open_d = */\t\t\t0x00,\t/* high */\n\t/* .rf_mux_ploy = */\t0x02,\t/* R26[7:6]=0 (LPF)  R26[1:0]=2 (low) */\n\t/* .tf_c = */\t\t\t0x44,\t/* R27[7:0]  band11,band11 */\n\t/* .xtal_cap20p = */\t0x02,\t/* R16[1:0]  20pF (10)   */\n\t/* .xtal_cap10p = */\t0x01,\n\t/* .xtal_cap0p = */\t\t0x00,\n\t}, {\n\t/* .freq = */\t\t\t80,\t/* Start freq, in MHz */\n\t/* .open_d = */\t\t\t0x00,\t/* high */\n\t/* .rf_mux_ploy = */\t0x02,\t/* R26[7:6]=0 (LPF)  R26[1:0]=2 (low) */\n\t/* .tf_c = */\t\t\t0x44,\t/* R27[7:0]  band11,band11 */\n\t/* .xtal_cap20p = */\t0x02,\t/* R16[1:0]  20pF (10)   */\n\t/* .xtal_cap10p = */\t0x01,\n\t/* .xtal_cap0p = */\t\t0x00,\n\t}, {\n\t/* .freq = */\t\t\t90,\t/* Start freq, in MHz */\n\t/* .open_d = */\t\t\t0x00,\t/* high */\n\t/* .rf_mux_ploy = */\t0x02,\t/* R26[7:6]=0 (LPF)  R26[1:0]=2 (low) */\n\t/* .tf_c = */\t\t\t0x34,\t/* R27[7:0]  band12,band11 */\n\t/* .xtal_cap20p = */\t0x01,\t/* R16[1:0]  10pF (01)   */\n\t/* .xtal_cap10p = */\t0x01,\n\t/* .xtal_cap0p = */\t\t0x00,\n\t}, {\n\t/* .freq = */\t\t\t100,\t/* Start freq, in MHz */\n\t/* .open_d = */\t\t\t0x00,\t/* high */\n\t/* .rf_mux_ploy = */\t0x02,\t/* R26[7:6]=0 (LPF)  R26[1:0]=2 (low) */\n\t/* .tf_c = */\t\t\t0x34,\t/* R27[7:0]  band12,band11 */\n\t/* .xtal_cap20p = */\t0x01,\t/* R16[1:0]  10pF (01)    */\n\t/* .xtal_cap10p = */\t0x01,\n\t/* .xtal_cap0p = */\t\t0x00,\n\t}, {\n\t/* .freq = */\t\t\t110,\t/* Start freq, in MHz */\n\t/* .open_d = */\t\t\t0x00,\t/* high */\n\t/* .rf_mux_ploy = */\t0x02,\t/* R26[7:6]=0 (LPF)  R26[1:0]=2 (low) */\n\t/* .tf_c = */\t\t\t0x24,\t/* R27[7:0]  band13,band11 */\n\t/* .xtal_cap20p = */\t0x01,\t/* R16[1:0]  10pF (01)   */\n\t/* .xtal_cap10p = */\t0x01,\n\t/* .xtal_cap0p = */\t\t0x00,\n\t}, {\n\t/* .freq = */\t\t\t120,\t/* Start freq, in MHz */\n\t/* .open_d = */\t\t\t0x00,\t/* high */\n\t/* .rf_mux_ploy = */\t0x02,\t/* R26[7:6]=0 (LPF)  R26[1:0]=2 (low) */\n\t/* .tf_c = */\t\t\t0x24,\t/* R27[7:0]  band13,band11 */\n\t/* .xtal_cap20p = */\t0x01,\t/* R16[1:0]  10pF (01)   */\n\t/* .xtal_cap10p = */\t0x01,\n\t/* .xtal_cap0p = */\t\t0x00,\n\t}, {\n\t/* .freq = */\t\t\t140,\t/* Start freq, in MHz */\n\t/* .open_d = */\t\t\t0x00,\t/* high */\n\t/* .rf_mux_ploy = */\t0x02,\t/* R26[7:6]=0 (LPF)  R26[1:0]=2 (low) */\n\t/* .tf_c = */\t\t\t0x14,\t/* R27[7:0]  band14,band11 */\n\t/* .xtal_cap20p = */\t0x01,\t/* R16[1:0]  10pF (01)   */\n\t/* .xtal_cap10p = */\t0x01,\n\t/* .xtal_cap0p = */\t\t0x00,\n\t}, {\n\t/* .freq = */\t\t\t180,\t/* Start freq, in MHz */\n\t/* .open_d = */\t\t\t0x00,\t/* high */\n\t/* .rf_mux_ploy = */\t0x02,\t/* R26[7:6]=0 (LPF)  R26[1:0]=2 (low) */\n\t/* .tf_c = */\t\t\t0x13,\t/* R27[7:0]  band14,band12 */\n\t/* .xtal_cap20p = */\t0x00,\t/* R16[1:0]  0pF (00)   */\n\t/* .xtal_cap10p = */\t0x00,\n\t/* .xtal_cap0p = */\t\t0x00,\n\t}, {\n\t/* .freq = */\t\t\t220,\t/* Start freq, in MHz */\n\t/* .open_d = */\t\t\t0x00,\t/* high */\n\t/* .rf_mux_ploy = */\t0x02,\t/* R26[7:6]=0 (LPF)  R26[1:0]=2 (low) */\n\t/* .tf_c = */\t\t\t0x13,\t/* R27[7:0]  band14,band12 */\n\t/* .xtal_cap20p = */\t0x00,\t/* R16[1:0]  0pF (00)   */\n\t/* .xtal_cap10p = */\t0x00,\n\t/* .xtal_cap0p = */\t\t0x00,\n\t}, {\n\t/* .freq = */\t\t\t250,\t/* Start freq, in MHz */\n\t/* .open_d = */\t\t\t0x00,\t/* high */\n\t/* .rf_mux_ploy = */\t0x02,\t/* R26[7:6]=0 (LPF)  R26[1:0]=2 (low) */\n\t/* .tf_c = */\t\t\t0x11,\t/* R27[7:0]  highest,highest */\n\t/* .xtal_cap20p = */\t0x00,\t/* R16[1:0]  0pF (00)   */\n\t/* .xtal_cap10p = */\t0x00,\n\t/* .xtal_cap0p = */\t\t0x00,\n\t}, {\n\t/* .freq = */\t\t\t280,\t/* Start freq, in MHz */\n\t/* .open_d = */\t\t\t0x00,\t/* high */\n\t/* .rf_mux_ploy = */\t0x02,\t/* R26[7:6]=0 (LPF)  R26[1:0]=2 (low) */\n\t/* .tf_c = */\t\t\t0x00,\t/* R27[7:0]  highest,highest */\n\t/* .xtal_cap20p = */\t0x00,\t/* R16[1:0]  0pF (00)   */\n\t/* .xtal_cap10p = */\t0x00,\n\t/* .xtal_cap0p = */\t\t0x00,\n\t}, {\n\t/* .freq = */\t\t\t310,\t/* Start freq, in MHz */\n\t/* .open_d = */\t\t\t0x00,\t/* high */\n\t/* .rf_mux_ploy = */\t0x41,\t/* R26[7:6]=1 (bypass)  R26[1:0]=1 (middle) */\n\t/* .tf_c = */\t\t\t0x00,\t/* R27[7:0]  highest,highest */\n\t/* .xtal_cap20p = */\t0x00,\t/* R16[1:0]  0pF (00)   */\n\t/* .xtal_cap10p = */\t0x00,\n\t/* .xtal_cap0p = */\t\t0x00,\n\t}, {\n\t/* .freq = */\t\t\t450,\t/* Start freq, in MHz */\n\t/* .open_d = */\t\t\t0x00,\t/* high */\n\t/* .rf_mux_ploy = */\t0x41,\t/* R26[7:6]=1 (bypass)  R26[1:0]=1 (middle) */\n\t/* .tf_c = */\t\t\t0x00,\t/* R27[7:0]  highest,highest */\n\t/* .xtal_cap20p = */\t0x00,\t/* R16[1:0]  0pF (00)   */\n\t/* .xtal_cap10p = */\t0x00,\n\t/* .xtal_cap0p = */\t\t0x00,\n\t}, {\n\t/* .freq = */\t\t\t588,\t/* Start freq, in MHz */\n\t/* .open_d = */\t\t\t0x00,\t/* high */\n\t/* .rf_mux_ploy = */\t0x40,\t/* R26[7:6]=1 (bypass)  R26[1:0]=0 (highest) */\n\t/* .tf_c = */\t\t\t0x00,\t/* R27[7:0]  highest,highest */\n\t/* .xtal_cap20p = */\t0x00,\t/* R16[1:0]  0pF (00)   */\n\t/* .xtal_cap10p = */\t0x00,\n\t/* .xtal_cap0p = */\t\t0x00,\n\t}, {\n\t/* .freq = */\t\t\t650,\t/* Start freq, in MHz */\n\t/* .open_d = */\t\t\t0x00,\t/* high */\n\t/* .rf_mux_ploy = */\t0x40,\t/* R26[7:6]=1 (bypass)  R26[1:0]=0 (highest) */\n\t/* .tf_c = */\t\t\t0x00,\t/* R27[7:0]  highest,highest */\n\t/* .xtal_cap20p = */\t0x00,\t/* R16[1:0]  0pF (00)   */\n\t/* .xtal_cap10p = */\t0x00,\n\t/* .xtal_cap0p = */\t\t0x00,\n\t}\n};\n\n/*\n * I2C read/write code and shadow registers logic\n */\nstatic void shadow_store(struct r82xx_priv *priv, uint8_t reg, const uint8_t *val,\n\t\t\t int len)\n{\n\tint r = reg - REG_SHADOW_START;\n\n\tif (r < 0) {\n\t\tlen += r;\n\t\tr = 0;\n\t}\n\tif (len <= 0)\n\t\treturn;\n\tif (len > NUM_REGS - r)\n\t\tlen = NUM_REGS - r;\n\n\tmemcpy(&priv->regs[r], val, len);\n}\n\nstatic int r82xx_write_arr(struct r82xx_priv *priv, uint8_t reg, const uint8_t *val,\n\t\t\t   unsigned int len)\n{\n\tint rc, size, k, regOff, regIdx, bufIdx, pos = 0;\n\n\t/* Store the shadow registers */\n\tshadow_store(priv, reg, val, len);\n\n\tdo {\n\t\tif (len > priv->cfg->max_i2c_msg_len - 1)\n\t\t\tsize = priv->cfg->max_i2c_msg_len - 1;\n\t\telse\n\t\t\tsize = len;\n\n\t\t/* Fill I2C buffer */\n\t\tpriv->buf[0] = reg;\n\t\tmemcpy(&priv->buf[1], &val[pos], size);\n\n\t\t/* override data in buffer */\n\t\tfor ( k = 0; k < size; ++k ) {\n\t\t\tregOff = pos + k;\n\t\t\tregIdx = reg - REG_SHADOW_START + regOff;\n\t\t\tif ( priv->override_mask[regIdx] ) {\n\t\t\t\tuint8_t oldBuf = priv->buf[1 + k];\n\t\t\t\tbufIdx = 1 + k;\n\t\t\t\tpriv->buf[bufIdx] = ( priv->buf[bufIdx] & (~ priv->override_mask[regIdx]) )\n\t\t\t\t\t\t\t\t| ( priv->override_mask[regIdx] & priv->override_data[regIdx] );\n\t\t\t\tfprintf(stderr, \"override writing register %d = x%02X value x%02X  by data x%02X mask x%02X => new value x%02X\\n\"\n\t\t\t\t\t\t, regIdx + REG_SHADOW_START\n\t\t\t\t\t\t, regIdx + REG_SHADOW_START\n\t\t\t\t\t\t, oldBuf\n\t\t\t\t\t\t, priv->override_data[regIdx]\n\t\t\t\t\t\t, priv->override_mask[regIdx]\n\t\t\t\t\t\t, priv->buf[bufIdx]\n\t\t\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\trc = rtlsdr_i2c_write_fn(priv->rtl_dev, priv->cfg->i2c_addr,\n\t\t\t\t\t priv->buf, size + 1);\n\n\t\tif (rc != size + 1) {\n\t\t\tfprintf(stderr, \"%s: i2c wr failed=%d reg=%02x len=%d\\n\",\n\t\t\t\t   __FUNCTION__, rc, reg, size);\n\t\t\tif (rc < 0)\n\t\t\t\treturn rc;\n\t\t\treturn -1;\n\t\t}\n\n\t\treg += size;\n\t\tlen -= size;\n\t\tpos += size;\n\t} while (len > 0);\n\n\treturn 0;\n}\n\nstatic int r82xx_write_reg(struct r82xx_priv *priv, uint8_t reg, uint8_t val)\n{\n\treturn r82xx_write_arr(priv, reg, &val, 1);\n}\n\nint r82xx_read_cache_reg(struct r82xx_priv *priv, int reg)\n{\n\treg -= REG_SHADOW_START;\n\n\tif (reg >= 0 && reg < NUM_REGS)\n\t\treturn priv->regs[reg];\n\telse\n\t\treturn -1;\n}\n\nint r82xx_write_reg_mask(struct r82xx_priv *priv, uint8_t reg, uint8_t val, uint8_t bit_mask)\n{\n\tint rc = r82xx_read_cache_reg(priv, reg);\n\n\tif (rc < 0)\n\t\treturn rc;\n\n\tval = (rc & ~bit_mask) | (val & bit_mask);\n\n\treturn r82xx_write_arr(priv, reg, &val, 1);\n}\n\nint r82xx_write_reg_mask_ext(struct r82xx_priv *priv, uint8_t reg, uint8_t val,\n\tuint8_t bit_mask, const char * func_name)\n{\n\tint r;\n#if USE_R82XX_ENV_VARS\n\tif (priv->printI2C) {\n\t\tfprintf(stderr, \"%s: setting I2C register %02X: old value = %02X, new value: %02X with mask %02X\\n\"\n\t\t\t, func_name, reg\n\t\t\t, r82xx_read_cache_reg(priv, reg)\n\t\t\t, val, bit_mask );\n\t}\n#endif\n\tr = r82xx_write_reg_mask(priv, reg, val, bit_mask);\n\treturn r;\n}\n\n\n\nstatic uint8_t r82xx_bitrev(uint8_t byte)\n{\n\tconst uint8_t lut[16] = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,\n\t\t\t\t  0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf };\n\n\treturn (lut[byte & 0xf] << 4) | lut[byte >> 4];\n}\n\nstatic int r82xx_read(struct r82xx_priv *priv, uint8_t reg, uint8_t *val, int len)\n{\n\tint rc, i;\n\tuint8_t *p = &priv->buf[1];\n\n\tpriv->buf[0] = reg;\n\trc = rtlsdr_i2c_read_fn(priv->rtl_dev, priv->cfg->i2c_addr, p, len);\n\n\tif (rc != len) {\n\t\tfprintf(stderr, \"%s: i2c rd failed=%d reg=%02x len=%d\\n\",\n\t\t\t   __FUNCTION__, rc, reg, len);\n\t\tif (rc < 0)\n\t\t\treturn rc;\n\t\treturn -1;\n\t}\n\n\t/* Copy data to the output buffer */\n\tfor (i = 0; i < len; i++)\n\t\tval[i] = r82xx_bitrev(p[i]);\n\n\treturn 0;\n}\n\nstatic void print_registers(struct r82xx_priv *priv)\n{\n\tuint8_t data[5];\n\tint rc;\n\tunsigned int i;\n\n\trc = r82xx_read(priv, 0x00, data, sizeof(data));\n\tif (rc < 0)\n\t\treturn;\n\tfor(i=0; i<sizeof(data); i++)\n\t\tprintf(\"%02x \", data[i]);\n\tprintf(\"\\n\");\n\tfor(i=sizeof(data); i<32; i++)\n\t\tprintf(\"%02x \", r82xx_read_cache_reg(priv, i));\n\tprintf(\"\\n\");\n}\n\n/*\n * r82xx tuning logic\n */\n\nstatic int r82xx_set_mux(struct r82xx_priv *priv, uint64_t freq)\n{\n\tconst struct r82xx_freq_range *range;\n\tint rc;\n\tunsigned int i;\n\tuint8_t val;\n\n\t/* Get the proper frequency range */\n\tfreq = freq / 1000000;\n\tfor (i = 0; i < ARRAY_SIZE(freq_ranges) - 1; i++) {\n\t\tif (freq < freq_ranges[i + 1].freq)\n\t\t\tbreak;\n\t}\n\trange = &freq_ranges[i];\n\n\t/* Open Drain */\n\trc = r82xx_write_reg_mask(priv, 0x17, range->open_d, 0x08);\n\tif (rc < 0)\n\t\treturn rc;\n\n\t/* RF_MUX,Polymux */\n\trc = r82xx_write_reg_mask(priv, 0x1a, range->rf_mux_ploy, 0xc3);\n\tif (rc < 0)\n\t\treturn rc;\n\n\t/* TF BAND */\n\trc = r82xx_write_reg(priv, 0x1b, range->tf_c);\n\tif (rc < 0)\n\t\treturn rc;\n\n\t/* XTAL CAP & Drive */\n\tswitch (priv->xtal_cap_sel) {\n\tcase XTAL_LOW_CAP_30P:\n\tcase XTAL_LOW_CAP_20P:\n\t\tval = range->xtal_cap20p | 0x08;\n\t\tbreak;\n\tcase XTAL_LOW_CAP_10P:\n\t\tval = range->xtal_cap10p | 0x08;\n\t\tbreak;\n\tcase XTAL_HIGH_CAP_0P:\n\t\tval = range->xtal_cap0p | 0x00;\n\t\tbreak;\n\tdefault:\n\tcase XTAL_LOW_CAP_0P:\n\t\tval = range->xtal_cap0p | 0x08;\n\t\tbreak;\n\t}\n\trc = r82xx_write_reg_mask(priv, 0x10, val, 0x0b);\n\n\treturn rc;\n}\n\n\n/* function of Youssef (AirSpy) and Carl (RTL-SDR) */\nstatic int r82xx_set_pll_yc(struct r82xx_priv *priv, uint32_t freq)\n{\n  const uint32_t vco_min = 1770000000;\n  const uint32_t vco_max = 3900000000U;\n  uint32_t pll_ref = (priv->cfg->xtal);\n  uint32_t pll_ref_2x = (pll_ref * 2);\n\n  int rc;\n  uint32_t vco_exact;\n  uint32_t vco_frac;\n  uint32_t con_frac;\n  uint32_t div_num;\n  uint32_t n_sdm;\n  uint16_t sdm;\n  uint8_t ni;\n  uint8_t si;\n  uint8_t nint;\n  uint8_t val_dith;\n  uint8_t data[5];\n\n  /* Calculate divider */\n  for (div_num = 0; div_num < 5; div_num++)\n  {\n    vco_exact = freq << (div_num + 1);\n    if (vco_exact >= vco_min && vco_exact <= vco_max)\n    {\n      break;\n    }\n  }\n\n  vco_exact = freq << (div_num + 1);\n  nint = (uint8_t) ((vco_exact + (pll_ref >> 16)) / pll_ref_2x);\n  vco_frac = vco_exact - pll_ref_2x * nint;\n\n  nint -= 13;\n  ni = (nint >> 2);\n  si = nint - (ni << 2);\n\n  /* Set the phase splitter */\n  rc = r82xx_write_reg_mask(priv, 0x10, (uint8_t) (div_num << 5), 0xe0);\n  if(rc < 0) {\n    if (priv->cfg->verbose)\n      fprintf(stderr, \"r82xx_set_pll_yc(): error writing 'phase splitter' into i2c reg 0x10\\n\");\n    return rc;\n  }\n\n  /* Disable Dither */\n  val_dith = (priv->disable_dither) ? 0x10 : 0x00;\n  rc = r82xx_write_reg_mask(priv, 0x12, val_dith, 0x18);\n  if (rc < 0) {\n    if (priv->cfg->verbose)\n      fprintf(stderr, \"r82xx_set_pll_yc(): error writing 'dither' into i2c reg 0x12\\n\");\n    return rc;\n  }\n\n  /* Set the rough VCO frequency */\n  rc = r82xx_write_reg(priv, 0x14, (uint8_t) (ni + (si << 6)));\n  if(rc < 0) {\n    if (priv->cfg->verbose)\n      fprintf(stderr, \"r82xx_set_pll_yc(): error writing 'rough VCO frequency' into i2c reg 0x14\\n\");\n    return rc;\n  }\n\n  if (vco_frac == 0) {\n    /* Disable frac pll */\n    rc = r82xx_write_reg_mask(priv, 0x12, 0x08, 0x08);\n    if(rc < 0) {\n      if (priv->cfg->verbose)\n        fprintf(stderr, \"r82xx_set_pll_yc(): error writing 'disable frac pll' into i2c reg 0x12\\n\");\n      return rc;\n    }\n  }\n  else\n  {\n    vco_frac += pll_ref >> 16;\n    sdm = 0;\n    for(n_sdm = 0; n_sdm < 16; n_sdm++)\n    {\n        con_frac = pll_ref >> n_sdm;\n        if (vco_frac >= con_frac)\n        {\n            sdm |= (uint16_t) (0x8000 >> n_sdm);\n            vco_frac -= con_frac;\n            if (vco_frac == 0)\n                break;\n        }\n    }\n\n/*\n    actual_freq = (((nint << 16) + sdm) * (uint64_t) pll_ref_2x) >> (div_num + 1 + 16);\n    delta = freq - actual_freq\n    if (actual_freq != freq)\n    {\n      fprintf(stderr,\"Tunning delta: %d Hz\", delta);\n    }\n*/\n    rc = r82xx_write_reg(priv, 0x15, (uint8_t)(sdm & 0xff));\n    if (rc < 0) {\n      if (priv->cfg->verbose)\n        fprintf(stderr, \"r82xx_set_pll_yc(): error writing 'sdm lo' into i2c reg 0x15\\n\");\n      return rc;\n    }\n\n    rc = r82xx_write_reg(priv, 0x16, (uint8_t)(sdm >> 8));\n    if (rc < 0) {\n      if (priv->cfg->verbose)\n        fprintf(stderr, \"r82xx_set_pll_yc(): error writing 'sdm hi' into i2c reg 0x16\\n\");\n      return rc;\n    }\n\n    /* Enable frac pll */\n    rc = r82xx_write_reg_mask(priv, 0x12, 0x00, 0x08);\n    if (rc < 0) {\n      if (priv->cfg->verbose)\n        fprintf(stderr, \"r82xx_set_pll_yc(): error writing 'enable frac pll' into i2c reg 0x12\\n\");\n      return rc;\n    }\n  }\n\n  /* all PLL stuff / registers set for this frequency */\n  priv->tuner_pll_set = 1;\n\n/***/\n\n  /* Check if PLL has locked */\n  rc = r82xx_read(priv, 0x00, data, 3);\n  if (rc < 0) {\n      if (priv->cfg->verbose)\n        fprintf(stderr, \"r82xx_set_pll_yc(): error reading 'pll lock status' from i2c reg 0x00..0x02\\n\");\n    return rc;\n  }\n  if (!(data[2] & 0x40)) {\n    if (priv->cfg->verbose || PRINT_PLL_ERRORS)\n      //fprintf(stderr, \"r82xx_set_pll_yc(): error writing 'sdm lo' into i2c reg 0x15\\n\");\n      fprintf(stderr, \"[R82XX] PLL not locked at Tuner LO %u Hz for RF %f MHz!\\n\",\n        freq, priv->rf_freq * 1E-6);\n    priv->has_lock = 0;\n    return -1;\n  }\n  priv->has_lock = 1;\n\n  return rc;\n\n}\n\n\nstatic int r82xx_set_pll(struct r82xx_priv *priv, uint32_t freq)\n{\n\t/* freq == tuner's LO frequency */\n\tint rc, i;\n\tuint64_t vco_freq;\n\tuint64_t vco_div;\n\tuint32_t vco_min = 1770000; /* kHz */\n\tuint32_t vco_max = (priv->cfg->vco_algo == 0) ? (vco_min * 2) : 3900000; /* kHz */\n\tuint32_t freq_khz, pll_ref;\n\tuint32_t sdm = 0;\n\tuint8_t mix_div = 2;\n\tuint8_t div_buf = 0;\n\tuint8_t div_num = 0;\n\tuint8_t vco_power_ref = 2;\n\tuint8_t refdiv2 = 0;\n\tuint8_t ni, si, nint, vco_fine_tune, val;\n\tuint8_t vco_curr_min = (priv->cfg->vco_curr_min == 0xff) ? 0x80 : ( priv->cfg->vco_curr_min << 5 );\n\tuint8_t vco_curr_max = (priv->cfg->vco_curr_max == 0xff) ? 0x60 : ( priv->cfg->vco_curr_max << 5 );\n\t/* devt->r82xx_c.vco_min = 0xff;  * VCO min/max current for R18/0x12 bits [7:5] in 0 .. 7. use 0xff for default */\n\t/* devt->r82xx_c.vco_max = 0xff;  * value is inverted: programmed is 7-value, that 0 is lowest current */\n\tuint8_t data[5];\n\n\tpriv->tuner_pll_set = 0;\n\n\tif (priv->cfg->vco_algo == 2)\n\t{\n\t\t/* r82xx_set_pll_yc() assumes fixed maximum current */\n\t\tif (priv->last_vco_curr != vco_curr_max) {\n\t\t\trc = r82xx_write_reg_mask(priv, 0x12, vco_curr_max, 0xe0);\n\t\t\tif (rc < 0) {\n\t\t\t\tif (priv->cfg->verbose)\n\t\t\t\t\tfprintf(stderr, \"r82xx_set_pll(): error writing 'vco current' into i2c reg 0x12\\n\");\n\t\t\t\treturn rc;\n\t\t\t}\n\t\t\tpriv->last_vco_curr = vco_curr_max;\n\t\t}\n\t\treturn r82xx_set_pll_yc(priv, freq);\n\t}\n\n\t/* Frequency in kHz */\n\tfreq_khz = (freq + 500) / 1000;\n\tpll_ref = priv->cfg->xtal;\n\n\trc = r82xx_write_reg_mask(priv, 0x10, refdiv2, 0x10);\n\tif (rc < 0) {\n\t\tif (priv->cfg->verbose)\n\t\t\tfprintf(stderr, \"r82xx_set_pll(): error writing 'refdiv2' into i2c reg 0x10\\n\");\n\t\treturn rc;\n\t}\n\n\t/* set pll autotune = 128kHz */\n\trc = r82xx_write_reg_mask(priv, 0x1a, 0x00, 0x0c);\n\tif (rc < 0) {\n\t\tif (priv->cfg->verbose)\n\t\t\tfprintf(stderr, \"r82xx_set_pll(): error writing 'pll autotune 128kHz' into i2c reg 0x1a\\n\");\n\t\treturn rc;\n\t}\n\n\t/* set VCO current = 100 */\n\tif (priv->last_vco_curr != vco_curr_min) {\n\t\trc = r82xx_write_reg_mask(priv, 0x12, vco_curr_min, 0xe0);\n\t\tif (rc < 0) {\n\t\t\tif (priv->cfg->verbose)\n\t\t\t\tfprintf(stderr, \"r82xx_set_pll(): error writing 'vco current min' into i2c reg 0x12\\n\");\n\t\t\treturn rc;\n\t\t}\n\t\tpriv->last_vco_curr = vco_curr_min;\n\t}\n\n#if 0\n\tfprintf(stderr, \"vco_last = 0x%02x; vcocmin << 5 = 0x%02x; vcocmax << 5 = 0x%02x\\n\",\n\t\t(unsigned)priv->last_vco_curr, (unsigned)vco_curr_min, (unsigned)vco_curr_max);\n#endif\n\n\t/* Calculate divider */\n\twhile (mix_div <= 64) {\n\t\tif (((freq_khz * mix_div) >= vco_min) &&\n\t\t   ((freq_khz * mix_div) < vco_max)) {\n\t\t\tdiv_buf = mix_div;\n\t\t\twhile (div_buf > 2) {\n\t\t\t\tdiv_buf = div_buf >> 1;\n\t\t\t\tdiv_num++;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tmix_div = mix_div << 1;\n\t}\n\n\trc = r82xx_read(priv, 0x00, data, sizeof(data));\n\tif (rc < 0) {\n\t\tif (priv->cfg->verbose)\n\t\t\tfprintf(stderr, \"r82xx_set_pll(): error reading 'status' from i2c reg 0x00 .. 0x04\\n\");\n\t\treturn rc;\n\t}\n\n\tif (priv->cfg->rafael_chip == CHIP_R828D)\n\t\tvco_power_ref = 1;\n\n\tvco_fine_tune = (data[4] & 0x30) >> 4;\n\n\tif (vco_fine_tune > vco_power_ref)\n\t\tdiv_num = div_num - 1;\n\telse if (vco_fine_tune < vco_power_ref)\n\t\tdiv_num = div_num + 1;\n\n\trc = r82xx_write_reg_mask(priv, 0x10, div_num << 5, 0xe0);\n\tif (rc < 0) {\n\t\tif (priv->cfg->verbose)\n\t\t\tfprintf(stderr, \"r82xx_set_pll(): error writing 'div_num' into i2c reg 0x10\\n\");\n\t\treturn rc;\n\t}\n\n\tvco_freq = (uint64_t)freq * (uint64_t)mix_div;\n\n\t/*\n\t * We want to approximate:\n\t *\n\t *  vco_freq / (2 * pll_ref)\n\t *\n\t * in the form:\n\t *\n\t *  nint + sdm/65536\n\t *\n\t * where nint,sdm are integers and 0 < nint, 0 <= sdm < 65536\n\t *\n\t * Scaling to fixed point and rounding:\n\t *\n\t *  vco_div = 65536*(nint + sdm/65536) = int( 0.5 + 65536 * vco_freq / (2 * pll_ref) )\n\t *  vco_div = 65536*nint + sdm         = int( (pll_ref + 65536 * vco_freq) / (2 * pll_ref) )\n\t */\n\n\tvco_div = (pll_ref + 65536 * vco_freq) / (2 * pll_ref);\n        nint = (uint32_t) (vco_div / 65536);\n\tsdm = (uint32_t) (vco_div % 65536);\n\n#if PRINT_ACTUAL_VCO_AND_ERR\n\t{\n\t  uint64_t actual_vco = (uint64_t)2 * pll_ref * nint + (uint64_t)2 * pll_ref * sdm / 65536;\n\t  fprintf(stderr, \"[R82XX] requested %u Hz; selected mix_div=%u vco_freq=%lu nint=%u sdm=%u; actual_vco=%lu; tuning error=%+dHz\\n\",\n\t\t  freq, mix_div, vco_freq, nint, sdm, actual_vco, (int32_t) (actual_vco - vco_freq) / mix_div);\n\t}\n#endif\n\n\tif (nint > ((128 / vco_power_ref) - 1)) {\n\t\tif (priv->cfg->verbose || PRINT_PLL_ERRORS)\n\t\t\tfprintf(stderr, \"[R82XX] No valid PLL values for %u Hz!\\n\", freq);\n\t\treturn -1;\n\t}\n\n\tni = (nint - 13) / 4;\n\tsi = nint - 4 * ni - 13;\n\n\trc = r82xx_write_reg(priv, 0x14, ni + (si << 6));\n\tif (rc < 0) {\n\t\tif (priv->cfg->verbose)\n\t\t\tfprintf(stderr, \"r82xx_set_pll(): error writing 'ni+(si<<6)' into i2c reg 0x14\\n\");\n\t\treturn rc;\n\t}\n\n\t/* pw_sdm */\n\tif (sdm == 0)\n\t\tval = 0x08;\n\telse\n\t\tval = 0x00;\n\n\tif (priv->disable_dither)\n\t\tval |= 0x10;\n\n\trc = r82xx_write_reg_mask(priv, 0x12, val, 0x18);\n\tif (rc < 0) {\n\t\tif (priv->cfg->verbose)\n\t\t\tfprintf(stderr, \"r82xx_set_pll(): error writing 'dither' into i2c reg 0x12\\n\");\n\t\treturn rc;\n\t}\n\n\trc = r82xx_write_reg(priv, 0x16, sdm >> 8);\n\tif (rc < 0) {\n\t\tif (priv->cfg->verbose)\n\t\t\tfprintf(stderr, \"r82xx_set_pll(): error writing 'sdm hi' into i2c reg 0x16\\n\");\n\t\treturn rc;\n\t}\n\trc = r82xx_write_reg(priv, 0x15, sdm & 0xff);\n\tif (rc < 0) {\n\t\tif (priv->cfg->verbose)\n\t\t\tfprintf(stderr, \"r82xx_set_pll(): error writing 'sdm lo' into i2c reg 0x12\\n\");\n\t\treturn rc;\n\t}\n\n\t/* all PLL stuff / registers set for this frequency - except 8 kHz pll autotune */\n\tpriv->tuner_pll_set = 1;\n\n\tfor (i = 0; i < 2; i++) {\n\n\t\t/* Check if PLL has locked */\n\t\trc = r82xx_read(priv, 0x00, data, 3);\n\t\tif (rc < 0) {\n\t\t\tif (priv->cfg->verbose)\n\t\t\t\tfprintf(stderr, \"r82xx_set_pll(): error reading 'pll lock status' from i2c reg 0x00 .. 0x02\\n\");\n\t\t\treturn rc;\n\t\t}\n\t\tif ( (data[2] & 0x40) || vco_curr_max == vco_curr_min )\n\t\t\tbreak;\n\n\t\tif (!i) {\n\t\t\t/* Didn't lock. Increase VCO current */\n\t\t\tif (priv->last_vco_curr != vco_curr_max) {\n\t\t\t\trc = r82xx_write_reg_mask(priv, 0x12, vco_curr_max, 0xe0);\n\t\t\t\tif (rc < 0) {\n\t\t\t\t\tif (priv->cfg->verbose)\n\t\t\t\t\t\tfprintf(stderr, \"r82xx_set_pll(): error writing 'vco current max' into i2c reg 0x12\\n\");\n\t\t\t\t\treturn rc;\n\t\t\t\t}\n\t\t\t\tpriv->last_vco_curr = vco_curr_max;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (!(data[2] & 0x40)) {\n\t\tif (priv->cfg->verbose || PRINT_PLL_ERRORS)\n\t\t\tfprintf(stderr, \"[R82XX] PLL not locked at Tuner LO %u Hz for RF %f MHz!\\n\",\n\t\t\t\tfreq, priv->rf_freq * 1E-6);\n\t\tpriv->has_lock = 0;\n\t\treturn -1;\n\t}\n#if 0\n\telse\n\t\tfprintf(stderr, \"[R82XX] PLL locked at Tuner LO %u Hz for RF %f MHz!\\n\", freq, priv->rf_freq * 1E-6);\n#endif\n\n\tpriv->has_lock = 1;\n\n\t/* set pll autotune = 8kHz */\n\trc = r82xx_write_reg_mask(priv, 0x1a, 0x08, 0x08);\n\tif (rc < 0 && priv->cfg->verbose)\n\t\tfprintf(stderr, \"r82xx_set_pll(): error writing 'pll autotune 8kHz' into i2c reg 0x1a\\n\");\n\n\treturn rc;\n}\n\n\nint r82xx_is_tuner_locked(struct r82xx_priv *priv)\n{\n\tint rc;\n\tuint8_t data[5];\n\n\t/* was all PLL stuff set for last frequency? */\n\tif (! priv->tuner_pll_set)\n\t\treturn 1;\n\n\t/* Check if PLL has locked */\n\trc = r82xx_read(priv, 0x00, data, sizeof(data));\n\tif (rc < 0)\n\t\treturn -3;\n\tif (!(data[2] & 0x40)) {\n\t\tif (priv->cfg->verbose || PRINT_PLL_ERRORS)\n\t\t\tfprintf(stderr, \"[R82XX] PLL not locked at check!\\n\");\n\t\treturn 1;\n\t}\n\treturn 0;\n}\n\n\nstatic int r82xx_sysfreq_sel(struct r82xx_priv *priv,\n\t\t\t\t enum r82xx_tuner_type type)\n{\n\tint rc;\n\n\tuint8_t lna_top = 0xe5;\t\t/* detect bw 3, lna top:4, predet top:2 */\n\tuint8_t pre_dect = 0x40;\n\tuint8_t air_cable1_in = 0x00;\n\tuint8_t cable2_in = 0x00;\n\n\tif (priv->cfg->use_predetect) {\n\t\trc = r82xx_write_reg_mask(priv, 0x06, pre_dect, 0x40);\n\t\tif (rc < 0)\n\t\t\treturn rc;\n\t}\n\n\tpriv->input = air_cable1_in;\n\n\t/* Air-IN only for Astrometa */\n\trc = r82xx_write_reg_mask(priv, 0x05, air_cable1_in, 0x60);\n\tif (rc < 0)\n\t\treturn rc;\n\trc = r82xx_write_reg_mask(priv, 0x06, cable2_in, 0x08);\n\tif (rc < 0)\n\t\treturn rc;\n\n\t/*\n\t * Set LNA\n\t */\n\n\tif (type != TUNER_ANALOG_TV) {\n\t\t/* LNA TOP: lowest */\n\t\trc = r82xx_write_reg_mask(priv, 0x1d, 0, 0x38);\n\t\tif (rc < 0)\n\t\t\treturn rc;\n\n\t\t/* 0: PRE_DECT off */\n\t\trc = r82xx_write_reg_mask(priv, 0x06, 0, 0x40);\n\t\tif (rc < 0)\n\t\t\treturn rc;\n\n\t\t/* agc clk 250hz */\n\t\trc = r82xx_write_reg_mask(priv, 0x1a, 0x30, 0x30);\n\t\tif (rc < 0)\n\t\t\treturn rc;\n\n\t\t/* write LNA TOP = 3 */\n\t\trc = r82xx_write_reg_mask(priv, 0x1d, 0x18, 0x38);\n\t\tif (rc < 0)\n\t\t\treturn rc;\n\n\t\t/* agc clk 60hz */\n\t\trc = r82xx_write_reg_mask(priv, 0x1a, 0x20, 0x30);\n\t\tif (rc < 0)\n\t\t\treturn rc;\n\t} else {\n\t\t/* PRE_DECT off */\n\t\trc = r82xx_write_reg_mask(priv, 0x06, 0, 0x40);\n\t\tif (rc < 0)\n\t\t\treturn rc;\n\n\t\t/* write LNA TOP */\n\t\trc = r82xx_write_reg_mask(priv, 0x1d, lna_top, 0x38);\n\t\tif (rc < 0)\n\t\t\treturn rc;\n\n\t\t/* agc clk 1Khz, external det1 cap 1u */\n\t\trc = r82xx_write_reg_mask(priv, 0x1a, 0x00, 0x30);\n\t\tif (rc < 0)\n\t\t\treturn rc;\n\n\t\trc = r82xx_write_reg_mask(priv, 0x10, 0x00, 0x04);\n\t\tif (rc < 0)\n\t\t\treturn rc;\n\t }\n\t return 0;\n}\n\nstatic int r82xx_set_tv_standard(struct r82xx_priv *priv,\n\t\t\t\t enum r82xx_tuner_type type,\n\t\t\t\t uint32_t delsys)\n\n{\n\tint rc, i;\n\tuint8_t data[5];\n\n\tint need_calibration = 1;\n\n\t/* BW < 6 MHz */\n\tuint8_t filt_q = 0x10;\t\t/* r10[4]:low q(1'b1) */\n\n\t/* for LT Gain test */\n\tif (type != TUNER_ANALOG_TV) {\n\t\trc = r82xx_write_reg_mask(priv, 0x1d, 0x00, 0x38);\n\t\tif (rc < 0)\n\t\t\treturn rc;\n\t}\n\tpriv->rf_freq = 56000 * 1000;  /* set a default frequency */\n\tpriv->if_band_center_freq = 0;\n\tpriv->int_freq = 3570 * 1000;\n\tpriv->sideband = 0;\n\n\t/* Check if standard changed. If so, filter calibration is needed */\n\t/* as we call this function only once in rtlsdr, force calibration */\n\n\tif (need_calibration) {\n\t\tfor (i = 0; i < 2; i++) {\n\n\t\t\t/* set cali clk =on */\n\t\t\trc = r82xx_write_reg_mask(priv, 0x0f, 0x04, 0x04);\n\t\t\tif (rc < 0)\n\t\t\t\treturn rc;\n\n\t\t\tpriv->tuner_pll_set = 0;\n\t\t\trc = r82xx_set_pll(priv, priv->rf_freq);\n\t\t\tif (rc < 0 || !priv->has_lock)\n\t\t\t\treturn rc;\n\n\t\t\t/* Start Trigger */\n\t\t\trc = r82xx_write_reg_mask_ext(priv, 0x0b, 0x10, 0x10, __FUNCTION__);\n\t\t\tif (rc < 0)\n\t\t\t\treturn rc;\n\n\t\t\t/* Stop Trigger */\n\t\t\trc = r82xx_write_reg_mask_ext(priv, 0x0b, 0x00, 0x10, __FUNCTION__);\n\t\t\tif (rc < 0)\n\t\t\t\treturn rc;\n\n\t\t\t/* set cali clk =off */\n\t\t\trc = r82xx_write_reg_mask(priv, 0x0f, 0x00, 0x04);\n\t\t\tif (rc < 0)\n\t\t\t\treturn rc;\n\n\t\t\t/* Check if calibration worked */\n\t\t\trc = r82xx_read(priv, 0x00, data, sizeof(data));\n\t\t\tif (rc < 0)\n\t\t\t\treturn rc;\n\n\t\t\tpriv->fil_cal_code = data[4] & 0x0f;\n\t\t\tif (priv->fil_cal_code && priv->fil_cal_code != 0x0f)\n\t\t\t\tbreak;\n\t\t}\n\t\t/* narrowest */\n\t\tif (priv->fil_cal_code == 0x0f)\n\t\t\tpriv->fil_cal_code = 0;\n\t}\n\n\trc = r82xx_write_reg_mask_ext(priv, 0x0a,\n\t\t\t\t  filt_q | priv->fil_cal_code, 0x1f, __FUNCTION__);\n\tif (rc < 0)\n\t\treturn rc;\n\n\t/* Store current standard. If it changes, re-calibrate the tuner */\n\tpriv->delsys = delsys;\n\tpriv->type = type;\n\tpriv->bw = 3;\n\n\treturn 0;\n}\n\n/* measured with a Racal 6103E GSM test set at 928 MHz with -60 dBm\n * input power, for raw results see:\n * http://steve-m.de/projects/rtl-sdr/gain_measurement/r820t/\n */\n\n#define VGA_BASE_GAIN\t-47\nstatic const int r82xx_vga_gain_steps[]  = {\n\t0, 26, 26, 30, 42, 35, 24, 13, 14, 32, 36, 34, 35, 37, 35, 36\n/* -47, -21, 5, 35, 77, 112, 136, 149, 163, 195, 231, 265, 300, 337, 372, 408 */\n};\n\nstatic const int r82xx_lna_gain_steps[]  = {\n\t0, 9, 13, 40, 38, 13, 31, 22, 26, 31, 26, 14, 19, 5, 35, 13\n};\n\nstatic const int r82xx_mixer_gain_steps[]  = {\n\t0, 5, 10, 10, 19, 9, 10, 25, 17, 10, 8, 16, 13, 6, 3, -8\n};\n\nstatic void r82xx_get_rf_gain_index(int gain, int *ptr_lna_index, int *ptr_mix_index)\n{\n\tint i, total_gain = 0;\n\tint mix_index = 0, lna_index = 0;\n\n\tfor (i = 0; i < 15; i++) {\n\t\tif (total_gain >= gain)\n\t\t\tbreak;\n\t\ttotal_gain += r82xx_lna_gain_steps[++lna_index];\n\t\tif (total_gain >= gain)\n\t\t\tbreak;\n\t\ttotal_gain += r82xx_mixer_gain_steps[++mix_index];\n\t}\n\n\t*ptr_lna_index = lna_index;\n\t*ptr_mix_index = mix_index;\n}\n\nstatic int r82xx_get_if_gain_index(int gain)\n{\n\tint vga_index, total_gain = VGA_BASE_GAIN;\n\n\tfor (vga_index = 0; vga_index < 15; vga_index++) {\n\t\tif (total_gain >= gain)\n\t\t\tbreak;\n\t\ttotal_gain += r82xx_vga_gain_steps[++vga_index];\n\t}\n\n\treturn vga_index;\n}\n\nstatic int r82xx_get_lna_gain_from_index(int lna_index)\n{\n\tint i, total_gain = 0;\n\tif ( lna_index < 0 || lna_index > 15 )\n\t\treturn 0;\n\tfor ( i = 0; i <= lna_index; ++i )\n\t\ttotal_gain += r82xx_lna_gain_steps[i];\n\treturn total_gain;\n}\n\nstatic int r82xx_get_mixer_gain_from_index(int mixer_index)\n{\n\tint i, total_gain = 0;\n\tif ( mixer_index < 0 || mixer_index > 15 )\n\t\treturn 0;\n\tfor ( i = 0; i <= mixer_index; ++i )\n\t\ttotal_gain += r82xx_mixer_gain_steps[i];\n\treturn total_gain;\n}\n\nstatic int r82xx_get_vga_gain_from_index(int vga_index)\n{\n\tint i, total_gain = VGA_BASE_GAIN;\n\tif ( vga_index < 0 || vga_index > 15 )\n\t\treturn 0;\n\tfor ( i = 0; i <= vga_index; ++i )\n\t\ttotal_gain += r82xx_vga_gain_steps[i];\n\treturn total_gain;\n}\n\n\n/* set HF gain (LNA/Mixer) and pass through for IF gain (VGA) */\nint r82xx_set_gain(struct r82xx_priv *priv, int set_manual_gain, int gain,\n  int extended_mode, int lna_gain_idx, int mixer_gain_idx, int vga_gain_idx, int *rtl_vga_control)\n{\n\tint rc;\n\tint new_if_mode = priv->last_if_mode;\n\tuint8_t data[4];\n\n\tif (extended_mode || set_manual_gain) {\n\n\t\tif (set_manual_gain) {\n\t\t\tr82xx_get_rf_gain_index(gain, &lna_gain_idx, &mixer_gain_idx);\n\t\t}\n\n\t\t/* LNA auto off == manual */\n\t\trc = r82xx_write_reg_mask(priv, 0x05, 0x10, 0x10);\n\t\tif (rc < 0)\n\t\t\treturn rc;\n\n\t\t/* Mixer auto off == manual mode */\n\t\trc = r82xx_write_reg_mask(priv, 0x07, 0, 0x10);\n\t\tif (rc < 0)\n\t\t\treturn rc;\n\n\t\trc = r82xx_read(priv, 0x00, data, sizeof(data));\n\t\tif (rc < 0)\n\t\t\treturn rc;\n\n\t\t/* Set LNA */\n\t\trc = r82xx_write_reg_mask(priv, 0x05, lna_gain_idx, 0x0f);\n\t\tif (rc < 0)\n\t\t\treturn rc;\n\n\t\t/* Set Mixer */\n\t\trc = r82xx_write_reg_mask(priv, 0x07, mixer_gain_idx, 0x0f);\n\t\tif (rc < 0)\n\t\t\treturn rc;\n\n\t\t/* save last values */\n\t\tpriv->last_manual_gain = set_manual_gain;\n\t\tpriv->last_extended_mode = extended_mode;\n\t\tpriv->last_LNA_value = lna_gain_idx;\n\t\tpriv->last_Mixer_value = mixer_gain_idx;\n\n\t\t/* prepare VGA */\n\t\tif (extended_mode) {\n\t\t\tnew_if_mode = vga_gain_idx +10000;\n\t\t}\n\n\t} else {\n\t\t/* LNA auto on = AGC */\n\t\trc = r82xx_write_reg_mask(priv, 0x05, 0, 0x10);\n\t\tif (rc < 0)\n\t\t\treturn rc;\n\n\t\t/* Mixer auto on = AGC */\n\t\trc = r82xx_write_reg_mask(priv, 0x07, 0x10, 0x10);\n\t\tif (rc < 0)\n\t\t\treturn rc;\n\n\t\t/* save last values */\n\t\tpriv->last_manual_gain = set_manual_gain;\n\t\tpriv->last_extended_mode = extended_mode;\n\n#ifdef VGA_FOR_AGC_MODE\n\t\tnew_if_mode = VGA_FOR_AGC_MODE;\n#endif\n\t}\n\n\t/* Set VGA */\n\trc = r82xx_set_if_mode(priv, new_if_mode, rtl_vga_control);\n\n\treturn rc;\n}\n\nint r82xx_get_rf_gain(struct r82xx_priv *priv)\n{\n\tint lna_gain = r82xx_get_lna_gain_from_index(priv->last_LNA_value);\n\tint mix_gain = r82xx_get_mixer_gain_from_index(priv->last_Mixer_value);\n\tint gain = lna_gain + mix_gain;\n\treturn gain;\n}\n\n\nint r82xx_get_if_gain(struct r82xx_priv *priv)\n{\n\tint vga_gain = r82xx_get_vga_gain_from_index(priv->last_VGA_value);\n\treturn vga_gain;\n}\n\n\n/* set IF gain (VGA) */\nint r82xx_set_if_mode(struct r82xx_priv *priv, int if_mode, int *rtl_vga_control)\n{\n\tint rc = 0, vga_gain_idx = 0;\n\tint is_rtlsdr_blog_v4;\n\n\tif (rtl_vga_control)\n\t\t*rtl_vga_control = 0;\n\n\tif ( 0 == if_mode || 10016 == if_mode ) {\n\t\tvga_gain_idx = 0x10;\n\n\t}\n\telse if ( -2500 <= if_mode && if_mode <= 2500 ) {\n\t\tvga_gain_idx = r82xx_get_if_gain_index(if_mode);\n\n\t}\n\telse if ( 2500 < if_mode && if_mode < 10000 ) {\n\t\tvga_gain_idx = r82xx_get_if_gain_index(if_mode - 5000);\n\n\t}\n\telse if ( 10000 <= if_mode && if_mode <= 10016+15 ) {\n\t\tvga_gain_idx = if_mode -10000;\n\n\t}\n\telse {\t/* assume 0 == default */\n\t\tfprintf(stderr, \"%s: invalid if_mode value %d; setting to default: %d\\n\",\n\t\t\t__FUNCTION__, if_mode, 10000 + DEFAULT_IF_VGA_VAL );\n\t\t/* was  26.5 dB == -12 dB + 0x0b * 3.5 dB  with AGC on\n\t\t * and  16.3 dB == -12 dB + 8 * 3.5 dB     with AGC off\n\t\t * BUT IT makes no sense to make this different!\n\t\t */\n\t\t/* vga_gain_idx = (priv->last_extended_mode || priv->last_manual_gain) ? 0x08 : 0x0b; */\n\t\tif_mode = 10000 + DEFAULT_IF_VGA_VAL;\n\t\tvga_gain_idx = DEFAULT_IF_VGA_VAL;\n\t}\n\n#if PRINT_VGA_REG\n\tfprintf(stderr, \"%s: writing 0x%02X (=%.1f dB) into VGA register %sactivating RTL AGC control\\n\", __FUNCTION__,\n\t\t(vga_gain_idx & 0x0f), (-12.0 + 3.5 * (vga_gain_idx & 0x0f)),\n\t\t( (vga_gain_idx & 0x10) && rtl_vga_control ) ? \"\" : \"de\" );\n#endif\n\n\t/* VGA auto control does not work on the V4, fix to an appropriate value instead like in Osmocom drivers\n\t* Furthermore, this auto VGA needs to be looked at more closely, it appears to cause a lot of spectrum pumping\n\t* and intermod on other devices. Fixed VGA gain always seems to yield better results.\n\t*/\n\tis_rtlsdr_blog_v4 = rtlsdr_check_dongle_model(priv->rtl_dev, \"RTLSDRBlog\", \"Blog V4\");\n\tif(is_rtlsdr_blog_v4)\n\t{\n\t\trc = r82xx_write_reg_mask(priv, 0x0c, 0x08, 0x9f);\n\t}\n\telse\n\t{\n\t\trc = r82xx_write_reg_mask(priv, 0x0c, vga_gain_idx, 0x1f);\n\t}\n\n\tif (rc < 0)\n\t\treturn rc;\n\tpriv->last_if_mode = if_mode;\n\tpriv->last_VGA_value = vga_gain_idx;\n\tif ( (vga_gain_idx & 0x10) && rtl_vga_control )\n\t\t*rtl_vga_control = 1;\n\n\treturn rc;\n}\n\n/* expose/permit tuner specific i2c register hacking! */\nint r82xx_set_i2c_register(struct r82xx_priv *priv, unsigned i2c_register, unsigned data, unsigned mask)\n{\n\tuint8_t reg = i2c_register & 0xFF;\n\tuint8_t reg_mask = mask & 0xFF;\n\tuint8_t reg_val = data & 0xFF;\n\treturn r82xx_write_reg_mask(priv, reg, reg_val, reg_mask);\n}\n\n//-cs-\nint r82xx_get_i2c_register(struct r82xx_priv *priv, unsigned char* data, int len)\n{\n\tint rc, i, len1;\n\n\t// The lower 5 I2C registers can be read with the normal read fct, the upper ones are read from the cache\n\tif(len < 5)\n\t\tlen1 = len;\n\telse\n\t\tlen1 = 5;\n\trc = r82xx_read(priv, 0x00, data, len1);\n\tif (rc < 0)\n\t\treturn rc;\n\tif(len > 5)\n\t\tfor (i = 5; i < len; i++)\n\t\t\tdata[i] = r82xx_read_cache_reg(priv, i);\n\treturn 0;\n}\n//-cs- end\n\nint r82xx_set_i2c_override(struct r82xx_priv *priv, unsigned i2c_register, unsigned data, unsigned mask)\n{\n\tuint8_t reg = i2c_register & 0xFF;\n\tuint8_t reg_mask = mask & 0xFF;\n\tuint8_t reg_val = data & 0xFF;\n\tfprintf(stderr, \"%s: register %d = %02X. mask %02X, data %03X\\n\"\n\t\t\t, __FUNCTION__, i2c_register, i2c_register, mask, data );\n\n\tif ( REG_SHADOW_START <= reg && reg < REG_SHADOW_START + NUM_REGS ) {\n\t\tuint8_t oldMask = priv->override_mask[reg - REG_SHADOW_START];\n\t\tuint8_t oldData = priv->override_data[reg - REG_SHADOW_START];\n\t\tif ( data & ~0xFF ) {\n\t\t\tpriv->override_mask[reg - REG_SHADOW_START] &= ~reg_mask;\n\t\t\tpriv->override_data[reg - REG_SHADOW_START] &= ~reg_mask;\n\t\t\tfprintf(stderr, \"%s: subtracted override mask for register %02X. old mask %02X, old data %02X. new mask is %02X, new data %02X\\n\"\n\t\t\t\t\t, __FUNCTION__\n\t\t\t\t\t, i2c_register\n\t\t\t\t\t, oldMask, oldData\n\t\t\t\t\t, priv->override_mask[reg - REG_SHADOW_START]\n\t\t\t\t\t, priv->override_data[reg - REG_SHADOW_START]\n\t\t\t\t\t);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tpriv->override_mask[reg - REG_SHADOW_START] |= reg_mask;\n\t\t\tpriv->override_data[reg - REG_SHADOW_START] &= (~reg_mask);\n\n\t\t\tfprintf(stderr, \"override_data[] &= ( ~(mask %02X) = %02X ) => %02X\\n\", reg_mask, ~reg_mask, priv->override_data[reg - REG_SHADOW_START] );\n\t\t\tpriv->override_data[reg - REG_SHADOW_START] |= (reg_mask & reg_val);\n\t\t\tfprintf(stderr, \"override_data[] |= ( mask %02X & val %02X )\\n\", reg_mask, reg_val );\n\t\t\tfprintf(stderr, \"%s: added override mask for register %d = %02X. old mask %02X, old data %02X. new mask is %02X, new data %02X\\n\"\n\t\t\t\t\t, __FUNCTION__\n\t\t\t\t\t, i2c_register, i2c_register\n\t\t\t\t\t, oldMask, oldData\n\t\t\t\t\t, priv->override_mask[reg - REG_SHADOW_START]\n\t\t\t\t\t, priv->override_data[reg - REG_SHADOW_START]\n\t\t\t\t\t);\n\t\t}\n\t\treturn r82xx_write_reg_mask_ext(priv, reg, 0, 0, __FUNCTION__);\n\t}\n\telse\n\t\treturn -1;\n}\n\n\n\nstruct IFinfo\n{\n\tint\tsharpCorner;\t/* 1 = at LSB (lower side band); 2 = at USB (upper side band); 3 = both LSB+USB */\n\tint\tbw;\t\t\t\t/* 3-dB bandwidth in kHz - available around IF frequency, which becomes center frequency */\n\tint\tfif;\t\t\t/* IF frequency in kHz for the RTL2832 */\n\tint\tfc;\t\t\t\t/* IF frequency correction in kHz */\n\tuint8_t reg10Lo;\t/* low-part of I2C register 0x0A */\n\tuint8_t\treg11;\t\t/* content of I2C register 0x0B */\n\tuint8_t\treg30Hi;\t\t/* R30 = 0x1E: channel filter extension \"on weak signal\" */\n};\n\n/* narrowest IF bandpass with reg10/reg11/reg30 = 0x0F, 0xEF, 0x60:\n *   539 .. 2002 kHz (mirrored from tuner)\n * calculate IF center frequency from that bandpass edges\n */\n#define IFA(BW)\t\t(2002 - BW / 2)\n#define IFB(BW)\t\t(539 + BW / 2)\n\n/* duplicated lower bandwidths to allow \"sideband\" selection: which is filtered with help of IF corner */\nstatic const struct IFinfo IFi[] = {\n#if (WITH_ASYM_FILTER)\n\t{ 1,  200+1, IFA( 200),  33, 0x0F, 0xEF, 0x60 },\t/* steep low  freq edge */\n\t{ 2,  200+2, IFB( 200),   3, 0x0F, 0xEF, 0x60 },\t/* steep high freq edge */\n#endif\n\n\t{ 3,  290+0,      1950, -25, 0x0F, 0xE7, 0x00 },\t/* centered with hpf - high pass filter */\n#if (WITH_ASYM_FILTER)\n\t{ 1,  290+1, IFA( 290),  26, 0x0F, 0xEF, 0x60 },\t/* steep low  freq edge */\n\t{ 2,  290+2, IFB( 290),   2, 0x0F, 0xEF, 0x60 },\t/* steep high freq edge */\n#endif\n\n\t{ 3,  375+0,      1870, -13, 0x0F, 0xE8, 0x00 },\t/* centered with hpf */\n#if (WITH_ASYM_FILTER)\n\t{ 1,  375+1, IFA( 375),  23, 0x0F, 0xEF, 0x60 },\t/* steep low  freq edge */\n\t{ 2,  375+2, IFB( 375),   3, 0x0F, 0xEF, 0x60 },\t/* steep high freq edge */\n#endif\n\n\t{ 3,  420+0,      2100,  21, 0x0F, 0xD7, 0x00 },\t/* centered with hpf */\n#if (WITH_ASYM_FILTER)\n\t{ 1,  420+1, IFA( 420),  23, 0x0F, 0xEF, 0x60 },\t/* steep low  freq edge */\n\t{ 2,  420+2, IFB( 420),   3, 0x0F, 0xEF, 0x60 },\t/* steep high freq edge */\n#endif\n\n\t{ 3,  470+0,      1800, -12, 0x0F, 0xE9, 0x00 },\t/* centered with hpf */\n#if (WITH_ASYM_FILTER)\n\t{ 1,  470+1, IFA( 470),  18, 0x0F, 0xEF, 0x60 },\t/* steep low  freq edge */\n\t{ 2,  470+2, IFB( 470),   2, 0x0F, 0xEF, 0x60 },\t/* steep high freq edge */\n#endif\n\n\t{ 3,  600+0,      1700,   6, 0x0F, 0xEA, 0x00 },\t/* centered with hpf */\n#if (WITH_ASYM_FILTER)\n\t{ 1,  600+1, IFA( 600),  16, 0x0F, 0xEF, 0x60 },\t/* steep low  freq edge */\n\t{ 2,  600+2, IFB( 600),   3, 0x0F, 0xEF, 0x60 },\t/* steep high freq edge */\n#endif\n\n\t{ 3,  860+0,      1550,   8, 0x0F, 0xEB, 0x00 },\t/* centered with hpf */\n#if (WITH_ASYM_FILTER)\n\t{ 1,  860+1, IFA( 860),  17, 0x0F, 0xEF, 0x60 },\t/* steep low  freq edge */\n\t{ 2,  860+2, IFB( 860), -12, 0x0F, 0xEF, 0x60 },\t/* steep high freq edge */\n#endif\n\n\t{ 3,  950+0,      2200,   5, 0x0F, 0x88, 0x00 },\t/* centered with hpf */\n#if (WITH_ASYM_FILTER)\n\t{ 1,  950+1, IFA( 950),   6, 0x0F, 0xEF, 0x60 },\t/* steep low  freq edge */\n\t{ 2,  950+2, IFB( 950),   0, 0x0F, 0xEF, 0x60 },\t/* steep high freq edge */\n#endif\n\n\t{ 3, 1100+0,      2100,  25, 0x0F, 0x89, 0x00 },\t/* centered with hpf */\n#if (WITH_ASYM_FILTER)\n\t{ 1, 1100+1, IFA(1100),  24, 0x0F, 0xEF, 0x60 },\t/* steep low  freq edge */\n\t{ 2, 1100+2, IFB(1100),   0, 0x0F, 0xEF, 0x60 },\t/* steep high freq edge */\n#endif\n\n\t{ 3, 1200+0,      1350,   0, 0x0F, 0xEE, 0x00 },\t/* centered with hpf */\n\n\t{ 3, 1300+0,      2050,  -7, 0x0F, 0x8A, 0x00 },\t/* centered with hpf */\n#if (WITH_ASYM_FILTER)\n\t{ 1, 1300+1, IFA(1300),  26, 0x0F, 0xEF, 0x60 },\t/* steep low  freq edge */\n\t{ 2, 1300+2, IFB(1300),   0, 0x0F, 0xEF, 0x60 },\t/* steep high freq edge */\n#endif\n\n\t{ 3, 1500+3,      1300, -24, 0x0F, 0xEF, 0x60 },\n\t{ 3, 1600+0,      1900,   0, 0x0F, 0x8B, 0x00 },\t/* centered with hpf */\n\t{ 3, 1750+3,      1400,  12, 0x0F, 0xCF, 0x60 },\t/* 20 */\n\n\t{ 3, 1800+0,      1400,   0, 0x0F, 0xAF, 0x00 },\n\n\t{ 3, 1950+3,      1500,  30, 0x0F, 0x8F, 0x60 },\n\n\t{ 3, 2200+0,      1600,   0, 0x0F, 0x8F, 0x00 },\n\t{ 3, 3000+0,      2000,   0, 0x04, 0x8F, 0x00 },\n\t{ 3, 5000+0,      3570,   0, 0x0B, 0x6B, 0x00 }\n\n};\n\n\n/* settings from Oldenburger:\nstatic const int r82xx_bws[]=     {  300,  450,  600,  900, 1100, 1200, 1300, 1500, 1800, 2200, 3000, 5000 };\nstatic const uint8_t r82xx_0xa[]= { 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0f, 0x0f, 0x04, 0x0b };\nstatic const uint8_t r82xx_0xb[]= { 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xaf, 0x8f, 0x8f, 0x6b };\nstatic const int r82xx_if[]  =    { 1700, 1650, 1600, 1500, 1400, 1350, 1320, 1270, 1400, 1600, 2000, 3570 };\n*/\n\n\nstatic const int r82xx_bw_tablen = sizeof(IFi) / sizeof(IFi[0]);\n\n\n#define FILT_HP_BW1 350000\n#define FILT_HP_BW2 380000\nint r82xx_set_bandwidth(struct r82xx_priv *priv, int bw, uint32_t rate, uint32_t * applied_bw, int apply)\n{\n\tint rc;\n\tint i;\n\tint real_bw = 0;\n#if USE_R82XX_ENV_VARS\n\tuint8_t reg_09, reg_0d =0, reg_0e =0;\n#endif\n\tuint8_t reg_mask;\n\tuint8_t reg_0a;\n\tuint8_t reg_0b;\n\tuint8_t reg_1e = 0x60;\t\t/* default: Enable Filter extension under weak signal */\n\n\tif (bw > 7000000) {\n\t\t// BW: 8 MHz\n\t\t*applied_bw = 8000000;\n\t\treg_0a = 0x10;\n\t\treg_0b = 0x0b;\n\t\tif (apply)\n\t\t\tpriv->int_freq = 4570000;\n\t} else if (bw > 6000000) {\n\t\t// BW: 7 MHz\n\t\t*applied_bw = 7000000;\n\t\treg_0a = 0x10;\n\t\treg_0b = 0x2a;\n\t\tif (apply)\n\t\t\tpriv->int_freq = 4570000;\n\t} else if (bw > 4500000) {\n\t\t// BW: 6 MHz\n\t\t*applied_bw = 6000000;\n\t\treg_0a = 0x10;\n\t\treg_0b = 0x6b;\n\t\tif (apply)\n\t\t\tpriv->int_freq = 3570000;\n\t} else {\n\t\tfor(i=0; i < r82xx_bw_tablen-1; ++i) {\n\t\t\tconst int bwnext = IFi[i+1].bw * 1000 + ( IFi[i+1].sharpCorner == 2 ? 400 : 0 );\n\t\t\tconst int bwcurr = IFi[i].bw * 1000 + ( IFi[i].sharpCorner == 2 ? 400 : 0 );\n\t\t\t/* bandwidth is compared to median of the current and next available bandwidth in the table */\n\t\t\tif (bw < (bwnext + bwcurr)/2)\n\t\t\t\tbreak;\n\t\t}\n\n\t\treg_0a = IFi[i].reg10Lo;\n\t\treg_0b = IFi[i].reg11;\n\t\treg_1e = IFi[i].reg30Hi;\n\t\treal_bw = IFi[i].bw * 1000;   /* kHz part */\n#if 0\n\t\tfprintf(stderr, \"%s: selected idx %d: R10 = %02X, R11 = %02X, Bw %d, IF %d\\n\"\n\t\t\t, __FUNCTION__, i\n\t\t\t, (unsigned)reg_0a\n\t\t\t, (unsigned)reg_0b\n\t\t\t, real_bw\n\t\t\t, IFi[i].fif * 1000 + IFi[i].fc\n\t\t\t);\n#endif\n\t\t*applied_bw = real_bw;\n\t\tif (apply)\n\t\t\tpriv->int_freq = ( IFi[i].fif + IFi[i].fc ) * 1000;\n\t}\n\n#if USE_R82XX_ENV_VARS\n\t// hacking RTLSDR IF-Center frequency - on environment variable\n\tif ( priv->filterCenter && apply )\n\t{\n#if 0\n\t\tfprintf(stderr, \"*** applied IF center %d\\n\", priv->filterCenter);\n#endif\n\t\tpriv->int_freq = priv->filterCenter;\n\t}\n#endif\n\n\tif (!apply)\n\t\treturn 0;\n\n#if USE_R82XX_ENV_VARS\n\t/* Register 0x9 = R9: IF Filter Power/Current */\n\tif ( priv->haveR9 )\n\t{\n\t\tfprintf(stderr, \"*** in function %s: PREV I2C register %02X value: %02X\\n\", __FUNCTION__, 0x09, r82xx_read_cache_reg(priv, 0x09) );\n\t\treg_09 = priv->valR9 << 6;\n\t\treg_mask = 0xC0;\t// 1100 0000\n\t\tfprintf(stderr, \"*** read R9 from environment: %d\\n\", priv->valR9);\n\t\trc = r82xx_write_reg_mask(priv, 0x09, reg_09, 0xc0);\n\t\tif (rc < 0)\n\t\t\tfprintf(stderr, \"ERROR setting I2C register 0x09 to value %02X with mask %02X\\n\", (unsigned)reg_09, (unsigned)reg_mask);\n\t}\n#endif\n\n\t/* Register 0xA = R10 */\n\treg_mask = 0x0F;\t// default: 0001 0000\n#if USE_R82XX_ENV_VARS\n\tif ( priv->haveR10H ) {\n\t\treg_0a = ( reg_0a & ~0xf0 ) | ( priv->valR10H << 4 );\n\t\treg_mask = 0xf0;\n\t}\n\tif ( priv->haveR10L ) {\n\t\treg_0a = ( reg_0a & ~0x0f ) | priv->valR10L;\n\t\treg_mask |= 0x0f;\n\t}\n#endif\n\trc = r82xx_write_reg_mask_ext(priv, 0x0a, reg_0a, reg_mask, __FUNCTION__);\n\tif (rc < 0) {\n\t\tfprintf(stderr, \"ERROR setting I2C register 0x0A to value %02X with mask %02X\\n\", (unsigned)reg_0a, (unsigned)reg_mask);\n\t\treturn rc;\n\t}\n\n\t/* Register 0xB = R11 with undocumented Bit 7 for filter bandwidth for Hi-part FILT_BW */\n\treg_mask = 0xEF;\t// default: 1110 1111\n#if USE_R82XX_ENV_VARS\n\tif ( priv->haveR11H ) {\n\t\treg_0b = ( reg_0b & ~0xE0 ) | ( priv->valR11H << 5 );\n\t}\n\tif ( priv->haveR11L ) {\n\t\treg_0b = ( reg_0b & ~0x0F ) | priv->valR11L;\n\t}\n#endif\n\trc = r82xx_write_reg_mask_ext(priv, 0x0b, reg_0b, reg_mask, __FUNCTION__);\n\tif (rc < 0) {\n\t\tfprintf(stderr, \"ERROR setting I2C register 0x0B to value %02X with mask %02X\\n\"\n\t\t\t, (unsigned)reg_0b, (unsigned)reg_mask);\n\t\treturn rc;\n\t}\n\n\n\t/* Register 0xD = R13: LNA agc power detector voltage threshold high + low setting */\n\treg_mask = 0x00;\t// default: 0000 0000\n#if USE_R82XX_ENV_VARS\n\tif ( priv->haveR13H ) {\n\t\treg_0d = ( reg_0d & ~0xf0 ) | ( priv->valR13H << 4 );\n\t\treg_mask |= 0xF0;\n\t}\n\tif ( priv->haveR13L ) {\n\t\treg_0d = ( reg_0d & ~0x0f ) | priv->valR13L;\n\t\treg_mask |= 0x0F;\n\t}\n\tif ( reg_mask ) {\n\t\trc = r82xx_write_reg_mask_ext(priv, 0x0d, reg_0d, reg_mask, __FUNCTION__);\n\t\tif (rc < 0)\n\t\t\tfprintf(stderr, \"ERROR setting I2C register 0x0D to value %02X with mask %02X\\n\"\n\t\t\t\t, (unsigned)reg_0d, (unsigned)reg_mask);\n\t}\n#endif\n\n\t/* Register 0xE = R14: MIXER agc power detector voltage threshold high + low setting */\n\treg_mask = 0x00;\t// default: 0000 0000\n#if USE_R82XX_ENV_VARS\n\tif ( priv->haveR14H ) {\n\t\treg_0e = ( reg_0e & ~0xf0 ) | ( priv->valR14H << 4 );\n\t\treg_mask |= 0xF0;\n\t}\n\tif ( priv->haveR14L ) {\n\t\treg_0e = ( reg_0e & ~0x0f ) | priv->valR14L;\n\t\treg_mask |= 0x0F;\n\t}\n\tif ( reg_mask ) {\n\t\trc = r82xx_write_reg_mask_ext(priv, 0x0e, reg_0e, reg_mask, __FUNCTION__);\n\t\tif (rc < 0)\n\t\t\tfprintf(stderr, \"%s: ERROR setting I2C register 0x0E to value %02X with mask %02X\\n\"\n\t\t\t, __FUNCTION__, (unsigned)reg_0e, (unsigned)reg_mask);\n\t}\n#endif\n\n\t/* channel filter extension */\n\treg_mask = 0x40;\n#if USE_R82XX_ENV_VARS\n\tif ( priv->haveR30H ) {\n\t\treg_1e = ( priv->valR30H << 6 );\n\t\treg_mask = reg_mask | 0xC0;\n\t}\n\tif ( priv->haveR30L ) {\n\t\treg_1e = reg_1e | priv->valR30L;\n\t\treg_mask = reg_mask | 0x3F;\n\t}\n#endif\n\trc = r82xx_write_reg_mask_ext(priv, 0x1e, reg_1e, reg_mask, __FUNCTION__);\n\tif (rc < 0)\n\t\tfprintf(stderr, \"%s: ERROR setting I2C register 0x1E to value %02X with mask %02X\\n\"\n\t\t, __FUNCTION__, (unsigned)reg_1e, (unsigned)reg_mask);\n\n\treturn priv->int_freq;\n}\n#undef FILT_HP_BW1\n#undef FILT_HP_BW2\n\nint r82xx_set_bw_center(struct r82xx_priv *priv, int32_t if_band_center_freq)\n{\n\tpriv->if_band_center_freq = if_band_center_freq;\n\treturn priv->int_freq;\n}\n\nint r82xx_set_sideband(struct r82xx_priv *priv, int sideband)\n{\n\tint rc;\n\tpriv->sideband = sideband;\n\trc = r82xx_write_reg_mask(priv, 0x07, (sideband << 7) & 0x80, 0x80);\n\tif (rc < 0)\n\t\treturn rc;\n\treturn 0;\n}\n\nint r82xx_get_sideband(struct r82xx_priv *priv)\n{\n\treturn priv->sideband;\n}\n\n\nstatic const uint32_t harm_sideband_xor[17] = {\n\t0\t/*  0 - should not happen */\n,\t0\t/*  1 - default - as without harmonic */\n,\t0\t/*  2: ( 2 * 90 deg) % 360 = 180 deg */\n,\t1\t/*  3: ( 3 * 90 deg) % 360 = -90 deg */\n,\t0\t/*  4: ( 4 * 90 deg) % 360 =   0 deg */\n,\t0\t/*  5: ( 5 * 90 deg) % 360 = +90 deg */\n,\t0\t/*  6: ( 6 * 90 deg) % 360 = 180 deg */\n,\t1\t/*  7: ( 7 * 90 deg) % 360 = -90 deg */\n,\t0\t/*  8: ( 8 * 90 deg) % 360 =   0 deg */\n,\t0\t/*  9: ( 9 * 90 deg) % 360 = +90 deg */\n,\t0\t/* 10: (10 * 90 deg) % 360 = 180 deg */\n,\t1\t/* 11: (11 * 90 deg) % 360 = -90 deg */\n,\t0\t/* 12: (12 * 90 deg) % 360 =   0 deg */\n,\t0\t/* 13: (13 * 90 deg) % 360 = +90 deg */\n,\t0\t/* 14: (14 * 90 deg) % 360 = 180 deg */\n,\t1\t/* 15: (15 * 90 deg) % 360 = -90 deg */\n,\t0\t/* 16: (16 * 90 deg) % 360 = 180 deg */\n};\n\nint r82xx_flip_rtl_sideband(struct r82xx_priv *priv)\n{\n\treturn harm_sideband_xor[priv->tuner_harmonic];\n}\n\n\nint r82xx_set_freq64(struct r82xx_priv *priv, uint64_t freq)\n{\n\tint rc = -1;\n\tint is_rtlsdr_blog_v4;\n\tuint64_t upconvert_freq;\n\tuint64_t lo_freq;\n\tuint32_t lo_freqHarm;\n\tuint8_t air_cable1_in;\n\tuint8_t open_d;\n\tuint8_t band;\n\tuint8_t cable_2_in;\n\tuint8_t cable_1_in;\n\tuint8_t air_in;\n\tint nth_harm;\n\tint harm;\n\n\tis_rtlsdr_blog_v4 = rtlsdr_check_dongle_model(priv->rtl_dev, \"RTLSDRBlog\", \"Blog V4\");\n        /* if it's an RTL-SDR Blog V4, automatically upconvert by 28.8 MHz if we tune to HF\n\t * so that we don't need to manually set any upconvert offset in the SDR software */\n\tupconvert_freq = is_rtlsdr_blog_v4 ? ((freq < MHZ(28.8)) ? (freq + MHZ(28.8)) : freq) : freq;\n\tharm = (priv->cfg->harmonic <= 0) ? DEFAULT_HARMONIC : priv->cfg->harmonic;\n\tnth_harm = ( freq > FIFTH_HARM_FRQ_THRESH_KHZ * (uint64_t)1000 ) ? 1 : 0;\n\n\tfor ( ; nth_harm < 2; ++nth_harm )\n\t{\n\t\tpriv->tuner_pll_set = 0;\n\t\tpriv->tuner_harmonic = ( nth_harm ) ? harm : 0;\n\n\t\tif (!freq)\n\t\t\tfreq = priv->rf_freq;\t/* ignore zero frequency; keep last one */\n\t\telse\n\t\t\tpriv->rf_freq = upconvert_freq;\n\n\t\tif ( priv->sideband ^ harm_sideband_xor[priv->tuner_harmonic] )\n\t\t\tlo_freq = upconvert_freq - priv->int_freq + priv->if_band_center_freq;\n\t\telse\n\t\t\tlo_freq = upconvert_freq + priv->int_freq + priv->if_band_center_freq;\n\n\t\tlo_freqHarm = (nth_harm) ? ( lo_freq / harm ) : lo_freq;\n\n#if PRINT_HARMONICS\n\t\tfprintf(stderr, \"%s(freq = %f MHz) @ %s--> intfreq %u Hz, ifcenter %d --> f %f MHz, PLL %f MHz\\n\"\n\t\t\t, __FUNCTION__, upconvert_freq * 1E-6, (priv->sideband ? \"USB\" : \"LSB\")\n\t\t\t, (unsigned)priv->int_freq, (int)priv->if_band_center_freq\n\t\t\t, lo_freq * 1E-6, lo_freqHarm * 1E-6 );\n#endif\n\n\t\trc = r82xx_set_mux(priv, lo_freq);\n\t\tif (rc < 0) {\n\t\t\tif (priv->cfg->verbose)\n\t\t\t\tfprintf(stderr, \"r82xx_set_freq(): error at r82xx_set_mux()\\n\");\n\t\t\tgoto err;\n\t\t}\n\n\t\trc = r82xx_set_pll(priv, lo_freqHarm);\n\t\tif (rc < 0 || !priv->has_lock)\n\t\t{\n\t\t\tif ( !nth_harm && lo_freq > RETRY_WITH_FIFTH_HARM_KHZ * 1000 )\n\t\t\t\tcontinue;\n\t\t\tgoto err;\n\t\t}\n\n\t\tif ( nth_harm )\n\t\t{\n#if 0\n\t\t\tfprintf(stderr, \"r82xx_set_freq(): set up for %d-th harmonic\\n\", harm);\n#endif\n\t\t}\n\n\t\tbreak;\n\t}\n\n\tif (is_rtlsdr_blog_v4) {\n\n\t\t/* determine if notch filters should be on or off notches are turned OFF\n\t\t * when tuned within the notch band and ON when tuned outside the notch band.\n\t\t */\n\t\topen_d = (freq <= MHZ(2.2) || (freq >= MHZ(85) && freq <= MHZ(112)) || (freq >= MHZ(172) && freq <= MHZ(242))) ? 0x00 : 0x08;\n\t\trc = r82xx_write_reg_mask(priv, 0x17, open_d, 0x08);\n\n\t\tif (rc < 0)\n\t\t\treturn rc;\n\n\t\t/* select tuner band based on frequency and only switch if there is a band change\n\t\t *(to avoid excessive register writes when tuning rapidly)\n\t\t */\n\t\tband = (freq <= MHZ(28.8)) ? HF : ((freq > MHZ(28.8) && freq < MHZ(250)) ? VHF : UHF);\n\t\t/* switch between tuner inputs on the RTL-SDR Blog V4 */\n\t\tif (band != priv->input) {\n\t\t\tpriv->input = band;\n\n\t\t\t/* activate cable 2 (HF input) */\n\t\t\tcable_2_in = (band == HF) ? 0x08 : 0x00;\n\t\t\trc = r82xx_write_reg_mask(priv, 0x06, cable_2_in, 0x08);\n\n\t\t\tif (rc < 0)\n\t\t\t\tgoto err;\n\n\t\t\t/* activate cable 1 (VHF input) */\n\t\t\tcable_1_in = (band == VHF) ? 0x40 : 0x00;\n\t\t\trc = r82xx_write_reg_mask(priv, 0x05, cable_1_in, 0x40);\n\n\t\t\tif (rc < 0)\n\t\t\t\tgoto err;\n\n\t\t\t/* activate air_in (UHF input) */\n\t\t\tair_in = (band == UHF) ? 0x00 : 0x20;\n\t\t\trc = r82xx_write_reg_mask(priv, 0x05, air_in, 0x20);\n\n\t\t\tif (rc < 0)\n\t\t\t\tgoto err;\n\t\t}\n\t}\n\telse\n\t{\n\t\t/* switch between 'Cable1' and 'Air-In' inputs on sticks with\n\t\t* R828D tuner. We switch at 345 MHz, because that's where the\n\t\t* noise-floor has about the same level with identical LNA\n\t\t* settings. The original driver used 320 MHz. */\n\t\tair_cable1_in = (freq > MHZ(345)) ? 0x00 : 0x60;\n\n\t\tif ((priv->cfg->rafael_chip == CHIP_R828D) &&\n\t\t\t(air_cable1_in != priv->input)) {\n\t\t\tpriv->input = air_cable1_in;\n\t\t\trc = r82xx_write_reg_mask(priv, 0x05, air_cable1_in, 0x60);\n\t\t}\n\t}\nerr:\n#if PRINT_PLL_ERRORS\n\tif (rc < 0)\n\t\tfprintf(stderr, \"%s: failed=%d\\n\", __FUNCTION__, rc);\n#endif\n\treturn rc;\n}\n\nint r82xx_set_freq(struct r82xx_priv *priv, uint32_t freq)\n{\n\treturn r82xx_set_freq64(priv, (uint64_t)freq);\n}\n\nint r82xx_set_dither(struct r82xx_priv *priv, int dither)\n{\n\tpriv->disable_dither = !dither;\n\treturn 0;\n}\n\n\n/*\n * r82xx standby logic\n */\n\nint r82xx_standby(struct r82xx_priv *priv)\n{\n\tint rc;\n\n\t/* If device was not initialized yet, don't need to standby */\n\tif (!priv->init_done)\n\t\treturn 0;\n\n\trc = r82xx_write_reg(priv, 0x06, 0xb1);\n\tif (rc < 0)\n\t\treturn rc;\n\trc = r82xx_write_reg(priv, 0x05, 0xa0);\n\tif (rc < 0)\n\t\treturn rc;\n\trc = r82xx_write_reg(priv, 0x07, 0x3a);\n\tif (rc < 0)\n\t\treturn rc;\n\trc = r82xx_write_reg(priv, 0x08, 0x40);\n\tif (rc < 0)\n\t\treturn rc;\n\trc = r82xx_write_reg(priv, 0x09, 0xc0);\n\tif (rc < 0)\n\t\treturn rc;\n\trc = r82xx_write_reg(priv, 0x0a, 0x36);\n\tif (rc < 0)\n\t\treturn rc;\n\trc = r82xx_write_reg(priv, 0x0c, 0x35);\n\tif (rc < 0)\n\t\treturn rc;\n\trc = r82xx_write_reg(priv, 0x0f, 0x68);\n\tif (rc < 0)\n\t\treturn rc;\n\trc = r82xx_write_reg(priv, 0x11, 0x03);\n\tif (rc < 0)\n\t\treturn rc;\n\trc = r82xx_write_reg(priv, 0x17, 0xf4);\n\tif (rc < 0)\n\t\treturn rc;\n\trc = r82xx_write_reg(priv, 0x19, 0x0c);\n\n\t/* Force initial calibration */\n\tpriv->type = -1;\n\n\treturn rc;\n}\n\n/*\n * r82xx device init logic\n */\n\nint r82xx_init(struct r82xx_priv *priv)\n{\n\tint rc;\n\n#if PRINT_INITIAL_REGISTERS\n#define INIT_NUM_READ_REGS 16\n\tuint8_t\t\tinitial_register_values[INIT_NUM_READ_REGS];\t/* see what is 'default' */\n\tint k;\n\t/* get initial register values - just to see .. */\n\tmemset( &(initial_register_values[0]), 0, sizeof(initial_register_values) );\n\tprintf(\"R820T/2 initial register settings:\\n\");\n\tr82xx_read(priv, 0x00, initial_register_values, sizeof(initial_register_values));\n\tfor (k=0; k < INIT_NUM_READ_REGS; ++k)\n\t\tprintf(\"register 0x%02x: 0x%02x\\n\", k, initial_register_values[k]);\n\tprintf(\"\\n\");\n#endif\n\n\t/* TODO: R828D might need r82xx_xtal_check() */\n\tpriv->xtal_cap_sel = XTAL_HIGH_CAP_0P;\n\n\tpriv->rf_freq = 0;\n\tpriv->if_band_center_freq = 0;\n\n\tpriv->last_if_mode = 0;\n\tpriv->last_manual_gain = 0;\n\tpriv->last_extended_mode = 0;\n\tpriv->last_LNA_value = 0;\n\tpriv->last_Mixer_value = 0;\n\tpriv->last_VGA_value = DEFAULT_IF_VGA_VAL;\n\tpriv->last_vco_curr = 0xff;\n\n\t/* Initialize override registers */\n\tmemset( &(priv->override_data[0]), 0, NUM_REGS * sizeof(uint8_t) );\n\tmemset( &(priv->override_mask[0]), 0, NUM_REGS * sizeof(uint8_t) );\n\n\t/* Initialize registers */\n\trc = r82xx_write_arr(priv, 0x05,\n\t\t\t r82xx_init_array, sizeof(r82xx_init_array));\n\n\tpriv->last_vco_curr = r82xx_init_array[0x12 - 0x05] & 0xe0;\n\n\trc = r82xx_set_tv_standard(priv, TUNER_DIGITAL_TV, 0);\n\tif (rc < 0)\n\t\tgoto err;\n\n\trc = r82xx_sysfreq_sel(priv, TUNER_DIGITAL_TV);\n\n#if USE_R82XX_ENV_VARS\n\tpriv->printI2C = 0;\n\tpriv->filterCenter = 0;\n\tpriv->haveR9 = priv->valR9 = 0;\n\tpriv->haveR10L = priv->valR10L = 0;\n\tpriv->haveR10H = priv->valR10H = 0;\n\tpriv->haveR11L = priv->valR11L = 0;\n\tpriv->haveR11H = priv->valR11H = 0;\n\tpriv->haveR13L = priv->valR13L = 0;\n\tpriv->haveR13H = priv->valR13H = 0;\n\tpriv->haveR14L = priv->valR14L = 0;\n\tpriv->haveR14H = priv->valR14H = 0;\n\tpriv->haveR30H = priv->valR30H = 0;\n\tpriv->haveR30L = priv->valR30L = 0;\n#endif\n\n\tpriv->init_done = 1;\n\n#if USE_R82XX_ENV_VARS\n\t// read environment variables\n\tif (1) {\n\t\tchar *pacPrintI2C;\n\t\tchar *pacFilterCenter, *pacR9;\n\t\tchar *pacR10Hi, *pacR10Lo, *pacR11Hi, *pacR11Lo;\n\t\tchar *pacR13Hi, *pacR13Lo, *pacR14Hi, *pacR14Lo;\n\t\tchar *pacR30Hi, *pacR30Lo;\n\n\t\tpacPrintI2C = getenv(\"RTL_R820_PRINT_I2C\");\n\t\tif ( pacPrintI2C )\n\t\t\tpriv->printI2C = atoi(pacPrintI2C);\n\n\t\tpacFilterCenter = getenv(\"RTL_R820_IF_CENTER\");\n\t\tif ( pacFilterCenter )\n\t\t\tpriv->filterCenter = atoi(pacFilterCenter);\n\n\t\tpacR9 = getenv(\"RTL_R820_R9_76\");\n\t\tif ( pacR9 ) {\n\t\t\tpriv->haveR9 = 1;\n\t\t\tpriv->valR9 = atoi(pacR9);\n\t\t\tif ( priv->valR9 > 3 ) {\n\t\t\t\tfprintf(stderr, \"*** read R9 from environment: %d - but value should be 0 - 3 for bit [7:6]\\n\", priv->valR9);\n\t\t\t\tpriv->haveR9 = 0;\n\t\t\t}\n\t\t\tfprintf(stderr, \"*** read R9 from environment: %d\\n\", priv->valR9);\n\t\t}\n\n\t\tpacR10Hi = getenv(\"RTL_R820_R10_HI\");\n\t\tif ( pacR10Hi ) {\n\t\t\tpriv->haveR10H = 1;\n\t\t\tpriv->valR10H = atoi(pacR10Hi);\n\t\t\tif ( priv->valR10H > 15 ) {\n\t\t\t\tfprintf(stderr, \"*** read R10_HI from environment: %d - but value should be 0 - 15 for bit [7:4]\\n\", priv->valR10H);\n\t\t\t\tpriv->haveR10H = 0;\n\t\t\t}\n\t\t\tfprintf(stderr, \"*** read R10_HI from environment: %d\\n\", priv->valR10H);\n\t\t}\n\n\t\tpacR10Lo = getenv(\"RTL_R820_R10_LO\");\n\t\tif ( pacR10Lo ) {\n\t\t\tpriv->haveR10L = 1;\n\t\t\tpriv->valR10L = atoi(pacR10Lo);\n\t\t\tif ( priv->valR10L > 15 ) {\n\t\t\t\tfprintf(stderr, \"*** read R10_LO from environment: %d - but value should be 0 - 15 for bit [3:0]\\n\", priv->valR10L);\n\t\t\t\tpriv->haveR10L = 0;\n\t\t\t}\n\t\t\tfprintf(stderr, \"*** read R10_LO from environment: %d\\n\", priv->valR10L);\n\t\t}\n\n\t\tpacR11Hi = getenv(\"RTL_R820_R11_HI\");\n\t\tif ( pacR11Hi ) {\n\t\t\tpriv->haveR11H = 1;\n\t\t\tpriv->valR11H = atoi(pacR11Hi);\n\t\t\tif ( priv->valR11H > 7 ) {\n\t\t\t\tfprintf(stderr, \"*** read R11_HI from environment: %d - but value should be 0 - 7 for bit [6:5]\\n\", priv->valR11H);\n\t\t\t\tpriv->haveR11H = 0;\n\t\t\t}\n\t\t\tfprintf(stderr, \"*** read R11_HI from environment: %d\\n\", priv->valR11H);\n\t\t}\n\n\t\tpacR11Lo = getenv(\"RTL_R820_R11_LO\");\n\t\tif ( pacR11Lo ) {\n\t\t\tpriv->haveR11L = 1;\n\t\t\tpriv->valR11L = atoi(pacR11Lo);\n\t\t\tif ( priv->valR11L > 15 ) {\n\t\t\t\tfprintf(stderr, \"*** read R11_LO from environment: %d - but value should be 0 - 15 for bit [3:0]\\n\", priv->valR11L);\n\t\t\t\tpriv->haveR11L = 0;\n\t\t\t}\n\t\t\tfprintf(stderr, \"*** read R11_LO from environment: %d\\n\", priv->valR11L);\n\t\t}\n\n\n\t\tpacR13Hi = getenv(\"RTL_R820_R13_HI\");\n\t\tif ( pacR13Hi ) {\n\t\t\tpriv->haveR13H = 1;\n\t\t\tpriv->valR13H = atoi(pacR13Hi);\n\t\t\tif ( priv->valR13H > 15 ) {\n\t\t\t\tfprintf(stderr, \"*** read R13_HI from environment: %d - but value should be 0 - 15 for bit [7:4]\\n\", priv->valR13H);\n\t\t\t\tpriv->haveR13H = 0;\n\t\t\t}\n\t\t\tfprintf(stderr, \"*** read R13_HI from environment: %d\\n\", priv->valR13H);\n\t\t}\n\n\t\tpacR13Lo = getenv(\"RTL_R820_R13_LO\");\n\t\tif ( pacR13Lo ) {\n\t\t\tpriv->haveR13L = 1;\n\t\t\tpriv->valR13L = atoi(pacR13Lo);\n\t\t\tif ( priv->valR13L > 15 ) {\n\t\t\t\tfprintf(stderr, \"*** read R13_LO from environment: %d - but value should be 0 - 15 for bit [3:0]\\n\", priv->valR13L);\n\t\t\t\tpriv->haveR13L = 0;\n\t\t\t}\n\t\t\tfprintf(stderr, \"*** read R13_LO from environment: %d\\n\", priv->valR13L);\n\t\t}\n\n\n\t\tpacR14Hi = getenv(\"RTL_R820_R14_HI\");\n\t\tif ( pacR14Hi ) {\n\t\t\tpriv->haveR14H = 1;\n\t\t\tpriv->valR14H = atoi(pacR14Hi);\n\t\t\tif ( priv->valR14H > 15 ) {\n\t\t\t\tfprintf(stderr, \"*** read R14_HI from environment: %d - but value should be 0 - 15 for bit [7:4]\\n\", priv->valR14H);\n\t\t\t\tpriv->haveR14H = 0;\n\t\t\t}\n\t\t\tfprintf(stderr, \"*** read R14_HI from environment: %d\\n\", priv->valR14H);\n\t\t}\n\n\t\tpacR14Lo = getenv(\"RTL_R820_R14_LO\");\n\t\tif ( pacR14Lo ) {\n\t\t\tpriv->haveR14L = 1;\n\t\t\tpriv->valR14L = atoi(pacR14Lo);\n\t\t\tif ( priv->valR14L > 15 ) {\n\t\t\t\tfprintf(stderr, \"*** read R14_LO from environment: %d - but value should be 0 - 15 for bits [3:0]\\n\", priv->valR14L);\n\t\t\t\tpriv->haveR14L = 0;\n\t\t\t}\n\t\t\tfprintf(stderr, \"*** read R14_LO from environment: %d\\n\", priv->valR14L);\n\t\t}\n\n\t\tpacR30Hi = getenv(\"RTL_R820_R30_HI\");\n\t\tif ( pacR30Hi ) {\n\t\t\tpriv->haveR30H = 1;\n\t\t\tpriv->valR30H = atoi(pacR30Hi);\n\t\t\tif ( priv->valR30H > 3 ) {\n\t\t\t\tfprintf(stderr, \"*** read R30_HI from environment: %d - but value should be 0 - 3 for bit [7:6]\\n\", priv->valR30H);\n\t\t\t\tpriv->haveR30H = 0;\n\t\t\t}\n\t\t\tfprintf(stderr, \"*** read R30_HI from environment: %d\\n\", priv->valR30H);\n\t\t}\n\n\t\tpacR30Lo = getenv(\"RTL_R820_R30_LO\");\n\t\tif ( pacR30Lo ) {\n\t\t\tpriv->haveR30L = 1;\n\t\t\tpriv->valR30L = atoi(pacR30Lo);\n\t\t\tif ( priv->valR30L > 63 ) {\n\t\t\t\tfprintf(stderr, \"*** read R30_LO from environment: %d - but value should be 0 - 63 for bit [5:0]\\n\", priv->valR30L);\n\t\t\t\tpriv->haveR30L = 0;\n\t\t\t}\n\t\t\tfprintf(stderr, \"*** read R30_LO from environment: %d\\n\", priv->valR30L);\n\t\t}\n\n\t}\n#endif\n\nerr:\n\tif (rc < 0)\n\t\tfprintf(stderr, \"%s: failed=%d\\n\", __FUNCTION__, rc);\n\treturn rc;\n}\n\n#if 0\n/* Not used, for now */\nstatic int r82xx_gpio(struct r82xx_priv *priv, int enable)\n{\n\treturn r82xx_write_reg_mask(priv, 0x0f, enable ? 1 : 0, 0x01);\n}\n#endif\n"
  },
  {
    "path": "win32-qtcreator/CMakeLists.txt",
    "content": "project(rtlsdr)\ncmake_minimum_required(VERSION 2.8)\n\n# created and tested with\n# Qt 5.6.1 for Windows 32-bit (MinGW 4.9.2) from\n# https://www.qt.io/download-open-source/#section-2\n#\n# and QtCreator 4.1.0\n#\n# and LibUSB 1.0.20 from\n# https://sourceforge.net/projects/libusb/files/\n#   libusb-1.0.20.7z\n#\n\n# edit this path\nSET( LIBUSBBASE C:/src/_foreign/libusb-1.0.20 )\n\nOPTION(RTL_FULL_STATIC_BUILD \"Build rtl-tools fully static.\" ON)\n\nif(RTL_FULL_STATIC_BUILD)\n    if (WIN32)\n        if(MINGW)\n            # Special MINGW stuff here\n            # see https://cmake.org/pipermail/cmake/2012-September/051970.html\n            # see http://stackoverflow.com/questions/13768515/how-to-do-static-linking-of-libwinpthread-1-dll-in-mingw\n            set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} -static -static-libgcc\")\n            set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -static -static-libgcc -static-libstdc++\")\n            set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS \"${CMAKE_SHARED_LIBRARY_LINK_C_FLAGS} -static -static-libgcc -s\")\n            set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS \"${CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS} -static -static-libgcc -static-libstdc++ -s\")\n        endif()\n    endif()\nendif()\n\n\nadd_definitions( -DWIN32 -D_WIN32 -DNDEBUG )\n\ninclude_directories(\n    ../include\n    ${LIBUSBBASE}/include/libusb-1.0\n)\n\nSET( LIBUSB ${LIBUSBBASE}/MinGW32/static/libusb-1.0.a )\n\nSET( SOCKLIBS ws2_32 wsock32 )\n\nSET( RTLLIBFILES\n    ../include/rtl_tcp.h\n    ../include/reg_field.h\n    ../include/rtlsdr_i2c.h\n\n    ../src/convenience/convenience.c\n    ../src/convenience/convenience.h\n    ../src/convenience/wavewrite.c\n    ../src/convenience/wavewrite.h\n\n    ../src/getopt/getopt.c\n    ../src/getopt/getopt.h\n\n    ../include/rtl-sdr_export.h\n    ../include/rtl-sdr.h\n    ../src/librtlsdr.c\n\n    ../include/tuner_e4k.h\n    ../src/tuner_e4k.c\n\n    ../include/tuner_fc0012.h\n    ../src/tuner_fc0012.c\n\n    ../include/tuner_fc0013.h\n    ../src/tuner_fc0013.c\n\n    ../include/tuner_fc2580.h\n    ../src/tuner_fc2580.c\n\n    ../include/tuner_r82xx.h\n    ../src/tuner_r82xx.c\n)\n\nadd_executable( rtl_test ../src/rtl_test.c  ${RTLLIBFILES} )\ntarget_link_libraries( rtl_test ${LIBUSB} )\n\nadd_executable( rtl_fm ../src/rtl_fm.c ${RTLLIBFILES} )\ntarget_link_libraries( rtl_fm ${LIBUSB} )\n\nadd_executable( rtl_tcp ../src/rtl_tcp.c ${RTLLIBFILES} )\ntarget_link_libraries( rtl_tcp ${LIBUSB} ${SOCKLIBS} )\n\nadd_executable( rtl_udp ../src/rtl_udp.c ${RTLLIBFILES} )\ntarget_link_libraries( rtl_udp ${LIBUSB} ${SOCKLIBS} )\n\nadd_executable( rtl_sdr ../src/rtl_sdr.c  ${RTLLIBFILES} )\ntarget_link_libraries( rtl_sdr ${LIBUSB} )\n\nadd_executable( rtl_adsb ../src/rtl_adsb.c ${RTLLIBFILES} )\ntarget_link_libraries( rtl_adsb ${LIBUSB} )\n\nadd_executable( rtl_power ../src/rtl_power.c ${RTLLIBFILES} )\ntarget_link_libraries( rtl_power ${LIBUSB} )\n\nadd_executable( rtl_ir ../src/rtl_ir.c ${RTLLIBFILES} )\ntarget_link_libraries( rtl_ir ${LIBUSB} )\n\nadd_executable( rtl_eeprom ../src/rtl_eeprom.c ${RTLLIBFILES} )\ntarget_link_libraries( rtl_eeprom ${LIBUSB} )\n\nif (NOT WIN32)\n  # errors at compilation with MinGW, e.g. missing include sys/select.h\n  add_executable( rtl_rpcd ../src/rtl_rpcd.c ../src/rtlsdr_rpc_msg.c ${RTLLIBFILES} )\n  target_link_libraries( rtl_rpcd ${LIBUSB} )\nendif()\n\n"
  },
  {
    "path": "win32-qtcreator/README.txt",
    "content": "\nthere is an outdated \"How to compile new releases of librtlsdr (and tools) on Windows\" at\nhttps://www.reddit.com/r/RTLSDR/comments/uce3e/how_to_compile_new_releases_of_librtlsdr_and/\nunfortunately the link to the CMakeLists.txt is broken!\n\nso, i needed to find another solution ..\n\n\n1) aquire and install Qt 5.5.x for Windows 32-bit (MinGW 4.9.2) from\nhttps://www.qt.io/download-open-source/#section-2\n\n2) aquire and install QtCreator 4.0.x\nfrom same site as 1)\nprobably this step is not necessary and you can use the qtcreator IDE from 1)\n\n3) aquire LibUSB 1.0.20 from\nhttps://sourceforge.net/projects/libusb/files/\nlast tested: libusb-1.0.20.7z\n\nand place the file at C:/src/_foreign/libusb-1.0.20\n\nor replace LIBUSBBASE path in CMakeLists.txt\n\n4) start qtcreator and open the (modified) CMakeLists.txt\nconfigure compiler/environment and compile\n\n\nthe resulting executables have no other dependencies than libwinpthread-1.dll\nfrom the MINGW system at C:\\Qt\\Qt5.5.1\\Tools\\mingw492_32\\bin\\\n  or C:\\Qt\\Qt5.5.1\\5.5\\mingw492_32\\bin\n\n=======================================================================\n\nopening main CMakeLists.txt in root (above win32-qtcreator) with above QT 5.5/qtcreator\n\nset RTL_STATIC_BUILD = ON\nset LIBUSB_FOUND = TRUE\nset LIBUSB_INCLUDE_DIR = C:/src/_foreign/libusb-1.0.20/include/libusb-1.0\nset LIBUSB_LIBRARIES = C:/src/_foreign/libusb-1.0.20/MinGW32/static/libusb-1.0.a\nset THREADS_PTHREADS_INCLUDE_DIR = C:/Qt/Qt5.6.1/Tools/mingw492_32/i686-w64-mingw32/include\nset THREADS_PTHREADS_WIN32_LIBRARY = C:/Qt/Qt5.6.1/Tools/mingw492_32/i686-w64-mingw32/lib/libwinpthread.a\n\nthe resulting executables have no other dependencies, except the freshly built librtlsdr.dll\n"
  }
]