├── AUTHORS ├── CMakeLists.txt ├── COPYING ├── README.md ├── README.rtlfm_cmdfile ├── README_improvements.md ├── cmake ├── Modules │ ├── FindLibUSB.cmake │ └── FindThreads.cmake └── cmake_uninstall.cmake.in ├── include ├── controlThread.h ├── rtl-sdr.h ├── rtl-sdr_export.h ├── rtl_tcp.h ├── rtlsdr_i2c.h ├── tuner_e4k.h ├── tuner_fc001x.h ├── tuner_fc2580.h └── tuner_r82xx.h ├── install-blacklist.sh ├── librtlsdr.pc.in ├── protocol_rtl_tcp.txt ├── rtl-sdr.rules ├── rtlsdr-blacklist.conf └── src ├── CMakeLists.txt ├── controlThread.c ├── controlThread2.c ├── convenience ├── convenience.c ├── convenience.h ├── wavewrite.c └── wavewrite.h ├── getopt ├── getopt.c └── getopt.h ├── librtlsdr.c ├── rtl2_tcp.c ├── rtl_biast.c ├── rtl_eeprom.c ├── rtl_fm.c ├── rtl_ir.c ├── rtl_power.c ├── rtl_sdr.c ├── rtl_tcp.c ├── rtl_test.c ├── rtlsdr.rc ├── tuner_e4k.c ├── tuner_fc001x.c ├── tuner_fc2580.c ├── tuner_r82xx.c └── version.h /AUTHORS: -------------------------------------------------------------------------------- 1 | Steve Markgraf 2 | Dimitri Stolnikov 3 | Hoernchen 4 | Kyle Keen 5 | Hayati Ayguen 6 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2012-2020 Osmocom Project 2 | # 3 | # This file is part of rtl-sdr 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | 19 | ######################################################################## 20 | # Project setup 21 | ######################################################################## 22 | cmake_minimum_required(VERSION 3.0) 23 | project(rtlsdr C) 24 | 25 | # CMP0075 Include file check macros honor CMAKE_REQUIRED_LIBRARIES 26 | if(POLICY CMP0075) 27 | cmake_policy(SET CMP0075 NEW) 28 | endif() 29 | 30 | #select the release build type by default to get optimization flags 31 | if(NOT CMAKE_BUILD_TYPE) 32 | set(CMAKE_BUILD_TYPE "Release") 33 | message(STATUS "Build type not specified: defaulting to release.") 34 | endif(NOT CMAKE_BUILD_TYPE) 35 | set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "") 36 | 37 | list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/Modules) 38 | 39 | if(NOT LIB_INSTALL_DIR) 40 | set(LIB_INSTALL_DIR lib) 41 | endif() 42 | 43 | OPTION(LINK_RTLTOOLS_AGAINST_STATIC_LIB "Link rtl-tools statically against librtlsdr" OFF) 44 | 45 | ######################################################################## 46 | # Compiler specific setup 47 | ######################################################################## 48 | if(CMAKE_COMPILER_IS_GNUCC) 49 | add_compile_options(-Wall) 50 | add_compile_options(-Wextra) 51 | add_compile_options(-Wsign-compare) 52 | add_compile_options(-Wdeclaration-after-statement) 53 | #http://gcc.gnu.org/wiki/Visibility 54 | add_compile_options(-fvisibility=hidden) 55 | elseif(MSVC14) 56 | #pthread-w32 issue, timespec is now part of time.h 57 | ADD_DEFINITIONS(-D_TIMESPEC_DEFINED) 58 | endif() 59 | 60 | if(MINGW) 61 | # Fix printf %zu 62 | ADD_DEFINITIONS(-D__USE_MINGW_ANSI_STDIO) 63 | endif() 64 | #ADD_DEFINITIONS(-DDEBUG) 65 | 66 | ######################################################################## 67 | # Find build dependencies 68 | ######################################################################## 69 | if(NOT WIN32) 70 | find_package(PkgConfig) 71 | find_package(LibUSB) 72 | if(NOT LIBUSB_FOUND) 73 | message(FATAL_ERROR "LibUSB 1.0 required to compile rtl-sdr") 74 | endif() 75 | endif() 76 | 77 | if(WIN32 AND NOT MINGW) 78 | set(THREADS_USE_PTHREADS_WIN32 true) 79 | endif() 80 | find_package(Threads REQUIRED) 81 | 82 | if(NOT THREADS_FOUND) 83 | message(FATAL_ERROR "pthreads(-win32) required to compile rtl-sdr") 84 | endif() 85 | 86 | ######################################################################## 87 | # Setup the include and linker paths 88 | ######################################################################## 89 | include_directories( 90 | ${PROJECT_SOURCE_DIR}/include 91 | if(NOT WIN32) 92 | ${LIBUSB_INCLUDE_DIR} 93 | endif() 94 | ${THREADS_PTHREADS_INCLUDE_DIR} 95 | ) 96 | 97 | ######################################################################## 98 | # Create uninstall target 99 | ######################################################################## 100 | configure_file( 101 | ${PROJECT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in 102 | ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake 103 | @ONLY) 104 | 105 | add_custom_target(uninstall 106 | ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake 107 | ) 108 | 109 | ######################################################################## 110 | # Install udev rules 111 | ######################################################################## 112 | option(INSTALL_UDEV_RULES "Install udev rules for RTL-SDR" OFF) 113 | if (INSTALL_UDEV_RULES) 114 | install ( 115 | FILES rtl-sdr.rules 116 | DESTINATION "/etc/udev/rules.d" 117 | COMPONENT "udev" 118 | ) 119 | else (INSTALL_UDEV_RULES) 120 | message (STATUS "Udev rules not being installed, install them with -DINSTALL_UDEV_RULES=ON") 121 | endif (INSTALL_UDEV_RULES) 122 | 123 | option(DETACH_KERNEL_DRIVER "Detach kernel driver if loaded" OFF) 124 | if (DETACH_KERNEL_DRIVER) 125 | message (STATUS "Building with kernel driver detaching enabled") 126 | add_definitions(-DDETACH_KERNEL_DRIVER=1) 127 | else (DETACH_KERNEL_DRIVER) 128 | message (STATUS "Building with kernel driver detaching disabled, use -DDETACH_KERNEL_DRIVER=ON to enable") 129 | endif (DETACH_KERNEL_DRIVER) 130 | 131 | option(ENABLE_ZEROCOPY "Enable usbfs zero-copy support" OFF) 132 | if (ENABLE_ZEROCOPY) 133 | message (STATUS "Building with usbfs zero-copy support enabled") 134 | add_definitions(-DENABLE_ZEROCOPY=1) 135 | else (ENABLE_ZEROCOPY) 136 | message (STATUS "Building with usbfs zero-copy support disabled, use -DENABLE_ZEROCOPY=ON to enable") 137 | endif (ENABLE_ZEROCOPY) 138 | 139 | ######################################################################## 140 | # Install public header files 141 | ######################################################################## 142 | install(FILES 143 | include/rtl-sdr.h 144 | include/rtl-sdr_export.h 145 | DESTINATION include 146 | ) 147 | ######################################################################## 148 | # Add subdirectories 149 | ######################################################################## 150 | add_subdirectory(src) 151 | 152 | ######################################################################## 153 | # Create Pkg Config File 154 | ######################################################################## 155 | FOREACH(inc ${LIBUSB_INCLUDE_DIR}) 156 | LIST(APPEND RTLSDR_PC_CFLAGS "-I${inc}") 157 | ENDFOREACH(inc) 158 | 159 | FOREACH(lib ${LIBUSB_LIBRARY_DIRS}) 160 | LIST(APPEND RTLSDR_PC_LIBS "-L${lib}") 161 | ENDFOREACH(lib) 162 | 163 | # use space-separation format for the pc file 164 | STRING(REPLACE ";" " " RTLSDR_PC_CFLAGS "${RTLSDR_PC_CFLAGS}") 165 | STRING(REPLACE ";" " " RTLSDR_PC_LIBS "${RTLSDR_PC_LIBS}") 166 | 167 | # unset these vars to avoid hard-coded paths to cross environment 168 | IF(CMAKE_CROSSCOMPILING) 169 | UNSET(RTLSDR_PC_CFLAGS) 170 | UNSET(RTLSDR_PC_LIBS) 171 | ENDIF(CMAKE_CROSSCOMPILING) 172 | 173 | set(prefix ${CMAKE_INSTALL_PREFIX}) 174 | set(exec_prefix \${prefix}) 175 | set(libdir \${exec_prefix}/${LIB_INSTALL_DIR}) 176 | set(includedir \${prefix}/include) 177 | 178 | CONFIGURE_FILE( 179 | ${CMAKE_CURRENT_SOURCE_DIR}/librtlsdr.pc.in 180 | ${CMAKE_CURRENT_BINARY_DIR}/librtlsdr.pc 181 | @ONLY) 182 | 183 | INSTALL( 184 | FILES ${CMAKE_CURRENT_BINARY_DIR}/librtlsdr.pc 185 | DESTINATION ${LIB_INSTALL_DIR}/pkgconfig 186 | ) 187 | 188 | ######################################################################## 189 | # Print Summary 190 | ######################################################################## 191 | MESSAGE(STATUS "Using install prefix: ${CMAKE_INSTALL_PREFIX}") 192 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | [![GPLv2 License](http://img.shields.io/badge/license-GPLv2-brightgreen.svg)](https://tldrlegal.com/license/gnu-general-public-license-v2) 3 | 4 | # Description 5 | 6 | rtl-sdr turns your Realtek RTL2832 based DVB dongle into a SDR receiver 7 | 8 | 9 | # New enhancements and features in this version 10 | 11 | Many different developments have been taken in this release. For an overview, see [improvements](README_improvements.md) 12 | 13 | # Build / Install (on debian/ubuntu) 14 | 15 | ## prerequisites 16 | development tools have to be installed: 17 | ``` 18 | sudo apt-get install build-essential cmake git 19 | ``` 20 | 21 | install the libusb-1.0 development package:: 22 | ``` 23 | sudo apt-get install libusb-dev libusb-1.0-0-dev 24 | ``` 25 | 26 | ## retrieve the sources - right branch 27 | 28 | ``` 29 | git clone https://github.com/old-dab/rtlsdr.git 30 | cd rtlsdr 31 | ``` 32 | 33 | ## build 34 | run cmake and start compilation. cmake will accept some options, e.g. 35 | * `-DINSTALL_UDEV_RULES=ON`, default is `OFF` 36 | * `-DDETACH_KERNEL_DRIVER=ON`, default is `OFF` 37 | * `-DENABLE_ZEROCOPY=ON`, default is `OFF` 38 | 39 | all cmake options are optional 40 | 41 | ``` 42 | mkdir build && cd build 43 | cmake ../ -DINSTALL_UDEV_RULES=ON 44 | make 45 | ``` 46 | 47 | ## install 48 | setup into prefix, usually will require `sudo`: 49 | ``` 50 | sudo make install 51 | sudo ldconfig 52 | ``` 53 | 54 | # Development builds / binaries 55 | 56 | [GitHub Releases](https://github.com/old-dab/rtlsdr/releases) is used for development builds for Windows 32/64. 57 | 58 | # For more information see: 59 | 60 | http://superkuh.com/rtlsdr.html 61 | 62 | https://osmocom.org/projects/rtl-sdr/wiki/Rtl-sdr 63 | 64 | 65 | # Setup for SDR only use - without DVB compatibility: 66 | 67 | - for permanent blacklisting you might check/call following from the clone git directory 68 | ```./install-blacklist.sh``` 69 | -------------------------------------------------------------------------------- /README.rtlfm_cmdfile: -------------------------------------------------------------------------------- 1 | 2 | rtl_fm now has option '-C' for a command file, from which a list of frequencies are read. 3 | So it's similar to using a frequency range, as with "-f 118M:137M:25k" 4 | The difference is, that you can parametrize one frequency per line together with 5 | - the tuner gain 6 | - condition for triggering 7 | - measurement duration 8 | and a command to execute. 9 | Lines starting with '#' are skipped / interpreted as comments. 10 | Parameters a seperated by comma. 11 | 12 | Here's an example: 13 | --- 14 | # freq in Hz or special keyword, gain in dB, trig_crit (in/out/lt/gt), trig_level, trig_tolerance, #meas, #blocks, trigger_command 15 | # windows: rtl_fm -f 105.2m -E rdc -w 350k -s 200k -m 2.2m -B 200000 -C cmdfile.csv -n -v 16 | # rtl_fm -f 105.2m -E rdc -w 350k -s 200k -m 2.2m -W 4 -B 10000 -C cmdfile.csv -n -v 17 | # linux: ./rtl_fm -f 105.2m -E rdc -w 350k -s 200k -m 2.2m -B 200000 -C cmdfile.csv -n -v 18 | # 19 | # windows command examples: 20 | # cmd.exe, /C echo hello world 21 | # cmd.exe, /C start notepad 22 | # calc.exe 23 | # 24 | # linux examples: 25 | # ssmtp 26 | # sendxmpp 27 | ## for piping some message to ssmtp or sendxmpp you'll need to write small scripts 28 | 29 | # 'adcmax' keyword in first column activates measurement of max adc value at capture rate to determine optimum gain and avoid oversteering 30 | # 'adcrms' keyword activates rms calculation at capture rate. for usual it's similar to adcmax. there are differences in case of oversteering 31 | # activate verbose output (option '-v') to get the output. The maximum possible sample value is 128. 32 | # You should have approx. 6 dB headroom to allow measuring stronger signals, that means measured baseline values should be below 64. 33 | # 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. 34 | adcmax, 35 | adcrms, 36 | 100.7m, 30, in, 0, 1, 10, 100, 37 | 33.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 } 38 | # now check for optimal gain in some steps, which should be done per frequency!: 39 | 100.7m, 0, gt, 400, 1, 1, 100, 40 | 100.7m, 3, gt, 400, 1, 1, 100, 41 | 100.7m, 6, gt, 400, 1, 1, 100, 42 | 100.7m, 12, gt, 400, 1, 1, 100, 43 | 100.7m, 18, gt, 400, 1, 1, 100, 44 | 45 | --- 46 | 47 | * first frequency is 100.7 MHz, tuned with ~ 30 dB tuner gain; 48 | condition is 'in' { 0 +/- 1 } dB, 49 | with 10 measurements, averaging the rms level in dB. 50 | Each single measurement is processed after decimation of block/buffer-size many samples (see option -W). 51 | The resulting number of decimated samples might get too small to allow a reliable measurement. 52 | This number also depends on the capture rate: ensure minimum capture rate with option '-m'. This is also important for reducing aliases. 53 | Check the output 'block length after decimation is ... samples'! 54 | If condition for measured level is true, then a command can be triggered, which is executed in background. 55 | Then, a next trigger for this frequency is blocked for 100 measurements. 56 | There is nothing triggered for 100.7 MHz. 57 | 58 | * 2nd frequency is 33.0 MHz, tuned with ~ 20 dB tuner gain; 59 | condition is 'out' { 60 +/- 3 } dB, 60 | with 10 measurements. 61 | That means, the trigger is activated when averaged level is below 57 dB or above 63 dB. 62 | Next trigger for this frequency is blocked for 400 measurements. 63 | Triggered command is the shell script '/home/odroid/test/simple.sh', 64 | with the arguments 'frq !freq! gain !gain! measured !mlevel! tenth dB !crit! { !reflevel! +/- !reftol! tenth dB }'. 65 | You can use following keywords in the arguments, which need to be free standing!: 66 | - !freq! 67 | current frequency in Hz 68 | 69 | - !gain! 70 | current tuner gain in tenth dB to allow easier evaluation from scripts. 71 | 72 | - !mlevel! 73 | average measured level in tenth dB 74 | 75 | - !crit! 76 | one of "in", "out", "<" or ">" for the tested condition 77 | 78 | - !reflevel! 79 | condition's reference level in tenth dB 80 | 81 | - !reftol! 82 | condition's reference tolerance in tenth dB 83 | 84 | 85 | Application might be monitoring of some stations 86 | and triggering a notification, e.g. via ssmtp or sendxmpp, 87 | when a stations power level is below it's expected value. 88 | 89 | Another application might be triggering a recording with a second RTL dongle. 90 | 91 | 92 | Send comments, suggestions or reports to 93 | Hayati Ayguen 94 | 95 | -------------------------------------------------------------------------------- /README_improvements.md: -------------------------------------------------------------------------------- 1 | # Improvements, compared to the Osmocom version on git://git.osmocom.org/rtl-sdr.git 2 | 3 | # Introduction 4 | After buying my first USB stick in 2020 with tuner FC0012, I found that DAB (Digital Audio Broadcast) and FM reception was much better with software that used the original Realtek driver than with software that used the Osmocom driver. There were also a lot of dropouts under Windows with DAB. It quickly became apparent that the gain setting of the tuner in the Osmocom software was inadequate. I wanted to improve it. I started with Hayati's version, which had some advantages over Osmocom: https://github.com/hayguen/librtlsdr/tree/development . The source code of the Linux kernel has revealed many insights. Bernhard (DB9PP) was very helpful in investigating the tuners and he carried out most of the measurements. When it comes to tools, I focused on rtl_tcp.exe, which has been optimized specifically for QIRX but is still backwards compatible with the Osmocom version. 5 | The main improvements are: 6 | * Much less data loss under Windows by not using LibUSB 7 | * AGC for all tuners, control range 100 dB 8 | * Additional filter bandwidths 9 | * Second data channel reporting gain, overload and register contents 10 | * More precise frequency setting and correction of the quartz frequency 11 | 12 | # LibUSB 13 | The Osmocom version uses LibUSB for all operating systems. This works very well on Linux. However, blocks of data are lost on slow PCs under Windows. This means that uninterrupted operation of DAB, for example, is not possible. The reason is that the LibUSB uses the WinUSB under Windows. To achieve maximum data throughput, the "RAW_IO" parameter should be set in WinUSB. Only then will the winusb.sys driver be able to buffer more than one USB bulk transfer. However, this is not yet possible with LibUSB. To solve the problem, one can either use a patched version of LibUSB that sets "RAW_IO" or omit the LibUSB altogether. I decided to leave it out. In librtlsdr.c, the WinUSB functions are called directly under Windows. 14 | 15 | # fprintf 16 | In librtlsdr.c, texts are output with fprintf to "stderr", whereas in rtl_tcp.c they are usually output with printf to "stdout". As a result, the different texts can overwrite each other under Windows and occasionally a jumble of characters appears. Therefore, I output all text messages uniformly to stderr. 17 | 18 | # Gain and AGC 19 | For all tuners, the LNA gain is controlled by an internal AGC. 20 | The IF amplifier can be set either by an AGC or by software. The RTL2832 enables AGC for IF amplification in the tuner. This is not programmed in the Osmocom version. 21 | The R820T and R828D tuners require an analog voltage on an AGC line. This is achieved using pulse width modulation followed by an RC low pass. Unfortunately, the capacitor is missing in the "RTL-SDR.COM V4", so the IF-AGC does not work. 22 | The tuners FC0012/13 and E4000 have a digital AGC. This requires 2 AGC lines. 00 and 11 means "Hold gain", 01 means "Increase gain", 10 means "Decrease gain". The FC2580 has an internal AGC. 23 | The realization of the mixer gain is solved in different ways depending on the tuner. Sometimes there is its own AGC, sometimes it is coupled to the AGC of the LNA or the IF. 24 | The total gain of all tuners can be read in steps of 1/10 dB. The accuracy is approximately ± 3 dB in the frequency range 50 MHz to 1 GHz , and ± 5 dB from 1 GHz up. The AGC achieves a control range of around 100 dB for all tuners. 25 | A disadvantage of the IF-AGC is that the overall gain of the tuner can no longer be determined accurately. The reason for the tuners R820T and R828D is that the resistor in the RC low pass varies depending on the dongle manufacturer. This has an influence on the control voltage. The software is adapted to the "RTL-SDR.COM V3" for the R820T and to the "Astrometa DVB-T/DVB-T2" for the R828D. The tuners FC0012/13 and E4000 have two outputs (I and Q), so that the ADC has twice the voltage compared to the R820T/R828D. To ensure that nothing is overdriven, the digital AGC of the RTL2832 must be switched on. Unfortunately, the control status of the digital AGC cannot be read out. 26 | That's why there is also a software AGC for the IF. However, in the event of adjacent channel interference, reception with hardware AGC is better. 27 | Summary of all advantages and disadvantages: 28 | 29 | HW-AGC: 30 | 31 | + best reception (except for ADS-B) 32 | + fastest response to level changes 33 | + easy operation 34 | - level display unusable 35 | 36 | manual gain setting: 37 | 38 | + accurate level display 39 | - worse reception in the event of adjacent channel interference 40 | - additional setting required 41 | 42 | SW-AGC: 43 | 44 | + accurate level display 45 | + easy operation 46 | - worst reception in the event of adjacent channel interference 47 | + delayed response to level changes 48 | 49 | # FIR filter 50 | There are three FIR filters in the RTL2832. The first works with a clock frequency of 28.8 MHz and is freely programmable. The second FIR filter operates at four times the sample rate of the output. The bandwidth is fixed to a value that matches the output sampling rate. A sampling rate of 2048 kHz results in a bandwidth of approximately 1.9 MHz. A third FIR filter, which works at the output sampling rate, can also be switched on. It is also freely programmable. 51 | In the Osmocom software, the first FIR filter is set to a bandwidth of 2.4 MHz. The third FIR filter is switched off. 52 | In order to achieve better adjacent channel attenuation, the first FIR filter can be set in my software to a bandwidth of 1.5 MHz and the third FIR filter to a bandwidth of 1.5 MHz or 300 kHz. The filters are set automatically along with the tuner bandwidth. 53 | 54 | # Data transfer to and from the tuners 55 | The tuners cannot be accessed directly via USB, but only via the RTL2832. The RTL2832 offers two options that differ in the USB protocol. Osmocom has opted for the more complex protocol with index register 0x600. I use the simpler protocol with index register 0x300. Less data is transferred via USB. Reading a tuner register can be done with a single USB transfer. The other protocol requires two USB transfers. 56 | 57 | # More precise frequency adjustment 58 | The tuner frequency can only be adjusted relatively roughly. With the R820T, for example, the smallest step size at 200 MHz is 27 Hz, and at 800 MHz it is even more than 100 Hz. In the RTL2832 this can be compensated by shifting the IF. This improves the setting accuracy to around 4 Hz. This also works when the IF is zero, such as on the E4000. 59 | 60 | # Additional features of the Library API 61 | * int rtlsdr_set_freq_correction_ppb(rtlsdr_dev_t *dev, int ppb): Sets the frequency correction for the tuner crystal in ppb (parts per billion). Thus, a value of 12345 corresponds to 12.345 ppm. 62 | * int rtlsdr_get_freq_correction_ppb(): Returns the frequency correction for the tuner crystal in ppb. 63 | * int rtlsdr_set_dithering(rtlsdr_dev_t *dev, int dither): Switches dithering on or off for the R820T/R828D tuners. 0 = off, 1 = on. 64 | * void rtlsdr_cal_imr(const int cal_imr): Enables calibration for the R820T/R828D tuners to improve the rejection of the unwanted sideband. The command sets a global variable in the library. This must happen before a device is opened. 65 | * int rtlsdr_set_tuner_gain_index(rtlsdr_dev_t *dev, unsigned int index): Sets the desired IF amplifier stage directly, without going through rtlsdr_set_tuner_gain. 66 | * int rtlsdr_set_tuner_gain_mode(rtlsdr_dev_t *dev, int mode): The parameter 'mode' is expanded. 0 = hardware AGC, 1 = manual gain mode, 2 = software AGC. 67 | The following functions were adopted by or were created together with hayguen/librtlsdr: 68 | * int rtlsdr_ir_query(rtlsdr_dev_t *dev, uint8_t *buf, size_t buf_len): Reads remote control data from the infrared sensor. buf = buffer for infrared data, buf_len = length of the data buffer. Returns 0 if no signal, >0 for number of bytes received, <0 for error. 69 | * int rtlsdr_set_opt_string(rtlsdr_dev_t *dev, const char *opts, int verbose): Sets multiple command line options in a single string. 70 | * const char * rtlsdr_get_opt_help(int longInfo): Lists the possibilities of "rtlsdr_set_opt_string". LongInfo = 0: in short version, LongInfo = 1: detailed. 71 | * int rtlsdr_set_and_get_tuner_bandwidth(rtlsdr_dev_t *dev, uint32_t bw, uint32_t *applied_bw, int apply_bw ): Sets and and gets the tuner's bandwidth. 72 | * int rtlsdr_set_tuner_sideband(rtlsdr_dev_t *dev, int sideband): Switches to the desired sideband in the tuner R820T/R828D. 0 = lower sideband, 1 = upper sideband. 73 | * int rtlsdr_get_tuner_i2c_register(rtlsdr_dev_t *dev, unsigned char *data, int *len, int *strength): Allows reading all tuner registers. data = data buffer, len = provides number of data bytes, strength = provides absolute gain of the tuner in 1/10 dB. 74 | * int rtlsdr_set_tuner_i2c_register(rtlsdr_dev_t *dev, unsigned i2c_register, unsigned mask, unsigned data): Sets a register in the tuner. i2c_register = number of the register, mask = bits to be overwritten in the register, data = data byte. 75 | 76 | # Tuner 77 | ## R820T, R828D 78 | * At Osmocom the IF amplifier is permanently set. LNA and mixer are adjustable, either with AGC or manually. In this way only about half of the possible dynamic range was available. In my version, the LNA and mixer always run with AGC, the IF amplifier can be set either with AGC or manually. 79 | * Appropriate bandwidths for DAB and ADS-B were added and the center frequencies of all filters were corrected. "Filter extension under weak signal" is deactivated for a stable filter characteristic. 80 | * The tuner has a register to optimize the rejection of the image frequency. With optimal settings, the suppression of the image frequency can be increased from around 50 dB to 60 dB. Because the optimal setting depends on the mixer gain, this must be measured for each level of mixer gain. For this purpose, the tuner contains its own calibration generator with which internal measurements are possible. A single call to rtl_tcp with the "-k" parameter takes about a second and saves the results in EEPROM. This means that the calibration does not have to be repeated every time the program starts. 81 | * If that's still not sufficient, the sidebands can additionally be switched. 82 | * The frequency setting had a small systematic error. The dithering offset was not taken into account. The exact VCO frequency is: 83 | 2 * pll_ref * (nint + (offset + sdm) / 65536). 84 | offset = 0 if sdm = 0, offset = 0.25 if dithering is on, offset = 0.5 if dithering is off. 85 | * Since the gain of the LNA is frequency dependent, it was measured for many frequencies. The measurements are contained in a table in the program code. The gain at other frequencies is determined by interpolation. 86 | * To improve the 3rd harmonic suppression, register settings in the frequency range 100 to 588 MHz were changed (bits 0 and 1 in register 26). 87 | * A description of all registers was added to the source code "tuner_r82xx.c", as far as known from the data sheets. 88 | 89 | ## FC0012 and FC0013 90 | * The FC0012/13 tuners were hardly usable in the Osmocom version because the IF amplifier was not adjustable and the gain was random. The received signal was either overloaded or too weak. Only the LNA could be adjusted in coarse steps. Now the IF amplifier together with the mixer can be set manually or controlled by the AGC. The LNA has its own AGC output which is connected to a level detector in the RTL2832. This makes it possible to automatically control the LNA gain. 91 | * The smallest adjustable bandwidth could be reduced from around 6.6 MHz to 5.0 MHz. There is a register for fine-tuning the bandwidth. To further improve the selection, the FIR filter in the RTL2832 can be switched to a smaller bandwidth. 92 | 93 | ## E4000 94 | * An AGC can be switched on in the IF amplifier. The LNA is governed by an internal AGC. The mixer does not have its own AGC. It is either set manually together with the IF amplifier or controlled by the LNA-AGC. 95 | * In the Osmocom version high gains in the IF amplifier could not be used because the automatic DC offset compensation was not switched on. 96 | * Since the gain of the LNA is frequency dependent, it was measured for many frequencies. The measurements are contained in a table in the program code. The gain at other frequencies is determined by interpolation. There were significant deviations from the data sheet for the LNA, mixer and IF amplifier. 97 | * In the Osmocom version the tuner bandwidth was incorrectly interpreted. The information in the data sheet refers to the bandwidth in the baseband. The RF bandwidth is twice as large. To improve selection, the FIR filter in the RTL2832 can be switched to a smaller bandwidth. 98 | * The tuner outputs I and Q differ significantly in their amplitudes. This creates image frequencies and a worse SNR for DAB. Some programs like "SDRSharp" can compensate for this (check "Correct IQ"). For programs that lack this feature, you can set it in rtl_tcp with the "-c" option. 99 | 100 | ## FC2580 101 | * Because you couldn't adjust the IF gain of this tuner, it couldn't be used meaningfully with the Osmocom software. Now the IF amplifier can be adjusted manually or controlled by an internal AGC. LNA and mixer are adjusted by internal AGCs. 102 | * The frequency could only be set accurately to 1 kHz. Now the frequency can be adjusted to 1 Hz at 200 MHz. 103 | * The smallest adjustable bandwidth was 5.5 MHz. Any bandwidth between 1.1 and 2.1 MHz can now be set. 104 | 105 | # rtl_tcp.exe 106 | In "rtl_tcp" a second TCP/IP connection can be activated, one port number higher than the normal connection. Controlled by a timer, this second connection sends the contents of the tuner registers, an overload message and the overall gain of the tuner in 1/10 dB to the PC every 500 ms. The periodic query of the tuner registers is also used to optimize the image frequency attenuation on the R820T and R828D and to set the LNA gain on the FC0012/13. 107 | Additional command line parameters not included in the Osmocom version: 108 | 109 | -c (correct I/Q ratio) 110 | -k (calibrate image rejection for R820T/R828D and store the results in EEPROM) 111 | -r (response port) 112 | -u (upper sideband for R820T/R828D) 113 | Additional TCP/IP features not included in the Osmocom version: 114 | SET_TUNER_BANDWIDTH, SET_I2C_TUNER_REGISTER, SET_SIDEBAND, REPORT_I2C_REGS, SET_DITHERING, SET_FREQUENCY_CORRECTION_PPB. 115 | 116 | ## rtl2_tcp.exe 117 | rtl2_tcp is a special version of rtl_tcp for QIRX with a different protocol. This makes it possible to select the USB device in a menu within QIRX when operating several sticks at the same time. 118 | 119 | -------------------------------------------------------------------------------- /cmake/Modules/FindLibUSB.cmake: -------------------------------------------------------------------------------- 1 | if(NOT LIBUSB_FOUND) 2 | pkg_check_modules (LIBUSB_PKG libusb-1.0) 3 | find_path(LIBUSB_INCLUDE_DIR NAMES libusb.h 4 | PATHS 5 | ${LIBUSB_PKG_INCLUDE_DIRS} 6 | /usr/include/libusb-1.0 7 | /usr/include 8 | /usr/local/include 9 | ) 10 | 11 | #standard library name for libusb-1.0 12 | set(libusb1_library_names usb-1.0 libusb-1.0) 13 | 14 | #libusb-1.0 compatible library on freebsd 15 | if((CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") OR (CMAKE_SYSTEM_NAME STREQUAL "kFreeBSD")) 16 | list(APPEND libusb1_library_names usb) 17 | endif() 18 | 19 | find_library(LIBUSB_LIBRARIES 20 | NAMES ${libusb1_library_names} 21 | PATHS 22 | ${LIBUSB_PKG_LIBRARY_DIRS} 23 | /usr/lib 24 | /usr/local/lib 25 | ) 26 | 27 | include(CheckFunctionExists) 28 | if(LIBUSB_INCLUDE_DIRS) 29 | set(CMAKE_REQUIRED_INCLUDES ${LIBUSB_INCLUDE_DIRS}) 30 | endif() 31 | if(LIBUSB_LIBRARIES) 32 | set(CMAKE_REQUIRED_LIBRARIES ${LIBUSB_LIBRARIES}) 33 | endif() 34 | 35 | CHECK_FUNCTION_EXISTS("libusb_handle_events_timeout_completed" HAVE_LIBUSB_HANDLE_EVENTS_TIMEOUT_COMPLETED) 36 | if(HAVE_LIBUSB_HANDLE_EVENTS_TIMEOUT_COMPLETED) 37 | add_definitions(-DHAVE_LIBUSB_HANDLE_EVENTS_TIMEOUT_COMPLETED=1) 38 | endif(HAVE_LIBUSB_HANDLE_EVENTS_TIMEOUT_COMPLETED) 39 | 40 | CHECK_FUNCTION_EXISTS("libusb_error_name" HAVE_LIBUSB_ERROR_NAME) 41 | if(HAVE_LIBUSB_ERROR_NAME) 42 | add_definitions(-DHAVE_LIBUSB_ERROR_NAME=1) 43 | endif(HAVE_LIBUSB_ERROR_NAME) 44 | 45 | if(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES) 46 | set(LIBUSB_FOUND TRUE CACHE INTERNAL "libusb-1.0 found") 47 | message(STATUS "Found libusb-1.0: ${LIBUSB_INCLUDE_DIR}, ${LIBUSB_LIBRARIES}") 48 | else(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES) 49 | set(LIBUSB_FOUND FALSE CACHE INTERNAL "libusb-1.0 found") 50 | message(STATUS "libusb-1.0 not found.") 51 | endif(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES) 52 | 53 | mark_as_advanced(LIBUSB_INCLUDE_DIR LIBUSB_LIBRARIES) 54 | 55 | endif(NOT LIBUSB_FOUND) 56 | -------------------------------------------------------------------------------- /cmake/Modules/FindThreads.cmake: -------------------------------------------------------------------------------- 1 | # Updated FindThreads.cmake that supports pthread-win32 2 | # Downloaded from http://www.vtk.org/Bug/bug_view_advanced_page.php?bug_id=6399 3 | 4 | # - This module determines the thread library of the system. 5 | # 6 | # The following variables are set 7 | # CMAKE_THREAD_LIBS_INIT - the thread library 8 | # CMAKE_USE_SPROC_INIT - are we using sproc? 9 | # CMAKE_USE_WIN32_THREADS_INIT - using WIN32 threads? 10 | # CMAKE_USE_PTHREADS_INIT - are we using pthreads 11 | # CMAKE_HP_PTHREADS_INIT - are we using hp pthreads 12 | # 13 | # If use of pthreads-win32 is desired, the following variables 14 | # can be set. 15 | # 16 | # THREADS_USE_PTHREADS_WIN32 - 17 | # Setting this to true searches for the pthreads-win32 18 | # port (since CMake 2.8.0) 19 | # 20 | # THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME 21 | # C = no exceptions (default) 22 | # (NOTE: This is the default scheme on most POSIX thread 23 | # implementations and what you should probably be using) 24 | # CE = C++ Exception Handling 25 | # SE = Structure Exception Handling (MSVC only) 26 | # (NOTE: Changing this option from the default may affect 27 | # the portability of your application. See pthreads-win32 28 | # documentation for more details.) 29 | # 30 | #====================================================== 31 | # Example usage where threading library 32 | # is provided by the system: 33 | # 34 | # find_package(Threads REQUIRED) 35 | # add_executable(foo foo.cc) 36 | # target_link_libraries(foo ${CMAKE_THREAD_LIBS_INIT}) 37 | # 38 | # Example usage if pthreads-win32 is desired on Windows 39 | # or a system provided thread library: 40 | # 41 | # set(THREADS_USE_PTHREADS_WIN32 true) 42 | # find_package(Threads REQUIRED) 43 | # include_directories(${THREADS_PTHREADS_INCLUDE_DIR}) 44 | # 45 | # add_executable(foo foo.cc) 46 | # target_link_libraries(foo ${CMAKE_THREAD_LIBS_INIT}) 47 | # 48 | 49 | INCLUDE (CheckIncludeFiles) 50 | INCLUDE (CheckLibraryExists) 51 | SET(Threads_FOUND FALSE) 52 | 53 | IF(WIN32 AND NOT CYGWIN AND THREADS_USE_PTHREADS_WIN32) 54 | SET(_Threads_ptwin32 true) 55 | ENDIF() 56 | 57 | # Do we have sproc? 58 | IF(CMAKE_SYSTEM MATCHES IRIX) 59 | CHECK_INCLUDE_FILES("sys/types.h;sys/prctl.h" CMAKE_HAVE_SPROC_H) 60 | ENDIF() 61 | 62 | IF(CMAKE_HAVE_SPROC_H) 63 | # We have sproc 64 | SET(CMAKE_USE_SPROC_INIT 1) 65 | 66 | ELSEIF(_Threads_ptwin32) 67 | 68 | IF(NOT DEFINED THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME) 69 | # Assign the default scheme 70 | SET(THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME "C") 71 | ELSE() 72 | # Validate the scheme specified by the user 73 | IF(NOT THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME STREQUAL "C" AND 74 | NOT THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME STREQUAL "CE" AND 75 | NOT THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME STREQUAL "SE") 76 | MESSAGE(FATAL_ERROR "See documentation for FindPthreads.cmake, only C, CE, and SE modes are allowed") 77 | ENDIF() 78 | IF(NOT MSVC AND THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME STREQUAL "SE") 79 | MESSAGE(FATAL_ERROR "Structured Exception Handling is only allowed for MSVC") 80 | ENDIF(NOT MSVC AND THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME STREQUAL "SE") 81 | ENDIF() 82 | 83 | FIND_PATH(THREADS_PTHREADS_INCLUDE_DIR pthread.h) 84 | 85 | # Determine the library filename 86 | IF(MSVC) 87 | SET(_Threads_pthreads_libname 88 | pthreadV${THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME}2) 89 | ELSEIF(MINGW) 90 | SET(_Threads_pthreads_libname 91 | pthreadG${THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME}2) 92 | ELSE() 93 | MESSAGE(FATAL_ERROR "This should never happen") 94 | ENDIF() 95 | 96 | # Use the include path to help find the library if possible 97 | SET(_Threads_lib_paths "") 98 | IF(THREADS_PTHREADS_INCLUDE_DIR) 99 | GET_FILENAME_COMPONENT(_Threads_root_dir 100 | ${THREADS_PTHREADS_INCLUDE_DIR} PATH) 101 | SET(_Threads_lib_paths ${_Threads_root_dir}/lib) 102 | ENDIF() 103 | FIND_LIBRARY(THREADS_PTHREADS_WIN32_LIBRARY 104 | NAMES ${_Threads_pthreads_libname} 105 | PATHS ${_Threads_lib_paths} 106 | DOC "The Portable Threads Library for Win32" 107 | NO_SYSTEM_PATH 108 | ) 109 | 110 | IF(THREADS_PTHREADS_INCLUDE_DIR AND THREADS_PTHREADS_WIN32_LIBRARY) 111 | MARK_AS_ADVANCED(THREADS_PTHREADS_INCLUDE_DIR) 112 | SET(CMAKE_THREAD_LIBS_INIT ${THREADS_PTHREADS_WIN32_LIBRARY}) 113 | SET(CMAKE_HAVE_THREADS_LIBRARY 1) 114 | SET(Threads_FOUND TRUE) 115 | ENDIF() 116 | 117 | MARK_AS_ADVANCED(THREADS_PTHREADS_WIN32_LIBRARY) 118 | 119 | ELSE() 120 | # Do we have pthreads? 121 | CHECK_INCLUDE_FILES("pthread.h" CMAKE_HAVE_PTHREAD_H) 122 | IF(CMAKE_HAVE_PTHREAD_H) 123 | 124 | # 125 | # We have pthread.h 126 | # Let's check for the library now. 127 | # 128 | SET(CMAKE_HAVE_THREADS_LIBRARY) 129 | IF(NOT THREADS_HAVE_PTHREAD_ARG) 130 | 131 | # Do we have -lpthreads 132 | CHECK_LIBRARY_EXISTS(pthreads pthread_create "" CMAKE_HAVE_PTHREADS_CREATE) 133 | IF(CMAKE_HAVE_PTHREADS_CREATE) 134 | SET(CMAKE_THREAD_LIBS_INIT "-lpthreads") 135 | SET(CMAKE_HAVE_THREADS_LIBRARY 1) 136 | SET(Threads_FOUND TRUE) 137 | ENDIF() 138 | 139 | # Ok, how about -lpthread 140 | CHECK_LIBRARY_EXISTS(pthread pthread_create "" CMAKE_HAVE_PTHREAD_CREATE) 141 | IF(CMAKE_HAVE_PTHREAD_CREATE) 142 | SET(CMAKE_THREAD_LIBS_INIT "-lpthread") 143 | SET(Threads_FOUND TRUE) 144 | SET(CMAKE_HAVE_THREADS_LIBRARY 1) 145 | ENDIF() 146 | 147 | IF(CMAKE_SYSTEM MATCHES "SunOS.*") 148 | # On sun also check for -lthread 149 | CHECK_LIBRARY_EXISTS(thread thr_create "" CMAKE_HAVE_THR_CREATE) 150 | IF(CMAKE_HAVE_THR_CREATE) 151 | SET(CMAKE_THREAD_LIBS_INIT "-lthread") 152 | SET(CMAKE_HAVE_THREADS_LIBRARY 1) 153 | SET(Threads_FOUND TRUE) 154 | ENDIF() 155 | ENDIF(CMAKE_SYSTEM MATCHES "SunOS.*") 156 | 157 | ENDIF(NOT THREADS_HAVE_PTHREAD_ARG) 158 | 159 | IF(NOT CMAKE_HAVE_THREADS_LIBRARY) 160 | # If we did not found -lpthread, -lpthread, or -lthread, look for -pthread 161 | IF("THREADS_HAVE_PTHREAD_ARG" MATCHES "^THREADS_HAVE_PTHREAD_ARG") 162 | MESSAGE(STATUS "Check if compiler accepts -pthread") 163 | TRY_RUN(THREADS_PTHREAD_ARG THREADS_HAVE_PTHREAD_ARG 164 | ${CMAKE_BINARY_DIR} 165 | ${CMAKE_ROOT}/Modules/CheckForPthreads.c 166 | CMAKE_FLAGS -DLINK_LIBRARIES:STRING=-pthread 167 | COMPILE_OUTPUT_VARIABLE OUTPUT) 168 | 169 | IF(THREADS_HAVE_PTHREAD_ARG) 170 | IF(THREADS_PTHREAD_ARG MATCHES "^2$") 171 | SET(Threads_FOUND TRUE) 172 | MESSAGE(STATUS "Check if compiler accepts -pthread - yes") 173 | ELSE() 174 | MESSAGE(STATUS "Check if compiler accepts -pthread - no") 175 | FILE(APPEND 176 | ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log 177 | "Determining if compiler accepts -pthread returned ${THREADS_PTHREAD_ARG} instead of 2. The compiler had the following output:\n${OUTPUT}\n\n") 178 | ENDIF() 179 | ELSE() 180 | MESSAGE(STATUS "Check if compiler accepts -pthread - no") 181 | FILE(APPEND 182 | ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log 183 | "Determining if compiler accepts -pthread failed with the following output:\n${OUTPUT}\n\n") 184 | ENDIF() 185 | 186 | ENDIF("THREADS_HAVE_PTHREAD_ARG" MATCHES "^THREADS_HAVE_PTHREAD_ARG") 187 | 188 | IF(THREADS_HAVE_PTHREAD_ARG) 189 | SET(Threads_FOUND TRUE) 190 | SET(CMAKE_THREAD_LIBS_INIT "-pthread") 191 | ENDIF() 192 | 193 | ENDIF(NOT CMAKE_HAVE_THREADS_LIBRARY) 194 | ENDIF(CMAKE_HAVE_PTHREAD_H) 195 | ENDIF() 196 | 197 | IF(CMAKE_THREAD_LIBS_INIT) 198 | SET(CMAKE_USE_PTHREADS_INIT 1) 199 | SET(Threads_FOUND TRUE) 200 | ENDIF() 201 | 202 | IF(CMAKE_SYSTEM MATCHES "Windows" 203 | AND NOT THREADS_USE_PTHREADS_WIN32) 204 | SET(CMAKE_USE_WIN32_THREADS_INIT 1) 205 | SET(Threads_FOUND TRUE) 206 | ENDIF() 207 | 208 | IF(CMAKE_USE_PTHREADS_INIT) 209 | IF(CMAKE_SYSTEM MATCHES "HP-UX-*") 210 | # Use libcma if it exists and can be used. It provides more 211 | # symbols than the plain pthread library. CMA threads 212 | # have actually been deprecated: 213 | # http://docs.hp.com/en/B3920-90091/ch12s03.html#d0e11395 214 | # http://docs.hp.com/en/947/d8.html 215 | # but we need to maintain compatibility here. 216 | # The CMAKE_HP_PTHREADS setting actually indicates whether CMA threads 217 | # are available. 218 | CHECK_LIBRARY_EXISTS(cma pthread_attr_create "" CMAKE_HAVE_HP_CMA) 219 | IF(CMAKE_HAVE_HP_CMA) 220 | SET(CMAKE_THREAD_LIBS_INIT "-lcma") 221 | SET(CMAKE_HP_PTHREADS_INIT 1) 222 | SET(Threads_FOUND TRUE) 223 | ENDIF(CMAKE_HAVE_HP_CMA) 224 | SET(CMAKE_USE_PTHREADS_INIT 1) 225 | ENDIF() 226 | 227 | IF(CMAKE_SYSTEM MATCHES "OSF1-V*") 228 | SET(CMAKE_USE_PTHREADS_INIT 0) 229 | SET(CMAKE_THREAD_LIBS_INIT ) 230 | ENDIF() 231 | 232 | IF(CMAKE_SYSTEM MATCHES "CYGWIN_NT*") 233 | SET(CMAKE_USE_PTHREADS_INIT 1) 234 | SET(Threads_FOUND TRUE) 235 | SET(CMAKE_THREAD_LIBS_INIT ) 236 | SET(CMAKE_USE_WIN32_THREADS_INIT 0) 237 | ENDIF() 238 | ENDIF(CMAKE_USE_PTHREADS_INIT) 239 | 240 | INCLUDE(FindPackageHandleStandardArgs) 241 | IF(_Threads_ptwin32) 242 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(Threads DEFAULT_MSG 243 | THREADS_PTHREADS_WIN32_LIBRARY THREADS_PTHREADS_INCLUDE_DIR) 244 | ELSE() 245 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(Threads DEFAULT_MSG Threads_FOUND) 246 | ENDIF() 247 | -------------------------------------------------------------------------------- /cmake/cmake_uninstall.cmake.in: -------------------------------------------------------------------------------- 1 | # http://www.vtk.org/Wiki/CMake_FAQ#Can_I_do_.22make_uninstall.22_with_CMake.3F 2 | 3 | IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 4 | MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") 5 | ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 6 | 7 | FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) 8 | STRING(REGEX REPLACE "\n" ";" files "${files}") 9 | FOREACH(file ${files}) 10 | MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") 11 | IF(EXISTS "$ENV{DESTDIR}${file}") 12 | EXEC_PROGRAM( 13 | "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" 14 | OUTPUT_VARIABLE rm_out 15 | RETURN_VALUE rm_retval 16 | ) 17 | IF(NOT "${rm_retval}" STREQUAL 0) 18 | MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") 19 | ENDIF(NOT "${rm_retval}" STREQUAL 0) 20 | ELSEIF(IS_SYMLINK "$ENV{DESTDIR}${file}") 21 | EXEC_PROGRAM( 22 | "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" 23 | OUTPUT_VARIABLE rm_out 24 | RETURN_VALUE rm_retval 25 | ) 26 | IF(NOT "${rm_retval}" STREQUAL 0) 27 | MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") 28 | ENDIF(NOT "${rm_retval}" STREQUAL 0) 29 | ELSE(EXISTS "$ENV{DESTDIR}${file}") 30 | MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") 31 | ENDIF(EXISTS "$ENV{DESTDIR}${file}") 32 | ENDFOREACH(file) 33 | -------------------------------------------------------------------------------- /include/controlThread.h: -------------------------------------------------------------------------------- 1 | /* 2 | * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver 3 | * Copyright (C) 2019 <> 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | #ifndef __RTL_CONTROL_THREAD_H 20 | #define __RTL_CONTROL_THREAD_H 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | typedef struct 27 | { 28 | rtlsdr_dev_t *dev; 29 | int port; 30 | int wait; 31 | int report_i2c; 32 | char *addr; 33 | int* pDoExit; 34 | } 35 | ctrl_thread_data_t; 36 | void *ctrl_thread_fn(void *arg); 37 | 38 | #ifdef __cplusplus 39 | } 40 | #endif 41 | 42 | #endif 43 | 44 | -------------------------------------------------------------------------------- /include/rtl-sdr_export.h: -------------------------------------------------------------------------------- 1 | /* 2 | * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver 3 | * Copyright (C) 2012 by Hoernchen 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | #ifndef RTLSDR_EXPORT_H 20 | #define RTLSDR_EXPORT_H 21 | 22 | #if defined __GNUC__ 23 | # if __GNUC__ >= 4 24 | # define __SDR_EXPORT __attribute__((visibility("default"))) 25 | # define __SDR_IMPORT __attribute__((visibility("default"))) 26 | # else 27 | # define __SDR_EXPORT 28 | # define __SDR_IMPORT 29 | # endif 30 | #elif _MSC_VER 31 | # define __SDR_EXPORT __declspec(dllexport) 32 | # define __SDR_IMPORT __declspec(dllimport) 33 | #else 34 | # define __SDR_EXPORT 35 | # define __SDR_IMPORT 36 | #endif 37 | 38 | #ifndef rtlsdr_STATIC 39 | # ifdef rtlsdr_EXPORTS 40 | # define RTLSDR_API __SDR_EXPORT 41 | # else 42 | # define RTLSDR_API __SDR_IMPORT 43 | # endif 44 | #else 45 | #define RTLSDR_API 46 | #endif 47 | #endif /* RTLSDR_EXPORT_H */ 48 | -------------------------------------------------------------------------------- /include/rtl_tcp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver 3 | * Copyright (C) 2012-2013 by Steve Markgraf 4 | * Copyright (C) 2012 by Dimitri Stolnikov 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #ifndef __RTL_TCP_H 21 | #define __RTL_TCP_H 22 | 23 | #ifdef __cplusplus 24 | extern "C" { 25 | #endif 26 | 27 | /*! 28 | * This enum defines the possible commands in rtl_tcp 29 | * commands 0x01..0x0E are compatible to osmocom's rtlsdr 30 | * see https://github.com/osmocom/rtl-sdr/blob/master/src/rtl_tcp.c 31 | * commands >= 0x40 are extensions 32 | */ 33 | enum RTL_TCP_COMMANDS { 34 | SET_FREQUENCY = 0x01, 35 | SET_SAMPLE_RATE = 0x02, 36 | SET_GAIN_MODE = 0x03, 37 | SET_GAIN = 0x04, 38 | SET_FREQUENCY_CORRECTION = 0x05, 39 | SET_IF_STAGE = 0x06, 40 | SET_TEST_MODE = 0x07, 41 | SET_AGC_MODE = 0x08, 42 | SET_DIRECT_SAMPLING = 0x09, 43 | SET_OFFSET_TUNING = 0x0A, 44 | SET_RTL_CRYSTAL = 0x0B, 45 | SET_TUNER_CRYSTAL = 0x0C, 46 | SET_TUNER_GAIN_BY_INDEX = 0x0D, 47 | #if 1 48 | /* development branch since 2018-10-03 */ 49 | SET_BIAS_TEE = 0x0E, 50 | SET_TUNER_BANDWIDTH = 0x40, 51 | #else 52 | /* prev code - used in ExtIO - to build compatible rtl_tcp.exe */ 53 | SET_TUNER_BANDWIDTH = 0x0E, 54 | SET_BIAS_TEE = 0x0F 55 | #endif 56 | UDP_ESTABLISH = 0x41, 57 | UDP_TERMINATE = 0x42, 58 | SET_I2C_TUNER_REGISTER = 0x43, /* for experiments: 32 bit data word: 59 | * 31 .. 20: register (12 bits) 60 | * 19 .. 12: mask (8 bits) 61 | * 11 .. 0: data (12 bits) */ 62 | SET_I2C_TUNER_OVERRIDE = 0x44, /* encoding as with SET_I2C_TUNER_REGISTER 63 | * data (bits 11 .. 0) > 255 removes override */ 64 | SET_TUNER_BW_IF_CENTER = 0x45, /* freq from SET_FREQUENCY stays in center; 65 | * the bandwidth (from SET_TUNER_BANDWIDTH) 66 | * is set to be centered at given IF frequency */ 67 | SET_SIDEBAND = 0x46, /* Mixer Sideband for R820T */ 68 | REPORT_I2C_REGS = 0x48, /* perodically report I2C registers 69 | * - if reverse channel is enabled */ 70 | SET_DITHERING = 0x49, /* Enable or disable frequency dithering for R820T */ 71 | SET_FREQUENCY_CORRECTION_001_PPM = 0x4A, /* Set frequency correction in multiples of 0.01 ppm */ 72 | CMD_SET_LNA_STATE = 0x4B, // 0: most sensitive, 8: least sensitive 73 | CMD_SET_REQUEST_ALL_SERIALS = 0x80, // request for all serials to be transmitted via back channel 74 | CMD_SET_SELECT_SERIAL = 0x81, // value is four bytes CRC-32 of the requested serial number 75 | SET_FREQUENCY_CORRECTION_PPB = 0x83 /* Set frequency correction in parts per billion */ 76 | }; 77 | 78 | enum eCommState 79 | { 80 | ST_IDLE = 0 81 | , ST_SERIALS_REQUESTED 82 | , ST_DEVICE_CREATED 83 | , ST_WELCOME_SENT 84 | , ST_DEVICE_RELEASED 85 | }; 86 | 87 | #define MAX_DEVICES 6 88 | 89 | #ifdef __cplusplus 90 | } 91 | #endif 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /include/rtlsdr_i2c.h: -------------------------------------------------------------------------------- 1 | #ifndef __I2C_H 2 | #define __I2C_H 3 | 4 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 5 | 6 | double rtlsdr_get_tuner_clock(void *dev); 7 | int rtlsdr_i2c_write_fn(void *dev, uint8_t addr, uint8_t reg, uint8_t *buf, int len); 8 | int rtlsdr_i2c_read_fn (void *dev, uint8_t addr, uint8_t reg, uint8_t *buf, int len); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /include/tuner_e4k.h: -------------------------------------------------------------------------------- 1 | #ifndef _E4K_TUNER_H 2 | #define _E4K_TUNER_H 3 | 4 | /* 5 | * Elonics E4000 tuner driver 6 | * 7 | * (C) 2011-2012 by Harald Welte 8 | * (C) 2012 by Sylvain Munaut 9 | * (C) 2012 by Hoernchen 10 | * 11 | * All Rights Reserved 12 | * 13 | * This program is free software; you can redistribute it and/or modify 14 | * it under the terms of the GNU General Public License as published by 15 | * the Free Software Foundation; either version 2 of the License, or 16 | * (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | * GNU General Public License for more details. 22 | * 23 | * You should have received a copy of the GNU General Public License 24 | * along with this program. If not, see . 25 | */ 26 | 27 | #define E4K_I2C_ADDR 0xc8 28 | #define E4K_CHECK_ADDR 0x02 29 | #define E4K_CHECK_VAL 0x40 30 | 31 | enum e4k_reg { 32 | E4K_REG_MASTER1 = 0x00, 33 | E4K_REG_MASTER2 = 0x01, 34 | E4K_REG_MASTER3 = 0x02, 35 | E4K_REG_MASTER4 = 0x03, 36 | E4K_REG_MASTER5 = 0x04, 37 | E4K_REG_CLK_INP = 0x05, 38 | E4K_REG_REF_CLK = 0x06, 39 | E4K_REG_SYNTH1 = 0x07, 40 | E4K_REG_SYNTH2 = 0x08, 41 | E4K_REG_SYNTH3 = 0x09, 42 | E4K_REG_SYNTH4 = 0x0a, 43 | E4K_REG_SYNTH5 = 0x0b, 44 | // gap 45 | E4K_REG_SYNTH7 = 0x0d, 46 | E4K_REG_SYNTH8 = 0x0e, 47 | E4K_REG_SYNTH9 = 0x0f, 48 | E4K_REG_FILT1 = 0x10, 49 | E4K_REG_FILT2 = 0x11, 50 | E4K_REG_FILT3 = 0x12, 51 | // gap 52 | E4K_REG_GAIN1 = 0x14, 53 | E4K_REG_GAIN2 = 0x15, 54 | E4K_REG_GAIN3 = 0x16, 55 | E4K_REG_GAIN4 = 0x17, 56 | // gap 57 | E4K_REG_AGC1 = 0x1a, 58 | E4K_REG_AGC2 = 0x1b, 59 | E4K_REG_AGC3 = 0x1c, 60 | E4K_REG_AGC4 = 0x1d, 61 | E4K_REG_AGC5 = 0x1e, 62 | E4K_REG_AGC6 = 0x1f, 63 | E4K_REG_AGC7 = 0x20, 64 | E4K_REG_AGC8 = 0x21, 65 | // gap 66 | E4K_REG_AGC11 = 0x24, 67 | E4K_REG_AGC12 = 0x25, 68 | // gap 69 | E4K_REG_DC1 = 0x29, 70 | E4K_REG_DC2 = 0x2a, 71 | E4K_REG_DC3 = 0x2b, 72 | E4K_REG_DC4 = 0x2c, 73 | E4K_REG_DC5 = 0x2d, 74 | E4K_REG_DC6 = 0x2e, 75 | E4K_REG_DC7 = 0x2f, 76 | E4K_REG_DC8 = 0x30, 77 | // gap 78 | E4K_REG_QLUT0 = 0x50, 79 | E4K_REG_QLUT1 = 0x51, 80 | E4K_REG_QLUT2 = 0x52, 81 | E4K_REG_QLUT3 = 0x53, 82 | // gap 83 | E4K_REG_ILUT0 = 0x60, 84 | E4K_REG_ILUT1 = 0x61, 85 | E4K_REG_ILUT2 = 0x62, 86 | E4K_REG_ILUT3 = 0x63, 87 | // gap 88 | E4K_REG_DCTIME1 = 0x70, 89 | E4K_REG_DCTIME2 = 0x71, 90 | E4K_REG_DCTIME3 = 0x72, 91 | E4K_REG_DCTIME4 = 0x73, 92 | E4K_REG_PWM1 = 0x74, 93 | E4K_REG_PWM2 = 0x75, 94 | E4K_REG_PWM3 = 0x76, 95 | E4K_REG_PWM4 = 0x77, 96 | E4K_REG_BIAS = 0x78, 97 | // gap 98 | E4K_REG_CLKOUT_PWDN = 0x7a, 99 | E4K_REG_CHFILT_CALIB = 0x7b, 100 | // gap 101 | E4K_REG_I2C_REG_ADDR = 0x7d, 102 | // FIXME 103 | }; 104 | 105 | #define E4K_MASTER1_RESET (1 << 0) 106 | #define E4K_MASTER1_NORM_STBY (1 << 1) 107 | #define E4K_MASTER1_POR_DET (1 << 2) 108 | 109 | #define E4K_SYNTH1_PLL_LOCK (1 << 0) 110 | #define E4K_SYNTH1_BAND_SHIF 1 111 | 112 | #define E4K_SYNTH7_3PHASE_EN (1 << 3) 113 | 114 | #define E4K_SYNTH8_VCOCAL_UPD (1 << 2) 115 | 116 | #define E4K_FILT3_DISABLE (1 << 5) 117 | 118 | #define E4K_AGC1_LIN_MODE (1 << 4) 119 | #define E4K_AGC1_LNA_UPDATE (1 << 5) 120 | #define E4K_AGC1_LNA_G_LOW (1 << 6) 121 | #define E4K_AGC1_LNA_G_HIGH (1 << 7) 122 | 123 | #define E4K_AGC6_LNA_CAL_REQ (1 << 4) 124 | 125 | #define E4K_AGC7_MIX_GAIN_AUTO (1 << 0) 126 | #define E4K_AGC7_GAIN_STEP_5dB (1 << 5) 127 | 128 | #define E4K_AGC8_SENS_LIN_AUTO (1 << 0) 129 | 130 | #define E4K_AGC11_LNA_GAIN_ENH (1 << 0) 131 | 132 | #define E4K_DC1_CAL_REQ (1 << 0) 133 | 134 | #define E4K_DC5_I_LUT_EN (1 << 0) 135 | #define E4K_DC5_Q_LUT_EN (1 << 1) 136 | #define E4K_DC5_RANGE_DET_EN (1 << 2) 137 | #define E4K_DC5_RANGE_EN (1 << 3) 138 | #define E4K_DC5_TIMEVAR_EN (1 << 4) 139 | 140 | #define E4K_CLKOUT_DISABLE 0x96 141 | 142 | #define E4K_CHFCALIB_CMD (1 << 0) 143 | 144 | #define E4K_AGC1_MOD_MASK 0xF 145 | 146 | enum e4k_agc_mode { 147 | E4K_AGC_MOD_SERIAL = 0x0, 148 | E4K_AGC_MOD_IF_PWM_LNA_SERIAL = 0x1, 149 | E4K_AGC_MOD_IF_PWM_LNA_AUTONL = 0x2, 150 | E4K_AGC_MOD_IF_PWM_LNA_SUPERV = 0x3, 151 | E4K_AGC_MOD_IF_SERIAL_LNA_PWM = 0x4, 152 | E4K_AGC_MOD_IF_PWM_LNA_PWM = 0x5, 153 | E4K_AGC_MOD_IF_DIG_LNA_SERIAL = 0x6, 154 | E4K_AGC_MOD_IF_DIG_LNA_AUTON = 0x7, 155 | E4K_AGC_MOD_IF_DIG_LNA_SUPERV = 0x8, 156 | E4K_AGC_MOD_IF_SERIAL_LNA_AUTON = 0x9, 157 | E4K_AGC_MOD_IF_SERIAL_LNA_SUPERV = 0xa, 158 | }; 159 | 160 | enum e4k_band { 161 | E4K_BAND_VHF2 = 0, 162 | E4K_BAND_VHF3 = 1, 163 | E4K_BAND_UHF = 2, 164 | E4K_BAND_L = 3, 165 | }; 166 | 167 | struct e4k_pll_params { 168 | double fosc; 169 | uint32_t flo; 170 | }; 171 | 172 | /* structure describing a field in a register */ 173 | struct reg_field { 174 | uint8_t reg; 175 | uint8_t shift; 176 | uint8_t width; 177 | }; 178 | 179 | struct e4k_state { 180 | void *i2c_dev; 181 | uint8_t i2c_addr; 182 | enum e4k_band band; 183 | struct e4k_pll_params vco; 184 | void *rtl_dev; 185 | }; 186 | 187 | int e4k_init(struct e4k_state *e4k); 188 | int e4k_standby(struct e4k_state *e4k, int enable); 189 | int e4k_if_gain_set(struct e4k_state *e4k, uint8_t stage, int8_t value); 190 | int e4k_tune_freq(struct e4k_state *e4k, uint32_t freq); 191 | int e4k_set_bandwidth(struct e4k_state *e4k, int bw, uint32_t *applied_bw, int apply); 192 | int e4k_enable_manual_gain(struct e4k_state *e4k, uint8_t manual); 193 | int e4k_set_gain_index(struct e4k_state *e4k, unsigned int index); 194 | int e4k_set_i2c_register(struct e4k_state *e4k, unsigned i2c_register, unsigned data, unsigned mask); 195 | int e4k_get_i2c_register(struct e4k_state *e4k, uint8_t *data, int *len, int *strength); 196 | const int *e4k_get_gains(int *len); 197 | #endif /* _E4K_TUNER_H */ 198 | -------------------------------------------------------------------------------- /include/tuner_fc001x.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Fitipower FC0012/FC0013 tuner driver 3 | * 4 | * Copyright (C) 2012 Hans-Frieder Vogt 5 | * 6 | * modified for use in librtlsdr 7 | * Copyright (C) 2012 Steve Markgraf 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program; if not, write to the Free Software 21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22 | * 23 | */ 24 | 25 | #ifndef _FC001X_H_ 26 | #define _FC001X_H_ 27 | 28 | #define FC001X_I2C_ADDR 0xc6 29 | #define FC001X_CHECK_ADDR 0x00 30 | #define FC0012_CHECK_VAL 0xa1 31 | #define FC0013_CHECK_VAL 0xa3 32 | 33 | int fc0012_init(void *dev); 34 | int fc0013_init(void *dev); 35 | int fc0012_set_freq(void *dev, uint32_t freq); 36 | int fc0013_set_freq(void *dev, uint32_t freq); 37 | int fc001x_set_gain_mode(void *dev, int manual); 38 | int fc0012_set_gain_index(void *dev, unsigned int index); 39 | int fc0013_set_gain_index(void *dev, unsigned int index); 40 | int fc001x_set_bw(void *dev, int bw, uint32_t *applied_bw, int apply); 41 | int fc001x_set_i2c_register(void *dev, unsigned i2c_register, unsigned data, unsigned mask); 42 | int fc0012_get_i2c_register(void *dev, unsigned char *data, int *len, int *strength); 43 | int fc0013_get_i2c_register(void *dev, unsigned char *data, int *len, int *strength); 44 | int fc0012_exit(void *dev); 45 | int fc0013_exit(void *dev); 46 | const int *fc001x_get_gains(int *len); 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /include/tuner_fc2580.h: -------------------------------------------------------------------------------- 1 | #ifndef __TUNER_FC2580_H 2 | #define __TUNER_FC2580_H 3 | 4 | #define FC2580_I2C_ADDR 0xac 5 | #define FC2580_CHECK_ADDR 0x01 6 | #define FC2580_CHECK_VAL 0x56 7 | 8 | /* 16.384 MHz (at least on the Logilink VG0002A) */ 9 | #define FC2580_XTAL_FREQ 16384000 10 | 11 | 12 | // The following context is FC2580 tuner API source code Definitions 13 | int fc2580_init(void *dev); 14 | int fc2580_exit(void *dev); 15 | int fc2580_set_bw(void *dev, int bw, uint32_t *applied_bw, int apply); 16 | int fc2580_set_freq(void *dev, unsigned int RfFreqHz); 17 | int fc2580_set_i2c_register(void *dev, unsigned i2c_register, unsigned data, unsigned mask); 18 | int fc2580_get_i2c_register(void *dev, unsigned char *data, int *len, int *strength); 19 | int fc2580_set_gain_mode(void *dev, int manual); 20 | int fc2580_set_gain_index(void *dev, unsigned int index); 21 | const int *fc2580_get_gains(int *len); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /include/tuner_r82xx.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Rafael Micro R820T/R828D driver 3 | * 4 | * Copyright (C) 2013 Mauro Carvalho Chehab 5 | * Copyright (C) 2013 Steve Markgraf 6 | * 7 | * This driver is a heavily modified version of the driver found in the 8 | * Linux kernel: 9 | * http://git.linuxtv.org/linux-2.6.git/history/HEAD:/drivers/media/tuners/r820t.c 10 | * 11 | * This program is free software: you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation, either version 2 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see . 23 | */ 24 | 25 | #ifndef R82XX_H 26 | #define R82XX_H 27 | 28 | #define R820T_I2C_ADDR 0x34 29 | #define R828D_I2C_ADDR 0x74 30 | #define R828D_XTAL_FREQ 16000000 31 | 32 | #define R82XX_CHECK_ADDR 0x00 33 | #define R82XX_CHECK_VAL 0x69 34 | 35 | #define R82XX_IF_FREQ 3570000 36 | 37 | #define REG_SHADOW_START 5 38 | #define NUM_REGS 32 39 | 40 | 41 | enum r82xx_chip { 42 | CHIP_R820T, 43 | CHIP_R620D, 44 | CHIP_R828D, 45 | CHIP_R828, 46 | CHIP_R828S, 47 | CHIP_R820C, 48 | }; 49 | 50 | enum r82xx_tuner_type { 51 | TUNER_RADIO = 1, 52 | TUNER_ANALOG_TV, 53 | TUNER_DIGITAL_TV 54 | }; 55 | 56 | struct r82xx_config { 57 | uint8_t i2c_addr; 58 | double xtal; 59 | enum r82xx_chip rafael_chip; 60 | int use_predetect; 61 | int cal_imr; 62 | }; 63 | 64 | struct r82xx_priv { 65 | const struct r82xx_config *cfg; 66 | uint8_t regs[NUM_REGS]; 67 | uint32_t int_freq; 68 | uint32_t freq; //in MHz 69 | int16_t abs_gain; 70 | uint8_t input; 71 | uint8_t old_gain; 72 | uint8_t reg8[16]; 73 | int has_lock; 74 | int init_done; 75 | int sideband; 76 | void *rtl_dev; 77 | }; 78 | 79 | struct r82xx_freq_range { 80 | uint32_t freq; 81 | uint8_t rf_mux_ploy; 82 | uint8_t tf_c; 83 | }; 84 | 85 | int r82xx_standby(struct r82xx_priv *priv); 86 | int r82xx_init(struct r82xx_priv *priv); 87 | int r82xx_set_freq(struct r82xx_priv *priv, uint32_t freq); 88 | int r82xx_set_gain_index(struct r82xx_priv *priv, unsigned int index); 89 | int r82xx_set_gain_mode(struct r82xx_priv *priv, int set_manual_gain); 90 | int r82xx_set_bandwidth(struct r82xx_priv *priv, int bandwidth, uint32_t * applied_bw, int apply); 91 | int r82xx_set_i2c_register(struct r82xx_priv *priv, unsigned i2c_register, unsigned data, unsigned mask); 92 | int r82xx_get_i2c_register(struct r82xx_priv *priv, unsigned char* data, int *len, int *strength); 93 | int r82xx_set_sideband(struct r82xx_priv *priv, int sideband); 94 | int r82xx_set_dither(struct r82xx_priv *priv, int dither); 95 | const int *r82xx_get_gains(int *len); 96 | #endif 97 | -------------------------------------------------------------------------------- /install-blacklist.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BLACKLIST_FN="" 4 | if [ -f /etc/modprobe.d/rtlsdr-blacklist.conf ]; then 5 | BLACKLIST_FN="rtlsdr-blacklist.conf" 6 | echo "found /etc/modprobe.d/${BLACKLIST_FN}" 7 | elif [ -f /etc/modprobe.d/blacklist-rtl8xxxu.conf ]; then 8 | BLACKLIST_FN="blacklist-rtl8xxxu.conf" 9 | echo "found /etc/modprobe.d/${BLACKLIST_FN}" 10 | elif [ -f /etc/modprobe.d/raspi-blacklist.conf ]; then 11 | BLACKLIST_FN="raspi-blacklist.conf" 12 | echo "found /etc/modprobe.d/${BLACKLIST_FN}" 13 | else 14 | BLACKLIST_FN="rtlsdr-blacklist.conf" 15 | echo "could not find existing blacklist. will use /etc/modprobe.d/${BLACKLIST_FN}" 16 | fi 17 | 18 | if [ -f /etc/modprobe.d/${BLACKLIST_FN} ]; then 19 | cat /etc/modprobe.d/${BLACKLIST_FN} rtlsdr-blacklist.conf | sort | uniq >/dev/shm/${BLACKLIST_FN} 20 | cp /dev/shm/${BLACKLIST_FN} /etc/modprobe.d/${BLACKLIST_FN} 21 | echo "updated /etc/modprobe.d/${BLACKLIST_FN} ; reboot to apply" 22 | else 23 | cp rtlsdr-blacklist.conf /etc/modprobe.d/${BLACKLIST_FN} 24 | echo "created /etc/modprobe.d/${BLACKLIST_FN} ; reboot to apply" 25 | fi 26 | 27 | -------------------------------------------------------------------------------- /librtlsdr.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | 6 | Name: RTL-SDR Library 7 | Description: C Utility Library 8 | Version: @VERSION@ 9 | Cflags: -I${includedir}/ 10 | Libs: -L${libdir} -lrtlsdr 11 | Libs.private: -lusb-1.0 @RTLSDR_PC_LIBS@ 12 | -------------------------------------------------------------------------------- /protocol_rtl_tcp.txt: -------------------------------------------------------------------------------- 1 | 2 | The command protocol of rtl_tcp is on port 1234 (by default): 3 | ============================================================= 4 | 5 | Commands are directed from a client application towards rtl_tcp. 6 | 7 | Each command consists of 2 fields: 8 | 9 | 1- command_id: value of enum RTL_TCP_COMMANDS, defined in rtl_tcp.h. 10 | This element is an unsigned character, starting at offset 0 11 | with length: 1 byte. 12 | 13 | 2- parameter: depends on the command id, 14 | e.g. is a frequency for SET_FREQUENCY. 15 | This element is a (signed or unsigned) 32 bit integer, 16 | starting at offset 1 with length: 4 bytes. 17 | 18 | Both fields are in Network Byte Order (Big Endian). 19 | Size of one command is 5 bytes, without padding. 20 | 21 | 22 | Reverse direction on command connection: 23 | ======================================== 24 | 25 | With accepting a connection, rtl_tcp initially transmits some dongle_info. 26 | 27 | The dongle_info consists of 3 fields: 28 | 29 | 1- magic string: identifies the rtl_tcp protocol. The value is "RTL0". 30 | This element is a fixed size string, starting at offset 0 31 | with length 4 bytes. 32 | 33 | 2- tuner type: identifies the tuner chip built in the controlled RTL-SDR model, 34 | e.g. E4000 or R820T. 35 | This element is an unsigned 32 bit integer, starting at offset 4 36 | with length: 4 bytes. 37 | 38 | 3- tuner gain count: reports the number of available gain values, 39 | necessary for the command SET_TUNER_GAIN_BY_INDEX. 40 | This element is an unsigned 32 bit integer, starting at offset 8 41 | with length: 4 bytes. 42 | 43 | Both fields are in Network Byte Order (Big Endian). 44 | Size of one dongle_info is 12 bytes, without padding. 45 | 46 | 47 | After that initial dongle_info, from offset 12 byte, just raw I/Q data is transferred. 48 | For each I/Q frame, in the commanded samplerate, I and Q values are transferred, 49 | each as unsigned 8 bit sample. Thus one I/Q-frame is 2 bytes, each frame 1 byte. 50 | 51 | 52 | 53 | Response channel: 54 | ================= 55 | The command channel does not allow specific response on commands. 56 | This is why an additional response channel got necessary. 57 | rtl_tcp now offers an additional tcp server "response" channel, 58 | by default, on the next port as the command protocol. 59 | Thus, by default on port 1235. 60 | 61 | 62 | The first two bytes of the response contain the complete length of the buffer sent. 63 | This is followed by any number of messages with the following structure: 64 | - 1 byte indication: The counterpart to the command, it shows what is being reported 65 | - 2 byte length of the indication payload. 66 | - n byte indication payload 67 | 68 | All fields are in Network Byte Order (Big Endian). 69 | Indications: 70 | 0x00 = gain indication. 71 | 0x48 = report i2c registers 72 | -------------------------------------------------------------------------------- /rtl-sdr.rules: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2012-2013 Osmocom rtl-sdr project 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | # original RTL2832U vid/pid (hama nano, for example) 19 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="2832", MODE:="0666" 20 | 21 | # modified RTL2832U vid/pid .. not known to dvb modules 22 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="2832", MODE:="0666" 23 | 24 | # RTL2832U OEM vid/pid, e.g. ezcap EzTV668 (E4000), Newsky TV28T (E4000/R820T) etc. 25 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="2838", MODE:="0666" 26 | 27 | # DigitalNow Quad DVB-T PCI-E card (4x FC0012?) 28 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="0413", ATTRS{idProduct}=="6680", MODE:="0666" 29 | 30 | # Leadtek WinFast DTV Dongle mini D (FC0012) 31 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="0413", ATTRS{idProduct}=="6f0f", MODE:="0666" 32 | 33 | # Genius TVGo DVB-T03 USB dongle (Ver. B) 34 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="0458", ATTRS{idProduct}=="707f", MODE:="0666" 35 | 36 | # Terratec Cinergy T Stick Black (rev 1) (FC0012) 37 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00a9", MODE:="0666" 38 | 39 | # Terratec NOXON rev 1 (FC0013) 40 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00b3", MODE:="0666" 41 | 42 | # Terratec Deutschlandradio DAB Stick (FC0013) 43 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00b4", MODE:="0666" 44 | 45 | # Terratec NOXON DAB Stick - Radio Energy (FC0013) 46 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00b5", MODE:="0666" 47 | 48 | # Terratec Media Broadcast DAB Stick (FC0013) 49 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00b7", MODE:="0666" 50 | 51 | # Terratec BR DAB Stick (FC0013) 52 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00b8", MODE:="0666" 53 | 54 | # Terratec WDR DAB Stick (FC0013) 55 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00b9", MODE:="0666" 56 | 57 | # Terratec MuellerVerlag DAB Stick (FC0013) 58 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00c0", MODE:="0666" 59 | 60 | # Terratec Fraunhofer DAB Stick (FC0013) 61 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00c6", MODE:="0666" 62 | 63 | # Terratec Cinergy T Stick RC (Rev.3) (E4000) 64 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00d3", MODE:="0666" 65 | 66 | # Terratec T Stick PLUS (E4000) 67 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00d7", MODE:="0666" 68 | 69 | # Terratec NOXON rev 2 (E4000) 70 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00e0", MODE:="0666" 71 | 72 | # PixelView PV-DT235U(RN) (FC0012) 73 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="1554", ATTRS{idProduct}=="5020", MODE:="0666" 74 | 75 | # Astrometa DVB-T/DVB-T2 (R828D) 76 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="15f4", ATTRS{idProduct}=="0131", MODE:="0666" 77 | 78 | # HanfTek DAB+FM+DVB-T 79 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="15f4", ATTRS{idProduct}=="0133", MODE:="0666" 80 | 81 | # Compro Videomate U620F (E4000) 82 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="185b", ATTRS{idProduct}=="0620", MODE:="0666" 83 | 84 | # Compro Videomate U650F (E4000) 85 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="185b", ATTRS{idProduct}=="0650", MODE:="0666" 86 | 87 | # Compro Videomate U680F (E4000) 88 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="185b", ATTRS{idProduct}=="0680", MODE:="0666" 89 | 90 | # GIGABYTE GT-U7300 (FC0012) 91 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d393", MODE:="0666" 92 | 93 | # DIKOM USB-DVBT HD 94 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d394", MODE:="0666" 95 | 96 | # Peak 102569AGPK (FC0012) 97 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d395", MODE:="0666" 98 | 99 | # KWorld KW-UB450-T USB DVB-T Pico TV (TUA9001) 100 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d397", MODE:="0666" 101 | 102 | # Zaapa ZT-MINDVBZP (FC0012) 103 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d398", MODE:="0666" 104 | 105 | # SVEON STV20 DVB-T USB & FM (FC0012) 106 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d39d", MODE:="0666" 107 | 108 | # Twintech UT-40 (FC0013) 109 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d3a4", MODE:="0666" 110 | 111 | # ASUS U3100MINI_PLUS_V2 (FC0013) 112 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d3a8", MODE:="0666" 113 | 114 | # SVEON STV27 DVB-T USB & FM (FC0013) 115 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d3af", MODE:="0666" 116 | 117 | # SVEON STV21 DVB-T USB & FM 118 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d3b0", MODE:="0666" 119 | 120 | # Dexatek DK DVB-T Dongle (Logilink VG0002A) (FC2580) 121 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="1d19", ATTRS{idProduct}=="1101", MODE:="0666" 122 | 123 | # Dexatek DK DVB-T Dongle (MSI DigiVox mini II V3.0) 124 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="1d19", ATTRS{idProduct}=="1102", MODE:="0666" 125 | 126 | # Dexatek DK 5217 DVB-T Dongle (FC2580) 127 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="1d19", ATTRS{idProduct}=="1103", MODE:="0666" 128 | 129 | # MSI DigiVox Micro HD (FC2580) 130 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="1d19", ATTRS{idProduct}=="1104", MODE:="0666" 131 | 132 | # Sweex DVB-T USB (FC0012) 133 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="1f4d", ATTRS{idProduct}=="a803", MODE:="0666" 134 | 135 | # GTek T803 (FC0012) 136 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="1f4d", ATTRS{idProduct}=="b803", MODE:="0666" 137 | 138 | # Lifeview LV5TDeluxe (FC0012) 139 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="1f4d", ATTRS{idProduct}=="c803", MODE:="0666" 140 | 141 | # MyGica TD312 (FC0012) 142 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="1f4d", ATTRS{idProduct}=="d286", MODE:="0666" 143 | 144 | # PROlectrix DV107669 (FC0012) 145 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="1f4d", ATTRS{idProduct}=="d803", MODE:="0666" 146 | -------------------------------------------------------------------------------- /rtlsdr-blacklist.conf: -------------------------------------------------------------------------------- 1 | blacklist dvb_usb_rtl28xxu 2 | blacklist dvb_usb_v2 3 | blacklist rtl_2830 4 | blacklist rtl_2832 5 | blacklist r820t 6 | blacklist rtl8xxxu 7 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2012 OSMOCOM Project 2 | # 3 | # This file is part of rtl-sdr 4 | # 5 | # GNU Radio is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 3, or (at your option) 8 | # any later version. 9 | # 10 | # GNU Radio is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with GNU Radio; see the file COPYING. If not, write to 17 | # the Free Software Foundation, Inc., 51 Franklin Street, 18 | # Boston, MA 02110-1301, USA. 19 | 20 | ######################################################################## 21 | # Setup library 22 | ######################################################################## 23 | LIST(APPEND rtlsdr_srcs 24 | librtlsdr.c 25 | tuner_e4k.c 26 | tuner_fc001x.c 27 | tuner_fc2580.c 28 | tuner_r82xx.c 29 | ) 30 | 31 | ######################################################################## 32 | # Setup shared library variant 33 | ######################################################################## 34 | add_library(rtlsdr_shared SHARED ${rtlsdr_srcs}) 35 | target_link_libraries(rtlsdr_shared ${LIBUSB_LIBRARIES} -Wl,-s) 36 | if(WIN32) 37 | target_link_libraries(rtlsdr_shared -lsetupapi -lwinusb ${CMAKE_THREAD_LIBS_INIT}) 38 | endif() 39 | set_target_properties(rtlsdr_shared PROPERTIES DEFINE_SYMBOL "rtlsdr_EXPORTS") 40 | set_target_properties(rtlsdr_shared PROPERTIES OUTPUT_NAME rtlsdr) 41 | 42 | ######################################################################## 43 | # Setup static library variant 44 | ######################################################################## 45 | add_library(rtlsdr_static STATIC ${rtlsdr_srcs}) 46 | target_link_libraries(rtlsdr_static ${LIBUSB_LIBRARIES} -s) 47 | if(WIN32) 48 | target_link_libraries(rtlsdr_static -lsetupapi -lwinusb ${CMAKE_THREAD_LIBS_INIT}) 49 | endif() 50 | set_property(TARGET rtlsdr_static APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" ) 51 | if(NOT WIN32) 52 | # Force same library filename for static and shared variants of the library 53 | set_target_properties(rtlsdr_static PROPERTIES OUTPUT_NAME rtlsdr) 54 | endif() 55 | 56 | ######################################################################## 57 | # Set up Windows DLL resource files 58 | ######################################################################## 59 | if(WIN32) 60 | target_sources(rtlsdr_shared PRIVATE rtlsdr.rc) 61 | endif() 62 | 63 | ######################################################################## 64 | # Set link library 65 | ######################################################################## 66 | if(LINK_RTLTOOLS_AGAINST_STATIC_LIB) 67 | set(RTLSDR_TOOL_LIB rtlsdr_static) 68 | else() 69 | set(RTLSDR_TOOL_LIB rtlsdr_shared) 70 | endif() 71 | 72 | ######################################################################## 73 | # Setup libraries used in executables 74 | ######################################################################## 75 | add_library(convenience_static STATIC 76 | convenience/convenience.c 77 | ) 78 | 79 | if(MSVC) 80 | add_library(libgetopt_static STATIC 81 | getopt/getopt.c 82 | ) 83 | endif() 84 | target_link_libraries(convenience_static 85 | ${RTLSDR_TOOL_LIB} 86 | ) 87 | 88 | ######################################################################## 89 | # Build utility 90 | ######################################################################## 91 | add_executable(rtl_sdr rtl_sdr.c convenience/wavewrite.c) 92 | add_executable(rtl_tcp rtl_tcp.c controlThread.c) 93 | add_executable(rtl2_tcp rtl2_tcp.c controlThread2.c) 94 | add_executable(rtl_test rtl_test.c) 95 | add_executable(rtl_fm rtl_fm.c convenience/wavewrite.c) 96 | add_executable(rtl_ir rtl_ir.c) 97 | add_executable(rtl_eeprom rtl_eeprom.c) 98 | add_executable(rtl_power rtl_power.c) 99 | set(INSTALL_TARGETS rtlsdr_shared rtlsdr_static 100 | rtl_sdr rtl_tcp rtl2_tcp rtl_test rtl_fm 101 | rtl_ir rtl_eeprom rtl_power 102 | ) 103 | 104 | target_link_libraries(rtl_sdr ${RTLSDR_TOOL_LIB} convenience_static 105 | ${LIBUSB_LIBRARIES} 106 | ${CMAKE_THREAD_LIBS_INIT} 107 | ) 108 | target_link_libraries(rtl_tcp ${RTLSDR_TOOL_LIB} convenience_static 109 | ${CMAKE_THREAD_LIBS_INIT} 110 | ) 111 | target_link_libraries(rtl2_tcp ${RTLSDR_TOOL_LIB} convenience_static 112 | ${CMAKE_THREAD_LIBS_INIT} 113 | ) 114 | target_link_libraries(rtl_test ${RTLSDR_TOOL_LIB} convenience_static 115 | ${CMAKE_THREAD_LIBS_INIT} 116 | ) 117 | target_link_libraries(rtl_fm ${RTLSDR_TOOL_LIB} convenience_static 118 | ${LIBUSB_LIBRARIES} 119 | ${CMAKE_THREAD_LIBS_INIT} 120 | ) 121 | target_link_libraries(rtl_ir ${RTLSDR_TOOL_LIB} convenience_static 122 | ${LIBUSB_LIBRARIES} 123 | ${CMAKE_THREAD_LIBS_INIT} 124 | ) 125 | target_link_libraries(rtl_eeprom ${RTLSDR_TOOL_LIB} convenience_static 126 | ${CMAKE_THREAD_LIBS_INIT} 127 | ) 128 | target_link_libraries(rtl_power ${RTLSDR_TOOL_LIB} convenience_static 129 | ${LIBUSB_LIBRARIES} 130 | ${CMAKE_THREAD_LIBS_INIT} 131 | ) 132 | 133 | if(UNIX) 134 | target_link_libraries(rtl_fm m) 135 | target_link_libraries(rtl_ir m) 136 | target_link_libraries(rtl_power m) 137 | target_link_libraries(rtl_tcp m) 138 | target_link_libraries(rtl2_tcp m) 139 | target_link_libraries(rtl_test m) 140 | endif() 141 | 142 | if(WIN32) 143 | if(MSVC) 144 | target_link_libraries(rtl_sdr libgetopt_static) 145 | target_link_libraries(rtl_tcp ws2_32 libgetopt_static) 146 | target_link_libraries(rtl2_tcp ws2_32 libgetopt_static) 147 | target_link_libraries(rtl_test libgetopt_static) 148 | target_link_libraries(rtl_fm libgetopt_static) 149 | target_link_libraries(rtl_ir libgetopt_static) 150 | target_link_libraries(rtl_eeprom libgetopt_static) 151 | target_link_libraries(rtl_power libgetopt_static) 152 | else() 153 | target_link_libraries(rtl_tcp ws2_32) 154 | target_link_libraries(rtl2_tcp ws2_32) 155 | target_link_libraries(rtl_test) 156 | endif() 157 | set_property(TARGET rtl_sdr APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" ) 158 | set_property(TARGET rtl_tcp APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" ) 159 | set_property(TARGET rtl2_tcp APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" ) 160 | set_property(TARGET rtl_test APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" ) 161 | set_property(TARGET rtl_fm APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" ) 162 | set_property(TARGET rtl_ir APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" ) 163 | set_property(TARGET rtl_eeprom APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" ) 164 | set_property(TARGET rtl_power APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" ) 165 | endif() 166 | 167 | ######################################################################## 168 | # Install built library files & utilities 169 | ######################################################################## 170 | install(TARGETS ${INSTALL_TARGETS} 171 | LIBRARY DESTINATION ${LIB_INSTALL_DIR} # .so/.dylib file 172 | ARCHIVE DESTINATION ${LIB_INSTALL_DIR} # .lib file 173 | RUNTIME DESTINATION bin # .dll file 174 | ) 175 | -------------------------------------------------------------------------------- /src/controlThread.c: -------------------------------------------------------------------------------- 1 | /* 2 | * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver 3 | * Copyright (C) 2012 by Steve Markgraf 4 | * Copyright (C) 2012-2013 by Hoernchen 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #ifndef _WIN32 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #else 36 | #include 37 | #endif 38 | 39 | #ifdef NEED_PTHREADS_WORKARROUND 40 | #define HAVE_STRUCT_TIMESPEC 41 | #endif 42 | 43 | #include "rtl-sdr.h" 44 | #include "rtl_tcp.h" 45 | #include "controlThread.h" 46 | 47 | #ifdef _WIN32 48 | #pragma comment(lib, "ws2_32.lib") 49 | 50 | typedef int socklen_t; 51 | 52 | #else 53 | #define closesocket close 54 | #define SOCKADDR struct sockaddr 55 | #define SOCKET int 56 | #define SOCKET_ERROR -1 57 | #endif 58 | 59 | #define MAX_I2C_REGISTERS 256 60 | #define TX_BUF_LEN (10+MAX_I2C_REGISTERS) 61 | 62 | extern int overload; 63 | 64 | ctrl_thread_data_t ctrl_thread_data; 65 | 66 | void *ctrl_thread_fn(void *arg) 67 | { 68 | unsigned char reg_values [MAX_I2C_REGISTERS]; 69 | unsigned char txbuf [TX_BUF_LEN]; 70 | int r = 1; 71 | struct timeval tv = { 1,0 }; 72 | struct linger ling = { 1,0 }; 73 | SOCKET listensocket; 74 | SOCKET controlSocket; 75 | int haveControlSocket = 0; 76 | struct sockaddr_in local, remote; 77 | socklen_t rlen; 78 | 79 | int result, tuner_gain, txlen, reglen; 80 | fd_set connfds; 81 | fd_set writefds; 82 | int bytesleft, bytessent, index; 83 | int old_gain = 0; 84 | 85 | ctrl_thread_data_t *data = (ctrl_thread_data_t *)arg; 86 | 87 | rtlsdr_dev_t *dev = data->dev; 88 | int port = data->port; 89 | int wait = data->wait; 90 | int report_i2c = data->report_i2c; 91 | char *addr = data->addr; 92 | volatile int* do_exit = data->pDoExit; 93 | u_long blockmode = 1; 94 | int retval; 95 | 96 | memset(reg_values, 0, MAX_I2C_REGISTERS); 97 | 98 | memset(&local, 0, sizeof(local)); 99 | local.sin_family = AF_INET; 100 | local.sin_port = htons(port); 101 | local.sin_addr.s_addr = inet_addr(addr); 102 | 103 | listensocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 104 | 105 | setsockopt(listensocket, SOL_SOCKET, SO_REUSEADDR, (char *)&r, sizeof(int)); 106 | setsockopt(listensocket, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling)); 107 | retval = bind(listensocket, (struct sockaddr *)&local, sizeof(local)); 108 | if (retval == SOCKET_ERROR) 109 | goto close; 110 | #ifdef _WIN32 111 | ioctlsocket(listensocket, FIONBIO, &blockmode); 112 | #else 113 | r = fcntl(listensocket, F_GETFL, 0); 114 | r = fcntl(listensocket, F_SETFL, r | O_NONBLOCK); 115 | #endif 116 | 117 | while (1) { 118 | fprintf(stderr, "listening on control port %d...\n", port); 119 | retval = listen(listensocket, 1); 120 | if (retval == SOCKET_ERROR) 121 | goto close; 122 | while (1) { 123 | FD_ZERO(&connfds); 124 | FD_SET(listensocket, &connfds); 125 | tv.tv_sec = 1; 126 | tv.tv_usec = 0; 127 | r = select(listensocket + 1, &connfds, NULL, NULL, &tv); 128 | if (*do_exit) { 129 | goto close; 130 | } 131 | else if (r) { 132 | rlen = sizeof(remote); 133 | controlSocket = accept(listensocket, (struct sockaddr *)&remote, &rlen); 134 | haveControlSocket = 1; 135 | break; 136 | } 137 | result = rtlsdr_get_tuner_i2c_register(dev, reg_values, ®len, &tuner_gain); 138 | tuner_gain = (tuner_gain + 5) / 10; 139 | if(old_gain != tuner_gain) 140 | { 141 | fprintf(stderr, "gain = %2d dB\r", tuner_gain); 142 | old_gain = tuner_gain; 143 | } 144 | } 145 | 146 | setsockopt(controlSocket, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling)); 147 | 148 | fprintf(stderr, "Control client accepted!\n"); 149 | //usleep(500000); 150 | 151 | while (1) { 152 | 153 | /* check if i2c reporting is to be (de)activated */ 154 | if ( report_i2c && !data->report_i2c ) 155 | report_i2c = 0; 156 | else if ( !report_i2c && data->report_i2c ) 157 | report_i2c = 1; 158 | 159 | /* @TODO: check if something else has to be transmitted */ 160 | if ( !report_i2c ) 161 | goto sleep; 162 | 163 | reglen = 0; 164 | result = rtlsdr_get_tuner_i2c_register(dev, reg_values, ®len, &tuner_gain); 165 | memset(txbuf, 0, TX_BUF_LEN); 166 | if (result) 167 | goto sleep; 168 | 169 | //Big Endian / Network Byte Order 170 | txlen = 2; // For the first two bytes 171 | // "gain" indication 172 | txbuf[2] = 0; 173 | // "gain" length 174 | txbuf[3] = 0; 175 | txbuf[4] = 2; 176 | // "gain" value 177 | tuner_gain -= 30; 178 | txbuf[5] = (tuner_gain >> 8) & 0xff; 179 | txbuf[6] = tuner_gain & 0xff; 180 | // "overload" indication 181 | txbuf[7] = 0x86; 182 | // "overload" length 183 | txbuf[8] = 0; 184 | txbuf[9] = 1; 185 | txbuf[10] = overload; 186 | txlen += 9; 187 | 188 | // "register" indication 189 | txbuf[11] = REPORT_I2C_REGS; 190 | // "register" length 191 | txbuf[12] = ((reglen) >> 8) & 0xff; 192 | txbuf[13] = reglen & 0xff; 193 | // register values 194 | memcpy(&txbuf[14], reg_values, reglen); 195 | txlen += reglen+3; 196 | 197 | // total length of the sent buffer 198 | txbuf[0] = (txlen >> 8) & 0xff; 199 | txbuf[1] = txlen & 0xff; 200 | 201 | /* now start (possibly blocking) transmission */ 202 | bytessent = 0; 203 | bytesleft = txlen; 204 | index = 0; 205 | while (bytesleft > 0) { 206 | FD_ZERO(&writefds); 207 | FD_SET(controlSocket, &writefds); 208 | tv.tv_sec = 1; 209 | tv.tv_usec = 0; 210 | r = select(controlSocket + 1, NULL, &writefds, NULL, &tv); 211 | if (r) { 212 | bytessent = send(controlSocket, (const char*)&txbuf[index], bytesleft, 0); 213 | bytesleft -= bytessent; 214 | index += bytessent; 215 | } 216 | if (bytessent == SOCKET_ERROR || *do_exit) { 217 | goto close; 218 | } 219 | } 220 | sleep: 221 | usleep(wait); 222 | } 223 | close: 224 | if (haveControlSocket) 225 | closesocket(controlSocket); 226 | if (*do_exit) 227 | { 228 | closesocket(listensocket); 229 | fprintf(stderr, "Control Thread terminates\n"); 230 | break; 231 | } 232 | } 233 | return 0; 234 | } 235 | 236 | -------------------------------------------------------------------------------- /src/controlThread2.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/old-dab/rtlsdr/ea2b50e91289acc448755ffa560c1cfff46e3879/src/controlThread2.c -------------------------------------------------------------------------------- /src/convenience/convenience.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 by Kyle Keen 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | /* a collection of user friendly tools 19 | * todo: use strtol for more flexible int parsing 20 | * */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #ifndef _WIN32 30 | #include 31 | #include 32 | #else 33 | #include 34 | #include 35 | #include 36 | #include 37 | #define _USE_MATH_DEFINES 38 | #endif 39 | 40 | #include 41 | 42 | #include "rtl-sdr.h" 43 | 44 | #ifdef _WIN32 45 | 46 | /* Offset between 1/1/1601 and 1/1/1970 in 100 nanosec units */ 47 | #define _W32_FT_OFFSET (116444736000000000) 48 | 49 | int gettimeofday(struct timeval *tp, void *tzp) 50 | { 51 | union { 52 | unsigned __int64 ns100; /* Time since 1 Jan 1601, in 100ns units */ 53 | FILETIME ft; 54 | } _now; 55 | (void) tzp; 56 | 57 | if(tp) { 58 | GetSystemTimeAsFileTime (&_now.ft); 59 | tp->tv_usec=(long)((_now.ns100 / 10) % 1000000 ); 60 | tp->tv_sec= (long)((_now.ns100 - _W32_FT_OFFSET) / 10000000); 61 | } 62 | 63 | return 0; 64 | } 65 | #endif 66 | 67 | double atofs(char *s) 68 | /* standard suffixes */ 69 | { 70 | char last; 71 | int len; 72 | double suff = 1.0; 73 | len = strlen(s); 74 | /* allow formatting spaces from .csv command file */ 75 | while ( len > 1 && isspace(s[len-1]) ) --len; 76 | last = s[len-1]; 77 | s[len-1] = '\0'; 78 | switch (last) { 79 | case 'g': 80 | case 'G': 81 | suff *= 1e3; 82 | /* fall-through */ 83 | case 'm': 84 | case 'M': 85 | suff *= 1e3; 86 | /* fall-through */ 87 | case 'k': 88 | case 'K': 89 | suff *= 1e3; 90 | suff *= atof(s); 91 | s[len-1] = last; 92 | return suff; 93 | } 94 | s[len-1] = last; 95 | return atof(s); 96 | } 97 | 98 | double atoft(char *s) 99 | /* time suffixes, returns seconds */ 100 | { 101 | char last; 102 | int len; 103 | double suff = 1.0; 104 | len = strlen(s); 105 | last = s[len-1]; 106 | s[len-1] = '\0'; 107 | switch (last) { 108 | case 'h': 109 | case 'H': 110 | suff *= 60; 111 | /* fall-through */ 112 | case 'm': 113 | case 'M': 114 | suff *= 60; 115 | /* fall-through */ 116 | case 's': 117 | case 'S': 118 | suff *= atof(s); 119 | s[len-1] = last; 120 | return suff; 121 | } 122 | s[len-1] = last; 123 | return atof(s); 124 | } 125 | 126 | double atofp(char *s) 127 | /* percent suffixes */ 128 | { 129 | char last; 130 | int len; 131 | double suff = 1.0; 132 | len = strlen(s); 133 | last = s[len-1]; 134 | s[len-1] = '\0'; 135 | switch (last) { 136 | case '%': 137 | suff *= 0.01; 138 | suff *= atof(s); 139 | s[len-1] = last; 140 | return suff; 141 | } 142 | s[len-1] = last; 143 | return atof(s); 144 | } 145 | 146 | int nearest_gain(rtlsdr_dev_t *dev, int target_gain) 147 | { 148 | int i, r, err1, err2, count, nearest; 149 | int* gains; 150 | r = rtlsdr_set_tuner_gain_mode(dev, 1); 151 | if (r < 0) { 152 | fprintf(stderr, "WARNING: Failed to enable manual gain.\n"); 153 | return r; 154 | } 155 | count = rtlsdr_get_tuner_gains(dev, NULL); 156 | if (count <= 0) { 157 | return 0; 158 | } 159 | gains = malloc(sizeof(int) * count); 160 | count = rtlsdr_get_tuner_gains(dev, gains); 161 | nearest = gains[0]; 162 | for (i=0; i 0) { 206 | if (applied_bw) 207 | fprintf(stderr, "Bandwidth parameter %u Hz resulted in %u Hz.\n", bandwidth, applied_bw); 208 | else 209 | fprintf(stderr, "Set bandwidth parameter %u Hz.\n", bandwidth); 210 | } else { 211 | fprintf(stderr, "Bandwidth set to automatic resulted in %u Hz.\n", applied_bw); 212 | } 213 | return r; 214 | } 215 | 216 | int verbose_direct_sampling(rtlsdr_dev_t *dev, int on) 217 | { 218 | int r; 219 | r = rtlsdr_set_direct_sampling(dev, on); 220 | if (r != 0) { 221 | fprintf(stderr, "WARNING: Failed to set direct sampling mode.\n"); 222 | return r; 223 | } 224 | if (on == 0) { 225 | fprintf(stderr, "Direct sampling mode disabled.\n");} 226 | if (on == 1) { 227 | fprintf(stderr, "Enabled direct sampling mode, input 1/I.\n");} 228 | if (on == 2) { 229 | fprintf(stderr, "Enabled direct sampling mode, input 2/Q.\n");} 230 | return r; 231 | } 232 | 233 | int verbose_offset_tuning(rtlsdr_dev_t *dev) 234 | { 235 | int r; 236 | r = rtlsdr_set_offset_tuning(dev, 1); 237 | if (r != 0) { 238 | if ( r == -2 ) 239 | fprintf(stderr, "WARNING: Failed to set offset tuning: tuner doesn't support offset tuning!\n"); 240 | else if ( r == -3 ) 241 | fprintf(stderr, "WARNING: Failed to set offset tuning: direct sampling not combinable with offset tuning!\n"); 242 | else 243 | fprintf(stderr, "WARNING: Failed to set offset tuning.\n"); 244 | } else { 245 | fprintf(stderr, "Offset tuning mode enabled.\n"); 246 | } 247 | return r; 248 | } 249 | 250 | int verbose_auto_gain(rtlsdr_dev_t *dev) 251 | { 252 | int r; 253 | r = rtlsdr_set_tuner_gain_mode(dev, 0); 254 | if (r != 0) { 255 | fprintf(stderr, "WARNING: Failed to enable automatic gain.\n"); 256 | } else { 257 | fprintf(stderr, "Tuner gain set to automatic.\n"); 258 | } 259 | return r; 260 | } 261 | 262 | int verbose_gain_set(rtlsdr_dev_t *dev, int gain) 263 | { 264 | int r; 265 | r = rtlsdr_set_tuner_gain_mode(dev, 1); 266 | if (r < 0) { 267 | fprintf(stderr, "WARNING: Failed to enable manual gain.\n"); 268 | return r; 269 | } 270 | r = rtlsdr_set_tuner_gain(dev, gain); 271 | if (r != 0) { 272 | fprintf(stderr, "WARNING: Failed to set tuner gain.\n"); 273 | } else { 274 | fprintf(stderr, "Tuner gain set to %0.2f dB.\n", gain/10.0); 275 | } 276 | return r; 277 | } 278 | 279 | int verbose_ppm_set(rtlsdr_dev_t *dev, float ppm_error) 280 | { 281 | int r; 282 | if (ppm_error == 0) { 283 | return 0;} 284 | r = rtlsdr_set_freq_correction_ppb(dev, (int)(ppm_error*1000.0)); 285 | if (r < 0) { 286 | fprintf(stderr, "WARNING: Failed to set ppm error.\n"); 287 | } else { 288 | fprintf(stderr, "Tuner error set to %0.3f ppm.\n", ppm_error); 289 | } 290 | return r; 291 | } 292 | 293 | int verbose_reset_buffer(rtlsdr_dev_t *dev) 294 | { 295 | int r; 296 | r = rtlsdr_reset_buffer(dev); 297 | if (r < 0) { 298 | fprintf(stderr, "WARNING: Failed to reset buffers.\n");} 299 | return r; 300 | } 301 | 302 | int verbose_device_search(char *s) 303 | { 304 | int i, device_count, device, offset; 305 | char *s2; 306 | char vendor[256], product[256], serial[256]; 307 | device_count = rtlsdr_get_device_count(); 308 | if (!device_count) 309 | { 310 | fprintf(stderr, "No supported devices found.\n"); 311 | return -1; 312 | } 313 | fprintf(stderr, "Found %d device(s):\n", device_count); 314 | for (i = 0; i < device_count; i++) 315 | { 316 | if(rtlsdr_get_device_usb_strings(i, vendor, product, serial) < 0) 317 | continue; 318 | fprintf(stderr, " %d: %s, %s, SN: %s\n", i, vendor, product, serial); 319 | } 320 | fprintf(stderr, "\n"); 321 | /* does string look like raw id number */ 322 | device = (int)strtol(s, &s2, 0); 323 | if (s2[0] == '\0' && device >= 0 && device < device_count) 324 | { 325 | fprintf(stderr, "Using device %d: %s\n", 326 | device, rtlsdr_get_device_name((uint32_t)device)); 327 | return device; 328 | } 329 | /* does string exact match a serial */ 330 | for (i = 0; i < device_count; i++) 331 | { 332 | if(rtlsdr_get_device_usb_strings(i, vendor, product, serial) < 0) 333 | continue; 334 | if (strcmp(s, serial) != 0) 335 | continue; 336 | device = i; 337 | fprintf(stderr, "Using device %d: %s\n", 338 | device, rtlsdr_get_device_name((uint32_t)device)); 339 | return device; 340 | } 341 | /* does string prefix match a serial */ 342 | for (i = 0; i < device_count; i++) 343 | { 344 | if(rtlsdr_get_device_usb_strings(i, vendor, product, serial) < 0) 345 | continue; 346 | if (strncmp(s, serial, strlen(s)) != 0) 347 | continue; 348 | device = i; 349 | fprintf(stderr, "Using device %d: %s\n", 350 | device, rtlsdr_get_device_name((uint32_t)device)); 351 | return device; 352 | } 353 | /* does string suffix match a serial */ 354 | for (i = 0; i < device_count; i++) 355 | { 356 | if(rtlsdr_get_device_usb_strings(i, vendor, product, serial) < 0) 357 | continue; 358 | offset = strlen(serial) - strlen(s); 359 | if (offset < 0) 360 | continue; 361 | if (strncmp(s, serial+offset, strlen(s)) != 0) 362 | continue; 363 | device = i; 364 | fprintf(stderr, "Using device %d: %s\n", 365 | device, rtlsdr_get_device_name((uint32_t)device)); 366 | return device; 367 | } 368 | fprintf(stderr, "No matching devices found.\n"); 369 | return -1; 370 | } 371 | -------------------------------------------------------------------------------- /src/convenience/convenience.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 by Kyle Keen 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | #ifndef __CONVENIENCE_H 18 | #define __CONVENIENCE_H 19 | 20 | #include 21 | 22 | #ifdef _WIN32 23 | int gettimeofday(struct timeval *tv, void* ignored); 24 | #endif 25 | 26 | /* a collection of user friendly tools */ 27 | 28 | /*! 29 | * Convert standard suffixes (k, M, G) to double 30 | * 31 | * \param s a string to be parsed 32 | * \return double 33 | */ 34 | 35 | double atofs(char *s); 36 | 37 | /*! 38 | * Convert time suffixes (s, m, h) to double 39 | * 40 | * \param s a string to be parsed 41 | * \return seconds as double 42 | */ 43 | 44 | double atoft(char *s); 45 | 46 | /*! 47 | * Convert percent suffixe (%) to double 48 | * 49 | * \param s a string to be parsed 50 | * \return double 51 | */ 52 | 53 | double atofp(char *s); 54 | 55 | /*! 56 | * Find nearest supported gain 57 | * 58 | * \param dev the device handle given by rtlsdr_open() 59 | * \param target_gain in tenths of a dB 60 | * \return 0 on success 61 | */ 62 | 63 | int nearest_gain(rtlsdr_dev_t *dev, int target_gain); 64 | 65 | /*! 66 | * Set device frequency and report status on stderr 67 | * 68 | * \param dev the device handle given by rtlsdr_open() 69 | * \param frequency in Hz 70 | * \return 0 on success 71 | */ 72 | 73 | int verbose_set_frequency(rtlsdr_dev_t *dev, uint32_t frequency); 74 | 75 | /*! 76 | * Set device sample rate and report status on stderr 77 | * 78 | * \param dev the device handle given by rtlsdr_open() 79 | * \param samp_rate in samples/second 80 | * \return 0 on success 81 | */ 82 | 83 | int verbose_set_sample_rate(rtlsdr_dev_t *dev, uint32_t samp_rate); 84 | 85 | /*! 86 | * Set device bandwidth and report status on stderr 87 | * 88 | * \param dev the device handle given by rtlsdr_open() 89 | * \param frequency in Hz 90 | * \return 0 on success 91 | */ 92 | 93 | int verbose_set_bandwidth(rtlsdr_dev_t *dev, uint32_t bandwidth); 94 | 95 | 96 | /*! 97 | * Enable or disable the direct sampling mode and report status on stderr 98 | * 99 | * \param dev the device handle given by rtlsdr_open() 100 | * \param on 0 means disabled, 1 I-ADC input enabled, 2 Q-ADC input enabled 101 | * \return 0 on success 102 | */ 103 | 104 | int verbose_direct_sampling(rtlsdr_dev_t *dev, int on); 105 | 106 | /*! 107 | * Enable offset tuning and report status on stderr 108 | * 109 | * \param dev the device handle given by rtlsdr_open() 110 | * \return 0 on success 111 | */ 112 | 113 | int verbose_offset_tuning(rtlsdr_dev_t *dev); 114 | 115 | /*! 116 | * Enable auto gain and report status on stderr 117 | * 118 | * \param dev the device handle given by rtlsdr_open() 119 | * \return 0 on success 120 | */ 121 | 122 | int verbose_auto_gain(rtlsdr_dev_t *dev); 123 | 124 | /*! 125 | * Set tuner gain and report status on stderr 126 | * 127 | * \param dev the device handle given by rtlsdr_open() 128 | * \param gain in tenths of a dB 129 | * \return 0 on success 130 | */ 131 | 132 | int verbose_gain_set(rtlsdr_dev_t *dev, int gain); 133 | 134 | /*! 135 | * Set the frequency correction value for the device and report status on stderr. 136 | * 137 | * \param dev the device handle given by rtlsdr_open() 138 | * \param ppm_error correction value in parts per million (ppm) 139 | * \return 0 on success 140 | */ 141 | 142 | int verbose_ppm_set(rtlsdr_dev_t *dev, float ppm_error); 143 | 144 | /*! 145 | * Reset buffer 146 | * 147 | * \param dev the device handle given by rtlsdr_open() 148 | * \return 0 on success 149 | */ 150 | 151 | int verbose_reset_buffer(rtlsdr_dev_t *dev); 152 | 153 | /*! 154 | * Find the closest matching device. 155 | * 156 | * \param s a string to be parsed 157 | * \return dev_index int, -1 on error 158 | */ 159 | 160 | int verbose_device_search(char *s); 161 | 162 | 163 | #endif /*__CONVENIENCE_H*/ 164 | -------------------------------------------------------------------------------- /src/convenience/wavewrite.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 by Hayati Ayguen 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #include "wavewrite.h" 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #ifndef _WIN32 27 | #include 28 | #include 29 | #else 30 | #include 31 | #include 32 | #include 33 | #include 34 | #define _USE_MATH_DEFINES 35 | #endif 36 | 37 | #include 38 | 39 | #ifndef _WIN32 40 | 41 | void executeInBackground( char * file, char * args, char * searchStr[], char * replaceStr[] ) 42 | { 43 | pid_t pid; 44 | char * argv[256] = { NULL }; 45 | int k, argc = 0; 46 | argv[argc++] = file; 47 | if (args) { 48 | argv[argc] = strtok(args, " "); 49 | while (argc < 256 && argv[argc]) { 50 | argv[++argc] = strtok(NULL, " "); 51 | for (k=0; argv[argc] && searchStr && replaceStr && searchStr[k] && replaceStr[k]; k++) { 52 | if (!strcmp(argv[argc], searchStr[k])) { 53 | argv[argc] = replaceStr[k]; 54 | break; 55 | } 56 | } 57 | } 58 | } 59 | 60 | pid = fork(); 61 | switch (pid) 62 | { 63 | case -1: 64 | /* Fork() has failed */ 65 | fprintf(stderr, "error: fork for '%s' failed!\n", file); 66 | break; 67 | case 0: 68 | execvp(file, argv); 69 | fprintf(stderr, "error: execv of '%s' from within fork failed!\n", file); 70 | exit(10); 71 | break; 72 | default: 73 | /* This is processed by the parent */ 74 | break; 75 | } 76 | } 77 | 78 | #else 79 | 80 | void executeInBackground( char * file, char * args, char * searchStr[], char * replaceStr[] ) 81 | { 82 | char * argv[256] = { NULL }; 83 | int k, argc = 0; 84 | argv[argc++] = file; 85 | if (args) { 86 | argv[argc] = strtok(args, " \t"); 87 | while (argc < 256 && argv[argc]) { 88 | argv[++argc] = strtok(NULL, " \t"); 89 | for (k=0; argv[argc] && searchStr && replaceStr && searchStr[k] && replaceStr[k]; k++) { 90 | if (!strcmp(argv[argc], searchStr[k])) { 91 | argv[argc] = replaceStr[k]; 92 | break; 93 | } 94 | } 95 | } 96 | } 97 | 98 | spawnvp(P_NOWAIT, file, argv); 99 | } 100 | 101 | int gettimeofday(struct timeval *tv, void* ignored); 102 | 103 | #endif 104 | 105 | 106 | #pragma pack(push) 107 | #pragma pack(1) 108 | 109 | typedef struct { 110 | uint16_t wYear; /* 1601 through 30827 */ 111 | uint16_t wMonth; /* 1..12 */ 112 | uint16_t wDayOfWeek; /* 0 .. 6: 0 == Sunday, .., 6 == Saturday */ 113 | uint16_t wDay; /* 1 .. 31 */ 114 | uint16_t wHour; /* 0 .. 23 */ 115 | uint16_t wMinute; /* 0 .. 59 */ 116 | uint16_t wSecond; /* 0 .. 59 */ 117 | uint16_t wMilliseconds; /* 0 .. 999 */ 118 | } Wind_SystemTime; 119 | 120 | 121 | typedef struct 122 | { 123 | /* RIFF header */ 124 | char riffID[4]; /* "RIFF" string */ 125 | uint32_t riffSize; /* full filesize - 8 bytes (maybe with some byte missing...) */ 126 | char waveID[4]; /* "WAVE" string */ 127 | 128 | /* FMT header */ 129 | char fmtID[4]; /* = "FMT " */ 130 | uint32_t fmtSize; 131 | int16_t wFormatTag; 132 | int16_t nChannels; 133 | int32_t nSamplesPerSec; 134 | int32_t nAvgBytesPerSec; 135 | int16_t nBlockAlign; 136 | int16_t nBitsPerSample; 137 | 138 | /* auxi header - used by SpectraVue / rfspace / HDSDR / .. */ 139 | char auxiID[4]; /* ="auxi" (chunk rfspace) */ 140 | uint32_t auxiSize; 141 | Wind_SystemTime StartTime; 142 | Wind_SystemTime StopTime; 143 | uint32_t centerFreq; /* receiver center frequency */ 144 | uint32_t ADsamplerate; /* A/D sample frequency before downsampling */ 145 | uint32_t IFFrequency; /* IF freq if an external down converter is used */ 146 | uint32_t Bandwidth; /* displayable BW if you want to limit the display to less than Nyquist band */ 147 | int32_t IQOffset; /* DC offset of the I and Q channels in 1/1000's of a count */ 148 | int32_t Unused2; 149 | int32_t Unused3; 150 | int32_t Unused4; 151 | int32_t Unused5; 152 | 153 | /* DATA header */ 154 | char dataID[4]; 155 | uint32_t dataSize; 156 | } waveFileHeader; 157 | 158 | static waveFileHeader waveHdr; 159 | 160 | #pragma pack(pop) 161 | 162 | 163 | uint32_t waveDataSize = 0; 164 | static int waveHdrStarted = 0; 165 | 166 | void waveSetTime(Wind_SystemTime *p) 167 | { 168 | struct timeval tv; 169 | struct tm t; 170 | 171 | gettimeofday(&tv, NULL); 172 | p->wMilliseconds = tv.tv_usec / 1000; 173 | 174 | #ifdef _WIN32 175 | t = *gmtime(&tv.tv_sec); 176 | #else 177 | gmtime_r(&tv.tv_sec, &t); 178 | #endif 179 | 180 | p->wYear = t.tm_year + 1900; /* 1601 through 30827 */ 181 | p->wMonth = t.tm_mon + 1; /* 1..12 */ 182 | p->wDayOfWeek = t.tm_wday; /* 0 .. 6: 0 == Sunday, .., 6 == Saturday */ 183 | p->wDay = t.tm_mday; /* 1 .. 31 */ 184 | p->wHour = t.tm_hour; /* 0 .. 23 */ 185 | p->wMinute = t.tm_min; /* 0 .. 59 */ 186 | p->wSecond = t.tm_sec; /* 0 .. 59 */ 187 | } 188 | 189 | void wavePrepareHeader(unsigned samplerate, unsigned freq, int bitsPerSample, int numChannels) 190 | { 191 | int bytesPerSample = bitsPerSample / 8; 192 | int bytesPerFrame = bytesPerSample * numChannels; 193 | 194 | memcpy( waveHdr.riffID, "RIFF", 4 ); 195 | waveHdr.riffSize = sizeof(waveFileHeader) - 8; /* to fix */ 196 | memcpy( waveHdr.waveID, "WAVE", 4 ); 197 | 198 | memcpy( waveHdr.fmtID, "fmt ", 4 ); 199 | waveHdr.fmtSize = 16; 200 | waveHdr.wFormatTag = 1; /* PCM */ 201 | waveHdr.nChannels = numChannels; /* I and Q channels */ 202 | waveHdr.nSamplesPerSec = samplerate; 203 | waveHdr.nAvgBytesPerSec = samplerate * bytesPerFrame; 204 | waveHdr.nBlockAlign = waveHdr.nChannels; 205 | waveHdr.nBitsPerSample = bitsPerSample; 206 | 207 | memcpy( waveHdr.auxiID, "auxi", 4 ); 208 | waveHdr.auxiSize = 2 * sizeof(Wind_SystemTime) + 9 * sizeof(int32_t); /* = 2 * 16 + 9 * 4 = 68 */ 209 | waveSetTime( &waveHdr.StartTime ); 210 | waveHdr.StopTime = waveHdr.StartTime; /* to fix */ 211 | waveHdr.centerFreq = freq; 212 | waveHdr.ADsamplerate = samplerate; 213 | waveHdr.IFFrequency = 0; 214 | waveHdr.Bandwidth = 0; 215 | waveHdr.IQOffset = 0; 216 | waveHdr.Unused2 = 0; 217 | waveHdr.Unused3 = 0; 218 | waveHdr.Unused4 = 0; 219 | waveHdr.Unused5 = 0; 220 | 221 | memcpy( waveHdr.dataID, "data", 4 ); 222 | waveHdr.dataSize = 0; /* to fix later */ 223 | waveDataSize = 0; 224 | } 225 | 226 | void waveWriteHeader(unsigned samplerate, unsigned freq, int bitsPerSample, int numChannels, FILE * f) 227 | { 228 | if (f != stdout) { 229 | assert( !waveHdrStarted ); 230 | wavePrepareHeader(samplerate, freq, bitsPerSample, numChannels); 231 | fwrite(&waveHdr, sizeof(waveFileHeader), 1, f); 232 | waveHdrStarted = 1; 233 | } 234 | } 235 | 236 | void waveFinalizeHeader(FILE * f) 237 | { 238 | if (f != stdout) { 239 | assert( waveHdrStarted ); 240 | waveSetTime( &waveHdr.StopTime ); 241 | waveHdr.dataSize = waveDataSize; 242 | waveHdr.riffSize += waveDataSize; 243 | 244 | fseek(f, 0, SEEK_SET); 245 | fwrite(&waveHdr, sizeof(waveFileHeader), 1, f); 246 | waveHdrStarted = 0; 247 | } 248 | } 249 | -------------------------------------------------------------------------------- /src/convenience/wavewrite.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 by Hayati Ayguen 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | #ifndef __WAVEWRITE_H 18 | #define __WAVEWRITE_H 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | 29 | void executeInBackground( char * file, char * args, char * searchStr[], char * replaceStr[] ); 30 | 31 | 32 | /*! 33 | * helper functions to write and finalize wave headers 34 | * with compatibility to some SDR programs - showing frequency: 35 | * raw sample data still have to be written by caller to FILE*. 36 | * call waveWriteHeader() before writing anything to to file 37 | * and call waveFinalizeHeader() afterwards, 38 | * AND count/increment the written raw size in variable 'waveDataSize'. 39 | * stdout/stdout can't be used, because seek to begin isn't possible. 40 | * 41 | */ 42 | 43 | extern uint32_t waveDataSize; 44 | void waveWriteHeader(unsigned samplerate, unsigned freq, int bitsPerSample, int numChannels, FILE * f); 45 | void waveFinalizeHeader(FILE * f); 46 | 47 | #ifdef __cplusplus 48 | } 49 | #endif 50 | 51 | #endif /*__WAVEWRITE_H*/ 52 | -------------------------------------------------------------------------------- /src/getopt/getopt.h: -------------------------------------------------------------------------------- 1 | /* Declarations for getopt. 2 | Copyright (C) 1989-1994, 1996-1999, 2001 Free Software Foundation, Inc. 3 | This file is part of the GNU C Library. 4 | 5 | The GNU C Library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | The GNU C Library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with the GNU C Library; if not, write to the Free 17 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 18 | 02111-1307 USA. */ 19 | 20 | #ifndef _GETOPT_H 21 | 22 | #ifndef __need_getopt 23 | # define _GETOPT_H 1 24 | #endif 25 | 26 | /* If __GNU_LIBRARY__ is not already defined, either we are being used 27 | standalone, or this is the first header included in the source file. 28 | If we are being used with glibc, we need to include , but 29 | that does not exist if we are standalone. So: if __GNU_LIBRARY__ is 30 | not defined, include , which will pull in for us 31 | if it's from glibc. (Why ctype.h? It's guaranteed to exist and it 32 | doesn't flood the namespace with stuff the way some other headers do.) */ 33 | #if !defined __GNU_LIBRARY__ 34 | # include 35 | #endif 36 | 37 | #ifdef __cplusplus 38 | extern "C" { 39 | #endif 40 | 41 | /* For communication from `getopt' to the caller. 42 | When `getopt' finds an option that takes an argument, 43 | the argument value is returned here. 44 | Also, when `ordering' is RETURN_IN_ORDER, 45 | each non-option ARGV-element is returned here. */ 46 | 47 | extern char *optarg; 48 | 49 | /* Index in ARGV of the next element to be scanned. 50 | This is used for communication to and from the caller 51 | and for communication between successive calls to `getopt'. 52 | 53 | On entry to `getopt', zero means this is the first call; initialize. 54 | 55 | When `getopt' returns -1, this is the index of the first of the 56 | non-option elements that the caller should itself scan. 57 | 58 | Otherwise, `optind' communicates from one call to the next 59 | how much of ARGV has been scanned so far. */ 60 | 61 | extern int optind; 62 | 63 | /* Callers store zero here to inhibit the error message `getopt' prints 64 | for unrecognized options. */ 65 | 66 | extern int opterr; 67 | 68 | /* Set to an option character which was unrecognized. */ 69 | 70 | extern int optopt; 71 | 72 | #ifndef __need_getopt 73 | /* Describe the long-named options requested by the application. 74 | The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector 75 | of `struct option' terminated by an element containing a name which is 76 | zero. 77 | 78 | The field `has_arg' is: 79 | no_argument (or 0) if the option does not take an argument, 80 | required_argument (or 1) if the option requires an argument, 81 | optional_argument (or 2) if the option takes an optional argument. 82 | 83 | If the field `flag' is not NULL, it points to a variable that is set 84 | to the value given in the field `val' when the option is found, but 85 | left unchanged if the option is not found. 86 | 87 | To have a long-named option do something other than set an `int' to 88 | a compiled-in constant, such as set a value from `optarg', set the 89 | option's `flag' field to zero and its `val' field to a nonzero 90 | value (the equivalent single-letter option character, if there is 91 | one). For long options that have a zero `flag' field, `getopt' 92 | returns the contents of the `val' field. */ 93 | 94 | struct option 95 | { 96 | # if (defined __STDC__ && __STDC__) || defined __cplusplus 97 | const char *name; 98 | # else 99 | char *name; 100 | # endif 101 | /* has_arg can't be an enum because some compilers complain about 102 | type mismatches in all the code that assumes it is an int. */ 103 | int has_arg; 104 | int *flag; 105 | int val; 106 | }; 107 | 108 | /* Names for the values of the `has_arg' field of `struct option'. */ 109 | 110 | # define no_argument 0 111 | # define required_argument 1 112 | # define optional_argument 2 113 | #endif /* need getopt */ 114 | 115 | 116 | /* Get definitions and prototypes for functions to process the 117 | arguments in ARGV (ARGC of them, minus the program name) for 118 | options given in OPTS. 119 | 120 | Return the option character from OPTS just read. Return -1 when 121 | there are no more options. For unrecognized options, or options 122 | missing arguments, `optopt' is set to the option letter, and '?' is 123 | returned. 124 | 125 | The OPTS string is a list of characters which are recognized option 126 | letters, optionally followed by colons, specifying that that letter 127 | takes an argument, to be placed in `optarg'. 128 | 129 | If a letter in OPTS is followed by two colons, its argument is 130 | optional. This behavior is specific to the GNU `getopt'. 131 | 132 | The argument `--' causes premature termination of argument 133 | scanning, explicitly telling `getopt' that there are no more 134 | options. 135 | 136 | If OPTS begins with `--', then non-option arguments are treated as 137 | arguments to the option '\0'. This behavior is specific to the GNU 138 | `getopt'. */ 139 | 140 | #if (defined __STDC__ && __STDC__) || defined __cplusplus 141 | # ifdef __GNU_LIBRARY__ 142 | /* Many other libraries have conflicting prototypes for getopt, with 143 | differences in the consts, in stdlib.h. To avoid compilation 144 | errors, only prototype getopt for the GNU C library. */ 145 | extern int getopt (int __argc, char *const *__argv, const char *__shortopts); 146 | # else /* not __GNU_LIBRARY__ */ 147 | extern int getopt (); 148 | # endif /* __GNU_LIBRARY__ */ 149 | 150 | # ifndef __need_getopt 151 | extern int getopt_long (int __argc, char *const *__argv, const char *__shortopts, 152 | const struct option *__longopts, int *__longind); 153 | extern int getopt_long_only (int __argc, char *const *__argv, 154 | const char *__shortopts, 155 | const struct option *__longopts, int *__longind); 156 | 157 | /* Internal only. Users should not call this directly. */ 158 | extern int _getopt_internal (int __argc, char *const *__argv, 159 | const char *__shortopts, 160 | const struct option *__longopts, int *__longind, 161 | int __long_only); 162 | # endif 163 | #else /* not __STDC__ */ 164 | extern int getopt (); 165 | # ifndef __need_getopt 166 | extern int getopt_long (); 167 | extern int getopt_long_only (); 168 | 169 | extern int _getopt_internal (); 170 | # endif 171 | #endif /* __STDC__ */ 172 | 173 | #ifdef __cplusplus 174 | } 175 | #endif 176 | 177 | /* Make sure we later can get all the definitions and declarations. */ 178 | #undef __need_getopt 179 | 180 | #endif /* getopt.h */ 181 | -------------------------------------------------------------------------------- /src/rtl_biast.c: -------------------------------------------------------------------------------- 1 | /* 2 | * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver 3 | * rtl_biast, tool to set bias tee gpio output 4 | * Copyright (C) 2012 by Steve Markgraf 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #ifndef _WIN32 25 | #include 26 | #else 27 | #include 28 | #include "getopt/getopt.h" 29 | #endif 30 | 31 | #include "rtl-sdr.h" 32 | #include "convenience/convenience.h" 33 | 34 | static rtlsdr_dev_t *dev = NULL; 35 | 36 | void usage(void) 37 | { 38 | fprintf(stderr, 39 | "rtl_biast, a tool for turning the RTL-SDR.com \n" 40 | "bias tee or any GPIO ON and OFF. Example to turn on the \n" 41 | "bias tee: rtl_biast -d 0 -b 1\n" 42 | "Any GPIO: rtl_biast -d 0 -g 1 -b 1\n\n" 43 | "Usage:\n" 44 | "\t[-d device_index (default: 0)]\n" 45 | "\t[-b bias_on (default: 0)]\n" 46 | "\t[-g GPIO select (default: 0)]\n"); 47 | exit(1); 48 | } 49 | 50 | int main(int argc, char **argv) 51 | { 52 | int r, opt; 53 | int dev_index = 0; 54 | int dev_given = 0; 55 | uint32_t bias_on = 0; 56 | uint32_t gpio_pin = 0; 57 | 58 | while ((opt = getopt(argc, argv, "d:b:g:h?")) != -1) { 59 | switch (opt) { 60 | case 'd': 61 | dev_index = verbose_device_search(optarg); 62 | dev_given = 1; 63 | break; 64 | case 'b': 65 | bias_on = atoi(optarg); 66 | break; 67 | case 'g': 68 | gpio_pin = atoi(optarg); 69 | break; 70 | default: 71 | usage(); 72 | break; 73 | } 74 | } 75 | 76 | if (!dev_given) { 77 | dev_index = verbose_device_search("0"); 78 | } 79 | 80 | if (dev_index < 0) { 81 | exit(1); 82 | } 83 | 84 | r = rtlsdr_open(&dev, dev_index); 85 | rtlsdr_set_bias_tee_gpio(dev, gpio_pin, bias_on); 86 | 87 | /* 88 | * Note - rtlsdr_close() in this tree does not clear the bias tee 89 | * GPIO line, so it leaves the bias tee enabled if a client program 90 | * doesn't explictly disable it. 91 | * 92 | * If that behaviour changes then another rtlsdr_close() will be 93 | * needed that takes some extension flags, and one of them should 94 | * be to either explicitly close the biast or leave it alone. 95 | */ 96 | rtlsdr_close(dev); 97 | 98 | return r >= 0 ? r : -r; 99 | } 100 | -------------------------------------------------------------------------------- /src/rtl_eeprom.c: -------------------------------------------------------------------------------- 1 | /* 2 | * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver 3 | * rtl_eeprom, EEPROM modification tool 4 | * Copyright (C) 2012 by Steve Markgraf 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #ifndef _WIN32 25 | #include 26 | #else 27 | #include 28 | #include "getopt/getopt.h" 29 | #endif 30 | 31 | #include "rtl-sdr.h" 32 | #include "version.h" 33 | 34 | #define EEPROM_SIZE 256 35 | #define MAX_STR_SIZE 256 36 | #define STR_OFFSET 0x09 37 | 38 | static rtlsdr_dev_t *dev = NULL; 39 | 40 | typedef struct rtlsdr_config { 41 | uint16_t vendor_id; 42 | uint16_t product_id; 43 | char manufacturer[MAX_STR_SIZE]; 44 | char product[MAX_STR_SIZE]; 45 | char serial[MAX_STR_SIZE]; 46 | int have_serial; 47 | int enable_ir; 48 | int remote_wakeup; 49 | int cal; 50 | char cal_values[13]; 51 | } rtlsdr_config_t; 52 | 53 | void dump_config(rtlsdr_config_t *conf) 54 | { 55 | fprintf(stderr, "__________________________________________\n"); 56 | fprintf(stderr, "Vendor ID:\t\t0x%04x\n", conf->vendor_id); 57 | fprintf(stderr, "Product ID:\t\t0x%04x\n", conf->product_id); 58 | fprintf(stderr, "Manufacturer:\t\t%s\n", conf->manufacturer); 59 | fprintf(stderr, "Product:\t\t%s\n", conf->product); 60 | fprintf(stderr, "Serial number:\t\t%s\n", conf->serial); 61 | fprintf(stderr, "Serial number enabled:\t"); 62 | fprintf(stderr, conf->have_serial ? "yes\n": "no\n"); 63 | fprintf(stderr, "IR endpoint enabled:\t"); 64 | fprintf(stderr, conf->enable_ir ? "yes\n": "no\n"); 65 | fprintf(stderr, "Remote wakeup enabled:\t"); 66 | fprintf(stderr, conf->remote_wakeup ? "yes\n": "no\n"); 67 | if(conf->cal) 68 | { 69 | fprintf(stderr, "Image rejection values:\t"); 70 | for(int i = 0; i < 13; i++) 71 | fprintf(stderr, "%02X ", conf->cal_values[i]); 72 | fprintf(stderr, "\n"); 73 | } 74 | fprintf(stderr, "__________________________________________\n"); 75 | } 76 | 77 | void usage(void) 78 | { 79 | fprintf(stderr, "rtl_eeprom, an EEPROM programming tool for RTL2832 based DVB-T receivers\n" 80 | "Version %d.%d.%d.%d, %s\n", 81 | RTLSDR_MAJOR, RTLSDR_MINOR, RTLSDR_MICRO, RTLSDR_NANO, __DATE__); 82 | fprintf(stderr, "rtlsdr library %d.%d.%d.%d %s\n\n", 83 | rtlsdr_get_version()>>24, rtlsdr_get_version()>>16 & 0xFF, 84 | rtlsdr_get_version()>>8 & 0xFF, rtlsdr_get_version() & 0xFF, 85 | rtlsdr_get_ver_id() ); 86 | fprintf(stderr, "Usage:\t[-d device_index (default: 0)]\n" 87 | "\t[-m set manufacturer string]\n" 88 | "\t[-p set product string]\n" 89 | "\t[-M set manufacturer ID (aka vendor ID) in hexadecimal]\n" 90 | "\t[-P set product ID in hexadecimal]\n" 91 | "\t[-n sets manufacturer and product ID to 0x1209/0x2832]\n" 92 | "\t[ as with '-g realtek_sdr']\n" 93 | "\t[-s set serial number string]\n" 94 | "\t[-i <0,1> disable/enable IR-endpoint]\n" 95 | "\t[-g generate default config and write to device]\n" 96 | "\t[ can be one of:]\n" 97 | "\t[ realtek\t\tRealtek default (as without EEPROM)]\n" 98 | "\t[ realtek_oem\t\tRealtek default OEM with EEPROM]\n" 99 | "\t[ noxon\t\tTerratec NOXON DAB Stick]\n" 100 | "\t[ terratec_black\tTerratec T Stick Black]\n" 101 | "\t[ terratec_plus\tTerratec T Stick+ (DVB-T/DAB)]\n" 102 | "\t[ realtek_sdr\t\tRealtek SDR - without DVB compatibility]\n" 103 | "\t[-w write dumped file to device]\n" 104 | "\t[-r dump EEPROM to file]\n" 105 | "\t[-h display this help text]\n" 106 | "\nUse on your own risk, especially -w, -M and -P!\n"); 107 | exit(1); 108 | } 109 | 110 | int get_string_descriptor(int pos, uint8_t *data, char *str) 111 | { 112 | int len, i, j = 0; 113 | 114 | len = data[pos]; 115 | 116 | if (data[pos + 1] != 0x03) 117 | fprintf(stderr, "Error: invalid string descriptor!\n"); 118 | 119 | for (i = 2; i < len; i += 2) 120 | str[j++] = data[pos + i]; 121 | 122 | str[j] = 0x00; 123 | 124 | return pos + i; 125 | } 126 | 127 | int set_string_descriptor(int pos, uint8_t *data, char *str) 128 | { 129 | int i = 0, j = 2; 130 | 131 | if (pos < 0) 132 | return -1; 133 | 134 | data[pos + 1] = 0x03; 135 | 136 | while (str[i] != 0x00) { 137 | if ((pos + j) >= 78) { 138 | fprintf(stderr, "Error: string too long, truncated!\n"); 139 | return -1; 140 | } 141 | data[pos + j++] = str[i++]; 142 | data[pos + j++] = 0x00; 143 | } 144 | 145 | data[pos] = j; 146 | 147 | return pos + j; 148 | } 149 | 150 | int parse_eeprom_to_conf(rtlsdr_config_t *conf, uint8_t *dat) 151 | { 152 | int pos, i, checksum; 153 | 154 | if ((dat[0] != 0x28) || (dat[1] != 0x32)) 155 | fprintf(stderr, "Error: invalid RTL2832 EEPROM header!\n"); 156 | 157 | conf->vendor_id = dat[2] | (dat[3] << 8); 158 | conf->product_id = dat[4] | (dat[5] << 8); 159 | conf->have_serial = (dat[6] == 0xa5) ? 1 : 0; 160 | conf->remote_wakeup = (dat[7] & 0x01) ? 1 : 0; 161 | conf->enable_ir = (dat[7] & 0x02) ? 1 : 0; 162 | 163 | conf->cal = 0; 164 | pos = 0x80; 165 | checksum = 0; 166 | for(i = 1; i < 14; i++) 167 | checksum += dat[pos+i]; 168 | if((dat[pos] == 14) && ((checksum & 0xff) == dat[pos+14])) // checksum ok 169 | { 170 | memcpy(conf->cal_values, dat+pos+1, 13); 171 | conf->cal = 1; 172 | } 173 | 174 | pos = get_string_descriptor(STR_OFFSET, dat, conf->manufacturer); 175 | pos = get_string_descriptor(pos, dat, conf->product); 176 | get_string_descriptor(pos, dat, conf->serial); 177 | 178 | return 0; 179 | } 180 | 181 | int gen_eeprom_from_conf(rtlsdr_config_t *conf, uint8_t *dat) 182 | { 183 | int pos; 184 | 185 | dat[0] = 0x28; 186 | dat[1] = 0x32; 187 | dat[2] = conf->vendor_id & 0xff; 188 | dat[3] = (conf->vendor_id >> 8) & 0xff ; 189 | dat[4] = conf->product_id & 0xff; 190 | dat[5] = (conf->product_id >> 8) & 0xff; 191 | dat[6] = conf->have_serial ? 0xa5 : 0x00; 192 | dat[7] = 0x14; 193 | dat[7] |= conf->remote_wakeup ? 0x01 : 0x00; 194 | dat[7] |= conf->enable_ir ? 0x02 : 0x00; 195 | dat[8] = 0x02; 196 | 197 | pos = set_string_descriptor(STR_OFFSET, dat, conf->manufacturer); 198 | pos = set_string_descriptor(pos, dat, conf->product); 199 | pos = set_string_descriptor(pos, dat, conf->serial); 200 | 201 | dat[78] = 0x00; /* length of IR config */ 202 | 203 | return pos; 204 | } 205 | 206 | enum configs { 207 | CONF_NONE = 0, 208 | REALTEK, 209 | REALTEK_EEPROM, 210 | TERRATEC_NOXON, 211 | TERRATEC_T_BLACK, 212 | TERRATEC_T_PLUS, 213 | REALTEK_SDR, 214 | }; 215 | 216 | void gen_default_conf(rtlsdr_config_t *conf, int config) 217 | { 218 | switch (config) { 219 | case REALTEK: 220 | fprintf(stderr, "Realtek default (as without EEPROM)\n"); 221 | conf->vendor_id = 0x0bda; 222 | conf->product_id = 0x2832; 223 | strcpy(conf->manufacturer, "Generic"); 224 | strcpy(conf->product, "RTL2832U DVB-T"); 225 | strcpy(conf->serial, "0"); 226 | conf->have_serial = 1; 227 | conf->enable_ir = 0; 228 | conf->remote_wakeup = 1; 229 | break; 230 | case REALTEK_EEPROM: 231 | fprintf(stderr, "Realtek default OEM with EEPROM\n"); 232 | conf->vendor_id = 0x0bda; 233 | conf->product_id = 0x2838; 234 | strcpy(conf->manufacturer, "Realtek"); 235 | strcpy(conf->product, "RTL2838UHIDIR"); 236 | strcpy(conf->serial, "00000001"); 237 | conf->have_serial = 1; 238 | conf->enable_ir = 1; 239 | conf->remote_wakeup = 0; 240 | break; 241 | case TERRATEC_NOXON: 242 | fprintf(stderr, "Terratec NOXON DAB Stick\n"); 243 | conf->vendor_id = 0x0ccd; 244 | conf->product_id = 0x00b3; 245 | strcpy(conf->manufacturer, "NOXON"); 246 | strcpy(conf->product, "DAB Stick"); 247 | strcpy(conf->serial, "0"); 248 | conf->have_serial = 1; 249 | conf->enable_ir = 0; 250 | conf->remote_wakeup = 1; 251 | break; 252 | case TERRATEC_T_BLACK: 253 | fprintf(stderr, "Terratec T Stick Black\n"); 254 | conf->vendor_id = 0x0ccd; 255 | conf->product_id = 0x00a9; 256 | strcpy(conf->manufacturer, "Realtek"); 257 | strcpy(conf->product, "RTL2838UHIDIR"); 258 | strcpy(conf->serial, "00000001"); 259 | conf->have_serial = 1; 260 | conf->enable_ir = 1; 261 | conf->remote_wakeup = 0; 262 | break; 263 | case TERRATEC_T_PLUS: 264 | fprintf(stderr, "Terratec ran T Stick+\n"); 265 | conf->vendor_id = 0x0ccd; 266 | conf->product_id = 0x00d7; 267 | strcpy(conf->manufacturer, "Realtek"); 268 | strcpy(conf->product, "RTL2838UHIDIR"); 269 | strcpy(conf->serial, "00000001"); 270 | conf->have_serial = 1; 271 | conf->enable_ir = 1; 272 | conf->remote_wakeup = 0; 273 | break; 274 | case REALTEK_SDR: 275 | fprintf(stderr, "Realtek SDR\n"); 276 | conf->vendor_id = 0x1209; 277 | conf->product_id = 0x2832; 278 | strcpy(conf->manufacturer, "Realtek"); 279 | strcpy(conf->product, "RTL2832U_SDR"); 280 | strcpy(conf->serial, "00000001"); 281 | conf->have_serial = 1; 282 | conf->enable_ir = 0; 283 | conf->remote_wakeup = 0; 284 | break; 285 | default: 286 | break; 287 | }; 288 | } 289 | 290 | int main(int argc, char **argv) 291 | { 292 | uint32_t i; 293 | int r, opt; 294 | uint32_t dev_index = 0; 295 | uint32_t device_count; 296 | char *filename = NULL; 297 | FILE *file = NULL; 298 | char *manuf_str = NULL; 299 | char *product_str = NULL; 300 | int manuf_id = 0; 301 | int product_id = 0; 302 | char *serial_str = NULL; 303 | uint8_t buf[EEPROM_SIZE]; 304 | rtlsdr_config_t conf; 305 | int flash_file = 0; 306 | int default_config = 0; 307 | int change = 0; 308 | int ir_endpoint = 0; 309 | char ch; 310 | 311 | while ((opt = getopt(argc, argv, "d:m:p:M:P:ns:i:g:w:r:h?")) != -1) { 312 | switch (opt) { 313 | case 'd': 314 | dev_index = atoi(optarg); 315 | break; 316 | case 'm': 317 | manuf_str = optarg; 318 | change = 1; 319 | break; 320 | case 'p': 321 | product_str = optarg; 322 | change = 1; 323 | break; 324 | case 'M': 325 | manuf_id = (int)strtol(optarg, NULL, 16); 326 | change = 1; 327 | break; 328 | case 'P': 329 | product_id = (int)strtol(optarg, NULL, 16); 330 | change = 1; 331 | break; 332 | case 'n': 333 | manuf_id = 0x1209; 334 | product_id = 0x2832; 335 | change = 1; 336 | break; 337 | case 's': 338 | serial_str = optarg; 339 | change = 1; 340 | break; 341 | case 'i': 342 | ir_endpoint = (atoi(optarg) > 0) ? 1 : -1; 343 | change = 1; 344 | break; 345 | case 'g': 346 | if (!strcmp(optarg, "realtek")) 347 | default_config = REALTEK; 348 | else if (!strcmp(optarg, "realtek_oem")) 349 | default_config = REALTEK_EEPROM; 350 | else if (!strcmp(optarg, "noxon")) 351 | default_config = TERRATEC_NOXON; 352 | else if (!strcmp(optarg, "terratec_black")) 353 | default_config = TERRATEC_T_BLACK; 354 | else if (!strcmp(optarg, "terratec_plus")) 355 | default_config = TERRATEC_T_PLUS; 356 | else if (!strcmp(optarg, "realtek_sdr")) 357 | default_config = REALTEK_SDR; 358 | if (default_config != CONF_NONE) 359 | change = 1; 360 | break; 361 | case 'w': 362 | flash_file = 1; 363 | change = 1; 364 | /* fall-through */ 365 | case 'r': 366 | filename = optarg; 367 | break; 368 | default: 369 | usage(); 370 | break; 371 | } 372 | } 373 | 374 | device_count = rtlsdr_get_device_count(); 375 | if (!device_count) { 376 | fprintf(stderr, "No supported devices found.\n"); 377 | exit(1); 378 | } 379 | 380 | fprintf(stderr, "Found %d device(s):\n", device_count); 381 | for (i = 0; i < device_count; i++) 382 | fprintf(stderr, " %d: %s\n", i, rtlsdr_get_device_name(i)); 383 | fprintf(stderr, "\n"); 384 | 385 | if(dev_index >= device_count) 386 | { 387 | fprintf(stderr, "No matching devices found.\n"); 388 | exit(1); 389 | } 390 | 391 | fprintf(stderr, "Using device %d: %s\n", 392 | dev_index, 393 | rtlsdr_get_device_name(dev_index)); 394 | 395 | r = rtlsdr_open(&dev, dev_index); 396 | if (r < 0) { 397 | fprintf(stderr, "Failed to open rtlsdr device #%d.\n", dev_index); 398 | exit(1); 399 | } 400 | 401 | fprintf(stderr, "\n"); 402 | 403 | r = rtlsdr_read_eeprom(dev, buf, 0, EEPROM_SIZE); 404 | if (r < 0) { 405 | if (r == -3) 406 | fprintf(stderr, "No EEPROM has been found.\n"); 407 | else 408 | fprintf(stderr, "Failed to read EEPROM, err %i.\n", r); 409 | goto exit; 410 | } 411 | 412 | fprintf(stderr, "Current configuration:\n"); 413 | parse_eeprom_to_conf(&conf, buf); 414 | dump_config(&conf); 415 | 416 | if (filename) { 417 | file = fopen(filename, flash_file ? "rb" : "wb"); 418 | if (!file) { 419 | fprintf(stderr, "Error opening file!\n"); 420 | goto exit; 421 | } 422 | if (flash_file) { 423 | if (fread(buf, 1, sizeof(buf), file) != sizeof(buf)) 424 | fprintf(stderr, "Error reading file!\n"); 425 | } else { 426 | if (fwrite(buf, 1, sizeof(buf), file) != sizeof(buf)) 427 | fprintf(stderr, "Short write, exiting!\n"); 428 | else 429 | fprintf(stderr, "\nDump to %s successful.\n", filename); 430 | } 431 | } 432 | 433 | if (manuf_str) 434 | strncpy((char*)&conf.manufacturer, manuf_str, MAX_STR_SIZE-1); 435 | 436 | if (product_str) 437 | strncpy((char*)&conf.product, product_str, MAX_STR_SIZE-1); 438 | 439 | if (manuf_id > 0) 440 | conf.vendor_id = manuf_id; 441 | 442 | if (product_id > 0) 443 | conf.product_id = product_id; 444 | 445 | if (serial_str) { 446 | conf.have_serial = 1; 447 | strncpy((char*)&conf.serial, serial_str, MAX_STR_SIZE-1); 448 | } 449 | 450 | if (ir_endpoint != 0) 451 | conf.enable_ir = (ir_endpoint > 0) ? 1 : 0; 452 | 453 | if (!change) 454 | goto exit; 455 | 456 | fprintf(stderr, "\nNew configuration:\n"); 457 | 458 | if (default_config != CONF_NONE) 459 | gen_default_conf(&conf, default_config); 460 | 461 | if (!flash_file) { 462 | if (gen_eeprom_from_conf(&conf, buf) < 0) 463 | goto exit; 464 | } 465 | 466 | parse_eeprom_to_conf(&conf, buf); 467 | dump_config(&conf); 468 | 469 | fprintf(stderr, "Write new configuration to device [y/n]? "); 470 | 471 | while ((ch = getchar())) { 472 | if (ch != 'y') 473 | goto exit; 474 | else 475 | break; 476 | } 477 | 478 | r = rtlsdr_write_eeprom(dev, buf, 0, flash_file ? EEPROM_SIZE : 128); 479 | if (r < 0) 480 | fprintf(stderr, "Error while writing EEPROM: %i\n", r); 481 | else 482 | fprintf(stderr, "\nConfiguration successfully written.\n" 483 | "Please replug the device for changes" 484 | " to take effect.\n"); 485 | 486 | exit: 487 | if (file) 488 | fclose(file); 489 | 490 | rtlsdr_close(dev); 491 | 492 | return r >= 0 ? r : -r; 493 | } 494 | -------------------------------------------------------------------------------- /src/rtl_ir.c: -------------------------------------------------------------------------------- 1 | /* 2 | * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver 3 | * Copyright (C) 2009 Antti Palosaari 4 | * Copyright (C) 2011 Antti Palosaari 5 | * Copyright (C) 2012 Thomas Mair 6 | * Copyright (C) 2012 by Steve Markgraf 7 | * Copyright (C) 2012 by Hoernchen 8 | * Copyright (C) 2012 by Kyle Keen 9 | * Copyright (C) 2013 by Elias Oenal 10 | * Copyright (C) 2016 by Robert X. Seger 11 | * 12 | * This program is free software: you can redistribute it and/or modify 13 | * it under the terms of the GNU General Public License as published by 14 | * the Free Software Foundation, either version 2 of the License, or 15 | * (at your option) any later version. 16 | * 17 | * This program is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | * GNU General Public License for more details. 21 | * 22 | * You should have received a copy of the GNU General Public License 23 | * along with this program. If not, see . 24 | */ 25 | 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #ifndef _WIN32 34 | #include 35 | #else 36 | #include 37 | #include 38 | #include 39 | #include "getopt/getopt.h" 40 | 41 | #if defined(_MSC_VER) && (_MSC_VER < 1800) 42 | #define round(x) (x > 0.0 ? floor(x + 0.5): ceil(x - 0.5)) 43 | #endif 44 | #define _USE_MATH_DEFINES 45 | #endif 46 | 47 | #include 48 | 49 | #include "rtl-sdr.h" 50 | #include "convenience/convenience.h" 51 | #include "version.h" 52 | 53 | static volatile int do_exit = 0; 54 | 55 | struct dongle_state 56 | { 57 | int exit_flag; 58 | rtlsdr_dev_t *dev; 59 | int dev_index; 60 | }; 61 | 62 | void dongle_init(struct dongle_state *s) 63 | { 64 | memset(s, 0, sizeof(struct dongle_state)); 65 | } 66 | 67 | struct dongle_state dongle; 68 | 69 | void usage(void) 70 | { 71 | fprintf(stderr, "rtl_ir, display received IR signals\n" 72 | "Version %d.%d.%d.%d, %s\n", 73 | RTLSDR_MAJOR, RTLSDR_MINOR, RTLSDR_MICRO, RTLSDR_NANO, __DATE__); 74 | fprintf(stderr, "rtlsdr library %d.%d.%d.%d %s\n\n", 75 | rtlsdr_get_version()>>24, rtlsdr_get_version()>>16 & 0xFF, 76 | rtlsdr_get_version()>>8 & 0xFF, rtlsdr_get_version() & 0xFF, 77 | rtlsdr_get_ver_id() ); 78 | fprintf(stderr, "Use:\trtl_ir [-options]\n" 79 | "\t[-d device_index (default: 0)]\n" 80 | "\t[-w wait_usec]\tDelay to wait before each iteration (10000)\n" 81 | "\t[-c max_count]\tMaximum number of loop iterations (0)\n" 82 | "\t[-b]\tDisplay output in binary (default), pulse=1, space=0; each 20 usec\n" 83 | "\t[-t]\tDisplay output in text format\n" 84 | "\t[-x]\tDisplay output in raw packed bytes, MSB=pulse/space, 7LSB=duration*20 usec\n" 85 | "\t[-h]\tHelp\n" 86 | ); 87 | exit(1); 88 | } 89 | 90 | #ifdef _WIN32 91 | BOOL WINAPI 92 | sighandler(int signum) 93 | { 94 | if (CTRL_C_EVENT == signum) { 95 | fprintf(stderr, "Signal caught, exiting!\n"); 96 | do_exit = 1; 97 | rtlsdr_cancel_async(dongle.dev); 98 | return TRUE; 99 | } 100 | return FALSE; 101 | } 102 | #else 103 | static void sighandler(int signum) 104 | { 105 | fprintf(stderr, "Signal caught, exiting!\n"); 106 | do_exit = 1; 107 | rtlsdr_cancel_async(dongle.dev); 108 | } 109 | #endif 110 | 111 | 112 | int main(int argc, char **argv) { 113 | #ifndef _WIN32 114 | struct sigaction sigact; 115 | #endif 116 | int r, opt; 117 | int i, j; 118 | unsigned int wait_usec = 100000; 119 | int max_count = 0, iteration_count = 0; 120 | int output_binary = 0, output_text = 0, output_packed = 0; 121 | uint8_t buf[128] = { 0 }; 122 | 123 | dongle_init(&dongle); 124 | 125 | while ((opt = getopt(argc, argv, "d:c:w:btxh")) != -1) { 126 | switch (opt) { 127 | case 'd': 128 | dongle.dev_index = verbose_device_search(optarg); 129 | break; 130 | case 'w': 131 | wait_usec = atoi(optarg); 132 | break; 133 | case 'c': 134 | max_count = atoi(optarg); 135 | break; 136 | case 'b': 137 | output_binary = 1; 138 | break; 139 | case 't': 140 | output_text = 1; 141 | break; 142 | case 'x': 143 | output_packed = 1; 144 | break; 145 | case 'h': 146 | default: 147 | usage(); 148 | break; 149 | } 150 | } 151 | 152 | if (dongle.dev_index < 0) { 153 | exit(1); 154 | } 155 | 156 | r = rtlsdr_open(&dongle.dev, (uint32_t)dongle.dev_index); 157 | if (r < 0) { 158 | fprintf(stderr, "Failed to open rtlsdr device #%d.\n", dongle.dev_index); 159 | exit(1); 160 | } 161 | #ifndef _WIN32 162 | sigact.sa_handler = sighandler; 163 | sigemptyset(&sigact.sa_mask); 164 | sigact.sa_flags = 0; 165 | sigaction(SIGINT, &sigact, NULL); 166 | sigaction(SIGTERM, &sigact, NULL); 167 | sigaction(SIGQUIT, &sigact, NULL); 168 | sigaction(SIGPIPE, &sigact, NULL); 169 | #else 170 | SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE ); 171 | #endif 172 | 173 | verbose_reset_buffer(dongle.dev); 174 | 175 | if (!output_binary && !output_text && !output_packed) 176 | output_binary = 1; 177 | 178 | while (!do_exit) { 179 | usleep(wait_usec); 180 | 181 | r = rtlsdr_ir_query(dongle.dev, buf, sizeof(buf)); 182 | if (r < 0) { 183 | fprintf(stderr, "rtlsdr_ir_query failed: %d\n", r); 184 | } 185 | 186 | for (i = 0; i < r; i++) { 187 | int pulse = buf[i] >> 7; 188 | int duration = buf[i] & 0x7f; 189 | 190 | if (output_text) { 191 | fprintf(stderr, "pulse %d, duration %d usec\n", pulse, duration * 20); 192 | } 193 | 194 | if (output_binary) { 195 | for (j = 0; j < duration; ++j) { 196 | fprintf(stderr, "%d", pulse); 197 | } 198 | } 199 | 200 | if (output_packed) { 201 | putchar(buf[i]); 202 | } 203 | } 204 | if (r != 0) fprintf(stderr, "\n"); 205 | fflush(stdout); 206 | 207 | if (max_count != 0 && ++iteration_count >= max_count) do_exit = 1; 208 | } 209 | 210 | if (do_exit) { 211 | fprintf(stderr, "\nUser cancel, exiting...\n");} 212 | else { 213 | fprintf(stderr, "\nLibrary error %d, exiting...\n", r);} 214 | 215 | rtlsdr_cancel_async(dongle.dev); 216 | 217 | rtlsdr_close(dongle.dev); 218 | return r >= 0 ? r : -r; 219 | 220 | return 0; 221 | } 222 | -------------------------------------------------------------------------------- /src/rtl_sdr.c: -------------------------------------------------------------------------------- 1 | /* 2 | * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver 3 | * Copyright (C) 2012 by Steve Markgraf 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #ifndef _WIN32 26 | #include 27 | #else 28 | #include 29 | #include 30 | #include 31 | #include "getopt/getopt.h" 32 | #endif 33 | 34 | #include "rtl-sdr.h" 35 | #include "convenience/convenience.h" 36 | #include "convenience/wavewrite.h" 37 | #include "version.h" 38 | 39 | #define DEFAULT_SAMPLE_RATE 2048000 40 | #define DEFAULT_BANDWIDTH 0 /* automatic bandwidth */ 41 | #define DEFAULT_BUF_LENGTH (16 * 16384) 42 | #define MINIMAL_BUF_LENGTH 512 43 | #define MAXIMAL_BUF_LENGTH (256 * 16384) 44 | 45 | static int do_exit = 0; 46 | static uint32_t bytes_to_read = 0; 47 | static rtlsdr_dev_t *dev = NULL; 48 | 49 | void usage(void) 50 | { 51 | fprintf(stderr, "rtl_sdr, an I/Q recorder for RTL2832 based DVB-T receivers\n" 52 | "Version %d.%d.%d.%d, %s\n", 53 | RTLSDR_MAJOR, RTLSDR_MINOR, RTLSDR_MICRO, RTLSDR_NANO, __DATE__); 54 | fprintf(stderr, "rtlsdr library %d.%d.%d.%d %s\n\n", 55 | rtlsdr_get_version()>>24, rtlsdr_get_version()>>16 & 0xFF, 56 | rtlsdr_get_version()>>8 & 0xFF, rtlsdr_get_version() & 0xFF, 57 | rtlsdr_get_ver_id() ); 58 | fprintf(stderr, "Usage:\t -f frequency_to_tune_to [Hz]\n" 59 | "\t[-s samplerate (default: 2048000 Hz)]\n" 60 | "\t[-w tuner_bandwidth (default: automatic)]\n" 61 | "\t[-d device_index or serial (default: 0)]\n" 62 | "\t[-g gain (default: 0 for auto)]\n" 63 | "\t 0 = hardware AGC, <0 = software AGC, >0 = gain in dB\n" 64 | "\t[-p ppm_error (default: 0)]\n" 65 | "\t[-O set RTL options string seperated with ':' ]\n" 66 | "\t f=:bw=:agc=:gain=\n" 67 | "\t dagc=:ds=:T=\n" 68 | "\t[-b output_block_size (default: 16 * 16384)]\n" 69 | "\t[-n number of samples to read (default: 0, infinite)]\n" 70 | "\t[-S force sync output (default: async)]\n" 71 | "\t[-H write wave Header to file (default: off)]\n" 72 | "\tfilename (a '-' dumps samples to stdout)\n\n"); 73 | exit(1); 74 | } 75 | 76 | #ifdef _WIN32 77 | BOOL WINAPI 78 | sighandler(int signum) 79 | { 80 | if (CTRL_C_EVENT == signum) { 81 | fprintf(stderr, "Signal caught, exiting!\n"); 82 | do_exit = 1; 83 | rtlsdr_cancel_async(dev); 84 | return TRUE; 85 | } 86 | return FALSE; 87 | } 88 | #else 89 | static void sighandler(int signum) 90 | { 91 | fprintf(stderr, "Signal caught, exiting!\n"); 92 | do_exit = 1; 93 | rtlsdr_cancel_async(dev); 94 | } 95 | #endif 96 | 97 | static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx) 98 | { 99 | if (ctx) { 100 | if (do_exit) 101 | return; 102 | 103 | if ((bytes_to_read > 0) && (bytes_to_read < len)) { 104 | len = bytes_to_read; 105 | do_exit = 1; 106 | rtlsdr_cancel_async(dev); 107 | } 108 | 109 | if (fwrite(buf, 1, len, (FILE*)ctx) != len) { 110 | fprintf(stderr, "Short write, samples lost, exiting!\n"); 111 | rtlsdr_cancel_async(dev); 112 | } 113 | else 114 | { 115 | waveDataSize += len; 116 | } 117 | 118 | if (bytes_to_read > 0) 119 | bytes_to_read -= len; 120 | } 121 | } 122 | 123 | int main(int argc, char **argv) 124 | { 125 | #ifndef _WIN32 126 | struct sigaction sigact; 127 | #endif 128 | char *filename = NULL; 129 | int n_read; 130 | int r, opt; 131 | int gain = 0; 132 | float ppm_error = 0; 133 | int sync_mode = 0; 134 | FILE *file; 135 | uint8_t *buffer; 136 | const char * rtlOpts = NULL; 137 | int dev_index = 0; 138 | int dev_given = 0; 139 | int writeWav = 0; 140 | uint32_t frequency = 100000000; 141 | uint32_t bandwidth = DEFAULT_BANDWIDTH; 142 | uint32_t samp_rate = DEFAULT_SAMPLE_RATE; 143 | uint32_t out_block_size = DEFAULT_BUF_LENGTH; 144 | int verbosity = 0; 145 | 146 | while ((opt = getopt(argc, argv, "d:f:g:s:w:b:n:p:O:SHvh")) != -1) { 147 | switch (opt) { 148 | case 'd': 149 | dev_index = verbose_device_search(optarg); 150 | dev_given = 1; 151 | break; 152 | case 'f': 153 | frequency = (uint32_t)atofs(optarg); 154 | break; 155 | case 'g': 156 | gain = (int)(atof(optarg) * 10); /* tenths of a dB */ 157 | break; 158 | case 's': 159 | samp_rate = (uint32_t)atofs(optarg); 160 | break; 161 | case 'w': 162 | bandwidth = (uint32_t)atofs(optarg); 163 | break; 164 | case 'p': 165 | ppm_error = atof(optarg); 166 | break; 167 | case 'O': 168 | rtlOpts = optarg; 169 | break; 170 | case 'b': 171 | out_block_size = (uint32_t)atof(optarg); 172 | break; 173 | case 'n': 174 | bytes_to_read = (uint32_t)atof(optarg) * 2; 175 | break; 176 | case 'S': 177 | sync_mode = 1; 178 | break; 179 | case 'H': 180 | writeWav = 1; 181 | break; 182 | case 'v': 183 | ++verbosity; 184 | break; 185 | case 'h': 186 | default: 187 | usage(); 188 | break; 189 | } 190 | } 191 | 192 | if (argc <= optind) { 193 | usage(); 194 | } else { 195 | filename = argv[optind]; 196 | } 197 | 198 | if(out_block_size < MINIMAL_BUF_LENGTH || 199 | out_block_size > MAXIMAL_BUF_LENGTH ){ 200 | fprintf(stderr, "Output block size wrong value, falling back to default\n"); 201 | fprintf(stderr, "Minimal length: %u\n", MINIMAL_BUF_LENGTH); 202 | fprintf(stderr, "Maximal length: %u\n", MAXIMAL_BUF_LENGTH); 203 | out_block_size = DEFAULT_BUF_LENGTH; 204 | } 205 | 206 | buffer = malloc(out_block_size * sizeof(uint8_t)); 207 | 208 | if (!dev_given) { 209 | dev_index = verbose_device_search("0"); 210 | } 211 | 212 | if (dev_index < 0) { 213 | exit(1); 214 | } 215 | 216 | r = rtlsdr_open(&dev, (uint32_t)dev_index); 217 | if (r < 0) { 218 | fprintf(stderr, "Failed to open rtlsdr device #%d.\n", dev_index); 219 | exit(1); 220 | } 221 | #ifndef _WIN32 222 | sigact.sa_handler = sighandler; 223 | sigemptyset(&sigact.sa_mask); 224 | sigact.sa_flags = 0; 225 | sigaction(SIGINT, &sigact, NULL); 226 | sigaction(SIGTERM, &sigact, NULL); 227 | sigaction(SIGQUIT, &sigact, NULL); 228 | sigaction(SIGPIPE, &sigact, NULL); 229 | #else 230 | SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE ); 231 | #endif 232 | /* Set the sample rate */ 233 | verbose_set_sample_rate(dev, samp_rate); 234 | 235 | /* Set the frequency */ 236 | verbose_set_frequency(dev, frequency); 237 | 238 | /* Set the tuner bandwidth */ 239 | verbose_set_bandwidth(dev, bandwidth); 240 | 241 | if (0 == gain) { 242 | /* Enable automatic gain */ 243 | verbose_auto_gain(dev); 244 | rtlsdr_set_agc_mode(dev, 1); 245 | fprintf(stderr, "Set agc mode 1\n"); 246 | } 247 | else if(gain < 0) { 248 | fprintf(stderr, "Set software AGC\n"); 249 | rtlsdr_set_tuner_gain_mode(dev, 2); 250 | } else { 251 | /* Enable manual gain */ 252 | gain = nearest_gain(dev, gain); 253 | verbose_gain_set(dev, gain); 254 | } 255 | 256 | if (rtlOpts) { 257 | rtlsdr_set_opt_string(dev, rtlOpts, verbosity); 258 | } 259 | 260 | verbose_ppm_set(dev, ppm_error); 261 | 262 | if(strcmp(filename, "-") == 0) { /* Write samples to stdout */ 263 | file = stdout; 264 | #ifdef _WIN32 265 | _setmode(_fileno(stdin), _O_BINARY); 266 | #endif 267 | } else { 268 | file = fopen(filename, "wb"); 269 | if (!file) { 270 | fprintf(stderr, "Failed to open %s\n", filename); 271 | goto out; 272 | } 273 | if (writeWav) { 274 | waveWriteHeader(samp_rate, frequency, 8, 2, file); 275 | } 276 | } 277 | 278 | /* Reset endpoint before we start reading from it (mandatory) */ 279 | verbose_reset_buffer(dev); 280 | 281 | if (sync_mode) { 282 | fprintf(stderr, "Reading samples in sync mode...\n"); 283 | while (!do_exit) { 284 | r = rtlsdr_read_sync(dev, buffer, out_block_size, &n_read); 285 | if (r < 0) { 286 | fprintf(stderr, "WARNING: sync read failed.\n"); 287 | break; 288 | } 289 | 290 | if ((bytes_to_read > 0) && (bytes_to_read < (uint32_t)n_read)) { 291 | n_read = bytes_to_read; 292 | do_exit = 1; 293 | } 294 | 295 | if (fwrite(buffer, 1, n_read, file) != (size_t)n_read) { 296 | fprintf(stderr, "Short write, samples lost, exiting!\n"); 297 | break; 298 | } 299 | waveDataSize += n_read; 300 | 301 | if ((uint32_t)n_read < out_block_size) { 302 | fprintf(stderr, "Short read, samples lost, exiting!\n"); 303 | break; 304 | } 305 | 306 | if (bytes_to_read > 0) 307 | bytes_to_read -= n_read; 308 | } 309 | } else { 310 | fprintf(stderr, "Reading samples in async mode...\n"); 311 | r = rtlsdr_read_async(dev, rtlsdr_callback, (void *)file, 312 | 0, out_block_size); 313 | } 314 | 315 | if (writeWav) { 316 | waveFinalizeHeader(file); 317 | } 318 | 319 | if (do_exit) 320 | fprintf(stderr, "\nUser cancel, exiting...\n"); 321 | else 322 | fprintf(stderr, "\nLibrary error %d, exiting...\n", r); 323 | 324 | if (file != stdout) 325 | fclose(file); 326 | 327 | rtlsdr_close(dev); 328 | free (buffer); 329 | out: 330 | return r >= 0 ? r : -r; 331 | } 332 | -------------------------------------------------------------------------------- /src/rtl_test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver 3 | * rtl_test, test and benchmark tool 4 | * 5 | * Copyright (C) 2012-2014 by Steve Markgraf 6 | * Copyright (C) 2012-2014 by Kyle Keen 7 | * Copyright (C) 2014 by Michael Tatarinov 8 | * 9 | * This program is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program. If not, see . 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #ifndef _WIN32 31 | #include 32 | #include 33 | #include 34 | #else 35 | #include 36 | #include "getopt/getopt.h" 37 | #endif 38 | 39 | #include "rtl-sdr.h" 40 | #include "convenience/convenience.h" 41 | #include "version.h" 42 | 43 | #define DEFAULT_SAMPLE_RATE 2048000 44 | 45 | #define MHZ(x) ((x)*1000*1000) 46 | 47 | #define PPM_DURATION 10 48 | #define PPM_DUMP_TIME 5 49 | 50 | struct time_generic 51 | /* holds all the platform specific values */ 52 | { 53 | #ifndef _WIN32 54 | time_t tv_sec; 55 | long tv_nsec; 56 | #else 57 | long tv_sec; 58 | long tv_nsec; 59 | int init; 60 | LARGE_INTEGER frequency; 61 | LARGE_INTEGER ticks; 62 | #endif 63 | }; 64 | 65 | static enum { 66 | NO_BENCHMARK, 67 | TUNER_BENCHMARK, 68 | PPM_BENCHMARK 69 | } test_mode = NO_BENCHMARK; 70 | 71 | static int do_exit = 0; 72 | static rtlsdr_dev_t *dev = NULL; 73 | 74 | static uint32_t samp_rate = DEFAULT_SAMPLE_RATE; 75 | 76 | static uint32_t total_samples = 0; 77 | static uint32_t dropped_samples = 0; 78 | 79 | static unsigned int ppm_duration = PPM_DURATION; 80 | 81 | void usage(void) 82 | { 83 | fprintf(stderr, "rtl_test, a benchmark tool for RTL2832 based DVB-T receivers\n" 84 | "Version %d.%d.%d.%d, %s\n", 85 | RTLSDR_MAJOR, RTLSDR_MINOR, RTLSDR_MICRO, RTLSDR_NANO, __DATE__); 86 | fprintf(stderr, "rtlsdr library %d.%d.%d.%d %s\n\n", 87 | rtlsdr_get_version()>>24, rtlsdr_get_version()>>16 & 0xFF, 88 | rtlsdr_get_version()>>8 & 0xFF, rtlsdr_get_version() & 0xFF, 89 | rtlsdr_get_ver_id() ); 90 | fprintf(stderr, "Usage:\t[-b number of buffers (default: 15, set by library)]\n" 91 | "\t[-d device_index or serial (default: 0)]\n" 92 | "\t[-l length of single buffer in units of 512 samples (default: 64)]\n" 93 | "\t[-s samplerate (default: 2048000 Hz)]\n" 94 | "\t[-t enable Elonics E4000 tuner benchmark]\n" 95 | "\t[-p[seconds] enable PPM error measurement (default: 10 seconds)]\n" 96 | "\t[-S force sync output (default: async)]\n"); 97 | exit(1); 98 | } 99 | 100 | #ifdef _WIN32 101 | BOOL WINAPI 102 | sighandler(int signum) 103 | { 104 | if (CTRL_C_EVENT == signum) { 105 | fprintf(stderr, "Signal caught, exiting!\n"); 106 | do_exit = 1; 107 | rtlsdr_cancel_async(dev); 108 | return TRUE; 109 | } 110 | return FALSE; 111 | } 112 | #else 113 | static void sighandler(int signum) 114 | { 115 | fprintf(stderr, "Signal caught, exiting!\n"); 116 | do_exit = 1; 117 | rtlsdr_cancel_async(dev); 118 | } 119 | #endif 120 | 121 | static void underrun_test(unsigned char *buf, uint32_t len, int mute) 122 | { 123 | uint32_t i, lost = 0; 124 | static uint8_t bcnt, uninit = 1; 125 | 126 | if (uninit) 127 | { 128 | bcnt = buf[0]; 129 | uninit = 0; 130 | } 131 | for (i = 0; i < len; i++) 132 | { 133 | if(bcnt != buf[i]) 134 | { 135 | if (buf[i] > bcnt) 136 | lost += (buf[i] - bcnt); 137 | else 138 | lost += (bcnt - buf[i]); 139 | bcnt = buf[i]; 140 | } 141 | bcnt++; 142 | } 143 | 144 | total_samples += len; 145 | dropped_samples += lost; 146 | if (mute) 147 | return; 148 | if (lost) 149 | fprintf(stderr, "lost at least %d of %d bytes\n", lost, len); 150 | 151 | } 152 | 153 | #ifdef _WIN32 154 | static int ppm_gettime(struct time_generic *tg) 155 | { 156 | int rv; 157 | int64_t frac; 158 | if (!tg->init) { 159 | QueryPerformanceFrequency(&tg->frequency); 160 | tg->init = 1; 161 | } 162 | rv = QueryPerformanceCounter(&tg->ticks); 163 | tg->tv_sec = tg->ticks.QuadPart / tg->frequency.QuadPart; 164 | frac = (int64_t)(tg->ticks.QuadPart - (tg->tv_sec * tg->frequency.QuadPart)); 165 | tg->tv_nsec = (long)(frac * 1000000000L / (int64_t)tg->frequency.QuadPart); 166 | return !rv; 167 | } 168 | #else 169 | static int ppm_gettime(struct time_generic *tg) 170 | { 171 | int rv = ENOSYS; 172 | #ifdef __unix__ 173 | struct timespec ts; 174 | 175 | rv = clock_gettime(CLOCK_MONOTONIC, &ts); 176 | tg->tv_sec = ts.tv_sec; 177 | tg->tv_nsec = ts.tv_nsec; 178 | #else 179 | struct timeval tv; 180 | 181 | rv = gettimeofday(&tv, NULL); 182 | tg->tv_sec = tv.tv_sec; 183 | tg->tv_nsec = tv.tv_usec * 1000; 184 | #endif 185 | return rv; 186 | } 187 | #endif 188 | 189 | 190 | static int ppm_report(uint64_t nsamples, uint64_t interval) 191 | { 192 | double real_rate, ppm; 193 | 194 | real_rate = nsamples * 1e9 / interval; 195 | ppm = 1e6 * (real_rate / (double)samp_rate - 1.); 196 | return (int)round(ppm); 197 | } 198 | 199 | static void ppm_test(uint32_t len) 200 | { 201 | static uint64_t nsamples = 0; 202 | static uint64_t interval = 0; 203 | static uint64_t nsamples_total = 0; 204 | static uint64_t interval_total = 0; 205 | static struct time_generic ppm_now; 206 | static struct time_generic ppm_recent; 207 | static enum { 208 | PPM_INIT_NO, 209 | PPM_INIT_DUMP, 210 | PPM_INIT_RUN 211 | } ppm_init = PPM_INIT_NO; 212 | 213 | ppm_gettime(&ppm_now); 214 | 215 | if (ppm_init != PPM_INIT_RUN) { 216 | /* 217 | * Kyle Keen wrote: 218 | * PPM_DUMP_TIME throws out the first N seconds of data. 219 | * The dongle's PPM is usually very bad when first starting up, 220 | * typically incorrect by more than twice the final value. 221 | * Discarding the first few seconds allows the value to stabilize much faster. 222 | */ 223 | if (ppm_init == PPM_INIT_NO) { 224 | ppm_recent.tv_sec = ppm_now.tv_sec + PPM_DUMP_TIME; 225 | ppm_init = PPM_INIT_DUMP; 226 | return; 227 | } 228 | if (ppm_init == PPM_INIT_DUMP && ppm_recent.tv_sec < ppm_now.tv_sec) 229 | return; 230 | ppm_recent = ppm_now; 231 | ppm_init = PPM_INIT_RUN; 232 | return; 233 | } 234 | 235 | nsamples += (uint64_t)(len / 2UL); 236 | interval = (uint64_t)(ppm_now.tv_sec - ppm_recent.tv_sec); 237 | if (interval < ppm_duration) 238 | return; 239 | interval *= 1000000000UL; 240 | interval += (int64_t)(ppm_now.tv_nsec - ppm_recent.tv_nsec); 241 | nsamples_total += nsamples; 242 | interval_total += interval; 243 | fprintf(stderr, "real sample rate: %i current PPM: %i cumulative PPM: %i\n", 244 | (int)((1000000000UL * nsamples) / interval), 245 | ppm_report(nsamples, interval), 246 | ppm_report(nsamples_total, interval_total)); 247 | ppm_recent = ppm_now; 248 | nsamples = 0; 249 | } 250 | 251 | static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx) 252 | { 253 | underrun_test(buf, len, 0); 254 | 255 | if (test_mode == PPM_BENCHMARK) 256 | ppm_test(len); 257 | } 258 | 259 | void e4k_benchmark(void) 260 | { 261 | uint32_t freq, gap_start = 0, gap_end = 0; 262 | uint32_t range_start = 0, range_end = 0; 263 | 264 | fprintf(stderr, "Benchmarking E4000 PLL...\n"); 265 | 266 | /* find tuner range start */ 267 | for (freq = MHZ(70); freq > MHZ(1); freq -= MHZ(1)) { 268 | if (rtlsdr_set_center_freq(dev, freq) < 0) { 269 | range_start = freq; 270 | break; 271 | } 272 | } 273 | 274 | /* find tuner range end */ 275 | for (freq = MHZ(2000); freq < MHZ(2300UL); freq += MHZ(1)) { 276 | if (rtlsdr_set_center_freq(dev, freq) < 0) { 277 | range_end = freq; 278 | break; 279 | } 280 | } 281 | 282 | /* find start of L-band gap */ 283 | for (freq = MHZ(1000); freq < MHZ(1300); freq += MHZ(1)) { 284 | if (rtlsdr_set_center_freq(dev, freq) < 0) { 285 | gap_start = freq; 286 | break; 287 | } 288 | } 289 | 290 | /* find end of L-band gap */ 291 | for (freq = MHZ(1300); freq > MHZ(1000); freq -= MHZ(1)) { 292 | if (rtlsdr_set_center_freq(dev, freq) < 0) { 293 | gap_end = freq; 294 | break; 295 | } 296 | } 297 | 298 | fprintf(stderr, "E4K range: %i to %i MHz\n", 299 | range_start/MHZ(1) + 1, range_end/MHZ(1) - 1); 300 | 301 | fprintf(stderr, "E4K L-band gap: %i to %i MHz\n", 302 | gap_start/MHZ(1), gap_end/MHZ(1)); 303 | } 304 | 305 | void r82xx_benchmark(void) 306 | { 307 | uint32_t freq; 308 | uint32_t range_start = 0, range_end = 0; 309 | 310 | fprintf(stderr, "Benchmarking R82xx PLL...\n"); 311 | 312 | /* find tuner range start */ 313 | for (freq = MHZ(70); freq > MHZ(1); freq -= MHZ(1)) { 314 | if (rtlsdr_set_center_freq(dev, freq) < 0) { 315 | range_start = freq; 316 | break; 317 | } 318 | } 319 | 320 | /* find tuner range end */ 321 | for (freq = MHZ(1770); freq < MHZ(2000); freq += MHZ(1)) { 322 | if (rtlsdr_set_center_freq(dev, freq) < 0) { 323 | range_end = freq; 324 | break; 325 | } 326 | } 327 | 328 | fprintf(stderr, "R8XX range: %i to %i MHz\n", 329 | range_start/MHZ(1) + 1, range_end/MHZ(1) - 1); 330 | 331 | } 332 | 333 | int main(int argc, char **argv) 334 | { 335 | #ifndef _WIN32 336 | struct sigaction sigact; 337 | #endif 338 | int n_read, r, opt, i; 339 | int sync_mode = 0; 340 | uint8_t *buffer; 341 | uint32_t buf_num = 0; 342 | int dev_index = 0; 343 | int dev_given = 0; 344 | uint32_t buf_len = 64 * 512; 345 | int count; 346 | int gains[100]; 347 | int tuner_type; 348 | 349 | while ((opt = getopt(argc, argv, "d:s:b:O:l:tp::Sh")) != -1) { 350 | switch (opt) { 351 | case 'b': 352 | buf_num = atoi(optarg); 353 | break; 354 | case 'd': 355 | dev_index = verbose_device_search(optarg); 356 | dev_given = 1; 357 | break; 358 | case 's': 359 | samp_rate = (uint32_t)atofs(optarg); 360 | break; 361 | case 'l': 362 | buf_len = 512 * atoi(optarg); 363 | break; 364 | case 't': 365 | test_mode = TUNER_BENCHMARK; 366 | break; 367 | case 'p': 368 | test_mode = PPM_BENCHMARK; 369 | if (optarg) 370 | ppm_duration = atoi(optarg); 371 | break; 372 | case 'S': 373 | sync_mode = 1; 374 | break; 375 | case 'h': 376 | default: 377 | usage(); 378 | break; 379 | } 380 | } 381 | 382 | buffer = malloc(buf_len * sizeof(uint8_t)); 383 | 384 | if (!dev_given) { 385 | dev_index = verbose_device_search("0"); 386 | } 387 | 388 | if (dev_index < 0) { 389 | exit(1); 390 | } 391 | 392 | r = rtlsdr_open(&dev, (uint32_t)dev_index); 393 | if (r < 0) { 394 | fprintf(stderr, "Failed to open rtlsdr device #%d.\n", dev_index); 395 | exit(1); 396 | } 397 | 398 | #ifndef _WIN32 399 | sigact.sa_handler = sighandler; 400 | sigemptyset(&sigact.sa_mask); 401 | sigact.sa_flags = 0; 402 | sigaction(SIGINT, &sigact, NULL); 403 | sigaction(SIGTERM, &sigact, NULL); 404 | sigaction(SIGQUIT, &sigact, NULL); 405 | sigaction(SIGPIPE, &sigact, NULL); 406 | #else 407 | SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE ); 408 | #endif 409 | count = rtlsdr_get_tuner_gains(dev, NULL); 410 | fprintf(stderr, "Supported gain values (%d): ", count); 411 | 412 | count = rtlsdr_get_tuner_gains(dev, gains); 413 | for (i = 0; i < count; i++) 414 | fprintf(stderr, "%.1f ", gains[i] / 10.0); 415 | fprintf(stderr, "\n"); 416 | 417 | /* Set the sample rate */ 418 | verbose_set_sample_rate(dev, samp_rate); 419 | 420 | if (test_mode == TUNER_BENCHMARK) { 421 | tuner_type = rtlsdr_get_tuner_type(dev); 422 | switch (tuner_type) { 423 | case RTLSDR_TUNER_E4000: 424 | e4k_benchmark(); 425 | break; 426 | case RTLSDR_TUNER_R820T: 427 | case RTLSDR_TUNER_R828D: 428 | r82xx_benchmark(); 429 | break; 430 | default: 431 | fprintf(stderr, "No supported tuner found\n"); 432 | } 433 | goto exit; 434 | } 435 | 436 | /* Enable test mode */ 437 | r = rtlsdr_set_testmode(dev, 1); 438 | 439 | if ((test_mode == PPM_BENCHMARK) && !sync_mode) { 440 | fprintf(stderr, "Reporting PPM error measurement every %u seconds...\n", ppm_duration); 441 | fprintf(stderr, "Press ^C after a few minutes.\n"); 442 | } 443 | 444 | if (test_mode == NO_BENCHMARK) { 445 | fprintf(stderr, "\nInfo: This tool will continuously" 446 | " read from the device, and report if\n" 447 | "samples get lost. If you observe no " 448 | "further output, everything is fine.\n\n"); 449 | } 450 | 451 | /* Reset endpoint before we start reading from it (mandatory) */ 452 | verbose_reset_buffer(dev); 453 | 454 | if (sync_mode) { 455 | fprintf(stderr, "Reading samples in sync mode...\n"); 456 | fprintf(stderr, "(Samples are being lost but not reported.)\n"); 457 | while (!do_exit) { 458 | r = rtlsdr_read_sync(dev, buffer, buf_len, &n_read); 459 | if (r < 0) { 460 | fprintf(stderr, "WARNING: sync read failed.\n"); 461 | break; 462 | } 463 | 464 | if ((uint32_t)n_read < buf_len) { 465 | fprintf(stderr, "Short read, samples lost, exiting!\n"); 466 | break; 467 | } 468 | underrun_test(buffer, n_read, 1); 469 | } 470 | } else { 471 | fprintf(stderr, "Reading samples in async mode...\n"); 472 | r = rtlsdr_read_async(dev, rtlsdr_callback, NULL, buf_num, buf_len); 473 | } 474 | 475 | if (do_exit) { 476 | fprintf(stderr, "\nUser cancel, exiting...\n"); 477 | fprintf(stderr, "Samples per million lost (minimum): %i\n", (int)(1000000L * dropped_samples / total_samples)); 478 | } 479 | else 480 | fprintf(stderr, "\nLibrary error %d, exiting...\n", r); 481 | 482 | exit: 483 | rtlsdr_close(dev); 484 | free (buffer); 485 | 486 | return r >= 0 ? r : -r; 487 | } 488 | -------------------------------------------------------------------------------- /src/rtlsdr.rc: -------------------------------------------------------------------------------- 1 | /* 2 | * For Windows: input this file to the Resource Compiler to produce a binary 3 | * .res file. This is then embedded in the resultant library (like any other 4 | * compilation object). 5 | * The information can then be queried using standard APIs and can also be 6 | * viewed with utilities such as Windows Explorer. 7 | */ 8 | 9 | #include "winresrc.h" 10 | #include "version.h" 11 | 12 | #ifndef RTLSDR_VERSIONSTRING 13 | #define LU_STR(s) #s 14 | #define LU_XSTR(s) LU_STR(s) 15 | #define RTLSDR_VERSIONSTRING \ 16 | LU_XSTR(RTLSDR_MAJOR) "." LU_XSTR(RTLSDR_MINOR) "." \ 17 | LU_XSTR(RTLSDR_MICRO) "." LU_XSTR(RTLSDR_NANO) RTLSDR_RC "\0" 18 | #endif 19 | 20 | VS_VERSION_INFO VERSIONINFO 21 | FILEVERSION RTLSDR_MAJOR,RTLSDR_MINOR,RTLSDR_MICRO,RTLSDR_NANO 22 | PRODUCTVERSION RTLSDR_MAJOR,RTLSDR_MINOR,RTLSDR_MICRO,RTLSDR_NANO 23 | FILEFLAGSMASK 0x3fL 24 | #ifndef NDEBUG 25 | FILEFLAGS 0x0L 26 | #else 27 | FILEFLAGS 0x1L 28 | #endif 29 | FILEOS VOS__WINDOWS32 30 | FILETYPE VFT_DLL 31 | FILESUBTYPE VFT2_DRV_INSTALLABLE 32 | BEGIN 33 | BLOCK "StringFileInfo" 34 | BEGIN 35 | BLOCK "040904b0" 36 | BEGIN 37 | VALUE "CompanyName", "\0" 38 | VALUE "FileDescription", "C library for USB-Dongles with RTL2832" 39 | VALUE "FileVersion", RTLSDR_VERSIONSTRING 40 | VALUE "InternalName", "librtlsdr" 41 | VALUE "LegalCopyright", "Licensed under GPLv2" 42 | VALUE "LegalTrademarks", "http://www.gnu.org/licenses/lgpl-2.1.html" 43 | VALUE "OriginalFilename", "librtlsdr.dll" 44 | VALUE "PrivateBuild", "\0" 45 | VALUE "ProductName", "github.com/old-dab/rtlsdr" 46 | VALUE "ProductVersion", RTLSDR_VERSIONSTRING 47 | VALUE "SpecialBuild", "\0" 48 | END 49 | END 50 | BLOCK "VarFileInfo" 51 | BEGIN 52 | VALUE "Translation", 0x409, 1200 53 | END 54 | END 55 | -------------------------------------------------------------------------------- /src/tuner_fc001x.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Fitipower FC0012/FC0013 tuner driver 3 | * 4 | * Copyright (C) 2012 Hans-Frieder Vogt 5 | * 6 | * modified for use in librtlsdr 7 | * Copyright (C) 2012 Steve Markgraf 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program; if not, write to the Free Software 21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #ifdef _WIN32 29 | #include 30 | #else 31 | #include 32 | #endif 33 | 34 | #include "rtlsdr_i2c.h" 35 | #include "rtl-sdr.h" 36 | #include "tuner_fc001x.h" 37 | 38 | /* Incomplete list of FC0012 register settings: 39 | * 40 | * Name Reg BitsDesc 41 | * CHIP_ID 0x00 0-7 Chip ID (constant 0xA1) 42 | * RF_A 0x01 0-3 Number of count-to-9 cycles in RF 43 | * divider (suggested: 2..9) 44 | * RF_M 0x02 0-4 Total number of cycles (to-8 and to-9) 45 | * in RF divider 46 | * RF_K_HIGH 0x03 0-6 Bits 8..14 of fractional divider 47 | * RF_K_LOW 0x04 0-7 Bits 0..7 of fractional RF divider 48 | * RF_OUTDIV_A 0x05 0-7 Power of two required? 49 | * LNA_POWER_DOWN 0x06 0 Set to 1 to switch off low noise amp 50 | * RF_OUTDIV_B 0x06 1 Set to select 3 instead of 2 for the 51 | * RF output divider 52 | * 0x06 2 Set to 1 to switch off IF amp 53 | * VCO_SPEED 0x06 3 Select tuning range of VCO: 54 | * 0 = Low range, (ca. 2.2 - 3.0GHz) 55 | * 1 = High range (ca. 2.8 - 3.6GHz) 56 | * BANDWIDTH 0x06 6-7 Set bandwidth 57 | * 6MHz=0x80, 7MHz=0x40, 8MHz=0x00 58 | * XTAL_SPEED 0x07 5 Set to 1 for 28.8MHz Crystal input 59 | * or 0 for 36MHz 60 | * 0x08 0-7 61 | * 0x09 0 1=loop_through on, 0=loop_through off 62 | * EN_CAL_RSSI 0x09 4 Enable calibrate RSSI 63 | * (Receive Signal Strength Indicator) 64 | * 0x09 7 1=Gap near 0 MHz 65 | * 0x0c 0-1 AGC Up-Down mode: 0=Realtek-mode 66 | * 0x0c 7 ? 67 | * LNA_FORCE 0x0d 0 ? 68 | * 0x0d 1 LNA Gain: 1=variable, 0=fixed 69 | * AGC_FORCE 0x0d 3 IF-AGC: 0=on, 1=off 70 | * 0x0d 4 1 = forcing rc_cal 71 | * 0x0d 7 1 = PLL loop off 72 | * VCO_CALIB 0x0e 7 Set high then low to calibrate VCO 73 | * (fast lock?) 74 | * VCO_VOLTAGE 0x0e 0-6 Read Control voltage of VCO 75 | * (big value -> low freq) 76 | * RC_cal value 0x10 0-3 rc_cal value 77 | * IF_GAIN 0x12 0-4 2 dB/step 78 | * 5-7 1 dB/step 79 | * LNA_GAIN 0x13 3-4 Low noise amp gain 80 | * 0x02=min, 0x08=middle, 0x10=max 81 | * LNA_COMPS 0x15 3 ? 82 | */ 83 | 84 | /* Incomplete list of FC0013 additional register settings: 85 | * 86 | * Name Reg BitsDesc 87 | * CHIP_ID 0x00 0-7 Chip ID (constant 0xA3) 88 | * VHF_TRACK_EN 0x07 4 1= Enable VHF track filter 89 | * LNA_FORCE 0x0d 0 LNA Gain: 1=variable, 0=maximal 90 | * 0x12 Mixer gain ? 91 | * 0x00=low, 0x0c=middle, 0x08=high, 0x0a=max 92 | * IF_GAIN 0x13 0-4 2 dB/step 93 | * 5-7 1 dB/step 94 | * LNA_GAIN 0x14 0-4 Low noise amp gain 95 | * 0x02=min, 0x08=middle, 0x10=max 96 | * BAND 0x14 5-6 0x00=VHF, 0x20=GPS, 0x40=UHF 97 | * VHF_TRACK_FILTER 0x1d 2-4 VHF track filter 98 | */ 99 | 100 | extern int16_t interpolate(int16_t freq, int size, const int16_t *freqs, const int16_t *gains); 101 | extern uint16_t rtlsdr_demod_read_reg(rtlsdr_dev_t *dev, uint16_t page, uint16_t addr, uint8_t len); 102 | 103 | static const int16_t abs_freqs[] = { 104 | 22,25,50,100,200,300,300,400,500,600,700,800,900,950,1000,1050,1100,1200,1300,1400,1500,1600,1700,1800}; 105 | static const int16_t abs_gains[] = { 106 | -7,-5, 0, -2, -4,-15,-20,-28,-33,-38,-37,-29,-35,-44, -65, -76,-103,-140,-187,-240,-296,-360,-446,-456}; 107 | static int abs_gain = 0; 108 | static uint8_t if_reg, lna_reg; 109 | static enum rtlsdr_tuner tuner_type; 110 | static uint8_t RSSI_Calibration_Value; 111 | 112 | static int fc001x_write(void *dev, uint8_t reg, uint8_t *buf, int len) 113 | { 114 | int rc = rtlsdr_i2c_write_fn(dev, FC001X_I2C_ADDR, reg, buf, len); 115 | if (rc != len) { 116 | fprintf(stderr, "%s: i2c wr failed=%d reg=%02x len=%d\n", 117 | __FUNCTION__, rc, reg, len); 118 | if (rc < 0) 119 | return rc; 120 | return -1; 121 | } 122 | 123 | return 0; 124 | } 125 | 126 | static inline int fc001x_writereg(void *dev, uint8_t reg, uint8_t val) 127 | { 128 | return fc001x_write(dev, reg, &val, 1); 129 | } 130 | 131 | static int fc001x_read(void *dev, uint8_t reg, uint8_t *buf, int len) 132 | { 133 | int rc = rtlsdr_i2c_read_fn(dev, FC001X_I2C_ADDR, reg, buf, len); 134 | if (rc != len) { 135 | fprintf(stderr, "%s: i2c rd failed=%d reg=%02x len=%d\n", 136 | __FUNCTION__, rc, reg, len); 137 | if (rc < 0) 138 | return rc; 139 | return -1; 140 | } 141 | return 0; 142 | } 143 | 144 | static inline int fc001x_readreg(void *dev, uint8_t reg, uint8_t *val) 145 | { 146 | return fc001x_read(dev, reg, val, 1); 147 | } 148 | 149 | static int fc001x_write_reg_mask(void *dev, uint8_t reg, uint8_t data, uint8_t bit_mask) 150 | { 151 | int rc; 152 | uint8_t val; 153 | 154 | if(bit_mask == 0xff) 155 | val = data; 156 | else 157 | { 158 | rc = fc001x_read(dev, reg, &val, 1); 159 | if(rc < 0) 160 | return -1; 161 | val = (val & ~bit_mask) | (data & bit_mask); 162 | } 163 | return fc001x_writereg(dev, reg, val); 164 | } 165 | 166 | /*static int print_registers(void *dev) 167 | { 168 | uint8_t data[22]; 169 | unsigned int i; 170 | 171 | if (fc001x_read(dev, 0, data, sizeof(data)) < 0) 172 | return -1; 173 | for(i=0; i<22; i++) 174 | fprintf(stderr, "%02x ", data[i]); 175 | fprintf(stderr, "\n"); 176 | return 0; 177 | }*/ 178 | 179 | 180 | int RSSI_Calibration(void *dev) 181 | { 182 | int ret; 183 | ret = fc001x_write_reg_mask(dev, 0x09, 0x10, 0x10); // set the register 9 bit4 EN_CAL_RSSI as 1 184 | ret |= fc001x_write_reg_mask(dev, 0x06, 0x01, 0x01); // set the register 6 bit 0 LNA_POWER_DOWN as 1 185 | usleep(100000); // delay 100ms 186 | // read DC value from RSSI pin as rssi_calibration 187 | RSSI_Calibration_Value = rtlsdr_demod_read_reg(dev, 3, 0x01, 1); 188 | ret |= fc001x_write_reg_mask(dev, 0x09, 0x00, 0x10); // set the register 9 bit4 EN_CAL_RSSI as 0 189 | ret |= fc001x_write_reg_mask(dev, 0x06, 0x00, 0x01); // set the register 6 bit 0 LNA_POWER_DOWN as 0 190 | return ret; 191 | } 192 | 193 | int fc0012_init(void *dev) 194 | { 195 | int ret; 196 | uint8_t reg[] = { 197 | 0x05, /* reg. 0x01 */ 198 | 0x10, /* reg. 0x02 */ 199 | 0x00, /* reg. 0x03 */ 200 | 0x00, /* reg. 0x04 */ 201 | 0x0f, /* reg. 0x05: modify for Realtek CNR test, may also be 0x0a */ 202 | 0x80, /* reg. 0x06: BW 6 Mhz, divider 2, VCO slow */ 203 | 0x20, /* reg. 0x07: may also be 0x0f */ 204 | 0xff, /* reg. 0x08: AGC Clock divide by 256, AGC gain 1/256, 205 | Loop Bw 1/8 */ 206 | 0x6e, /* reg. 0x09: Disable LoopThrough, Enable LoopThrough: 0x6f */ 207 | 0xb8, /* reg. 0x0a: Disable LO Test Buffer */ 208 | 0x82, /* reg. 0x0b: Output Clock is same as clock frequency, 209 | may also be 0x83 */ 210 | 0xfc, /* reg. 0x0c: depending on AGC Up-Down mode, may need 0xf8 */ 211 | 0x12, /* reg. 0x0d: AGC Not Forcing & LNA Forcing, forcing rc_cal */ 212 | 0x00, /* reg. 0x0e */ 213 | 0x00, /* reg. 0x0f */ 214 | 0x00, /* reg. 0x10 */ 215 | 0x00, /* reg. 0x11 */ 216 | 0x1f, /* reg. 0x12: Set to maximum gain */ 217 | 0x10, /* reg. 0x13: Set to High Gain: 0x10, 218 | Low Gain: 0x00, Middle Gain: 0x08, enable IX2: 0x80 */ 219 | 0x00, /* reg. 0x14 */ 220 | 0x04, /* reg. 0x15: Enable LNA COMPS */ 221 | }; 222 | tuner_type = RTLSDR_TUNER_FC0012; 223 | if_reg = 0x12; 224 | lna_reg = 0x13; 225 | ret = fc001x_write(dev, 1, reg, sizeof(reg)); 226 | ret |= RSSI_Calibration(dev); 227 | return ret; 228 | } 229 | 230 | int fc0013_init(void *dev) 231 | { 232 | int ret; 233 | uint8_t reg[] = { 234 | 0x09, /* reg. 0x01 */ 235 | 0x16, /* reg. 0x02 */ 236 | 0x00, /* reg. 0x03 */ 237 | 0x00, /* reg. 0x04 */ 238 | 0x17, /* reg. 0x05 */ 239 | 0x82, /* reg. 0x06: BW 6 Mhz, divider 2, VCO slow */ 240 | 0x2a, /* reg. 0x07: 28.8MHz, modified by Realtek */ 241 | 0xff, /* reg. 0x08: AGC Clock divide by 256, AGC gain 1/256, Loop Bw 1/8 */ 242 | 0x6e, /* reg. 0x09: Disable LoopThrough, Enable LoopThrough: 0x6f */ 243 | 0xb8, /* reg. 0x0a: Disable LO Test Buffer */ 244 | 0x82, /* reg. 0x0b: */ 245 | 0xfc, /* reg. 0x0c: depending on AGC Up-Down mode, may need 0xf8 */ 246 | 0x11, /* reg. 0x0d: AGC Not Forcing & LNA Forcing, forcing rc_cal */ 247 | 0x00, /* reg. 0x0e */ 248 | 0x00, /* reg. 0x0f */ 249 | 0x00, /* reg. 0x10 */ 250 | 0x00, /* reg. 0x11 */ 251 | 0x00, /* reg. 0x12 */ 252 | 0x00, /* reg. 0x13 */ 253 | 0x10, /* reg. 0x14: VHF High Gain */ 254 | 0x01, /* reg. 0x15 */ 255 | }; 256 | tuner_type = RTLSDR_TUNER_FC0013; 257 | if_reg = 0x13; 258 | lna_reg = 0x14; 259 | ret = fc001x_write(dev, 1, reg, sizeof(reg)); 260 | ret |= RSSI_Calibration(dev); 261 | return ret; 262 | } 263 | 264 | static int fc0013_set_vhf_track(void *dev, uint32_t freq) 265 | { 266 | int ret; 267 | uint8_t tmp; 268 | 269 | ret = fc001x_readreg(dev, 0x1d, &tmp); 270 | if (ret) 271 | goto error_out; 272 | tmp &= 0xe3; 273 | if (freq <= 177500000) /* VHF Track: 7 */ 274 | ret = fc001x_writereg(dev, 0x1d, tmp | 0x1c); 275 | else if (freq <= 184500000) /* VHF Track: 6 */ 276 | ret = fc001x_writereg(dev, 0x1d, tmp | 0x18); 277 | else if (freq <= 191500000) /* VHF Track: 5 */ 278 | ret = fc001x_writereg(dev, 0x1d, tmp | 0x14); 279 | else if (freq <= 198500000) /* VHF Track: 4 */ 280 | ret = fc001x_writereg(dev, 0x1d, tmp | 0x10); 281 | else if (freq <= 205500000) /* VHF Track: 3 */ 282 | ret = fc001x_writereg(dev, 0x1d, tmp | 0x0c); 283 | else if (freq <= 219500000) /* VHF Track: 2 */ 284 | ret = fc001x_writereg(dev, 0x1d, tmp | 0x08); 285 | else if (freq < 300000000) /* VHF Track: 1 */ 286 | ret = fc001x_writereg(dev, 0x1d, tmp | 0x04); 287 | else /* UHF and GPS */ 288 | ret = fc001x_writereg(dev, 0x1d, tmp | 0x1c); 289 | 290 | error_out: 291 | return ret; 292 | } 293 | 294 | static int fc001x_set_freq(void *dev, uint32_t freq) 295 | { 296 | int ret = 0; 297 | uint8_t reg[7], am, pm, tmp; 298 | uint8_t multi; //multi * freq = f_vco 299 | int64_t f_vco; //VCO frequency 300 | double xtal_freq_div_2; //14.4 MHz 301 | uint16_t xdiv; 302 | int16_t xin; 303 | int vco_select = 0; 304 | 305 | xtal_freq_div_2 = rtlsdr_get_tuner_clock(dev) / 2; 306 | 307 | if(tuner_type == RTLSDR_TUNER_FC0013) 308 | { 309 | /* set VHF track */ 310 | ret = fc0013_set_vhf_track(dev, freq); 311 | if (ret) 312 | goto exit; 313 | 314 | if (freq < 300000000) 315 | { 316 | /* enable VHF filter */ 317 | ret = fc001x_write_reg_mask(dev, 0x07, 0x10, 0x10); 318 | if (ret) 319 | goto exit; 320 | 321 | /* disable UHF & disable GPS */ 322 | ret = fc001x_write_reg_mask(dev, 0x14, 0, 0x60); 323 | if (ret) 324 | goto exit; 325 | } 326 | else 327 | { 328 | /* disable VHF filter */ 329 | ret = fc001x_write_reg_mask(dev, 0x07, 0, 0x10); 330 | if (ret) 331 | goto exit; 332 | 333 | /* enable UHF & disable GPS */ 334 | ret = fc001x_write_reg_mask(dev, 0x14, 0x40, 0x60); 335 | if (ret) 336 | goto exit; 337 | } 338 | } 339 | 340 | /* select frequency divider and the frequency of VCO */ 341 | if (freq < 37084000) { /* freq * 96 < 3560000000 */ 342 | multi = 96; 343 | reg[5] = 0x82; 344 | } else if (freq < 55625000) { /* freq * 64 < 3560000000 */ 345 | multi = 64; 346 | reg[5] = (tuner_type == RTLSDR_TUNER_FC0012) ? 0x82 : 0x02; 347 | } else if (freq < 74167000) { /* freq * 48 < 3560000000 */ 348 | multi = 48; 349 | reg[5] = 0x42; 350 | } else if (freq < 111250000) { /* freq * 32 < 3560000000 */ 351 | multi = 32; 352 | reg[5] = (tuner_type == RTLSDR_TUNER_FC0012) ? 0x42 : 0x82; 353 | } else if (freq < 148334000) { /* freq * 24 < 3560000000 */ 354 | multi = 24; 355 | reg[5] = 0x22; 356 | } else if (freq < 222500000) { /* freq * 16 < 3560000000 */ 357 | multi = 16; 358 | reg[5] = (tuner_type == RTLSDR_TUNER_FC0012) ? 0x22 : 0x42; 359 | } else if (freq < 296667000) { /* freq * 12 < 3560000000 */ 360 | multi = 12; 361 | reg[5] = 0x12; 362 | } else if (freq < 445000000) { /* freq * 8 < 3560000000 */ 363 | multi = 8; 364 | reg[5] = (tuner_type == RTLSDR_TUNER_FC0012) ? 0x12 : 0x22; 365 | } else if (freq < 593334000) { /* freq * 6 < 3560000000 */ 366 | multi = 6; 367 | reg[5] = 0x0a; 368 | } else { 369 | if(tuner_type == RTLSDR_TUNER_FC0012) 370 | { 371 | multi = 4; 372 | reg[5] = 0x0a; 373 | } 374 | else 375 | { 376 | if (freq < 948600000) { /* freq * 4 < 3800000000 */ 377 | multi = 4; 378 | reg[5] = 0x12; 379 | } else { 380 | multi = 2; 381 | reg[5] = 0x0a; 382 | } 383 | } 384 | } 385 | reg[6] = ((multi % 3) == 0) ? 0x00 : 0x02; 386 | 387 | f_vco = (int64_t)freq * multi; 388 | if (f_vco >= 3060000000U) { 389 | reg[6] |= 0x08; 390 | vco_select = 1; 391 | } 392 | 393 | /* From divided value (XDIV) determined the FA and FP value */ 394 | xdiv = (uint16_t)(f_vco / xtal_freq_div_2); 395 | if ((f_vco - xdiv * xtal_freq_div_2) >= (xtal_freq_div_2 / 2)) 396 | xdiv++; 397 | 398 | pm = (uint8_t)(xdiv / 8); 399 | am = (uint8_t)(xdiv - (8 * pm)); 400 | 401 | if (am < 2) { 402 | am += 8; 403 | pm--; 404 | } 405 | 406 | if (pm > 31) { 407 | reg[1] = am + (8 * (pm - 31)); 408 | reg[2] = 31; 409 | } else { 410 | reg[1] = am; 411 | reg[2] = pm; 412 | } 413 | 414 | if ((reg[1] > 15) || (reg[2] < 0x0b)) { 415 | fprintf(stderr, "[FC001X] no valid PLL combination " 416 | "found for %u Hz!\n", freq); 417 | return -1; 418 | } 419 | 420 | /* fix clock out */ 421 | reg[6] |= 0x20; 422 | 423 | /* From VCO frequency determines the XIN (fractional part of Delta 424 | Sigma PLL) and divided value (XDIV) */ 425 | xin = (int16_t)(((f_vco % (int64_t)xtal_freq_div_2) << 15) / (int64_t)xtal_freq_div_2); 426 | if (xin >= 16384) 427 | xin -= 32768; 428 | reg[3] = xin >> 8; 429 | reg[4] = xin & 0xff; 430 | 431 | ret = fc001x_readreg(dev, 0x06, &tmp); 432 | if (ret) 433 | goto exit; 434 | reg[6] |= tmp & 0xc0; /* bits 6 and 7 describe the bandwidth */ 435 | 436 | /* modified for Realtek demod */ 437 | reg[5] |= 0x07; 438 | 439 | ret = fc001x_write(dev, 1, ®[1], 6); 440 | if (ret) 441 | goto exit; 442 | 443 | if(tuner_type == RTLSDR_TUNER_FC0013) 444 | { 445 | if (multi == 64) 446 | ret = fc001x_write_reg_mask(dev, 0x11, 0x04, 0x04); 447 | else 448 | ret = fc001x_write_reg_mask(dev, 0x11, 0, 0x04); 449 | if (ret) 450 | goto exit; 451 | } 452 | 453 | /* VCO Calibration */ 454 | ret = fc001x_writereg(dev, 0x0e, 0x80); 455 | if (!ret) 456 | ret = fc001x_writereg(dev, 0x0e, 0x00); 457 | 458 | /* VCO Re-Calibration if needed */ 459 | if (!ret) 460 | ret = fc001x_writereg(dev, 0x0e, 0x00); 461 | if (!ret) 462 | ret = fc001x_readreg(dev, 0x0e, &tmp); 463 | if (ret) 464 | goto exit; 465 | 466 | /* vco selection */ 467 | tmp &= 0x3f; 468 | 469 | if (vco_select) { 470 | if (tmp > 0x3c) { 471 | reg[6] &= ~0x08; 472 | ret = fc001x_writereg(dev, 0x06, reg[6]); 473 | if (!ret) 474 | ret = fc001x_writereg(dev, 0x0e, 0x80); 475 | if (!ret) 476 | ret = fc001x_writereg(dev, 0x0e, 0x00); 477 | } 478 | } else { 479 | if (tmp < 0x02) { 480 | reg[6] |= 0x08; 481 | ret = fc001x_writereg(dev, 0x06, reg[6]); 482 | if (!ret) 483 | ret = fc001x_writereg(dev, 0x0e, 0x80); 484 | if (!ret) 485 | ret = fc001x_writereg(dev, 0x0e, 0x00); 486 | } 487 | } 488 | { 489 | int64_t actual_vco = xtal_freq_div_2 * xdiv + xtal_freq_div_2 * xin / 32768; 490 | int tuning_error = (f_vco - actual_vco) / multi; 491 | ret = rtlsdr_set_if_freq(dev, tuning_error); 492 | } 493 | abs_gain = interpolate(freq/1000000, ARRAY_SIZE(abs_gains), abs_freqs, abs_gains); 494 | 495 | exit: 496 | return ret; 497 | } 498 | 499 | int fc0012_set_freq(void *dev, uint32_t freq) { 500 | // select V-band/U-band filter 501 | rtlsdr_set_gpio_bit(dev, 6, (freq > 300000000) ? 1 : 0); 502 | return fc001x_set_freq(dev, freq); 503 | } 504 | 505 | int fc0013_set_freq(void *dev, uint32_t freq) { 506 | return fc001x_set_freq(dev, freq); 507 | } 508 | 509 | int fc001x_set_gain_mode(void *dev, int manual) 510 | { 511 | return fc001x_write_reg_mask(dev, 0x0d, manual ? 8 : 0, 0x08); 512 | } 513 | 514 | 515 | static const int fc001x_gains[] = 516 | //Total dB*10 517 | { 0, 31, 65, 103, 143, 183, 223, 263, 303, 343, 383, 423, 463, 503, 543, 583, 623, 663, 703}; 518 | 519 | static const uint8_t if_gains[]= 520 | {0x80,0x40,0x20,0x01,0x03,0x05,0x07,0x09,0x0b,0x0d,0x0f,0x11,0x13,0x15,0x17,0x19,0x1b,0x1d,0x1f}; 521 | 522 | 523 | static int fc001x_set_gain_index(void *dev, unsigned int i) 524 | { 525 | uint8_t gain_mode; 526 | 527 | int ret = fc001x_readreg(dev, 0x0d, &gain_mode); 528 | if (ret < 0) 529 | return ret; 530 | if((gain_mode & 8) == 0) 531 | return 0; //don't set gain in AGC mode 532 | if(tuner_type == RTLSDR_TUNER_FC0013) 533 | ret = fc001x_writereg(dev, 0x12, 0); //set FC0013 mixer gain to 0 534 | ret |= fc001x_writereg(dev, if_reg, if_gains[i]); 535 | //print_registers(dev); 536 | return ret; 537 | } 538 | 539 | int fc0012_set_gain_index(void *dev, unsigned int index) 540 | { 541 | return fc001x_set_gain_index(dev, index); 542 | } 543 | 544 | int fc0013_set_gain_index(void *dev, unsigned int index) 545 | { 546 | return fc001x_set_gain_index(dev, index); 547 | } 548 | 549 | int fc001x_set_bw(void *dev, int bw, uint32_t *applied_bw, int apply) 550 | { 551 | (void) dev; 552 | (void) bw; 553 | (void) apply; 554 | 555 | *applied_bw = 5000000; 556 | return 0; 557 | } 558 | 559 | int fc0012_exit(void *dev) { 560 | // switch off tuner 561 | rtlsdr_set_gpio_bit(dev, 4, 1); 562 | return 0; 563 | } 564 | 565 | int fc0013_exit(void *dev) { 566 | // switch off LNA and IF amp 567 | return fc001x_write_reg_mask(dev, 0x06, 0x05, 0x05); 568 | } 569 | 570 | /* expose/permit tuner specific i2c register hacking! */ 571 | int fc001x_set_i2c_register(void *dev, unsigned i2c_register, unsigned data, unsigned mask) 572 | { 573 | return fc001x_write_reg_mask(dev, i2c_register & 0xFF, data & 0xff, mask & 0xff); 574 | } 575 | 576 | static const int lna_gain_table[] = { 577 | 32, 37, 0, 25, 32, 30, 41, 36, // very low gain 578 | 167, 165, 163, 161, 159, 156, 154, 151, // middle gain 579 | 307, 301, 297, 294, 290, 286, 280, 274, // high gain 580 | 69, 71, 54, 65, 69, 68, 78, 72 // low gain 581 | }; 582 | static const int if_gain_table[] = { 83, 65, 31, 48, 0, 0, 13, 0}; 583 | 584 | static const int mix_gain_table[] = { 0, 0, 0, 0, 21, 21, 21, 21, 585 | 60, 60, 122, 100, 42, 42, 42, 42}; 586 | 587 | static int fc001x_get_signal_strength(uint8_t vga, uint8_t lna, uint8_t mix) 588 | { 589 | int if_gain = (vga & 0x1f) * 20; 590 | int lna_gain = lna_gain_table[lna & 0x1f]; 591 | int mix_gain = mix_gain_table[mix & 0x0f] + ((mix >> 4) & 3) * 6; 592 | if_gain += if_gain_table[(vga >> 5) & 0x07]; 593 | return if_gain + lna_gain + mix_gain + abs_gain; 594 | } 595 | 596 | static int fc001x_get_i2c_register(void *dev, unsigned char* data, int *len, int *tuner_gain) 597 | { 598 | int rc; 599 | uint8_t mixer, gain_mode; 600 | uint8_t LNA_value; 601 | uint8_t RSSI_Value; 602 | int RSSI_Difference; 603 | 604 | rc = fc001x_readreg(dev, 0x0d, &gain_mode); 605 | if (rc < 0) 606 | return rc; 607 | if((gain_mode & 8) == 0) //AGC mode 608 | { 609 | if(tuner_type == RTLSDR_TUNER_FC0013) 610 | { 611 | rc = fc001x_writereg(dev, 0x12, 0); //mixer gain 612 | if (rc < 0) 613 | return rc; 614 | } 615 | rc = fc001x_writereg(dev, if_reg, 0); 616 | if (rc < 0) 617 | return rc; 618 | } 619 | rc = fc001x_read(dev, 0, data, *len); 620 | if (rc < 0) 621 | return rc; 622 | 623 | mixer = (tuner_type == RTLSDR_TUNER_FC0013) ? data[0x12] : 0; 624 | *tuner_gain = fc001x_get_signal_strength(data[if_reg], data[lna_reg], mixer); 625 | 626 | RSSI_Value = rtlsdr_demod_read_reg(dev, 3, 0x01, 1); 627 | RSSI_Difference = RSSI_Value - RSSI_Calibration_Value; // Calculate voltage difference of RSSI 628 | 629 | LNA_value = data[lna_reg] & 0x1f; 630 | switch(LNA_value) 631 | { 632 | case 0x10: 633 | if( RSSI_Difference > 6 ) 634 | rc = fc001x_write_reg_mask(dev, lna_reg, 0x17, 0x1f); 635 | break; 636 | case 0x17: 637 | if( RSSI_Difference > 15 ) 638 | rc = fc001x_write_reg_mask(dev, lna_reg, 0x08, 0x1f); 639 | else if( RSSI_Difference < 3 ) 640 | rc = fc001x_write_reg_mask(dev, lna_reg, 0x10, 0x1f); 641 | break; 642 | case 0x08: 643 | if( RSSI_Difference > 14 ) 644 | rc = fc001x_write_reg_mask(dev, lna_reg, 0x1e, 0x1f); 645 | else if( RSSI_Difference < 3 ) 646 | rc = fc001x_write_reg_mask(dev, lna_reg, 0x17, 0x1f); 647 | break; 648 | case 0x1e: 649 | if( RSSI_Difference > 13 ) 650 | rc = fc001x_write_reg_mask(dev, lna_reg, 0x02, 0x1f); 651 | else if( RSSI_Difference < 3 ) 652 | rc = fc001x_write_reg_mask(dev, lna_reg, 0x08, 0x1f); 653 | break; 654 | case 0x02: 655 | if( RSSI_Difference < 3 ) 656 | rc = fc001x_write_reg_mask(dev, lna_reg, 0x1e, 0x1f); 657 | break; 658 | default: 659 | rc = fc001x_write_reg_mask(dev, lna_reg, 0x10, 0x1f); 660 | break; 661 | } 662 | return rc; 663 | } 664 | 665 | int fc0012_get_i2c_register(void *dev, unsigned char *data, int *len, int *strength) 666 | { 667 | *len = 22; 668 | return fc001x_get_i2c_register(dev, data, len, strength); 669 | } 670 | 671 | int fc0013_get_i2c_register(void *dev, unsigned char *data, int *len, int *strength) 672 | { 673 | *len = 30; 674 | return fc001x_get_i2c_register(dev, data, len, strength); 675 | } 676 | 677 | const int *fc001x_get_gains(int *len) 678 | { 679 | *len = sizeof(fc001x_gains); 680 | return fc001x_gains; 681 | } 682 | -------------------------------------------------------------------------------- /src/tuner_fc2580.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * FCI FC2580 silicon tuner driver 4 | * 5 | * Copyright (C) 2012 Antti Palosaari 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #ifndef _WIN32 13 | #include 14 | #else 15 | #include 16 | #endif 17 | 18 | #include "rtlsdr_i2c.h" 19 | #include "rtl-sdr.h" 20 | #include "tuner_fc2580.h" 21 | 22 | /* 23 | Registers 24 | 25 | Reg Bitmap Description 26 | ------------------------------------------------------------------------------ 27 | R1 [7:0] CHIP_ID, reference check point for read mode: 0x56 28 | 0x01 29 | ------------------------------------------------------------------------------ 30 | R2 [7:6] Band switch and VCO divider 31 | 0x02 00: UHF, PLL = VCO/4 32 | 01: L-Band, PLL = VCO/2 33 | 10: VHF, PLL = VCO/12 34 | [5] 0: Use internal XTAL Oscillator, 1: Use External Clock input 35 | [3] 0: Lower VCO band < 2.6 GHz, 1: upper VCO band > 2.6 GHz 36 | [2] 0: Standby, 1: active 37 | ------------------------------------------------------------------------------ 38 | R24 [6:4] Reference divider R, 00: /1, 01: /2, 10: /4 39 | 0x18 [3:0] High part of 'K' value 40 | ------------------------------------------------------------------------------ 41 | R26 Middle part of 'K' value 42 | 0x1a 43 | ------------------------------------------------------------------------------ 44 | R27 Lower part of 'K' value 45 | 0x1b 46 | ------------------------------------------------------------------------------ 47 | R28 'N' value 48 | 0x1c 49 | ------------------------------------------------------------------------------ 50 | R46 Command register for filter PLL 51 | 0x2e 52 | ------------------------------------------------------------------------------ 53 | R47 [7:6] Filter PLL status, 11: Filter PLL in sync 54 | 0x2f [5:0] Filter PLL value 55 | ------------------------------------------------------------------------------ 56 | R54 [6] Filter bandwidth course tune 57 | 0x36 0: Wide bandwidth, 4...10 MHz 58 | 1: Small bandwidth, 1...3 MHz 59 | ------------------------------------------------------------------------------ 60 | R55 Filter bandwidth fine tune 61 | 0x37 62 | ------------------------------------------------------------------------------ 63 | R69 [5:4] 00: Manual VGA gain control 64 | 0x45 01: Internal AGC mode 65 | 10: Voltage controlled AGC mode 66 | ------------------------------------------------------------------------------ 67 | R73 [2:0] IF manual attenuator control * -6 dB 68 | 0x49 69 | ------------------------------------------------------------------------------ 70 | R74 IF manual gain control * 0.25 dB 71 | 0x4a 72 | ------------------------------------------------------------------------------ 73 | R75 AGC clock's pre-divide ratio 74 | 0x4b 75 | ------------------------------------------------------------------------------ 76 | R76 [1] 0: Internal IF AGC mode 77 | 0x4c 1: Voltage controlled IF AGC mode 78 | ------------------------------------------------------------------------------ 79 | R103-R106 LNA and Mixer agc power detector voltage threshold 80 | 0x67-0x6a low and high settings 81 | ------------------------------------------------------------------------------ 82 | R107 IF agc power detector voltage threshold low setting 83 | 0x6b 84 | ------------------------------------------------------------------------------ 85 | R108 IF agc power detector voltage threshold high setting 86 | 0x6c 87 | ------------------------------------------------------------------------------ 88 | R113 Indication of LNA gain 89 | 0x71 90 | ------------------------------------------------------------------------------ 91 | R114 Indication of Mixer gain 92 | 0x72 93 | ------------------------------------------------------------------------------ 94 | R115 [2:0] Indication of IF attenuator * -6 dB 95 | 0x73 96 | ------------------------------------------------------------------------------ 97 | R116 Indication of IF gain * 0.25 dB 98 | 0x74 99 | ------------------------------------------------------------------------------ 100 | */ 101 | 102 | typedef enum { 103 | FC2580_VHF_BAND, 104 | FC2580_UHF1_BAND, 105 | FC2580_UHF2_BAND, 106 | FC2580_UHF3_BAND, 107 | FC2580_L_BAND 108 | } fc2580_band_type; 109 | 110 | static fc2580_band_type curr_band = FC2580_VHF_BAND; 111 | 112 | static const struct { 113 | uint8_t reg; 114 | uint8_t val; 115 | } fc2580_reg_val[] = { 116 | {0x00, 0x00}, 117 | {0x12, 0x86}, 118 | {0x14, 0x5c}, 119 | {0x16, 0x3c}, 120 | {0x1f, 0xd2}, 121 | {0x09, 0xd7}, 122 | {0x0b, 0xd5}, 123 | {0x0c, 0x32}, 124 | {0x0e, 0x43}, 125 | {0x21, 0x0a}, 126 | {0x22, 0x82}, 127 | {0x45, 0x10}, //internal AGC 128 | {0x4c, 0x00}, 129 | {0x3f, 0x88}, 130 | {0x02, 0x0e}, 131 | {0x25, 0xf0}, //for UHF 132 | {0x27, 0x77}, //for VHF and UHF 133 | {0x2b, 0x70}, //for L-Band 134 | {0x2c, 0x37}, //for L-Band 135 | {0x30, 0x09}, 136 | {0x44, 0x20}, //for L-Band 137 | {0x50, 0x8c}, 138 | {0x53, 0x50}, 139 | {0x58, 0x14}, 140 | {0x6b, 0x11}, //threshold VGA 141 | {0x6c, 0x13} //threshold VGA 142 | }; 143 | 144 | static const struct { 145 | uint32_t freq; 146 | uint8_t div_out; 147 | uint8_t band; 148 | } fc2580_pll[] = { 149 | { 400000000, 12, 0x80}, // VHF 150 | { 538000000, 4, 0x00}, // UHF1 151 | { 794000000, 4, 0x00}, // UHF2 152 | { 925000000, 4, 0x00}, // UHF3 153 | {0xffffffff, 2, 0x40} // L-Band 154 | }; 155 | 156 | static const struct { 157 | uint8_t reg; 158 | uint8_t val[5]; 159 | } fc2580_freq_regs[] = { 160 | {0x28, {0x33,0x53,0x53,0x53,0xff}}, 161 | {0x29, {0x40,0x60,0x60,0x60,0xff}}, 162 | {0x2d, {0xff,0x9f,0x9f,0x8f,0xe7}}, // UHF LNA Load Cap 163 | {0x5f, {0x0f,0x13,0x15,0x15,0x0f}}, 164 | {0x61, {0x07,0x07,0x03,0x07,0x0f}}, 165 | {0x62, {0x00,0x06,0x03,0x06,0x00}}, 166 | {0x63, {0x15,0x15,0x15,0x15,0x13}}, 167 | {0x67, {0x03,0x06,0x03,0x07,0x00}}, 168 | {0x68, {0x05,0x08,0x05,0x09,0x02}}, 169 | {0x69, {0x10,0x10,0x0c,0x10,0x0c}}, 170 | {0x6a, {0x12,0x12,0x0e,0x12,0x0e}}, 171 | {0x6d, {0x78,0x78,0x78,0x78,0xa0}}, 172 | {0x6e, {0x32,0x32,0x32,0x32,0x50}}, 173 | {0x6f, {0x54,0x14,0x14,0x14,0x14}}, 174 | }; 175 | 176 | 177 | /* 178 | * TODO: 179 | * I2C write and read works only for one single register. Multiple registers 180 | * could not be accessed using normal register address auto-increment. 181 | * There could be (very likely) register to change that behavior.... 182 | */ 183 | static int fc2580_write(void *dev, unsigned char reg, unsigned char val) 184 | { 185 | int rc = rtlsdr_i2c_write_fn(dev, FC2580_I2C_ADDR, reg, &val, 1); 186 | if (rc != 1) { 187 | fprintf(stderr, "%s: i2c wr failed=%d reg=%02x len=1\n", 188 | __FUNCTION__, rc, reg); 189 | if (rc < 0) 190 | return rc; 191 | return -1; 192 | } 193 | 194 | return 0; 195 | } 196 | 197 | /* write single register conditionally only when value differs from 0xff 198 | * XXX: This is special routine meant only for writing fc2580_freq_regs[] 199 | * values. Do not use for the other purposes. */ 200 | static int fc2580_wr_reg_ff(void *dev, uint8_t reg, uint8_t val) 201 | { 202 | if (val == 0xff) 203 | return 0; 204 | else 205 | return fc2580_write(dev, reg, val); 206 | } 207 | 208 | static int fc2580_read(void *dev, unsigned char reg, unsigned char *data) 209 | { 210 | int rc = rtlsdr_i2c_read_fn(dev, FC2580_I2C_ADDR, reg, data, 1); 211 | if (rc != 1) { 212 | fprintf(stderr, "%s: i2c wr failed=%d reg=%02x len=1\n", 213 | __FUNCTION__, rc, reg); 214 | if (rc < 0) 215 | return rc; 216 | return -1; 217 | } 218 | 219 | return 0; 220 | } 221 | 222 | static int fc2580_write_reg_mask(void *dev, uint8_t reg, uint8_t data, uint8_t bit_mask) 223 | { 224 | int rc; 225 | uint8_t val; 226 | 227 | if(bit_mask == 0xff) 228 | val = data; 229 | else 230 | { 231 | rc = fc2580_read(dev, reg, &val); 232 | if(rc < 0) 233 | return -1; 234 | val = (val & ~bit_mask) | (data & bit_mask); 235 | } 236 | return fc2580_write(dev, reg, val); 237 | } 238 | 239 | int fc2580_set_i2c_register(void *dev, unsigned i2c_register, unsigned data, unsigned mask) 240 | { 241 | return fc2580_write_reg_mask(dev, i2c_register & 0xFF, data & 0xff, mask & 0xff); 242 | } 243 | 244 | static const int lna_gains[][5] = { 245 | { 0, 0, 0, 0, 0}, 246 | { -6, -6, -6, -6, -6}, 247 | {-19, -17, -17, -17, -11}, 248 | {-24, -22, -22, -22, -16}, 249 | {-32, -30, -30, -30, -34}, 250 | }; 251 | 252 | /*============================================================================== 253 | 254 | This function returns fc2580's current RSSI value. 255 | 256 | 257 | unsigned char *data: fc2580's registers 258 | 259 | 260 | int rssi : estimated input power in 1/10 dB. 261 | 262 | ==============================================================================*/ 263 | static int fc2580_get_rssi(unsigned char *data) 264 | { 265 | #define OFS_RSSI 57 266 | uint8_t s_lna = data[0x71]; 267 | uint8_t s_rfvga = data[0x72]; 268 | uint8_t s_cfs = data[0x73]; 269 | uint8_t s_ifvga = data[0x74]; 270 | int ofs_lna = lna_gains[s_lna][curr_band]; 271 | int ofs_rfvga = -s_rfvga+((s_rfvga>=11)? 1 : 0) + ((s_rfvga>=18)? 1 : 0); 272 | int ofs_csf = -6*(s_cfs & 7); 273 | int ofs_ifvga = s_ifvga*10/4; 274 | int rssi = (OFS_RSSI+ofs_lna+ofs_rfvga+ofs_csf) * 10 + ofs_ifvga; 275 | return rssi; 276 | } 277 | 278 | int fc2580_get_i2c_register(void *dev, uint8_t *data, int *len, int *strength) 279 | { 280 | int rc, i; 281 | 282 | *len = 118; 283 | *strength = 0; 284 | rc = 0; 285 | for(i=0; i<118; i++) 286 | { 287 | rc = fc2580_read(dev, i, &data[i]); 288 | if (rc < 0) 289 | return rc; 290 | } 291 | *strength = fc2580_get_rssi(data); 292 | return 0; 293 | } 294 | 295 | /*static int print_registers(void *dev) 296 | { 297 | uint8_t data = 0; 298 | unsigned int i, j; 299 | 300 | fprintf(stderr, " 0 1 2 3 4 5 6 7 8 9 a b c d e f\n"); 301 | for(i=0; i<8; i++) 302 | { 303 | fprintf(stderr, "%01x ", i); 304 | for(j=0; j<16; j++) 305 | { 306 | fc2580_read(dev, i*16+j, &data); 307 | fprintf(stderr, "%02x ", data); 308 | } 309 | fprintf(stderr, "\n"); 310 | } 311 | return 0; 312 | }*/ 313 | 314 | int fc2580_init(void *dev) 315 | { 316 | int ret; 317 | unsigned int i; 318 | 319 | for (i = 0; i < ARRAY_SIZE(fc2580_reg_val); i++) { 320 | ret = fc2580_write(dev, fc2580_reg_val[i].reg, 321 | fc2580_reg_val[i].val); 322 | if (ret) 323 | goto err; 324 | } 325 | for (i = 0; i < ARRAY_SIZE(fc2580_freq_regs); i++){ 326 | ret = fc2580_wr_reg_ff(dev, fc2580_freq_regs[i].reg, 327 | fc2580_freq_regs[i].val[curr_band]); 328 | if (ret) 329 | goto err; 330 | } 331 | //print_registers(dev); 332 | return 0; 333 | err: 334 | fprintf(stderr, "%s: failed=%d\n", __FUNCTION__, ret); 335 | return ret; 336 | } 337 | 338 | int fc2580_set_freq(void *dev, unsigned int frequency) 339 | { 340 | unsigned int i, uitmp, div_ref, div_ref_val, div_n, k_cw, div_out; 341 | uint64_t f_vco; 342 | uint8_t synth_config = 0; 343 | int ret = 0; 344 | double freq_xtal = rtlsdr_get_tuner_clock(dev); 345 | 346 | /* 347 | * Fractional-N synthesizer 348 | * 349 | * +---------------------------------------+ 350 | * v | 351 | * Fref +----+ +----+ +-------+ +----+ +------+ +---+ 352 | * ------> | /R | --> | PD | --> | VCO | ------> | /2 | --> | /N.F | <-- | K | 353 | * +----+ +----+ +-------+ +----+ +------+ +---+ 354 | * | 355 | * | 356 | * v 357 | * +-------+ Fout 358 | * | /Rout | ------> 359 | * +-------+ 360 | */ 361 | for (i = 0; i < ARRAY_SIZE(fc2580_pll); i++) { 362 | if (frequency <= fc2580_pll[i].freq) 363 | break; 364 | } 365 | if (i == ARRAY_SIZE(fc2580_pll)) { 366 | ret = -1; 367 | goto err; 368 | } 369 | 370 | #define DIV_PRE_N 2 371 | div_out = fc2580_pll[i].div_out; 372 | f_vco = (uint64_t)frequency * div_out; 373 | synth_config |= fc2580_pll[i].band; 374 | if (f_vco < 2600000000ULL) //Select VCO Band 375 | synth_config |= 0x06; 376 | else 377 | synth_config |= 0x0e; 378 | 379 | /* select reference divider R (keep PLL div N in valid range) */ 380 | #define DIV_N_MIN 76 381 | if (f_vco >= (uint64_t)(DIV_PRE_N * DIV_N_MIN * freq_xtal)) { 382 | div_ref = 1; 383 | div_ref_val = 0x00; 384 | } else if (f_vco >= (uint64_t)(DIV_PRE_N * DIV_N_MIN * freq_xtal / 2)) { 385 | div_ref = 2; 386 | div_ref_val = 0x10; 387 | } else { 388 | div_ref = 4; 389 | div_ref_val = 0x20; 390 | } 391 | 392 | /* calculate PLL integer and fractional control word */ 393 | uitmp = DIV_PRE_N * freq_xtal / div_ref; 394 | div_n = f_vco / uitmp; 395 | k_cw = (f_vco % uitmp) * 0x100000 / uitmp; 396 | 397 | #if 0 398 | fprintf(stderr, "frequency=%u f_vco=%llu freq_xtal=%.1f div_ref=%u div_n=%u div_out=%u k_cw=%0x\n", 399 | frequency, f_vco, freq_xtal, div_ref, div_n, div_out, k_cw); 400 | #endif 401 | 402 | ret |= fc2580_write(dev, 0x02, synth_config); 403 | ret |= fc2580_write(dev, 0x18, div_ref_val << 0 | k_cw >> 16); //Load 'R' value and high part of 'K' value 404 | ret |= fc2580_write(dev, 0x1a, (k_cw >> 8) & 0xff); //Load middle part of 'K' value 405 | ret |= fc2580_write(dev, 0x1b, (k_cw >> 0) & 0xff); //Load lower part of 'K' value 406 | ret |= fc2580_write(dev, 0x1c, div_n); //Load 'N' value 407 | if (ret) 408 | goto err; 409 | 410 | /* registers */ 411 | if(curr_band != i) 412 | { 413 | curr_band = i; 414 | for (i = 0; i < ARRAY_SIZE(fc2580_freq_regs); i++) 415 | ret |= fc2580_wr_reg_ff(dev, fc2580_freq_regs[i].reg, fc2580_freq_regs[i].val[curr_band]); 416 | } 417 | if (ret) 418 | goto err; 419 | 420 | return 0; 421 | err: 422 | fprintf(stderr, "%s: failed=%d\n", __FUNCTION__, ret); 423 | return ret; 424 | } 425 | 426 | /*============================================================================== 427 | 428 | This function changes Bandwidth frequency of fc2580's channel selection filter 429 | 430 | 431 | filter_bw: bandwidth in kHz 432 | 433 | ==============================================================================*/ 434 | static int fc2580_set_filter(void *dev, int filter_bw) 435 | { 436 | // Set tuner bandwidth mode. 437 | unsigned int freq_xtal = (rtlsdr_get_tuner_clock(dev) + 500) / 1000; 438 | unsigned char cal_mon = 0, i; 439 | int result = 0; 440 | 441 | result |= fc2580_write(dev, 0x36, 0x1C); 442 | result |= fc2580_write(dev, 0x37, (uint8_t)(63*freq_xtal/filter_bw/10) ); 443 | result |= fc2580_write(dev, 0x39, 0x00); 444 | result |= fc2580_write(dev, 0x2E, 0x09); 445 | for(i=0; i<5; i++) 446 | { 447 | result &= fc2580_read(dev, 0x2F, &cal_mon); 448 | if( (cal_mon & 0xC0) != 0xC0) 449 | { 450 | result |= fc2580_write(dev, 0x2E, 0x01); 451 | result |= fc2580_write(dev, 0x2E, 0x09); 452 | } 453 | else 454 | break; 455 | } 456 | result |= fc2580_write(dev, 0x2E, 0x01); 457 | 458 | return result; 459 | } 460 | 461 | int fc2580_set_bw(void *dev, int bw, uint32_t *applied_bw, int apply) 462 | { 463 | if (bw < 1050000) 464 | *applied_bw = 1050000; 465 | else if (bw <= 2900000) 466 | *applied_bw = bw; 467 | else 468 | *applied_bw = 2900000; 469 | if(!apply) 470 | return 0; 471 | return fc2580_set_filter(dev, *applied_bw/1000); 472 | } 473 | 474 | int fc2580_set_gain_mode(void *dev, int manual) 475 | { 476 | return fc2580_write(dev, 0x45, manual ? 0 : 0x10); 477 | } 478 | 479 | static const int fc2580_gains[] = { 480 | //Total dB*10 481 | 0,30,60,90,120,150,180,210,240,270,300,330,360,390,420,450,480,510,540,570,600,630,660,690}; 482 | static const uint8_t fc2580_r73[] = { 483 | 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0}; 484 | static const uint8_t fc2580_r74[] = { 485 | 0,12,24,36, 48, 60, 72, 84, 96, 84, 96, 84, 96, 84, 96, 84, 96, 84, 96,108,120,132,144,156}; 486 | 487 | int fc2580_set_gain_index(void *dev, unsigned int i) 488 | { 489 | int ret = fc2580_write(dev, 0x49, fc2580_r73[i]); 490 | ret |= fc2580_write(dev, 0x4a, fc2580_r74[i]); 491 | 492 | return ret; 493 | } 494 | 495 | const int *fc2580_get_gains(int *len) 496 | { 497 | *len = sizeof(fc2580_gains); 498 | return fc2580_gains; 499 | } 500 | 501 | int fc2580_exit(void *dev) 502 | { 503 | rtlsdr_set_gpio_bit(dev, 4, 1); 504 | return 0; 505 | } 506 | -------------------------------------------------------------------------------- /src/version.h: -------------------------------------------------------------------------------- 1 | /* This file is parsed by m4 and windres and RC.EXE so please keep it simple. */ 2 | 3 | #ifndef RTLSDR_MAJOR 4 | #define RTLSDR_MAJOR 0 5 | #endif 6 | #ifndef RTLSDR_MINOR 7 | #define RTLSDR_MINOR 9 8 | #endif 9 | #ifndef RTLSDR_MICRO 10 | #define RTLSDR_MICRO 7 11 | #endif 12 | #ifndef RTLSDR_NANO 13 | #define RTLSDR_NANO 0 14 | #endif 15 | 16 | /* RTLSDR__RC is the release candidate suffix. Should normally be empty. */ 17 | #ifndef RTLSDR_RC 18 | #define RTLSDR_RC "" 19 | 20 | #define RTL_VER_ID "github.com/old-dab/rtlsdr" 21 | 22 | #endif 23 | --------------------------------------------------------------------------------