Initial upload rtl_sdr direct SP
commit
c30d3646af
|
@ -0,0 +1,41 @@
|
|||
Makefile
|
||||
Makefile.in
|
||||
.deps
|
||||
.libs
|
||||
*.o
|
||||
*.lo
|
||||
*.la
|
||||
*.pc
|
||||
aclocal.m4
|
||||
acinclude.m4
|
||||
aminclude.am
|
||||
m4/*.m4
|
||||
autom4te.cache
|
||||
config.h*
|
||||
config.sub
|
||||
config.log
|
||||
config.status
|
||||
config.guess
|
||||
configure
|
||||
depcomp
|
||||
missing
|
||||
ltmain.sh
|
||||
install-sh
|
||||
stamp-h1
|
||||
libtool
|
||||
Doxyfile
|
||||
|
||||
.tarball-version
|
||||
.version
|
||||
|
||||
.*.swp
|
||||
|
||||
doc/
|
||||
|
||||
src/rtl_sdr
|
||||
src/rtl_tcp
|
||||
|
||||
CMakeCache.txt
|
||||
*/CMakeFiles
|
||||
CMakeFiles
|
||||
*.cmake
|
|
@ -0,0 +1,10 @@
|
|||
language: c
|
||||
compiler:
|
||||
- gcc
|
||||
- clang
|
||||
|
||||
before_install:
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -qq libusb-1.0-0-dev
|
||||
|
||||
script: cmake . && make && sudo make install
|
|
@ -0,0 +1,4 @@
|
|||
Steve Markgraf <steve@steve-m.de>
|
||||
Dimitri Stolnikov <horiz0n@gmx.net>
|
||||
Hoernchen <la@tfc-server.de>
|
||||
Kyle Keen <keenerd@gmail.com>
|
|
@ -0,0 +1,170 @@
|
|||
# Copyright 2012 OSMOCOM Project
|
||||
#
|
||||
# This file is part of rtl-sdr
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
|
||||
########################################################################
|
||||
# Project setup
|
||||
########################################################################
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
project(rtlsdr C)
|
||||
|
||||
#select the release build type by default to get optimization flags
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "Release")
|
||||
message(STATUS "Build type not specified: defaulting to release.")
|
||||
endif(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "")
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules)
|
||||
|
||||
if(NOT LIB_INSTALL_DIR)
|
||||
set(LIB_INSTALL_DIR lib)
|
||||
endif()
|
||||
|
||||
# Set the version information here
|
||||
set(VERSION_INFO_MAJOR_VERSION 0) # increment major on api compatibility changes
|
||||
set(VERSION_INFO_MINOR_VERSION 5) # increment minor on feature-level changes
|
||||
set(VERSION_INFO_PATCH_VERSION git) # increment patch for bug fixes and docs
|
||||
include(Version) # setup version info
|
||||
|
||||
########################################################################
|
||||
# Compiler specific setup
|
||||
########################################################################
|
||||
if(CMAKE_COMPILER_IS_GNUCC AND NOT WIN32)
|
||||
ADD_DEFINITIONS(-Wall)
|
||||
ADD_DEFINITIONS(-Wextra)
|
||||
ADD_DEFINITIONS(-Wno-unused-parameter)
|
||||
ADD_DEFINITIONS(-Wno-unused)
|
||||
ADD_DEFINITIONS(-Wsign-compare)
|
||||
ADD_DEFINITIONS(-Wdeclaration-after-statement)
|
||||
#http://gcc.gnu.org/wiki/Visibility
|
||||
add_definitions(-fvisibility=hidden)
|
||||
endif()
|
||||
|
||||
########################################################################
|
||||
# Find build dependencies
|
||||
########################################################################
|
||||
find_package(PkgConfig)
|
||||
find_package(LibUSB)
|
||||
set(THREADS_USE_PTHREADS_WIN32 true)
|
||||
find_package(Threads)
|
||||
|
||||
if(NOT LIBUSB_FOUND)
|
||||
message(FATAL_ERROR "LibUSB 1.0 required to compile rtl-sdr")
|
||||
endif()
|
||||
if(NOT THREADS_FOUND)
|
||||
message(FATAL_ERROR "pthreads(-win32) required to compile rtl-sdr")
|
||||
endif()
|
||||
########################################################################
|
||||
# Setup the include and linker paths
|
||||
########################################################################
|
||||
include_directories(
|
||||
${CMAKE_SOURCE_DIR}/include
|
||||
${LIBUSB_INCLUDE_DIR}
|
||||
${THREADS_PTHREADS_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
#link_directories(
|
||||
# ...
|
||||
#)
|
||||
|
||||
# Set component parameters
|
||||
#set(INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include CACHE INTERNAL "" FORCE)
|
||||
|
||||
########################################################################
|
||||
# Create uninstall target
|
||||
########################################################################
|
||||
configure_file(
|
||||
${CMAKE_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake
|
||||
@ONLY)
|
||||
|
||||
add_custom_target(uninstall
|
||||
${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake
|
||||
)
|
||||
|
||||
########################################################################
|
||||
# Install udev rules
|
||||
########################################################################
|
||||
option(INSTALL_UDEV_RULES "Install udev rules for RTL-SDR" OFF)
|
||||
if (INSTALL_UDEV_RULES)
|
||||
install (
|
||||
FILES rtl-sdr.rules
|
||||
DESTINATION "/etc/udev/rules.d"
|
||||
COMPONENT "udev"
|
||||
)
|
||||
else (INSTALL_UDEV_RULES)
|
||||
message (STATUS "Udev rules not being installed, install them with -DINSTALL_UDEV_RULES=ON")
|
||||
endif (INSTALL_UDEV_RULES)
|
||||
|
||||
option(DETACH_KERNEL_DRIVER "Detach kernel driver if loaded" OFF)
|
||||
if (DETACH_KERNEL_DRIVER)
|
||||
message (STATUS "Building with kernel driver detaching enabled")
|
||||
add_definitions(-DDETACH_KERNEL_DRIVER=1)
|
||||
else (DETACH_KERNEL_DRIVER)
|
||||
message (STATUS "Building with kernel driver detaching disabled, use -DDETACH_KERNEL_DRIVER=ON to enable")
|
||||
endif (DETACH_KERNEL_DRIVER)
|
||||
|
||||
########################################################################
|
||||
# Add subdirectories
|
||||
########################################################################
|
||||
add_subdirectory(include)
|
||||
add_subdirectory(src)
|
||||
|
||||
########################################################################
|
||||
# Create Pkg Config File
|
||||
########################################################################
|
||||
FOREACH(inc ${LIBUSB_INCLUDE_DIR})
|
||||
LIST(APPEND RTLSDR_PC_CFLAGS "-I${inc}")
|
||||
ENDFOREACH(inc)
|
||||
|
||||
FOREACH(lib ${LIBUSB_LIBRARY_DIRS})
|
||||
LIST(APPEND RTLSDR_PC_LIBS "-L${lib}")
|
||||
ENDFOREACH(lib)
|
||||
|
||||
# use space-separation format for the pc file
|
||||
STRING(REPLACE ";" " " RTLSDR_PC_CFLAGS "${RTLSDR_PC_CFLAGS}")
|
||||
STRING(REPLACE ";" " " RTLSDR_PC_LIBS "${RTLSDR_PC_LIBS}")
|
||||
|
||||
# unset these vars to avoid hard-coded paths to cross environment
|
||||
IF(CMAKE_CROSSCOMPILING)
|
||||
UNSET(RTLSDR_PC_CFLAGS)
|
||||
UNSET(RTLSDR_PC_LIBS)
|
||||
ENDIF(CMAKE_CROSSCOMPILING)
|
||||
|
||||
set(prefix ${CMAKE_INSTALL_PREFIX})
|
||||
set(exec_prefix \${prefix})
|
||||
set(libdir \${exec_prefix}/${LIB_INSTALL_DIR})
|
||||
set(includedir \${prefix}/include)
|
||||
|
||||
CONFIGURE_FILE(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/librtlsdr.pc.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/librtlsdr.pc
|
||||
@ONLY)
|
||||
|
||||
INSTALL(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/librtlsdr.pc
|
||||
DESTINATION ${LIB_INSTALL_DIR}/pkgconfig
|
||||
)
|
||||
|
||||
########################################################################
|
||||
# Print Summary
|
||||
########################################################################
|
||||
MESSAGE(STATUS "Building for version: ${VERSION} / ${LIBVER}")
|
||||
MESSAGE(STATUS "Using install prefix: ${CMAKE_INSTALL_PREFIX}")
|
|
@ -0,0 +1,339 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,49 @@
|
|||
AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
INCLUDES = $(all_includes) -I$(top_srcdir)/include
|
||||
SUBDIRS = include src
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = librtlsdr.pc
|
||||
|
||||
BUILT_SOURCES = $(top_srcdir)/.version
|
||||
$(top_srcdir)/.version:
|
||||
echo $(VERSION) > $@-t && mv $@-t $@
|
||||
dist-hook:
|
||||
echo $(VERSION) > $(distdir)/.tarball-version
|
||||
|
||||
install-udev-rules:
|
||||
$(INSTALL_DATA) rtl-sdr.rules /etc/udev/rules.d
|
||||
|
||||
uninstall-udev-rules:
|
||||
rm -rf /etc/udev/rules.d/rtl-sdr.rules
|
||||
|
||||
EXTRA_DIST = git-version-gen
|
||||
|
||||
if HAVE_DOXYGEN
|
||||
|
||||
pkgdocdir=$(docdir)/$(PACKAGE)-$(VERSION)
|
||||
doc_htmldir=$(pkgdocdir)/html
|
||||
|
||||
doc_html_DATA = $(top_builddir)/doc/html.tar
|
||||
|
||||
$(doc_html_DATA): $(top_builddir)/doc/html/index.html
|
||||
cd $(top_builddir)/doc && tar cf html.tar html
|
||||
|
||||
$(top_builddir)/doc/html/index.html: $(SOURCES) Doxyfile
|
||||
@rm -rf doc
|
||||
mkdir -p doc
|
||||
$(DOXYGEN) Doxyfile
|
||||
|
||||
install-data-hook:
|
||||
cd $(DESTDIR)$(doc_htmldir) && tar xf html.tar --strip-components 1 && rm -f html.tar
|
||||
|
||||
uninstall-hook:
|
||||
cd $(DESTDIR) && rm -rf $(doc_htmldir)
|
||||
|
||||
DX_CLEAN = doc/{html,latex}/* doc/html.tar
|
||||
|
||||
endif
|
||||
|
||||
MOSTLYCLEANFILES = $(DX_CLEAN)
|
|
@ -0,0 +1,19 @@
|
|||
rtl-sdr
|
||||
turns your Realtek RTL2832 based DVB dongle into a SDR receiver
|
||||
======================================================================
|
||||
|
||||
For more information see:
|
||||
http://sdr.osmocom.org/trac/wiki/rtl-sdr
|
||||
|
||||
## Dependencies
|
||||
|
||||
build-essential, cmake, libusb-1.0-0-dev
|
||||
|
||||
## Install
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ../ -DINSTALL_UDEV_RULES=ON
|
||||
make
|
||||
sudo make install
|
||||
sudo ldconfig
|
|
@ -0,0 +1,55 @@
|
|||
if(NOT LIBUSB_FOUND)
|
||||
pkg_check_modules (LIBUSB_PKG libusb-1.0)
|
||||
find_path(LIBUSB_INCLUDE_DIR NAMES libusb.h
|
||||
PATHS
|
||||
${LIBUSB_PKG_INCLUDE_DIRS}
|
||||
/usr/include/libusb-1.0
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
)
|
||||
|
||||
#standard library name for libusb-1.0
|
||||
set(libusb1_library_names usb-1.0)
|
||||
|
||||
#libusb-1.0 compatible library on freebsd
|
||||
if((CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") OR (CMAKE_SYSTEM_NAME STREQUAL "kFreeBSD"))
|
||||
list(APPEND libusb1_library_names usb)
|
||||
endif()
|
||||
|
||||
find_library(LIBUSB_LIBRARIES
|
||||
NAMES ${libusb1_library_names}
|
||||
PATHS
|
||||
${LIBUSB_PKG_LIBRARY_DIRS}
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
)
|
||||
|
||||
include(CheckFunctionExists)
|
||||
if(LIBUSB_INCLUDE_DIRS)
|
||||
set(CMAKE_REQUIRED_INCLUDES ${LIBUSB_INCLUDE_DIRS})
|
||||
endif()
|
||||
if(LIBUSB_LIBRARIES)
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${LIBUSB_LIBRARIES})
|
||||
endif()
|
||||
|
||||
CHECK_FUNCTION_EXISTS("libusb_handle_events_timeout_completed" HAVE_LIBUSB_HANDLE_EVENTS_TIMEOUT_COMPLETED)
|
||||
if(HAVE_LIBUSB_HANDLE_EVENTS_TIMEOUT_COMPLETED)
|
||||
add_definitions(-DHAVE_LIBUSB_HANDLE_EVENTS_TIMEOUT_COMPLETED=1)
|
||||
endif(HAVE_LIBUSB_HANDLE_EVENTS_TIMEOUT_COMPLETED)
|
||||
|
||||
CHECK_FUNCTION_EXISTS("libusb_error_name" HAVE_LIBUSB_ERROR_NAME)
|
||||
if(HAVE_LIBUSB_ERROR_NAME)
|
||||
add_definitions(-DHAVE_LIBUSB_ERROR_NAME=1)
|
||||
endif(HAVE_LIBUSB_ERROR_NAME)
|
||||
|
||||
if(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES)
|
||||
set(LIBUSB_FOUND TRUE CACHE INTERNAL "libusb-1.0 found")
|
||||
message(STATUS "Found libusb-1.0: ${LIBUSB_INCLUDE_DIR}, ${LIBUSB_LIBRARIES}")
|
||||
else(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES)
|
||||
set(LIBUSB_FOUND FALSE CACHE INTERNAL "libusb-1.0 found")
|
||||
message(STATUS "libusb-1.0 not found.")
|
||||
endif(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES)
|
||||
|
||||
mark_as_advanced(LIBUSB_INCLUDE_DIR LIBUSB_LIBRARIES)
|
||||
|
||||
endif(NOT LIBUSB_FOUND)
|
|
@ -0,0 +1,246 @@
|
|||
# Updated FindThreads.cmake that supports pthread-win32
|
||||
# Downloaded from http://www.vtk.org/Bug/bug_view_advanced_page.php?bug_id=6399
|
||||
|
||||
# - This module determines the thread library of the system.
|
||||
#
|
||||
# The following variables are set
|
||||
# CMAKE_THREAD_LIBS_INIT - the thread library
|
||||
# CMAKE_USE_SPROC_INIT - are we using sproc?
|
||||
# CMAKE_USE_WIN32_THREADS_INIT - using WIN32 threads?
|
||||
# CMAKE_USE_PTHREADS_INIT - are we using pthreads
|
||||
# CMAKE_HP_PTHREADS_INIT - are we using hp pthreads
|
||||
#
|
||||
# If use of pthreads-win32 is desired, the following variables
|
||||
# can be set.
|
||||
#
|
||||
# THREADS_USE_PTHREADS_WIN32 -
|
||||
# Setting this to true searches for the pthreads-win32
|
||||
# port (since CMake 2.8.0)
|
||||
#
|
||||
# THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME
|
||||
# C = no exceptions (default)
|
||||
# (NOTE: This is the default scheme on most POSIX thread
|
||||
# implementations and what you should probably be using)
|
||||
# CE = C++ Exception Handling
|
||||
# SE = Structure Exception Handling (MSVC only)
|
||||
# (NOTE: Changing this option from the default may affect
|
||||
# the portability of your application. See pthreads-win32
|
||||
# documentation for more details.)
|
||||
#
|
||||
#======================================================
|
||||
# Example usage where threading library
|
||||
# is provided by the system:
|
||||
#
|
||||
# find_package(Threads REQUIRED)
|
||||
# add_executable(foo foo.cc)
|
||||
# target_link_libraries(foo ${CMAKE_THREAD_LIBS_INIT})
|
||||
#
|
||||
# Example usage if pthreads-win32 is desired on Windows
|
||||
# or a system provided thread library:
|
||||
#
|
||||
# set(THREADS_USE_PTHREADS_WIN32 true)
|
||||
# find_package(Threads REQUIRED)
|
||||
# include_directories(${THREADS_PTHREADS_INCLUDE_DIR})
|
||||
#
|
||||
# add_executable(foo foo.cc)
|
||||
# target_link_libraries(foo ${CMAKE_THREAD_LIBS_INIT})
|
||||
#
|
||||
|
||||
INCLUDE (CheckIncludeFiles)
|
||||
INCLUDE (CheckLibraryExists)
|
||||
SET(Threads_FOUND FALSE)
|
||||
|
||||
IF(WIN32 AND NOT CYGWIN AND THREADS_USE_PTHREADS_WIN32)
|
||||
SET(_Threads_ptwin32 true)
|
||||
ENDIF()
|
||||
|
||||
# Do we have sproc?
|
||||
IF(CMAKE_SYSTEM MATCHES IRIX)
|
||||
CHECK_INCLUDE_FILES("sys/types.h;sys/prctl.h" CMAKE_HAVE_SPROC_H)
|
||||
ENDIF()
|
||||
|
||||
IF(CMAKE_HAVE_SPROC_H)
|
||||
# We have sproc
|
||||
SET(CMAKE_USE_SPROC_INIT 1)
|
||||
|
||||
ELSEIF(_Threads_ptwin32)
|
||||
|
||||
IF(NOT DEFINED THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME)
|
||||
# Assign the default scheme
|
||||
SET(THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME "C")
|
||||
ELSE()
|
||||
# Validate the scheme specified by the user
|
||||
IF(NOT THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME STREQUAL "C" AND
|
||||
NOT THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME STREQUAL "CE" AND
|
||||
NOT THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME STREQUAL "SE")
|
||||
MESSAGE(FATAL_ERROR "See documentation for FindPthreads.cmake, only C, CE, and SE modes are allowed")
|
||||
ENDIF()
|
||||
IF(NOT MSVC AND THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME STREQUAL "SE")
|
||||
MESSAGE(FATAL_ERROR "Structured Exception Handling is only allowed for MSVC")
|
||||
ENDIF(NOT MSVC AND THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME STREQUAL "SE")
|
||||
ENDIF()
|
||||
|
||||
FIND_PATH(THREADS_PTHREADS_INCLUDE_DIR pthread.h)
|
||||
|
||||
# Determine the library filename
|
||||
IF(MSVC)
|
||||
SET(_Threads_pthreads_libname
|
||||
pthreadV${THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME}2)
|
||||
ELSEIF(MINGW)
|
||||
SET(_Threads_pthreads_libname
|
||||
pthreadG${THREADS_PTHREADS_WIN32_EXCEPTION_SCHEME}2)
|
||||
ELSE()
|
||||
MESSAGE(FATAL_ERROR "This should never happen")
|
||||
ENDIF()
|
||||
|
||||
# Use the include path to help find the library if possible
|
||||
SET(_Threads_lib_paths "")
|
||||
IF(THREADS_PTHREADS_INCLUDE_DIR)
|
||||
GET_FILENAME_COMPONENT(_Threads_root_dir
|
||||
${THREADS_PTHREADS_INCLUDE_DIR} PATH)
|
||||
SET(_Threads_lib_paths ${_Threads_root_dir}/lib)
|
||||
ENDIF()
|
||||
FIND_LIBRARY(THREADS_PTHREADS_WIN32_LIBRARY
|
||||
NAMES ${_Threads_pthreads_libname}
|
||||
PATHS ${_Threads_lib_paths}
|
||||
DOC "The Portable Threads Library for Win32"
|
||||
NO_SYSTEM_PATH
|
||||
)
|
||||
|
||||
IF(THREADS_PTHREADS_INCLUDE_DIR AND THREADS_PTHREADS_WIN32_LIBRARY)
|
||||
MARK_AS_ADVANCED(THREADS_PTHREADS_INCLUDE_DIR)
|
||||
SET(CMAKE_THREAD_LIBS_INIT ${THREADS_PTHREADS_WIN32_LIBRARY})
|
||||
SET(CMAKE_HAVE_THREADS_LIBRARY 1)
|
||||
SET(Threads_FOUND TRUE)
|
||||
ENDIF()
|
||||
|
||||
MARK_AS_ADVANCED(THREADS_PTHREADS_WIN32_LIBRARY)
|
||||
|
||||
ELSE()
|
||||
# Do we have pthreads?
|
||||
CHECK_INCLUDE_FILES("pthread.h" CMAKE_HAVE_PTHREAD_H)
|
||||
IF(CMAKE_HAVE_PTHREAD_H)
|
||||
|
||||
#
|
||||
# We have pthread.h
|
||||
# Let's check for the library now.
|
||||
#
|
||||
SET(CMAKE_HAVE_THREADS_LIBRARY)
|
||||
IF(NOT THREADS_HAVE_PTHREAD_ARG)
|
||||
|
||||
# Do we have -lpthreads
|
||||
CHECK_LIBRARY_EXISTS(pthreads pthread_create "" CMAKE_HAVE_PTHREADS_CREATE)
|
||||
IF(CMAKE_HAVE_PTHREADS_CREATE)
|
||||
SET(CMAKE_THREAD_LIBS_INIT "-lpthreads")
|
||||
SET(CMAKE_HAVE_THREADS_LIBRARY 1)
|
||||
SET(Threads_FOUND TRUE)
|
||||
ENDIF()
|
||||
|
||||
# Ok, how about -lpthread
|
||||
CHECK_LIBRARY_EXISTS(pthread pthread_create "" CMAKE_HAVE_PTHREAD_CREATE)
|
||||
IF(CMAKE_HAVE_PTHREAD_CREATE)
|
||||
SET(CMAKE_THREAD_LIBS_INIT "-lpthread")
|
||||
SET(Threads_FOUND TRUE)
|
||||
SET(CMAKE_HAVE_THREADS_LIBRARY 1)
|
||||
ENDIF()
|
||||
|
||||
IF(CMAKE_SYSTEM MATCHES "SunOS.*")
|
||||
# On sun also check for -lthread
|
||||
CHECK_LIBRARY_EXISTS(thread thr_create "" CMAKE_HAVE_THR_CREATE)
|
||||
IF(CMAKE_HAVE_THR_CREATE)
|
||||
SET(CMAKE_THREAD_LIBS_INIT "-lthread")
|
||||
SET(CMAKE_HAVE_THREADS_LIBRARY 1)
|
||||
SET(Threads_FOUND TRUE)
|
||||
ENDIF()
|
||||
ENDIF(CMAKE_SYSTEM MATCHES "SunOS.*")
|
||||
|
||||
ENDIF(NOT THREADS_HAVE_PTHREAD_ARG)
|
||||
|
||||
IF(NOT CMAKE_HAVE_THREADS_LIBRARY)
|
||||
# If we did not found -lpthread, -lpthread, or -lthread, look for -pthread
|
||||
IF("THREADS_HAVE_PTHREAD_ARG" MATCHES "^THREADS_HAVE_PTHREAD_ARG")
|
||||
MESSAGE(STATUS "Check if compiler accepts -pthread")
|
||||
TRY_RUN(THREADS_PTHREAD_ARG THREADS_HAVE_PTHREAD_ARG
|
||||
${CMAKE_BINARY_DIR}
|
||||
${CMAKE_ROOT}/Modules/CheckForPthreads.c
|
||||
CMAKE_FLAGS -DLINK_LIBRARIES:STRING=-pthread
|
||||
COMPILE_OUTPUT_VARIABLE OUTPUT)
|
||||
|
||||
IF(THREADS_HAVE_PTHREAD_ARG)
|
||||
IF(THREADS_PTHREAD_ARG MATCHES "^2$")
|
||||
SET(Threads_FOUND TRUE)
|
||||
MESSAGE(STATUS "Check if compiler accepts -pthread - yes")
|
||||
ELSE()
|
||||
MESSAGE(STATUS "Check if compiler accepts -pthread - no")
|
||||
FILE(APPEND
|
||||
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
|
||||
"Determining if compiler accepts -pthread returned ${THREADS_PTHREAD_ARG} instead of 2. The compiler had the following output:\n${OUTPUT}\n\n")
|
||||
ENDIF()
|
||||
ELSE()
|
||||
MESSAGE(STATUS "Check if compiler accepts -pthread - no")
|
||||
FILE(APPEND
|
||||
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
|
||||
"Determining if compiler accepts -pthread failed with the following output:\n${OUTPUT}\n\n")
|
||||
ENDIF()
|
||||
|
||||
ENDIF("THREADS_HAVE_PTHREAD_ARG" MATCHES "^THREADS_HAVE_PTHREAD_ARG")
|
||||
|
||||
IF(THREADS_HAVE_PTHREAD_ARG)
|
||||
SET(Threads_FOUND TRUE)
|
||||
SET(CMAKE_THREAD_LIBS_INIT "-pthread")
|
||||
ENDIF()
|
||||
|
||||
ENDIF(NOT CMAKE_HAVE_THREADS_LIBRARY)
|
||||
ENDIF(CMAKE_HAVE_PTHREAD_H)
|
||||
ENDIF()
|
||||
|
||||
IF(CMAKE_THREAD_LIBS_INIT)
|
||||
SET(CMAKE_USE_PTHREADS_INIT 1)
|
||||
SET(Threads_FOUND TRUE)
|
||||
ENDIF()
|
||||
|
||||
IF(CMAKE_SYSTEM MATCHES "Windows"
|
||||
AND NOT THREADS_USE_PTHREADS_WIN32)
|
||||
SET(CMAKE_USE_WIN32_THREADS_INIT 1)
|
||||
SET(Threads_FOUND TRUE)
|
||||
ENDIF()
|
||||
|
||||
IF(CMAKE_USE_PTHREADS_INIT)
|
||||
IF(CMAKE_SYSTEM MATCHES "HP-UX-*")
|
||||
# Use libcma if it exists and can be used. It provides more
|
||||
# symbols than the plain pthread library. CMA threads
|
||||
# have actually been deprecated:
|
||||
# http://docs.hp.com/en/B3920-90091/ch12s03.html#d0e11395
|
||||
# http://docs.hp.com/en/947/d8.html
|
||||
# but we need to maintain compatibility here.
|
||||
# The CMAKE_HP_PTHREADS setting actually indicates whether CMA threads
|
||||
# are available.
|
||||
CHECK_LIBRARY_EXISTS(cma pthread_attr_create "" CMAKE_HAVE_HP_CMA)
|
||||
IF(CMAKE_HAVE_HP_CMA)
|
||||
SET(CMAKE_THREAD_LIBS_INIT "-lcma")
|
||||
SET(CMAKE_HP_PTHREADS_INIT 1)
|
||||
SET(Threads_FOUND TRUE)
|
||||
ENDIF(CMAKE_HAVE_HP_CMA)
|
||||
SET(CMAKE_USE_PTHREADS_INIT 1)
|
||||
ENDIF()
|
||||
|
||||
IF(CMAKE_SYSTEM MATCHES "OSF1-V*")
|
||||
SET(CMAKE_USE_PTHREADS_INIT 0)
|
||||
SET(CMAKE_THREAD_LIBS_INIT )
|
||||
ENDIF()
|
||||
|
||||
IF(CMAKE_SYSTEM MATCHES "CYGWIN_NT*")
|
||||
SET(CMAKE_USE_PTHREADS_INIT 1)
|
||||
SET(Threads_FOUND TRUE)
|
||||
SET(CMAKE_THREAD_LIBS_INIT )
|
||||
SET(CMAKE_USE_WIN32_THREADS_INIT 0)
|
||||
ENDIF()
|
||||
ENDIF(CMAKE_USE_PTHREADS_INIT)
|
||||
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
IF(_Threads_ptwin32)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Threads DEFAULT_MSG
|
||||
THREADS_PTHREADS_WIN32_LIBRARY THREADS_PTHREADS_INCLUDE_DIR)
|
||||
ELSE()
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Threads DEFAULT_MSG Threads_FOUND)
|
||||
ENDIF()
|
|
@ -0,0 +1,60 @@
|
|||
# Copyright 2013 OSMOCOM Project
|
||||
#
|
||||
# This file is part of rtl-sdr
|
||||
#
|
||||
# rtl-sdr is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# rtl-sdr is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with rtl-sdr; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
if(DEFINED __INCLUDED_VERSION_CMAKE)
|
||||
return()
|
||||
endif()
|
||||
set(__INCLUDED_VERSION_CMAKE TRUE)
|
||||
|
||||
# VERSION_INFO_* variables must be provided by user
|
||||
set(MAJOR_VERSION ${VERSION_INFO_MAJOR_VERSION})
|
||||
set(MINOR_VERSION ${VERSION_INFO_MINOR_VERSION})
|
||||
set(PATCH_VERSION ${VERSION_INFO_PATCH_VERSION})
|
||||
|
||||
########################################################################
|
||||
# Extract the version string from git describe.
|
||||
########################################################################
|
||||
find_package(Git QUIET)
|
||||
|
||||
if(GIT_FOUND)
|
||||
message(STATUS "Extracting version information from git describe...")
|
||||
execute_process(
|
||||
COMMAND ${GIT_EXECUTABLE} describe --always --abbrev=4 --long
|
||||
OUTPUT_VARIABLE GIT_DESCRIBE OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
)
|
||||
else()
|
||||
set(GIT_DESCRIBE "v${MAJOR_VERSION}.${MINOR_VERSION}.x-xxx-xunknown")
|
||||
endif()
|
||||
|
||||
########################################################################
|
||||
# Use the logic below to set the version constants
|
||||
########################################################################
|
||||
if("${PATCH_VERSION}" STREQUAL "git")
|
||||
# VERSION: 3.6git-xxx-gxxxxxxxx
|
||||
# LIBVER: 3.6git
|
||||
set(VERSION "${GIT_DESCRIBE}")
|
||||
set(LIBVER "${MAJOR_VERSION}.${MINOR_VERSION}${PATCH_VERSION}")
|
||||
else()
|
||||
# This is a numbered release.
|
||||
# VERSION: 3.6.1
|
||||
# LIBVER: 3.6.1
|
||||
set(VERSION "${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}")
|
||||
set(LIBVER "${VERSION}")
|
||||
endif()
|
|
@ -0,0 +1,32 @@
|
|||
# http://www.vtk.org/Wiki/CMake_FAQ#Can_I_do_.22make_uninstall.22_with_CMake.3F
|
||||
|
||||
IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
|
||||
MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"")
|
||||
ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
|
||||
|
||||
FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
|
||||
STRING(REGEX REPLACE "\n" ";" files "${files}")
|
||||
FOREACH(file ${files})
|
||||
MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"")
|
||||
IF(EXISTS "$ENV{DESTDIR}${file}")
|
||||
EXEC_PROGRAM(
|
||||
"@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
|
||||
OUTPUT_VARIABLE rm_out
|
||||
RETURN_VALUE rm_retval
|
||||
)
|
||||
IF(NOT "${rm_retval}" STREQUAL 0)
|
||||
MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"")
|
||||
ENDIF(NOT "${rm_retval}" STREQUAL 0)
|
||||
ELSEIF(IS_SYMLINK "$ENV{DESTDIR}${file}")
|
||||
EXEC_PROGRAM(
|
||||
"@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
|
||||
OUTPUT_VARIABLE rm_out
|
||||
RETURN_VALUE rm_retval
|
||||
)
|
||||
IF(NOT "${rm_retval}" STREQUAL 0)
|
||||
MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"")
|
||||
ENDIF(NOT "${rm_retval}" STREQUAL 0)
|
||||
ELSE(EXISTS "$ENV{DESTDIR}${file}")
|
||||
MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.")
|
||||
ENDIF(EXISTS "$ENV{DESTDIR}${file}")
|
||||
ENDFOREACH(file)
|
|
@ -0,0 +1,86 @@
|
|||
AC_INIT([librtlsdr],
|
||||
m4_esyscmd([./git-version-gen .tarball-version]),
|
||||
[osmocom-sdr@lists.osmocom.org])
|
||||
|
||||
AM_INIT_AUTOMAKE([dist-bzip2])
|
||||
|
||||
dnl kernel style compile messages
|
||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
||||
|
||||
dnl checks for programs
|
||||
AC_PROG_MAKE_SET
|
||||
AC_PROG_CC
|
||||
AC_PROG_INSTALL
|
||||
AM_PROG_CC_C_O
|
||||
LT_INIT
|
||||
AC_PROG_LIBTOOL
|
||||
|
||||
PKG_CHECK_MODULES(LIBUSB, libusb-1.0 >= 1.0)
|
||||
LIBS="$LIBS $LIBUSB_LIBS"
|
||||
CFLAGS="$CFLAGS $LIBUSB_CFLAGS"
|
||||
|
||||
AC_PATH_PROG(DOXYGEN,doxygen,false)
|
||||
AM_CONDITIONAL(HAVE_DOXYGEN, test $DOXYGEN != false)
|
||||
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
|
||||
dnl checks for header files
|
||||
AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS(sys/types.h)
|
||||
AC_CHECK_HEADERS(pthread.h,, [AC_MSG_ERROR([pthread.h required])])
|
||||
|
||||
# pc variables
|
||||
AC_SUBST(RTLSDR_PC_LIBS,["$LIBS"])
|
||||
AC_SUBST(RTLSDR_PC_CFLAGS,["$CFLAGS"])
|
||||
|
||||
dnl checks for required libraries
|
||||
dnl pthreads
|
||||
AC_CHECK_LIB(pthread, pthread_create, [LIBS="$LIBS -lpthread"])
|
||||
|
||||
dnl libmath (for rtl_fm)
|
||||
AC_CHECK_LIB(m, atan2, [LIBS="$LIBS -lm"])
|
||||
|
||||
dnl libmath (for rtl_adsb)
|
||||
AC_CHECK_LIB(m, sqrt, [LIBS="$LIBS -lm"])
|
||||
|
||||
dnl libmath (for rtl_power)
|
||||
AC_CHECK_LIB(m, atan2, [LIBS="$LIBS -lm"])
|
||||
|
||||
dnl librealtime (for rtl_test)
|
||||
AC_CHECK_LIB(rt, clock_gettime, [LIBS="$LIBS -lrt"])
|
||||
|
||||
# The following test is taken from WebKit's webkit.m4
|
||||
saved_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -fvisibility=hidden "
|
||||
AC_MSG_CHECKING([if ${CC} supports -fvisibility=hidden])
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([char foo;])],
|
||||
[ AC_MSG_RESULT([yes])
|
||||
SYMBOL_VISIBILITY="-fvisibility=hidden"],
|
||||
AC_MSG_RESULT([no]))
|
||||
CFLAGS="$saved_CFLAGS"
|
||||
AC_SUBST(SYMBOL_VISIBILITY)
|
||||
|
||||
AC_MSG_CHECKING(whether compiler understands -Wall)
|
||||
old_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -Wall -Wextra -Wno-unused-parameter -Wno-unused -Wsign-compare -Wdeclaration-after-statement"
|
||||
AC_TRY_COMPILE([],[],
|
||||
AC_MSG_RESULT(yes),
|
||||
AC_MSG_RESULT(no)
|
||||
CFLAGS="$old_CFLAGS")
|
||||
|
||||
AC_ARG_ENABLE(driver-detach,
|
||||
[ --enable-driver-detach Enable detaching of kernel driver (disabled by default)],
|
||||
[if test x$enableval = xyes; then
|
||||
CFLAGS="$CFLAGS -DDETACH_KERNEL_DRIVER"
|
||||
fi])
|
||||
|
||||
dnl Generate the output
|
||||
AC_CONFIG_HEADER(config.h)
|
||||
|
||||
AC_OUTPUT(
|
||||
librtlsdr.pc
|
||||
include/Makefile
|
||||
src/Makefile
|
||||
Makefile
|
||||
Doxyfile
|
||||
)
|
|
@ -0,0 +1,151 @@
|
|||
#!/bin/sh
|
||||
# Print a version string.
|
||||
scriptversion=2010-01-28.01
|
||||
|
||||
# Copyright (C) 2007-2010 Free Software Foundation, Inc.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# This script is derived from GIT-VERSION-GEN from GIT: http://git.or.cz/.
|
||||
# It may be run two ways:
|
||||
# - from a git repository in which the "git describe" command below
|
||||
# produces useful output (thus requiring at least one signed tag)
|
||||
# - from a non-git-repo directory containing a .tarball-version file, which
|
||||
# presumes this script is invoked like "./git-version-gen .tarball-version".
|
||||
|
||||
# In order to use intra-version strings in your project, you will need two
|
||||
# separate generated version string files:
|
||||
#
|
||||
# .tarball-version - present only in a distribution tarball, and not in
|
||||
# a checked-out repository. Created with contents that were learned at
|
||||
# the last time autoconf was run, and used by git-version-gen. Must not
|
||||
# be present in either $(srcdir) or $(builddir) for git-version-gen to
|
||||
# give accurate answers during normal development with a checked out tree,
|
||||
# but must be present in a tarball when there is no version control system.
|
||||
# Therefore, it cannot be used in any dependencies. GNUmakefile has
|
||||
# hooks to force a reconfigure at distribution time to get the value
|
||||
# correct, without penalizing normal development with extra reconfigures.
|
||||
#
|
||||
# .version - present in a checked-out repository and in a distribution
|
||||
# tarball. Usable in dependencies, particularly for files that don't
|
||||
# want to depend on config.h but do want to track version changes.
|
||||
# Delete this file prior to any autoconf run where you want to rebuild
|
||||
# files to pick up a version string change; and leave it stale to
|
||||
# minimize rebuild time after unrelated changes to configure sources.
|
||||
#
|
||||
# It is probably wise to add these two files to .gitignore, so that you
|
||||
# don't accidentally commit either generated file.
|
||||
#
|
||||
# Use the following line in your configure.ac, so that $(VERSION) will
|
||||
# automatically be up-to-date each time configure is run (and note that
|
||||
# since configure.ac no longer includes a version string, Makefile rules
|
||||
# should not depend on configure.ac for version updates).
|
||||
#
|
||||
# AC_INIT([GNU project],
|
||||
# m4_esyscmd([build-aux/git-version-gen .tarball-version]),
|
||||
# [bug-project@example])
|
||||
#
|
||||
# Then use the following lines in your Makefile.am, so that .version
|
||||
# will be present for dependencies, and so that .tarball-version will
|
||||
# exist in distribution tarballs.
|
||||
#
|
||||
# BUILT_SOURCES = $(top_srcdir)/.version
|
||||
# $(top_srcdir)/.version:
|
||||
# echo $(VERSION) > $@-t && mv $@-t $@
|
||||
# dist-hook:
|
||||
# echo $(VERSION) > $(distdir)/.tarball-version
|
||||
|
||||
case $# in
|
||||
1) ;;
|
||||
*) echo 1>&2 "Usage: $0 \$srcdir/.tarball-version"; exit 1;;
|
||||
esac
|
||||
|
||||
tarball_version_file=$1
|
||||
nl='
|
||||
'
|
||||
|
||||
# First see if there is a tarball-only version file.
|
||||
# then try "git describe", then default.
|
||||
if test -f $tarball_version_file
|
||||
then
|
||||
v=`cat $tarball_version_file` || exit 1
|
||||
case $v in
|
||||
*$nl*) v= ;; # reject multi-line output
|
||||
[0-9]*) ;;
|
||||
*) v= ;;
|
||||
esac
|
||||
test -z "$v" \
|
||||
&& echo "$0: WARNING: $tarball_version_file seems to be damaged" 1>&2
|
||||
fi
|
||||
|
||||
if test -n "$v"
|
||||
then
|
||||
: # use $v
|
||||
elif
|
||||
v=`git describe --abbrev=4 --match='v*' HEAD 2>/dev/null \
|
||||
|| git describe --abbrev=4 HEAD 2>/dev/null` \
|
||||
&& case $v in
|
||||
[0-9]*) ;;
|
||||
v[0-9]*) ;;
|
||||
*) (exit 1) ;;
|
||||
esac
|
||||
then
|
||||
# Is this a new git that lists number of commits since the last
|
||||
# tag or the previous older version that did not?
|
||||
# Newer: v6.10-77-g0f8faeb
|
||||
# Older: v6.10-g0f8faeb
|
||||
case $v in
|
||||
*-*-*) : git describe is okay three part flavor ;;
|
||||
*-*)
|
||||
: git describe is older two part flavor
|
||||
# Recreate the number of commits and rewrite such that the
|
||||
# result is the same as if we were using the newer version
|
||||
# of git describe.
|
||||
vtag=`echo "$v" | sed 's/-.*//'`
|
||||
numcommits=`git rev-list "$vtag"..HEAD | wc -l`
|
||||
v=`echo "$v" | sed "s/\(.*\)-\(.*\)/\1-$numcommits-\2/"`;
|
||||
;;
|
||||
esac
|
||||
|
||||
# Change the first '-' to a '.', so version-comparing tools work properly.
|
||||
# Remove the "g" in git describe's output string, to save a byte.
|
||||
v=`echo "$v" | sed 's/-/./;s/\(.*\)-g/\1-/'`;
|
||||
else
|
||||
v=UNKNOWN
|
||||
fi
|
||||
|
||||
v=`echo "$v" |sed 's/^v//'`
|
||||
|
||||
# Don't declare a version "dirty" merely because a time stamp has changed.
|
||||
git status > /dev/null 2>&1
|
||||
|
||||
dirty=`sh -c 'git diff-index --name-only HEAD' 2>/dev/null` || dirty=
|
||||
case "$dirty" in
|
||||
'') ;;
|
||||
*) # Append the suffix only if there isn't one already.
|
||||
case $v in
|
||||
*-dirty) ;;
|
||||
*) v="$v-dirty" ;;
|
||||
esac ;;
|
||||
esac
|
||||
|
||||
# Omit the trailing newline, so that m4_esyscmd can use the result directly.
|
||||
echo "$v" | tr -d '\012'
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-end: "$"
|
||||
# End:
|
|
@ -0,0 +1,27 @@
|
|||
# Copyright 2012 OSMOCOM Project
|
||||
#
|
||||
# This file is part of rtl-sdr
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
########################################################################
|
||||
# Install public header files
|
||||
########################################################################
|
||||
install(FILES
|
||||
rtl-sdr.h
|
||||
rtl-sdr_export.h
|
||||
DESTINATION include
|
||||
)
|
|
@ -0,0 +1,5 @@
|
|||
rtlsdr_HEADERS = rtl-sdr.h rtl-sdr_export.h
|
||||
|
||||
noinst_HEADERS = reg_field.h rtlsdr_i2c.h tuner_e4k.h tuner_fc0012.h tuner_fc0013.h tuner_fc2580.h tuner_r82xx.h
|
||||
|
||||
rtlsdrdir = $(includedir)
|
|
@ -0,0 +1,60 @@
|
|||
#ifndef _REG_FIELD_H
|
||||
#define _REG_FIELD_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
enum cmd_op {
|
||||
CMD_OP_GET = (1 << 0),
|
||||
CMD_OP_SET = (1 << 1),
|
||||
CMD_OP_EXEC = (1 << 2),
|
||||
};
|
||||
|
||||
enum pstate {
|
||||
ST_IN_CMD,
|
||||
ST_IN_ARG,
|
||||
};
|
||||
|
||||
struct strbuf {
|
||||
uint8_t idx;
|
||||
char buf[32];
|
||||
};
|
||||
|
||||
struct cmd_state {
|
||||
struct strbuf cmd;
|
||||
struct strbuf arg;
|
||||
enum pstate state;
|
||||
void (*out)(const char *format, va_list ap);
|
||||
};
|
||||
|
||||
struct cmd {
|
||||
const char *cmd;
|
||||
uint32_t ops;
|
||||
int (*cb)(struct cmd_state *cs, enum cmd_op op, const char *cmd,
|
||||
int argc, char **argv);
|
||||
const char *help;
|
||||
};
|
||||
|
||||
/* structure describing a field in a register */
|
||||
struct reg_field {
|
||||
uint8_t reg;
|
||||
uint8_t shift;
|
||||
uint8_t width;
|
||||
};
|
||||
|
||||
struct reg_field_ops {
|
||||
const struct reg_field *fields;
|
||||
const char **field_names;
|
||||
uint32_t num_fields;
|
||||
void *data;
|
||||
int (*write_cb)(void *data, uint32_t reg, uint32_t val);
|
||||
uint32_t (*read_cb)(void *data, uint32_t reg);
|
||||
};
|
||||
|
||||
uint32_t reg_field_read(struct reg_field_ops *ops, struct reg_field *field);
|
||||
int reg_field_write(struct reg_field_ops *ops, struct reg_field *field, uint32_t val);
|
||||
int reg_field_cmd(struct cmd_state *cs, enum cmd_op op,
|
||||
const char *cmd, int argc, char **argv,
|
||||
struct reg_field_ops *ops);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,387 @@
|
|||
/*
|
||||
* rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver
|
||||
* Copyright (C) 2012-2013 by Steve Markgraf <steve@steve-m.de>
|
||||
* Copyright (C) 2012 by Dimitri Stolnikov <horiz0n@gmx.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __RTL_SDR_H
|
||||
#define __RTL_SDR_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <rtl-sdr_export.h>
|
||||
|
||||
typedef struct rtlsdr_dev rtlsdr_dev_t;
|
||||
|
||||
RTLSDR_API uint32_t rtlsdr_get_device_count(void);
|
||||
|
||||
RTLSDR_API const char* rtlsdr_get_device_name(uint32_t index);
|
||||
|
||||
/*!
|
||||
* Get USB device strings.
|
||||
*
|
||||
* NOTE: The string arguments must provide space for up to 256 bytes.
|
||||
*
|
||||
* \param index the device index
|
||||
* \param manufact manufacturer name, may be NULL
|
||||
* \param product product name, may be NULL
|
||||
* \param serial serial number, may be NULL
|
||||
* \return 0 on success
|
||||
*/
|
||||
RTLSDR_API int rtlsdr_get_device_usb_strings(uint32_t index,
|
||||
char *manufact,
|
||||
char *product,
|
||||
char *serial);
|
||||
|
||||
/*!
|
||||
* Get device index by USB serial string descriptor.
|
||||
*
|
||||
* \param serial serial string of the device
|
||||
* \return device index of first device where the name matched
|
||||
* \return -1 if name is NULL
|
||||
* \return -2 if no devices were found at all
|
||||
* \return -3 if devices were found, but none with matching name
|
||||
*/
|
||||
RTLSDR_API int rtlsdr_get_index_by_serial(const char *serial);
|
||||
|
||||
RTLSDR_API int rtlsdr_open(rtlsdr_dev_t **dev, uint32_t index);
|
||||
|
||||
RTLSDR_API int rtlsdr_close(rtlsdr_dev_t *dev);
|
||||
|
||||
/* configuration functions */
|
||||
|
||||
/*!
|
||||
* Set crystal oscillator frequencies used for the RTL2832 and the tuner IC.
|
||||
*
|
||||
* Usually both ICs use the same clock. Changing the clock may make sense if
|
||||
* you are applying an external clock to the tuner or to compensate the
|
||||
* frequency (and samplerate) error caused by the original (cheap) crystal.
|
||||
*
|
||||
* NOTE: Call this function only if you fully understand the implications.
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \param rtl_freq frequency value used to clock the RTL2832 in Hz
|
||||
* \param tuner_freq frequency value used to clock the tuner IC in Hz
|
||||
* \return 0 on success
|
||||
*/
|
||||
RTLSDR_API int rtlsdr_set_xtal_freq(rtlsdr_dev_t *dev, uint32_t rtl_freq,
|
||||
uint32_t tuner_freq);
|
||||
|
||||
/*!
|
||||
* Get crystal oscillator frequencies used for the RTL2832 and the tuner IC.
|
||||
*
|
||||
* Usually both ICs use the same clock.
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \param rtl_freq frequency value used to clock the RTL2832 in Hz
|
||||
* \param tuner_freq frequency value used to clock the tuner IC in Hz
|
||||
* \return 0 on success
|
||||
*/
|
||||
RTLSDR_API int rtlsdr_get_xtal_freq(rtlsdr_dev_t *dev, uint32_t *rtl_freq,
|
||||
uint32_t *tuner_freq);
|
||||
|
||||
/*!
|
||||
* Get USB device strings.
|
||||
*
|
||||
* NOTE: The string arguments must provide space for up to 256 bytes.
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \param manufact manufacturer name, may be NULL
|
||||
* \param product product name, may be NULL
|
||||
* \param serial serial number, may be NULL
|
||||
* \return 0 on success
|
||||
*/
|
||||
RTLSDR_API int rtlsdr_get_usb_strings(rtlsdr_dev_t *dev, char *manufact,
|
||||
char *product, char *serial);
|
||||
|
||||
/*!
|
||||
* Write the device EEPROM
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \param data buffer of data to be written
|
||||
* \param offset address where the data should be written
|
||||
* \param len length of the data
|
||||
* \return 0 on success
|
||||
* \return -1 if device handle is invalid
|
||||
* \return -2 if EEPROM size is exceeded
|
||||
* \return -3 if no EEPROM was found
|
||||
*/
|
||||
|
||||
RTLSDR_API int rtlsdr_write_eeprom(rtlsdr_dev_t *dev, uint8_t *data,
|
||||
uint8_t offset, uint16_t len);
|
||||
|
||||
/*!
|
||||
* Read the device EEPROM
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \param data buffer where the data should be written
|
||||
* \param offset address where the data should be read from
|
||||
* \param len length of the data
|
||||
* \return 0 on success
|
||||
* \return -1 if device handle is invalid
|
||||
* \return -2 if EEPROM size is exceeded
|
||||
* \return -3 if no EEPROM was found
|
||||
*/
|
||||
|
||||
RTLSDR_API int rtlsdr_read_eeprom(rtlsdr_dev_t *dev, uint8_t *data,
|
||||
uint8_t offset, uint16_t len);
|
||||
|
||||
RTLSDR_API int rtlsdr_set_center_freq(rtlsdr_dev_t *dev, uint32_t freq);
|
||||
|
||||
/*!
|
||||
* Get actual frequency the device is tuned to.
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \return 0 on error, frequency in Hz otherwise
|
||||
*/
|
||||
RTLSDR_API uint32_t rtlsdr_get_center_freq(rtlsdr_dev_t *dev);
|
||||
|
||||
/*!
|
||||
* Set the frequency correction value for the device.
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \param ppm correction value in parts per million (ppm)
|
||||
* \return 0 on success
|
||||
*/
|
||||
RTLSDR_API int rtlsdr_set_freq_correction(rtlsdr_dev_t *dev, int ppm);
|
||||
|
||||
/*!
|
||||
* Get actual frequency correction value of the device.
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \return correction value in parts per million (ppm)
|
||||
*/
|
||||
RTLSDR_API int rtlsdr_get_freq_correction(rtlsdr_dev_t *dev);
|
||||
|
||||
enum rtlsdr_tuner {
|
||||
RTLSDR_TUNER_UNKNOWN = 0,
|
||||
RTLSDR_TUNER_E4000,
|
||||
RTLSDR_TUNER_FC0012,
|
||||
RTLSDR_TUNER_FC0013,
|
||||
RTLSDR_TUNER_FC2580,
|
||||
RTLSDR_TUNER_R820T,
|
||||
RTLSDR_TUNER_R828D
|
||||
};
|
||||
|
||||
/*!
|
||||
* Get the tuner type.
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \return RTLSDR_TUNER_UNKNOWN on error, tuner type otherwise
|
||||
*/
|
||||
RTLSDR_API enum rtlsdr_tuner rtlsdr_get_tuner_type(rtlsdr_dev_t *dev);
|
||||
|
||||
/*!
|
||||
* Get a list of gains supported by the tuner.
|
||||
*
|
||||
* NOTE: The gains argument must be preallocated by the caller. If NULL is
|
||||
* being given instead, the number of available gain values will be returned.
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \param gains array of gain values. In tenths of a dB, 115 means 11.5 dB.
|
||||
* \return <= 0 on error, number of available (returned) gain values otherwise
|
||||
*/
|
||||
RTLSDR_API int rtlsdr_get_tuner_gains(rtlsdr_dev_t *dev, int *gains);
|
||||
|
||||
/*!
|
||||
* Set the gain for the device.
|
||||
* Manual gain mode must be enabled for this to work.
|
||||
*
|
||||
* Valid gain values (in tenths of a dB) for the E4000 tuner:
|
||||
* -10, 15, 40, 65, 90, 115, 140, 165, 190,
|
||||
* 215, 240, 290, 340, 420, 430, 450, 470, 490
|
||||
*
|
||||
* Valid gain values may be queried with \ref rtlsdr_get_tuner_gains function.
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \param gain in tenths of a dB, 115 means 11.5 dB.
|
||||
* \return 0 on success
|
||||
*/
|
||||
RTLSDR_API int rtlsdr_set_tuner_gain(rtlsdr_dev_t *dev, int gain);
|
||||
|
||||
/*!
|
||||
* Set the bandwidth for the device.
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \param bw bandwidth in Hz. Zero means automatic BW selection.
|
||||
* \return 0 on success
|
||||
*/
|
||||
RTLSDR_API int rtlsdr_set_tuner_bandwidth(rtlsdr_dev_t *dev, uint32_t bw);
|
||||
|
||||
/*!
|
||||
* Get actual gain the device is configured to.
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \return 0 on error, gain in tenths of a dB, 115 means 11.5 dB.
|
||||
*/
|
||||
RTLSDR_API int rtlsdr_get_tuner_gain(rtlsdr_dev_t *dev);
|
||||
|
||||
/*!
|
||||
* Set the intermediate frequency gain for the device.
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \param stage intermediate frequency gain stage number (1 to 6 for E4000)
|
||||
* \param gain in tenths of a dB, -30 means -3.0 dB.
|
||||
* \return 0 on success
|
||||
*/
|
||||
RTLSDR_API int rtlsdr_set_tuner_if_gain(rtlsdr_dev_t *dev, int stage, int gain);
|
||||
|
||||
/*!
|
||||
* Set the gain mode (automatic/manual) for the device.
|
||||
* Manual gain mode must be enabled for the gain setter function to work.
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \param manual gain mode, 1 means manual gain mode shall be enabled.
|
||||
* \return 0 on success
|
||||
*/
|
||||
RTLSDR_API int rtlsdr_set_tuner_gain_mode(rtlsdr_dev_t *dev, int manual);
|
||||
|
||||
/*!
|
||||
* Set the sample rate for the device, also selects the baseband filters
|
||||
* according to the requested sample rate for tuners where this is possible.
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \param samp_rate the sample rate to be set, possible values are:
|
||||
* 225001 - 300000 Hz
|
||||
* 900001 - 3200000 Hz
|
||||
* sample loss is to be expected for rates > 2400000
|
||||
* \return 0 on success, -EINVAL on invalid rate
|
||||
*/
|
||||
RTLSDR_API int rtlsdr_set_sample_rate(rtlsdr_dev_t *dev, uint32_t rate);
|
||||
|
||||
/*!
|
||||
* Get actual sample rate the device is configured to.
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \return 0 on error, sample rate in Hz otherwise
|
||||
*/
|
||||
RTLSDR_API uint32_t rtlsdr_get_sample_rate(rtlsdr_dev_t *dev);
|
||||
|
||||
/*!
|
||||
* Enable test mode that returns an 8 bit counter instead of the samples.
|
||||
* The counter is generated inside the RTL2832.
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \param test mode, 1 means enabled, 0 disabled
|
||||
* \return 0 on success
|
||||
*/
|
||||
RTLSDR_API int rtlsdr_set_testmode(rtlsdr_dev_t *dev, int on);
|
||||
|
||||
/*!
|
||||
* Enable or disable the internal digital AGC of the RTL2832.
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \param digital AGC mode, 1 means enabled, 0 disabled
|
||||
* \return 0 on success
|
||||
*/
|
||||
RTLSDR_API int rtlsdr_set_agc_mode(rtlsdr_dev_t *dev, int on);
|
||||
|
||||
/*!
|
||||
* Enable or disable the direct sampling mode. When enabled, the IF mode
|
||||
* of the RTL2832 is activated, and rtlsdr_set_center_freq() will control
|
||||
* the IF-frequency of the DDC, which can be used to tune from 0 to 28.8 MHz
|
||||
* (xtal frequency of the RTL2832).
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \param on 0 means disabled, 1 I-ADC input enabled, 2 Q-ADC input enabled
|
||||
* \return 0 on success
|
||||
*/
|
||||
RTLSDR_API int rtlsdr_set_direct_sampling(rtlsdr_dev_t *dev, int on);
|
||||
|
||||
/*!
|
||||
* Get state of the direct sampling mode
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \return -1 on error, 0 means disabled, 1 I-ADC input enabled
|
||||
* 2 Q-ADC input enabled
|
||||
*/
|
||||
RTLSDR_API int rtlsdr_get_direct_sampling(rtlsdr_dev_t *dev);
|
||||
|
||||
/*!
|
||||
* Enable or disable offset tuning for zero-IF tuners, which allows to avoid
|
||||
* problems caused by the DC offset of the ADCs and 1/f noise.
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \param on 0 means disabled, 1 enabled
|
||||
* \return 0 on success
|
||||
*/
|
||||
RTLSDR_API int rtlsdr_set_offset_tuning(rtlsdr_dev_t *dev, int on);
|
||||
|
||||
/*!
|
||||
* Get state of the offset tuning mode
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \return -1 on error, 0 means disabled, 1 enabled
|
||||
*/
|
||||
RTLSDR_API int rtlsdr_get_offset_tuning(rtlsdr_dev_t *dev);
|
||||
|
||||
/* streaming functions */
|
||||
|
||||
RTLSDR_API int rtlsdr_reset_buffer(rtlsdr_dev_t *dev);
|
||||
|
||||
RTLSDR_API int rtlsdr_read_sync(rtlsdr_dev_t *dev, void *buf, int len, int *n_read);
|
||||
|
||||
typedef void(*rtlsdr_read_async_cb_t)(unsigned char *buf, uint32_t len, void *ctx);
|
||||
|
||||
/*!
|
||||
* Read samples from the device asynchronously. This function will block until
|
||||
* it is being canceled using rtlsdr_cancel_async()
|
||||
*
|
||||
* NOTE: This function is deprecated and is subject for removal.
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \param cb callback function to return received samples
|
||||
* \param ctx user specific context to pass via the callback function
|
||||
* \return 0 on success
|
||||
*/
|
||||
RTLSDR_API int rtlsdr_wait_async(rtlsdr_dev_t *dev, rtlsdr_read_async_cb_t cb, void *ctx);
|
||||
|
||||
/*!
|
||||
* Read samples from the device asynchronously. This function will block until
|
||||
* it is being canceled using rtlsdr_cancel_async()
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \param cb callback function to return received samples
|
||||
* \param ctx user specific context to pass via the callback function
|
||||
* \param buf_num optional buffer count, buf_num * buf_len = overall buffer size
|
||||
* set to 0 for default buffer count (15)
|
||||
* \param buf_len optional buffer length, must be multiple of 512,
|
||||
* should be a multiple of 16384 (URB size), set to 0
|
||||
* for default buffer length (16 * 32 * 512)
|
||||
* \return 0 on success
|
||||
*/
|
||||
RTLSDR_API int rtlsdr_read_async(rtlsdr_dev_t *dev,
|
||||
rtlsdr_read_async_cb_t cb,
|
||||
void *ctx,
|
||||
uint32_t buf_num,
|
||||
uint32_t buf_len);
|
||||
|
||||
/*!
|
||||
* Cancel all pending asynchronous operations on the device.
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \return 0 on success
|
||||
*/
|
||||
RTLSDR_API int rtlsdr_cancel_async(rtlsdr_dev_t *dev);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __RTL_SDR_H */
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver
|
||||
* Copyright (C) 2012 by Hoernchen <la@tfc-server.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef RTLSDR_EXPORT_H
|
||||
#define RTLSDR_EXPORT_H
|
||||
|
||||
#if defined __GNUC__
|
||||
# if __GNUC__ >= 4
|
||||
# define __SDR_EXPORT __attribute__((visibility("default")))
|
||||
# define __SDR_IMPORT __attribute__((visibility("default")))
|
||||
# else
|
||||
# define __SDR_EXPORT
|
||||
# define __SDR_IMPORT
|
||||
# endif
|
||||
#elif _MSC_VER
|
||||
# define __SDR_EXPORT __declspec(dllexport)
|
||||
# define __SDR_IMPORT __declspec(dllimport)
|
||||
#else
|
||||
# define __SDR_EXPORT
|
||||
# define __SDR_IMPORT
|
||||
#endif
|
||||
|
||||
#ifndef rtlsdr_STATIC
|
||||
# ifdef rtlsdr_EXPORTS
|
||||
# define RTLSDR_API __SDR_EXPORT
|
||||
# else
|
||||
# define RTLSDR_API __SDR_IMPORT
|
||||
# endif
|
||||
#else
|
||||
#define RTLSDR_API
|
||||
#endif
|
||||
#endif /* RTLSDR_EXPORT_H */
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef __I2C_H
|
||||
#define __I2C_H
|
||||
|
||||
uint32_t rtlsdr_get_tuner_clock(void *dev);
|
||||
int rtlsdr_i2c_write_fn(void *dev, uint8_t addr, uint8_t *buf, int len);
|
||||
int rtlsdr_i2c_read_fn(void *dev, uint8_t addr, uint8_t *buf, int len);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,222 @@
|
|||
#ifndef _E4K_TUNER_H
|
||||
#define _E4K_TUNER_H
|
||||
|
||||
/*
|
||||
* Elonics E4000 tuner driver
|
||||
*
|
||||
* (C) 2011-2012 by Harald Welte <laforge@gnumonks.org>
|
||||
* (C) 2012 by Sylvain Munaut <tnt@246tNt.com>
|
||||
* (C) 2012 by Hoernchen <la@tfc-server.de>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define E4K_I2C_ADDR 0xc8
|
||||
#define E4K_CHECK_ADDR 0x02
|
||||
#define E4K_CHECK_VAL 0x40
|
||||
|
||||
enum e4k_reg {
|
||||
E4K_REG_MASTER1 = 0x00,
|
||||
E4K_REG_MASTER2 = 0x01,
|
||||
E4K_REG_MASTER3 = 0x02,
|
||||
E4K_REG_MASTER4 = 0x03,
|
||||
E4K_REG_MASTER5 = 0x04,
|
||||
E4K_REG_CLK_INP = 0x05,
|
||||
E4K_REG_REF_CLK = 0x06,
|
||||
E4K_REG_SYNTH1 = 0x07,
|
||||
E4K_REG_SYNTH2 = 0x08,
|
||||
E4K_REG_SYNTH3 = 0x09,
|
||||
E4K_REG_SYNTH4 = 0x0a,
|
||||
E4K_REG_SYNTH5 = 0x0b,
|
||||
E4K_REG_SYNTH6 = 0x0c,
|
||||
E4K_REG_SYNTH7 = 0x0d,
|
||||
E4K_REG_SYNTH8 = 0x0e,
|
||||
E4K_REG_SYNTH9 = 0x0f,
|
||||
E4K_REG_FILT1 = 0x10,
|
||||
E4K_REG_FILT2 = 0x11,
|
||||
E4K_REG_FILT3 = 0x12,
|
||||
// gap
|
||||
E4K_REG_GAIN1 = 0x14,
|
||||
E4K_REG_GAIN2 = 0x15,
|
||||
E4K_REG_GAIN3 = 0x16,
|
||||
E4K_REG_GAIN4 = 0x17,
|
||||
// gap
|
||||
E4K_REG_AGC1 = 0x1a,
|
||||
E4K_REG_AGC2 = 0x1b,
|
||||
E4K_REG_AGC3 = 0x1c,
|
||||
E4K_REG_AGC4 = 0x1d,
|
||||
E4K_REG_AGC5 = 0x1e,
|
||||
E4K_REG_AGC6 = 0x1f,
|
||||
E4K_REG_AGC7 = 0x20,
|
||||
E4K_REG_AGC8 = 0x21,
|
||||
// gap
|
||||
E4K_REG_AGC11 = 0x24,
|
||||
E4K_REG_AGC12 = 0x25,
|
||||
// gap
|
||||
E4K_REG_DC1 = 0x29,
|
||||
E4K_REG_DC2 = 0x2a,
|
||||
E4K_REG_DC3 = 0x2b,
|
||||
E4K_REG_DC4 = 0x2c,
|
||||
E4K_REG_DC5 = 0x2d,
|
||||
E4K_REG_DC6 = 0x2e,
|
||||
E4K_REG_DC7 = 0x2f,
|
||||
E4K_REG_DC8 = 0x30,
|
||||
// gap
|
||||
E4K_REG_QLUT0 = 0x50,
|
||||
E4K_REG_QLUT1 = 0x51,
|
||||
E4K_REG_QLUT2 = 0x52,
|
||||
E4K_REG_QLUT3 = 0x53,
|
||||
// gap
|
||||
E4K_REG_ILUT0 = 0x60,
|
||||
E4K_REG_ILUT1 = 0x61,
|
||||
E4K_REG_ILUT2 = 0x62,
|
||||
E4K_REG_ILUT3 = 0x63,
|
||||
// gap
|
||||
E4K_REG_DCTIME1 = 0x70,
|
||||
E4K_REG_DCTIME2 = 0x71,
|
||||
E4K_REG_DCTIME3 = 0x72,
|
||||
E4K_REG_DCTIME4 = 0x73,
|
||||
E4K_REG_PWM1 = 0x74,
|
||||
E4K_REG_PWM2 = 0x75,
|
||||
E4K_REG_PWM3 = 0x76,
|
||||
E4K_REG_PWM4 = 0x77,
|
||||
E4K_REG_BIAS = 0x78,
|
||||
E4K_REG_CLKOUT_PWDN = 0x7a,
|
||||
E4K_REG_CHFILT_CALIB = 0x7b,
|
||||
E4K_REG_I2C_REG_ADDR = 0x7d,
|
||||
// FIXME
|
||||
};
|
||||
|
||||
#define E4K_MASTER1_RESET (1 << 0)
|
||||
#define E4K_MASTER1_NORM_STBY (1 << 1)
|
||||
#define E4K_MASTER1_POR_DET (1 << 2)
|
||||
|
||||
#define E4K_SYNTH1_PLL_LOCK (1 << 0)
|
||||
#define E4K_SYNTH1_BAND_SHIF 1
|
||||
|
||||
#define E4K_SYNTH7_3PHASE_EN (1 << 3)
|
||||
|
||||
#define E4K_SYNTH8_VCOCAL_UPD (1 << 2)
|
||||
|
||||
#define E4K_FILT3_DISABLE (1 << 5)
|
||||
|
||||
#define E4K_AGC1_LIN_MODE (1 << 4)
|
||||
#define E4K_AGC1_LNA_UPDATE (1 << 5)
|
||||
#define E4K_AGC1_LNA_G_LOW (1 << 6)
|
||||
#define E4K_AGC1_LNA_G_HIGH (1 << 7)
|
||||
|
||||
#define E4K_AGC6_LNA_CAL_REQ (1 << 4)
|
||||
|
||||
#define E4K_AGC7_MIX_GAIN_AUTO (1 << 0)
|
||||
#define E4K_AGC7_GAIN_STEP_5dB (1 << 5)
|
||||
|
||||
#define E4K_AGC8_SENS_LIN_AUTO (1 << 0)
|
||||
|
||||
#define E4K_AGC11_LNA_GAIN_ENH (1 << 0)
|
||||
|
||||
#define E4K_DC1_CAL_REQ (1 << 0)
|
||||
|
||||
#define E4K_DC5_I_LUT_EN (1 << 0)
|
||||
#define E4K_DC5_Q_LUT_EN (1 << 1)
|
||||
#define E4K_DC5_RANGE_DET_EN (1 << 2)
|
||||
#define E4K_DC5_RANGE_EN (1 << 3)
|
||||
#define E4K_DC5_TIMEVAR_EN (1 << 4)
|
||||
|
||||
#define E4K_CLKOUT_DISABLE 0x96
|
||||
|
||||
#define E4K_CHFCALIB_CMD (1 << 0)
|
||||
|
||||
#define E4K_AGC1_MOD_MASK 0xF
|
||||
|
||||
enum e4k_agc_mode {
|
||||
E4K_AGC_MOD_SERIAL = 0x0,
|
||||
E4K_AGC_MOD_IF_PWM_LNA_SERIAL = 0x1,
|
||||
E4K_AGC_MOD_IF_PWM_LNA_AUTONL = 0x2,
|
||||
E4K_AGC_MOD_IF_PWM_LNA_SUPERV = 0x3,
|
||||
E4K_AGC_MOD_IF_SERIAL_LNA_PWM = 0x4,
|
||||
E4K_AGC_MOD_IF_PWM_LNA_PWM = 0x5,
|
||||
E4K_AGC_MOD_IF_DIG_LNA_SERIAL = 0x6,
|
||||
E4K_AGC_MOD_IF_DIG_LNA_AUTON = 0x7,
|
||||
E4K_AGC_MOD_IF_DIG_LNA_SUPERV = 0x8,
|
||||
E4K_AGC_MOD_IF_SERIAL_LNA_AUTON = 0x9,
|
||||
E4K_AGC_MOD_IF_SERIAL_LNA_SUPERV = 0xa,
|
||||
};
|
||||
|
||||
enum e4k_band {
|
||||
E4K_BAND_VHF2 = 0,
|
||||
E4K_BAND_VHF3 = 1,
|
||||
E4K_BAND_UHF = 2,
|
||||
E4K_BAND_L = 3,
|
||||
};
|
||||
|
||||
enum e4k_mixer_filter_bw {
|
||||
E4K_F_MIX_BW_27M = 0,
|
||||
E4K_F_MIX_BW_4M6 = 8,
|
||||
E4K_F_MIX_BW_4M2 = 9,
|
||||
E4K_F_MIX_BW_3M8 = 10,
|
||||
E4K_F_MIX_BW_3M4 = 11,
|
||||
E4K_F_MIX_BW_3M = 12,
|
||||
E4K_F_MIX_BW_2M7 = 13,
|
||||
E4K_F_MIX_BW_2M3 = 14,
|
||||
E4K_F_MIX_BW_1M9 = 15,
|
||||
};
|
||||
|
||||
enum e4k_if_filter {
|
||||
E4K_IF_FILTER_MIX,
|
||||
E4K_IF_FILTER_CHAN,
|
||||
E4K_IF_FILTER_RC
|
||||
};
|
||||
struct e4k_pll_params {
|
||||
uint32_t fosc;
|
||||
uint32_t intended_flo;
|
||||
uint32_t flo;
|
||||
uint16_t x;
|
||||
uint8_t z;
|
||||
uint8_t r;
|
||||
uint8_t r_idx;
|
||||
uint8_t threephase;
|
||||
};
|
||||
|
||||
struct e4k_state {
|
||||
void *i2c_dev;
|
||||
uint8_t i2c_addr;
|
||||
enum e4k_band band;
|
||||
struct e4k_pll_params vco;
|
||||
void *rtl_dev;
|
||||
};
|
||||
|
||||
int e4k_init(struct e4k_state *e4k);
|
||||
int e4k_standby(struct e4k_state *e4k, int enable);
|
||||
int e4k_if_gain_set(struct e4k_state *e4k, uint8_t stage, int8_t value);
|
||||
int e4k_mixer_gain_set(struct e4k_state *e4k, int8_t value);
|
||||
int e4k_commonmode_set(struct e4k_state *e4k, int8_t value);
|
||||
int e4k_tune_freq(struct e4k_state *e4k, uint32_t freq);
|
||||
int e4k_tune_params(struct e4k_state *e4k, struct e4k_pll_params *p);
|
||||
uint32_t e4k_compute_pll_params(struct e4k_pll_params *oscp, uint32_t fosc, uint32_t intended_flo);
|
||||
int e4k_if_filter_bw_get(struct e4k_state *e4k, enum e4k_if_filter filter);
|
||||
int e4k_if_filter_bw_set(struct e4k_state *e4k, enum e4k_if_filter filter,
|
||||
uint32_t bandwidth);
|
||||
int e4k_if_filter_chan_enable(struct e4k_state *e4k, int on);
|
||||
int e4k_rf_filter_set(struct e4k_state *e4k);
|
||||
|
||||
int e4k_manual_dc_offset(struct e4k_state *e4k, int8_t iofs, int8_t irange, int8_t qofs, int8_t qrange);
|
||||
int e4k_dc_offset_calibrate(struct e4k_state *e4k);
|
||||
int e4k_dc_offset_gen_table(struct e4k_state *e4k);
|
||||
|
||||
int e4k_set_lna_gain(struct e4k_state *e4k, int32_t gain);
|
||||
int e4k_enable_manual_gain(struct e4k_state *e4k, uint8_t manual);
|
||||
int e4k_set_enh_gain(struct e4k_state *e4k, int32_t gain);
|
||||
#endif /* _E4K_TUNER_H */
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Fitipower FC0012 tuner driver
|
||||
*
|
||||
* Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net>
|
||||
*
|
||||
* modified for use in librtlsdr
|
||||
* Copyright (C) 2012 Steve Markgraf <steve@steve-m.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _FC0012_H_
|
||||
#define _FC0012_H_
|
||||
|
||||
#define FC0012_I2C_ADDR 0xc6
|
||||
#define FC0012_CHECK_ADDR 0x00
|
||||
#define FC0012_CHECK_VAL 0xa1
|
||||
|
||||
int fc0012_init(void *dev);
|
||||
int fc0012_set_params(void *dev, uint32_t freq, uint32_t bandwidth);
|
||||
int fc0012_set_gain(void *dev, int gain);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Fitipower FC0013 tuner driver
|
||||
*
|
||||
* Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net>
|
||||
*
|
||||
* modified for use in librtlsdr
|
||||
* Copyright (C) 2012 Steve Markgraf <steve@steve-m.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _FC0013_H_
|
||||
#define _FC0013_H_
|
||||
|
||||
#define FC0013_I2C_ADDR 0xc6
|
||||
#define FC0013_CHECK_ADDR 0x00
|
||||
#define FC0013_CHECK_VAL 0xa3
|
||||
|
||||
int fc0013_init(void *dev);
|
||||
int fc0013_set_params(void *dev, uint32_t freq, uint32_t bandwidth);
|
||||
int fc0013_set_gain_mode(void *dev, int manual);
|
||||
int fc0013_set_lna_gain(void *dev, int gain);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,127 @@
|
|||
#ifndef __TUNER_FC2580_H
|
||||
#define __TUNER_FC2580_H
|
||||
|
||||
#define BORDER_FREQ 2600000 //2.6GHz : The border frequency which determines whether Low VCO or High VCO is used
|
||||
#define USE_EXT_CLK 0 //0 : Use internal XTAL Oscillator / 1 : Use External Clock input
|
||||
#define OFS_RSSI 57
|
||||
|
||||
#define FC2580_I2C_ADDR 0xac
|
||||
#define FC2580_CHECK_ADDR 0x01
|
||||
#define FC2580_CHECK_VAL 0x56
|
||||
|
||||
typedef enum {
|
||||
FC2580_UHF_BAND,
|
||||
FC2580_L_BAND,
|
||||
FC2580_VHF_BAND,
|
||||
FC2580_NO_BAND
|
||||
} fc2580_band_type;
|
||||
|
||||
typedef enum {
|
||||
FC2580_FCI_FAIL,
|
||||
FC2580_FCI_SUCCESS
|
||||
} fc2580_fci_result_type;
|
||||
|
||||
enum FUNCTION_STATUS
|
||||
{
|
||||
FUNCTION_SUCCESS,
|
||||
FUNCTION_ERROR,
|
||||
};
|
||||
|
||||
extern void fc2580_wait_msec(void *pTuner, int a);
|
||||
|
||||
fc2580_fci_result_type fc2580_i2c_write(void *pTuner, unsigned char reg, unsigned char val);
|
||||
fc2580_fci_result_type fc2580_i2c_read(void *pTuner, unsigned char reg, unsigned char *read_data);
|
||||
|
||||
/*==============================================================================
|
||||
fc2580 initial setting
|
||||
|
||||
This function is a generic function which gets called to initialize
|
||||
|
||||
fc2580 in DVB-H mode or L-Band TDMB mode
|
||||
|
||||
<input parameter>
|
||||
|
||||
ifagc_mode
|
||||
type : integer
|
||||
1 : Internal AGC
|
||||
2 : Voltage Control Mode
|
||||
|
||||
==============================================================================*/
|
||||
fc2580_fci_result_type fc2580_set_init(void *pTuner, int ifagc_mode, unsigned int freq_xtal );
|
||||
|
||||
/*==============================================================================
|
||||
fc2580 frequency setting
|
||||
|
||||
This function is a generic function which gets called to change LO Frequency
|
||||
|
||||
of fc2580 in DVB-H mode or L-Band TDMB mode
|
||||
|
||||
<input parameter>
|
||||
|
||||
f_lo
|
||||
Value of target LO Frequency in 'kHz' unit
|
||||
ex) 2.6GHz = 2600000
|
||||
|
||||
==============================================================================*/
|
||||
fc2580_fci_result_type fc2580_set_freq(void *pTuner, unsigned int f_lo, unsigned int freq_xtal );
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
fc2580 filter BW setting
|
||||
|
||||
This function is a generic function which gets called to change Bandwidth
|
||||
|
||||
frequency of fc2580's channel selection filter
|
||||
|
||||
<input parameter>
|
||||
|
||||
filter_bw
|
||||
1 : 1.53MHz(TDMB)
|
||||
6 : 6MHz
|
||||
7 : 7MHz
|
||||
8 : 7.8MHz
|
||||
|
||||
|
||||
==============================================================================*/
|
||||
fc2580_fci_result_type fc2580_set_filter( void *pTuner, unsigned char filter_bw, unsigned int freq_xtal );
|
||||
|
||||
// The following context is FC2580 tuner API source code
|
||||
// Definitions
|
||||
|
||||
// AGC mode
|
||||
enum FC2580_AGC_MODE
|
||||
{
|
||||
FC2580_AGC_INTERNAL = 1,
|
||||
FC2580_AGC_EXTERNAL = 2,
|
||||
};
|
||||
|
||||
|
||||
// Bandwidth mode
|
||||
enum FC2580_BANDWIDTH_MODE
|
||||
{
|
||||
FC2580_BANDWIDTH_1530000HZ = 1,
|
||||
FC2580_BANDWIDTH_6000000HZ = 6,
|
||||
FC2580_BANDWIDTH_7000000HZ = 7,
|
||||
FC2580_BANDWIDTH_8000000HZ = 8,
|
||||
};
|
||||
|
||||
// Manipulaing functions
|
||||
int
|
||||
fc2580_Initialize(
|
||||
void *pTuner
|
||||
);
|
||||
|
||||
int
|
||||
fc2580_SetRfFreqHz(
|
||||
void *pTuner,
|
||||
unsigned long RfFreqHz
|
||||
);
|
||||
|
||||
// Extra manipulaing functions
|
||||
int
|
||||
fc2580_SetBandwidthMode(
|
||||
void *pTuner,
|
||||
int BandwidthMode
|
||||
);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Rafael Micro R820T/R828D driver
|
||||
*
|
||||
* Copyright (C) 2013 Mauro Carvalho Chehab <mchehab@redhat.com>
|
||||
* Copyright (C) 2013 Steve Markgraf <steve@steve-m.de>
|
||||
*
|
||||
* This driver is a heavily modified version of the driver found in the
|
||||
* Linux kernel:
|
||||
* http://git.linuxtv.org/linux-2.6.git/history/HEAD:/drivers/media/tuners/r820t.c
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef R82XX_H
|
||||
#define R82XX_H
|
||||
|
||||
#define R820T_I2C_ADDR 0x34
|
||||
#define R828D_I2C_ADDR 0x74
|
||||
#define R828D_XTAL_FREQ 16000000
|
||||
|
||||
#define R82XX_CHECK_ADDR 0x00
|
||||
#define R82XX_CHECK_VAL 0x69
|
||||
|
||||
#define R82XX_IF_FREQ 3570000
|
||||
|
||||
#define REG_SHADOW_START 5
|
||||
#define NUM_REGS 30
|
||||
#define NUM_IMR 5
|
||||
#define IMR_TRIAL 9
|
||||
|
||||
#define VER_NUM 49
|
||||
|
||||
enum r82xx_chip {
|
||||
CHIP_R820T,
|
||||
CHIP_R620D,
|
||||
CHIP_R828D,
|
||||
CHIP_R828,
|
||||
CHIP_R828S,
|
||||
CHIP_R820C,
|
||||
};
|
||||
|
||||
enum r82xx_tuner_type {
|
||||
TUNER_RADIO = 1,
|
||||
TUNER_ANALOG_TV,
|
||||
TUNER_DIGITAL_TV
|
||||
};
|
||||
|
||||
enum r82xx_xtal_cap_value {
|
||||
XTAL_LOW_CAP_30P = 0,
|
||||
XTAL_LOW_CAP_20P,
|
||||
XTAL_LOW_CAP_10P,
|
||||
XTAL_LOW_CAP_0P,
|
||||
XTAL_HIGH_CAP_0P
|
||||
};
|
||||
|
||||
struct r82xx_config {
|
||||
uint8_t i2c_addr;
|
||||
uint32_t xtal;
|
||||
enum r82xx_chip rafael_chip;
|
||||
unsigned int max_i2c_msg_len;
|
||||
int use_predetect;
|
||||
};
|
||||
|
||||
struct r82xx_priv {
|
||||
struct r82xx_config *cfg;
|
||||
|
||||
uint8_t regs[NUM_REGS];
|
||||
uint8_t buf[NUM_REGS + 1];
|
||||
enum r82xx_xtal_cap_value xtal_cap_sel;
|
||||
uint16_t pll; /* kHz */
|
||||
uint32_t int_freq;
|
||||
uint8_t fil_cal_code;
|
||||
uint8_t input;
|
||||
int has_lock;
|
||||
int init_done;
|
||||
|
||||
/* Store current mode */
|
||||
uint32_t delsys;
|
||||
enum r82xx_tuner_type type;
|
||||
|
||||
uint32_t bw; /* in MHz */
|
||||
|
||||
void *rtl_dev;
|
||||
};
|
||||
|
||||
struct r82xx_freq_range {
|
||||
uint32_t freq;
|
||||
uint8_t open_d;
|
||||
uint8_t rf_mux_ploy;
|
||||
uint8_t tf_c;
|
||||
uint8_t xtal_cap20p;
|
||||
uint8_t xtal_cap10p;
|
||||
uint8_t xtal_cap0p;
|
||||
};
|
||||
|
||||
enum r82xx_delivery_system {
|
||||
SYS_UNDEFINED,
|
||||
SYS_DVBT,
|
||||
SYS_DVBT2,
|
||||
SYS_ISDBT,
|
||||
};
|
||||
|
||||
int r82xx_standby(struct r82xx_priv *priv);
|
||||
int r82xx_init(struct r82xx_priv *priv);
|
||||
int r82xx_set_freq(struct r82xx_priv *priv, uint32_t freq);
|
||||
int r82xx_set_gain(struct r82xx_priv *priv, int set_manual_gain, int gain);
|
||||
int r82xx_set_bandwidth(struct r82xx_priv *priv, int bandwidth, uint32_t rate);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,11 @@
|
|||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: RTL-SDR Library
|
||||
Description: C Utility Library
|
||||
Version: @VERSION@
|
||||
Cflags: -I${includedir}/ @RTLSDR_PC_CFLAGS@
|
||||
Libs: -L${libdir} -lrtlsdr -lusb-1.0
|
||||
Libs.private: @RTLSDR_PC_LIBS@
|
|
@ -0,0 +1,2 @@
|
|||
/libtool.m4
|
||||
/lt*.m4
|
|
@ -0,0 +1,139 @@
|
|||
#
|
||||
# Copyright 2012-2013 Osmocom rtl-sdr project
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# original RTL2832U vid/pid (hama nano, for example)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="2832", MODE:="0666"
|
||||
|
||||
# RTL2832U OEM vid/pid, e.g. ezcap EzTV668 (E4000), Newsky TV28T (E4000/R820T) etc.
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="2838", MODE:="0666"
|
||||
|
||||
# DigitalNow Quad DVB-T PCI-E card (4x FC0012?)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0413", ATTRS{idProduct}=="6680", MODE:="0666"
|
||||
|
||||
# Leadtek WinFast DTV Dongle mini D (FC0012)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0413", ATTRS{idProduct}=="6f0f", MODE:="0666"
|
||||
|
||||
# Genius TVGo DVB-T03 USB dongle (Ver. B)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0458", ATTRS{idProduct}=="707f", MODE:="0666"
|
||||
|
||||
# Terratec Cinergy T Stick Black (rev 1) (FC0012)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00a9", MODE:="0666"
|
||||
|
||||
# Terratec NOXON rev 1 (FC0013)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00b3", MODE:="0666"
|
||||
|
||||
# Terratec Deutschlandradio DAB Stick (FC0013)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00b4", MODE:="0666"
|
||||
|
||||
# Terratec NOXON DAB Stick - Radio Energy (FC0013)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00b5", MODE:="0666"
|
||||
|
||||
# Terratec Media Broadcast DAB Stick (FC0013)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00b7", MODE:="0666"
|
||||
|
||||
# Terratec BR DAB Stick (FC0013)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00b8", MODE:="0666"
|
||||
|
||||
# Terratec WDR DAB Stick (FC0013)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00b9", MODE:="0666"
|
||||
|
||||
# Terratec MuellerVerlag DAB Stick (FC0013)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00c0", MODE:="0666"
|
||||
|
||||
# Terratec Fraunhofer DAB Stick (FC0013)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00c6", MODE:="0666"
|
||||
|
||||
# Terratec Cinergy T Stick RC (Rev.3) (E4000)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00d3", MODE:="0666"
|
||||
|
||||
# Terratec T Stick PLUS (E4000)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00d7", MODE:="0666"
|
||||
|
||||
# Terratec NOXON rev 2 (E4000)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00e0", MODE:="0666"
|
||||
|
||||
# PixelView PV-DT235U(RN) (FC0012)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1554", ATTRS{idProduct}=="5020", MODE:="0666"
|
||||
|
||||
# Astrometa DVB-T/DVB-T2 (R828D)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="15f4", ATTRS{idProduct}=="0131", MODE:="0666"
|
||||
|
||||
# Compro Videomate U620F (E4000)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="185b", ATTRS{idProduct}=="0620", MODE:="0666"
|
||||
|
||||
# Compro Videomate U650F (E4000)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="185b", ATTRS{idProduct}=="0650", MODE:="0666"
|
||||
|
||||
# Compro Videomate U680F (E4000)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="185b", ATTRS{idProduct}=="0680", MODE:="0666"
|
||||
|
||||
# GIGABYTE GT-U7300 (FC0012)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d393", MODE:="0666"
|
||||
|
||||
# DIKOM USB-DVBT HD
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d394", MODE:="0666"
|
||||
|
||||
# Peak 102569AGPK (FC0012)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d395", MODE:="0666"
|
||||
|
||||
# KWorld KW-UB450-T USB DVB-T Pico TV (TUA9001)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d397", MODE:="0666"
|
||||
|
||||
# Zaapa ZT-MINDVBZP (FC0012)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d398", MODE:="0666"
|
||||
|
||||
# SVEON STV20 DVB-T USB & FM (FC0012)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d39d", MODE:="0666"
|
||||
|
||||
# Twintech UT-40 (FC0013)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d3a4", MODE:="0666"
|
||||
|
||||
# ASUS U3100MINI_PLUS_V2 (FC0013)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d3a8", MODE:="0666"
|
||||
|
||||
# SVEON STV27 DVB-T USB & FM (FC0013)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d3af", MODE:="0666"
|
||||
|
||||
# SVEON STV21 DVB-T USB & FM
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d3b0", MODE:="0666"
|
||||
|
||||
# Dexatek DK DVB-T Dongle (Logilink VG0002A) (FC2580)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1d19", ATTRS{idProduct}=="1101", MODE:="0666"
|
||||
|
||||
# Dexatek DK DVB-T Dongle (MSI DigiVox mini II V3.0)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1d19", ATTRS{idProduct}=="1102", MODE:="0666"
|
||||
|
||||
# Dexatek DK 5217 DVB-T Dongle (FC2580)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1d19", ATTRS{idProduct}=="1103", MODE:="0666"
|
||||
|
||||
# MSI DigiVox Micro HD (FC2580)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1d19", ATTRS{idProduct}=="1104", MODE:="0666"
|
||||
|
||||
# Sweex DVB-T USB (FC0012)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1f4d", ATTRS{idProduct}=="a803", MODE:="0666"
|
||||
|
||||
# GTek T803 (FC0012)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1f4d", ATTRS{idProduct}=="b803", MODE:="0666"
|
||||
|
||||
# Lifeview LV5TDeluxe (FC0012)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1f4d", ATTRS{idProduct}=="c803", MODE:="0666"
|
||||
|
||||
# MyGica TD312 (FC0012)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1f4d", ATTRS{idProduct}=="d286", MODE:="0666"
|
||||
|
||||
# PROlectrix DV107669 (FC0012)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1f4d", ATTRS{idProduct}=="d803", MODE:="0666"
|
|
@ -0,0 +1,158 @@
|
|||
# Copyright 2012 OSMOCOM Project
|
||||
#
|
||||
# This file is part of rtl-sdr
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GNU Radio is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GNU Radio; see the file COPYING. If not, write to
|
||||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
MACRO(RTLSDR_APPEND_SRCS)
|
||||
LIST(APPEND rtlsdr_srcs ${ARGV})
|
||||
ENDMACRO(RTLSDR_APPEND_SRCS)
|
||||
|
||||
RTLSDR_APPEND_SRCS(
|
||||
librtlsdr.c
|
||||
tuner_e4k.c
|
||||
tuner_fc0012.c
|
||||
tuner_fc0013.c
|
||||
tuner_fc2580.c
|
||||
tuner_r82xx.c
|
||||
)
|
||||
|
||||
########################################################################
|
||||
# Set up Windows DLL resource files
|
||||
########################################################################
|
||||
IF(MSVC)
|
||||
include(${CMAKE_SOURCE_DIR}/cmake/Modules/Version.cmake)
|
||||
|
||||
configure_file(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rtlsdr.rc.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/rtlsdr.rc
|
||||
@ONLY)
|
||||
|
||||
RTLSDR_APPEND_SRCS(${CMAKE_CURRENT_BINARY_DIR}/rtlsdr.rc)
|
||||
ENDIF(MSVC)
|
||||
|
||||
########################################################################
|
||||
# Setup shared library variant
|
||||
########################################################################
|
||||
add_library(rtlsdr_shared SHARED ${rtlsdr_srcs})
|
||||
target_link_libraries(rtlsdr_shared ${LIBUSB_LIBRARIES})
|
||||
set_target_properties(rtlsdr_shared PROPERTIES DEFINE_SYMBOL "rtlsdr_EXPORTS")
|
||||
set_target_properties(rtlsdr_shared PROPERTIES OUTPUT_NAME rtlsdr)
|
||||
set_target_properties(rtlsdr_shared PROPERTIES SOVERSION ${MAJOR_VERSION})
|
||||
set_target_properties(rtlsdr_shared PROPERTIES VERSION ${LIBVER})
|
||||
|
||||
########################################################################
|
||||
# Setup static library variant
|
||||
########################################################################
|
||||
add_library(rtlsdr_static STATIC ${rtlsdr_srcs})
|
||||
target_link_libraries(rtlsdr_static ${LIBUSB_LIBRARIES})
|
||||
set_property(TARGET rtlsdr_static APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
|
||||
if(NOT WIN32)
|
||||
# Force same library filename for static and shared variants of the library
|
||||
set_target_properties(rtlsdr_static PROPERTIES OUTPUT_NAME rtlsdr)
|
||||
endif()
|
||||
|
||||
########################################################################
|
||||
# Setup libraries used in executables
|
||||
########################################################################
|
||||
add_library(convenience_static STATIC
|
||||
convenience/convenience.c
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
add_library(libgetopt_static STATIC
|
||||
getopt/getopt.c
|
||||
)
|
||||
target_link_libraries(convenience_static
|
||||
rtlsdr_shared
|
||||
)
|
||||
endif()
|
||||
|
||||
########################################################################
|
||||
# Build utility
|
||||
########################################################################
|
||||
add_executable(rtl_sdr rtl_sdr.c)
|
||||
add_executable(rtl_tcp rtl_tcp.c)
|
||||
add_executable(rtl_test rtl_test.c)
|
||||
add_executable(rtl_fm rtl_fm.c)
|
||||
add_executable(rtl_eeprom rtl_eeprom.c)
|
||||
add_executable(rtl_adsb rtl_adsb.c)
|
||||
add_executable(rtl_power rtl_power.c)
|
||||
set(INSTALL_TARGETS rtlsdr_shared rtlsdr_static rtl_sdr rtl_tcp rtl_test rtl_fm rtl_eeprom rtl_adsb rtl_power)
|
||||
|
||||
target_link_libraries(rtl_sdr rtlsdr_shared convenience_static
|
||||
${LIBUSB_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
)
|
||||
target_link_libraries(rtl_tcp rtlsdr_shared convenience_static
|
||||
${LIBUSB_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
)
|
||||
target_link_libraries(rtl_test rtlsdr_shared convenience_static
|
||||
${LIBUSB_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
)
|
||||
target_link_libraries(rtl_fm rtlsdr_shared convenience_static
|
||||
${LIBUSB_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
)
|
||||
target_link_libraries(rtl_eeprom rtlsdr_shared convenience_static
|
||||
${LIBUSB_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
)
|
||||
target_link_libraries(rtl_adsb rtlsdr_shared convenience_static
|
||||
${LIBUSB_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
)
|
||||
target_link_libraries(rtl_power rtlsdr_shared convenience_static
|
||||
${LIBUSB_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
)
|
||||
if(UNIX)
|
||||
target_link_libraries(rtl_fm m)
|
||||
target_link_libraries(rtl_adsb m)
|
||||
target_link_libraries(rtl_power m)
|
||||
if(APPLE)
|
||||
target_link_libraries(rtl_test m)
|
||||
else()
|
||||
target_link_libraries(rtl_test m rt)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(rtl_sdr libgetopt_static)
|
||||
target_link_libraries(rtl_tcp ws2_32 libgetopt_static)
|
||||
target_link_libraries(rtl_test libgetopt_static)
|
||||
target_link_libraries(rtl_fm libgetopt_static)
|
||||
target_link_libraries(rtl_eeprom libgetopt_static)
|
||||
target_link_libraries(rtl_adsb libgetopt_static)
|
||||
target_link_libraries(rtl_power libgetopt_static)
|
||||
set_property(TARGET rtl_sdr APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
|
||||
set_property(TARGET rtl_tcp APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
|
||||
set_property(TARGET rtl_test APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
|
||||
set_property(TARGET rtl_fm APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
|
||||
set_property(TARGET rtl_eeprom APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
|
||||
set_property(TARGET rtl_adsb APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
|
||||
set_property(TARGET rtl_power APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" )
|
||||
endif()
|
||||
########################################################################
|
||||
# Install built library files & utilities
|
||||
########################################################################
|
||||
install(TARGETS ${INSTALL_TARGETS}
|
||||
LIBRARY DESTINATION ${LIB_INSTALL_DIR} # .so/.dylib file
|
||||
ARCHIVE DESTINATION ${LIB_INSTALL_DIR} # .lib file
|
||||
RUNTIME DESTINATION bin # .dll file
|
||||
)
|
|
@ -0,0 +1,36 @@
|
|||
# This is _NOT_ the library release version, it's an API version.
|
||||
# Please read Chapter 6 "Library interface versions" of the libtool documentation before making any modification
|
||||
LIBVERSION=0:5:0
|
||||
|
||||
AUTOMAKE_OPTIONS = subdir-objects
|
||||
INCLUDES = $(all_includes) -I$(top_srcdir)/include
|
||||
noinst_HEADERS = convenience/convenience.h
|
||||
AM_CFLAGS = ${CFLAGS} -fPIC ${SYMBOL_VISIBILITY}
|
||||
|
||||
lib_LTLIBRARIES = librtlsdr.la
|
||||
|
||||
librtlsdr_la_SOURCES = librtlsdr.c tuner_e4k.c tuner_fc0012.c tuner_fc0013.c tuner_fc2580.c tuner_r82xx.c
|
||||
librtlsdr_la_LDFLAGS = -version-info $(LIBVERSION)
|
||||
|
||||
bin_PROGRAMS = rtl_sdr rtl_tcp rtl_test rtl_fm rtl_eeprom rtl_adsb rtl_power
|
||||
|
||||
rtl_sdr_SOURCES = rtl_sdr.c convenience/convenience.c
|
||||
rtl_sdr_LDADD = librtlsdr.la
|
||||
|
||||
rtl_tcp_SOURCES = rtl_tcp.c convenience/convenience.c
|
||||
rtl_tcp_LDADD = librtlsdr.la
|
||||
|
||||
rtl_test_SOURCES = rtl_test.c convenience/convenience.c
|
||||
rtl_test_LDADD = librtlsdr.la $(LIBM)
|
||||
|
||||
rtl_fm_SOURCES = rtl_fm.c convenience/convenience.c
|
||||
rtl_fm_LDADD = librtlsdr.la $(LIBM)
|
||||
|
||||
rtl_eeprom_SOURCES = rtl_eeprom.c convenience/convenience.c
|
||||
rtl_eeprom_LDADD = librtlsdr.la $(LIBM)
|
||||
|
||||
rtl_adsb_SOURCES = rtl_adsb.c convenience/convenience.c
|
||||
rtl_adsb_LDADD = librtlsdr.la $(LIBM)
|
||||
|
||||
rtl_power_SOURCES = rtl_power.c convenience/convenience.c
|
||||
rtl_power_LDADD = librtlsdr.la $(LIBM)
|
|
@ -0,0 +1,304 @@
|
|||
/*
|
||||
* Copyright (C) 2014 by Kyle Keen <keenerd@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* a collection of user friendly tools
|
||||
* todo: use strtol for more flexible int parsing
|
||||
* */
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
#define _USE_MATH_DEFINES
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "rtl-sdr.h"
|
||||
|
||||
double atofs(char *s)
|
||||
/* standard suffixes */
|
||||
{
|
||||
char last;
|
||||
int len;
|
||||
double suff = 1.0;
|
||||
len = strlen(s);
|
||||
last = s[len-1];
|
||||
s[len-1] = '\0';
|
||||
switch (last) {
|
||||
case 'g':
|
||||
case 'G':
|
||||
suff *= 1e3;
|
||||
case 'm':
|
||||
case 'M':
|
||||
suff *= 1e3;
|
||||
case 'k':
|
||||
case 'K':
|
||||
suff *= 1e3;
|
||||
suff *= atof(s);
|
||||
s[len-1] = last;
|
||||
return suff;
|
||||
}
|
||||
s[len-1] = last;
|
||||
return atof(s);
|
||||
}
|
||||
|
||||
double atoft(char *s)
|
||||
/* time suffixes, returns seconds */
|
||||
{
|
||||
char last;
|
||||
int len;
|
||||
double suff = 1.0;
|
||||
len = strlen(s);
|
||||
last = s[len-1];
|
||||
s[len-1] = '\0';
|
||||
switch (last) {
|
||||
case 'h':
|
||||
case 'H':
|
||||
suff *= 60;
|
||||
case 'm':
|
||||
case 'M':
|
||||
suff *= 60;
|
||||
case 's':
|
||||
case 'S':
|
||||
suff *= atof(s);
|
||||
s[len-1] = last;
|
||||
return suff;
|
||||
}
|
||||
s[len-1] = last;
|
||||
return atof(s);
|
||||
}
|
||||
|
||||
double atofp(char *s)
|
||||
/* percent suffixes */
|
||||
{
|
||||
char last;
|
||||
int len;
|
||||
double suff = 1.0;
|
||||
len = strlen(s);
|
||||
last = s[len-1];
|
||||
s[len-1] = '\0';
|
||||
switch (last) {
|
||||
case '%':
|
||||
suff *= 0.01;
|
||||
suff *= atof(s);
|
||||
s[len-1] = last;
|
||||
return suff;
|
||||
}
|
||||
s[len-1] = last;
|
||||
return atof(s);
|
||||
}
|
||||
|
||||
int nearest_gain(rtlsdr_dev_t *dev, int target_gain)
|
||||
{
|
||||
int i, r, err1, err2, count, nearest;
|
||||
int* gains;
|
||||
r = rtlsdr_set_tuner_gain_mode(dev, 1);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "WARNING: Failed to enable manual gain.\n");
|
||||
return r;
|
||||
}
|
||||
count = rtlsdr_get_tuner_gains(dev, NULL);
|
||||
if (count <= 0) {
|
||||
return 0;
|
||||
}
|
||||
gains = malloc(sizeof(int) * count);
|
||||
count = rtlsdr_get_tuner_gains(dev, gains);
|
||||
nearest = gains[0];
|
||||
for (i=0; i<count; i++) {
|
||||
err1 = abs(target_gain - nearest);
|
||||
err2 = abs(target_gain - gains[i]);
|
||||
if (err2 < err1) {
|
||||
nearest = gains[i];
|
||||
}
|
||||
}
|
||||
free(gains);
|
||||
return nearest;
|
||||
}
|
||||
|
||||
int verbose_set_frequency(rtlsdr_dev_t *dev, uint32_t frequency)
|
||||
{
|
||||
int r;
|
||||
r = rtlsdr_set_center_freq(dev, frequency);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "WARNING: Failed to set center freq.\n");
|
||||
} else {
|
||||
fprintf(stderr, "Tuned to %u Hz.\n", frequency);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int verbose_set_sample_rate(rtlsdr_dev_t *dev, uint32_t samp_rate)
|
||||
{
|
||||
int r;
|
||||
r = rtlsdr_set_sample_rate(dev, samp_rate);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "WARNING: Failed to set sample rate.\n");
|
||||
} else {
|
||||
fprintf(stderr, "Sampling at %u S/s.\n", samp_rate);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int verbose_direct_sampling(rtlsdr_dev_t *dev, int on)
|
||||
{
|
||||
int r;
|
||||
r = rtlsdr_set_direct_sampling(dev, on);
|
||||
if (r != 0) {
|
||||
fprintf(stderr, "WARNING: Failed to set direct sampling mode.\n");
|
||||
return r;
|
||||
}
|
||||
if (on == 0) {
|
||||
fprintf(stderr, "Direct sampling mode disabled.\n");}
|
||||
if (on == 1) {
|
||||
fprintf(stderr, "Enabled direct sampling mode, input 1/I.\n");}
|
||||
if (on == 2) {
|
||||
fprintf(stderr, "Enabled direct sampling mode, input 2/Q.\n");}
|
||||
return r;
|
||||
}
|
||||
|
||||
int verbose_offset_tuning(rtlsdr_dev_t *dev)
|
||||
{
|
||||
int r;
|
||||
r = rtlsdr_set_offset_tuning(dev, 1);
|
||||
if (r != 0) {
|
||||
fprintf(stderr, "WARNING: Failed to set offset tuning.\n");
|
||||
} else {
|
||||
fprintf(stderr, "Offset tuning mode enabled.\n");
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int verbose_auto_gain(rtlsdr_dev_t *dev)
|
||||
{
|
||||
int r;
|
||||
r = rtlsdr_set_tuner_gain_mode(dev, 0);
|
||||
if (r != 0) {
|
||||
fprintf(stderr, "WARNING: Failed to set tuner gain.\n");
|
||||
} else {
|
||||
fprintf(stderr, "Tuner gain set to automatic.\n");
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int verbose_gain_set(rtlsdr_dev_t *dev, int gain)
|
||||
{
|
||||
int r;
|
||||
r = rtlsdr_set_tuner_gain_mode(dev, 1);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "WARNING: Failed to enable manual gain.\n");
|
||||
return r;
|
||||
}
|
||||
r = rtlsdr_set_tuner_gain(dev, gain);
|
||||
if (r != 0) {
|
||||
fprintf(stderr, "WARNING: Failed to set tuner gain.\n");
|
||||
} else {
|
||||
fprintf(stderr, "Tuner gain set to %0.2f dB.\n", gain/10.0);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int verbose_ppm_set(rtlsdr_dev_t *dev, int ppm_error)
|
||||
{
|
||||
int r;
|
||||
if (ppm_error == 0) {
|
||||
return 0;}
|
||||
r = rtlsdr_set_freq_correction(dev, ppm_error);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "WARNING: Failed to set ppm error.\n");
|
||||
} else {
|
||||
fprintf(stderr, "Tuner error set to %i ppm.\n", ppm_error);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int verbose_reset_buffer(rtlsdr_dev_t *dev)
|
||||
{
|
||||
int r;
|
||||
r = rtlsdr_reset_buffer(dev);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "WARNING: Failed to reset buffers.\n");}
|
||||
return r;
|
||||
}
|
||||
|
||||
int verbose_device_search(char *s)
|
||||
{
|
||||
int i, device_count, device, offset;
|
||||
char *s2;
|
||||
char vendor[256], product[256], serial[256];
|
||||
device_count = rtlsdr_get_device_count();
|
||||
if (!device_count) {
|
||||
fprintf(stderr, "No supported devices found.\n");
|
||||
return -1;
|
||||
}
|
||||
fprintf(stderr, "Found %d device(s):\n", device_count);
|
||||
for (i = 0; i < device_count; i++) {
|
||||
rtlsdr_get_device_usb_strings(i, vendor, product, serial);
|
||||
fprintf(stderr, " %d: %s, %s, SN: %s\n", i, vendor, product, serial);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
/* does string look like raw id number */
|
||||
device = (int)strtol(s, &s2, 0);
|
||||
if (s2[0] == '\0' && device >= 0 && device < device_count) {
|
||||
fprintf(stderr, "Using device %d: %s\n",
|
||||
device, rtlsdr_get_device_name((uint32_t)device));
|
||||
return device;
|
||||
}
|
||||
/* does string exact match a serial */
|
||||
for (i = 0; i < device_count; i++) {
|
||||
rtlsdr_get_device_usb_strings(i, vendor, product, serial);
|
||||
if (strcmp(s, serial) != 0) {
|
||||
continue;}
|
||||
device = i;
|
||||
fprintf(stderr, "Using device %d: %s\n",
|
||||
device, rtlsdr_get_device_name((uint32_t)device));
|
||||
return device;
|
||||
}
|
||||
/* does string prefix match a serial */
|
||||
for (i = 0; i < device_count; i++) {
|
||||
rtlsdr_get_device_usb_strings(i, vendor, product, serial);
|
||||
if (strncmp(s, serial, strlen(s)) != 0) {
|
||||
continue;}
|
||||
device = i;
|
||||
fprintf(stderr, "Using device %d: %s\n",
|
||||
device, rtlsdr_get_device_name((uint32_t)device));
|
||||
return device;
|
||||
}
|
||||
/* does string suffix match a serial */
|
||||
for (i = 0; i < device_count; i++) {
|
||||
rtlsdr_get_device_usb_strings(i, vendor, product, serial);
|
||||
offset = strlen(serial) - strlen(s);
|
||||
if (offset < 0) {
|
||||
continue;}
|
||||
if (strncmp(s, serial+offset, strlen(s)) != 0) {
|
||||
continue;}
|
||||
device = i;
|
||||
fprintf(stderr, "Using device %d: %s\n",
|
||||
device, rtlsdr_get_device_name((uint32_t)device));
|
||||
return device;
|
||||
}
|
||||
fprintf(stderr, "No matching devices found.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// vim: tabstop=8:softtabstop=8:shiftwidth=8:noexpandtab
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* Copyright (C) 2014 by Kyle Keen <keenerd@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* a collection of user friendly tools */
|
||||
|
||||
/*!
|
||||
* Convert standard suffixes (k, M, G) to double
|
||||
*
|
||||
* \param s a string to be parsed
|
||||
* \return double
|
||||
*/
|
||||
|
||||
double atofs(char *s);
|
||||
|
||||
/*!
|
||||
* Convert time suffixes (s, m, h) to double
|
||||
*
|
||||
* \param s a string to be parsed
|
||||
* \return seconds as double
|
||||
*/
|
||||
|
||||
double atoft(char *s);
|
||||
|
||||
/*!
|
||||
* Convert percent suffixe (%) to double
|
||||
*
|
||||
* \param s a string to be parsed
|
||||
* \return double
|
||||
*/
|
||||
|
||||
double atofp(char *s);
|
||||
|
||||
/*!
|
||||
* Find nearest supported gain
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \param target_gain in tenths of a dB
|
||||
* \return 0 on success
|
||||
*/
|
||||
|
||||
int nearest_gain(rtlsdr_dev_t *dev, int target_gain);
|
||||
|
||||
/*!
|
||||
* Set device frequency and report status on stderr
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \param frequency in Hz
|
||||
* \return 0 on success
|
||||
*/
|
||||
|
||||
int verbose_set_frequency(rtlsdr_dev_t *dev, uint32_t frequency);
|
||||
|
||||
/*!
|
||||
* Set device sample rate and report status on stderr
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \param samp_rate in samples/second
|
||||
* \return 0 on success
|
||||
*/
|
||||
|
||||
int verbose_set_sample_rate(rtlsdr_dev_t *dev, uint32_t samp_rate);
|
||||
|
||||
/*!
|
||||
* Enable or disable the direct sampling mode and report status on stderr
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \param on 0 means disabled, 1 I-ADC input enabled, 2 Q-ADC input enabled
|
||||
* \return 0 on success
|
||||
*/
|
||||
|
||||
int verbose_direct_sampling(rtlsdr_dev_t *dev, int on);
|
||||
|
||||
/*!
|
||||
* Enable offset tuning and report status on stderr
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \return 0 on success
|
||||
*/
|
||||
|
||||
int verbose_offset_tuning(rtlsdr_dev_t *dev);
|
||||
|
||||
/*!
|
||||
* Enable auto gain and report status on stderr
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \return 0 on success
|
||||
*/
|
||||
|
||||
int verbose_auto_gain(rtlsdr_dev_t *dev);
|
||||
|
||||
/*!
|
||||
* Set tuner gain and report status on stderr
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \param gain in tenths of a dB
|
||||
* \return 0 on success
|
||||
*/
|
||||
|
||||
int verbose_gain_set(rtlsdr_dev_t *dev, int gain);
|
||||
|
||||
/*!
|
||||
* Set the frequency correction value for the device and report status on stderr.
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \param ppm_error correction value in parts per million (ppm)
|
||||
* \return 0 on success
|
||||
*/
|
||||
|
||||
int verbose_ppm_set(rtlsdr_dev_t *dev, int ppm_error);
|
||||
|
||||
/*!
|
||||
* Reset buffer
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \return 0 on success
|
||||
*/
|
||||
|
||||
int verbose_reset_buffer(rtlsdr_dev_t *dev);
|
||||
|
||||
/*!
|
||||
* Find the closest matching device.
|
||||
*
|
||||
* \param s a string to be parsed
|
||||
* \return dev_index int, -1 on error
|
||||
*/
|
||||
|
||||
int verbose_device_search(char *s);
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,180 @@
|
|||
/* Declarations for getopt.
|
||||
Copyright (C) 1989-1994, 1996-1999, 2001 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 USA. */
|
||||
|
||||
#ifndef _GETOPT_H
|
||||
|
||||
#ifndef __need_getopt
|
||||
# define _GETOPT_H 1
|
||||
#endif
|
||||
|
||||
/* If __GNU_LIBRARY__ is not already defined, either we are being used
|
||||
standalone, or this is the first header included in the source file.
|
||||
If we are being used with glibc, we need to include <features.h>, but
|
||||
that does not exist if we are standalone. So: if __GNU_LIBRARY__ is
|
||||
not defined, include <ctype.h>, which will pull in <features.h> for us
|
||||
if it's from glibc. (Why ctype.h? It's guaranteed to exist and it
|
||||
doesn't flood the namespace with stuff the way some other headers do.) */
|
||||
#if !defined __GNU_LIBRARY__
|
||||
# include <ctype.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* For communication from `getopt' to the caller.
|
||||
When `getopt' finds an option that takes an argument,
|
||||
the argument value is returned here.
|
||||
Also, when `ordering' is RETURN_IN_ORDER,
|
||||
each non-option ARGV-element is returned here. */
|
||||
|
||||
extern char *optarg;
|
||||
|
||||
/* Index in ARGV of the next element to be scanned.
|
||||
This is used for communication to and from the caller
|
||||
and for communication between successive calls to `getopt'.
|
||||
|
||||
On entry to `getopt', zero means this is the first call; initialize.
|
||||
|
||||
When `getopt' returns -1, this is the index of the first of the
|
||||
non-option elements that the caller should itself scan.
|
||||
|
||||
Otherwise, `optind' communicates from one call to the next
|
||||
how much of ARGV has been scanned so far. */
|
||||
|
||||
extern int optind;
|
||||
|
||||
/* Callers store zero here to inhibit the error message `getopt' prints
|
||||
for unrecognized options. */
|
||||
|
||||
extern int opterr;
|
||||
|
||||
/* Set to an option character which was unrecognized. */
|
||||
|
||||
extern int optopt;
|
||||
|
||||
#ifndef __need_getopt
|
||||
/* Describe the long-named options requested by the application.
|
||||
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
|
||||
of `struct option' terminated by an element containing a name which is
|
||||
zero.
|
||||
|
||||
The field `has_arg' is:
|
||||
no_argument (or 0) if the option does not take an argument,
|
||||
required_argument (or 1) if the option requires an argument,
|
||||
optional_argument (or 2) if the option takes an optional argument.
|
||||
|
||||
If the field `flag' is not NULL, it points to a variable that is set
|
||||
to the value given in the field `val' when the option is found, but
|
||||
left unchanged if the option is not found.
|
||||
|
||||
To have a long-named option do something other than set an `int' to
|
||||
a compiled-in constant, such as set a value from `optarg', set the
|
||||
option's `flag' field to zero and its `val' field to a nonzero
|
||||
value (the equivalent single-letter option character, if there is
|
||||
one). For long options that have a zero `flag' field, `getopt'
|
||||
returns the contents of the `val' field. */
|
||||
|
||||
struct option
|
||||
{
|
||||
# if (defined __STDC__ && __STDC__) || defined __cplusplus
|
||||
const char *name;
|
||||
# else
|
||||
char *name;
|
||||
# endif
|
||||
/* has_arg can't be an enum because some compilers complain about
|
||||
type mismatches in all the code that assumes it is an int. */
|
||||
int has_arg;
|
||||
int *flag;
|
||||
int val;
|
||||
};
|
||||
|
||||
/* Names for the values of the `has_arg' field of `struct option'. */
|
||||
|
||||
# define no_argument 0
|
||||
# define required_argument 1
|
||||
# define optional_argument 2
|
||||
#endif /* need getopt */
|
||||
|
||||
|
||||
/* Get definitions and prototypes for functions to process the
|
||||
arguments in ARGV (ARGC of them, minus the program name) for
|
||||
options given in OPTS.
|
||||
|
||||
Return the option character from OPTS just read. Return -1 when
|
||||
there are no more options. For unrecognized options, or options
|
||||
missing arguments, `optopt' is set to the option letter, and '?' is
|
||||
returned.
|
||||
|
||||
The OPTS string is a list of characters which are recognized option
|
||||
letters, optionally followed by colons, specifying that that letter
|
||||
takes an argument, to be placed in `optarg'.
|
||||
|
||||
If a letter in OPTS is followed by two colons, its argument is
|
||||
optional. This behavior is specific to the GNU `getopt'.
|
||||
|
||||
The argument `--' causes premature termination of argument
|
||||
scanning, explicitly telling `getopt' that there are no more
|
||||
options.
|
||||
|
||||
If OPTS begins with `--', then non-option arguments are treated as
|
||||
arguments to the option '\0'. This behavior is specific to the GNU
|
||||
`getopt'. */
|
||||
|
||||
#if (defined __STDC__ && __STDC__) || defined __cplusplus
|
||||
# ifdef __GNU_LIBRARY__
|
||||
/* Many other libraries have conflicting prototypes for getopt, with
|
||||
differences in the consts, in stdlib.h. To avoid compilation
|
||||
errors, only prototype getopt for the GNU C library. */
|
||||
extern int getopt (int __argc, char *const *__argv, const char *__shortopts);
|
||||
# else /* not __GNU_LIBRARY__ */
|
||||
extern int getopt ();
|
||||
# endif /* __GNU_LIBRARY__ */
|
||||
|
||||
# ifndef __need_getopt
|
||||
extern int getopt_long (int __argc, char *const *__argv, const char *__shortopts,
|
||||
const struct option *__longopts, int *__longind);
|
||||
extern int getopt_long_only (int __argc, char *const *__argv,
|
||||
const char *__shortopts,
|
||||
const struct option *__longopts, int *__longind);
|
||||
|
||||
/* Internal only. Users should not call this directly. */
|
||||
extern int _getopt_internal (int __argc, char *const *__argv,
|
||||
const char *__shortopts,
|
||||
const struct option *__longopts, int *__longind,
|
||||
int __long_only);
|
||||
# endif
|
||||
#else /* not __STDC__ */
|
||||
extern int getopt ();
|
||||
# ifndef __need_getopt
|
||||
extern int getopt_long ();
|
||||
extern int getopt_long_only ();
|
||||
|
||||
extern int _getopt_internal ();
|
||||
# endif
|
||||
#endif /* __STDC__ */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Make sure we later can get all the definitions and declarations. */
|
||||
#undef __need_getopt
|
||||
|
||||
#endif /* getopt.h */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,494 @@
|
|||
/*
|
||||
* rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver
|
||||
* Copyright (C) 2012 by Steve Markgraf <steve@steve-m.de>
|
||||
* Copyright (C) 2012 by Hoernchen <la@tfc-server.de>
|
||||
* Copyright (C) 2012 by Kyle Keen <keenerd@gmail.com>
|
||||
* Copyright (C) 2012 by Youssef Touil <youssef@sdrsharp.com>
|
||||
* Copyright (C) 2012 by Ian Gilmour <ian@sdrsharp.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
#include "getopt/getopt.h"
|
||||
#endif
|
||||
|
||||
#include <pthread.h>
|
||||
#include <libusb.h>
|
||||
|
||||
#include "rtl-sdr.h"
|
||||
#include "convenience/convenience.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define sleep Sleep
|
||||
#define round(x) (x > 0.0 ? floor(x + 0.5): ceil(x - 0.5))
|
||||
#endif
|
||||
|
||||
#define ADSB_RATE 2000000
|
||||
#define ADSB_FREQ 1090000000
|
||||
#define DEFAULT_ASYNC_BUF_NUMBER 12
|
||||
#define DEFAULT_BUF_LENGTH (16 * 16384)
|
||||
#define AUTO_GAIN -100
|
||||
|
||||
#define MESSAGEGO 253
|
||||
#define OVERWRITE 254
|
||||
#define BADSAMPLE 255
|
||||
|
||||
static pthread_t demod_thread;
|
||||
static pthread_cond_t ready;
|
||||
static pthread_mutex_t ready_m;
|
||||
static volatile int do_exit = 0;
|
||||
static rtlsdr_dev_t *dev = NULL;
|
||||
|
||||
uint16_t squares[256];
|
||||
|
||||
/* todo, bundle these up in a struct */
|
||||
uint8_t *buffer; /* also abused for uint16_t */
|
||||
int verbose_output = 0;
|
||||
int short_output = 0;
|
||||
int quality = 10;
|
||||
int allowed_errors = 5;
|
||||
FILE *file;
|
||||
int adsb_frame[14];
|
||||
#define preamble_len 16
|
||||
#define long_frame 112
|
||||
#define short_frame 56
|
||||
|
||||
/* signals are not threadsafe by default */
|
||||
#define safe_cond_signal(n, m) pthread_mutex_lock(m); pthread_cond_signal(n); pthread_mutex_unlock(m)
|
||||
#define safe_cond_wait(n, m) pthread_mutex_lock(m); pthread_cond_wait(n, m); pthread_mutex_unlock(m)
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"rtl_adsb, a simple ADS-B decoder\n\n"
|
||||
"Use:\trtl_adsb [-R] [-g gain] [-p ppm] [output file]\n"
|
||||
"\t[-d device_index (default: 0)]\n"
|
||||
"\t[-V verbove output (default: off)]\n"
|
||||
"\t[-S show short frames (default: off)]\n"
|
||||
"\t[-Q quality (0: no sanity checks, 0.5: half bit, 1: one bit (default), 2: two bits)]\n"
|
||||
"\t[-e allowed_errors (default: 5)]\n"
|
||||
"\t[-g tuner_gain (default: automatic)]\n"
|
||||
"\t[-p ppm_error (default: 0)]\n"
|
||||
"\tfilename (a '-' dumps samples to stdout)\n"
|
||||
"\t (omitting the filename also uses stdout)\n\n"
|
||||
"Streaming with netcat:\n"
|
||||
"\trtl_adsb | netcat -lp 8080\n"
|
||||
"\twhile true; do rtl_adsb | nc -lp 8080; done\n"
|
||||
"Streaming with socat:\n"
|
||||
"\trtl_adsb | socat -u - TCP4:sdrsharp.com:47806\n"
|
||||
"\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
BOOL WINAPI
|
||||
sighandler(int signum)
|
||||
{
|
||||
if (CTRL_C_EVENT == signum) {
|
||||
fprintf(stderr, "Signal caught, exiting!\n");
|
||||
do_exit = 1;
|
||||
rtlsdr_cancel_async(dev);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
#else
|
||||
static void sighandler(int signum)
|
||||
{
|
||||
fprintf(stderr, "Signal caught, exiting!\n");
|
||||
do_exit = 1;
|
||||
rtlsdr_cancel_async(dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
void display(int *frame, int len)
|
||||
{
|
||||
int i, df;
|
||||
if (!short_output && len <= short_frame) {
|
||||
return;}
|
||||
df = (frame[0] >> 3) & 0x1f;
|
||||
if (quality == 0 && !(df==11 || df==17 || df==18 || df==19)) {
|
||||
return;}
|
||||
fprintf(file, "*");
|
||||
for (i=0; i<((len+7)/8); i++) {
|
||||
fprintf(file, "%02x", frame[i]);}
|
||||
fprintf(file, ";\r\n");
|
||||
if (!verbose_output) {
|
||||
return;}
|
||||
fprintf(file, "DF=%i CA=%i\n", df, frame[0] & 0x07);
|
||||
fprintf(file, "ICAO Address=%06x\n", frame[1] << 16 | frame[2] << 8 | frame[3]);
|
||||
if (len <= short_frame) {
|
||||
return;}
|
||||
fprintf(file, "PI=0x%06x\n", frame[11] << 16 | frame[12] << 8 | frame[13]);
|
||||
fprintf(file, "Type Code=%i S.Type/Ant.=%x\n", (frame[4] >> 3) & 0x1f, frame[4] & 0x07);
|
||||
fprintf(file, "--------------\n");
|
||||
}
|
||||
|
||||
int abs8(int x)
|
||||
/* do not subtract 127 from the raw iq, this handles it */
|
||||
{
|
||||
if (x >= 127) {
|
||||
return x - 127;}
|
||||
return 127 - x;
|
||||
}
|
||||
|
||||
void squares_precompute(void)
|
||||
/* equiv to abs(x-128) ^ 2 */
|
||||
{
|
||||
int i, j;
|
||||
// todo, check if this LUT is actually any faster
|
||||
for (i=0; i<256; i++) {
|
||||
j = abs8(i);
|
||||
squares[i] = (uint16_t)(j*j);
|
||||
}
|
||||
}
|
||||
|
||||
int magnitute(uint8_t *buf, int len)
|
||||
/* takes i/q, changes buf in place (16 bit), returns new len (16 bit) */
|
||||
{
|
||||
int i;
|
||||
uint16_t *m;
|
||||
for (i=0; i<len; i+=2) {
|
||||
m = (uint16_t*)(&buf[i]);
|
||||
*m = squares[buf[i]] + squares[buf[i+1]];
|
||||
}
|
||||
return len/2;
|
||||
}
|
||||
|
||||
inline uint16_t single_manchester(uint16_t a, uint16_t b, uint16_t c, uint16_t d)
|
||||
/* takes 4 consecutive real samples, return 0 or 1, BADSAMPLE on error */
|
||||
{
|
||||
int bit, bit_p;
|
||||
bit_p = a > b;
|
||||
bit = c > d;
|
||||
|
||||
if (quality == 0) {
|
||||
return bit;}
|
||||
|
||||
if (quality == 5) {
|
||||
if ( bit && bit_p && b > c) {
|
||||
return BADSAMPLE;}
|
||||
if (!bit && !bit_p && b < c) {
|
||||
return BADSAMPLE;}
|
||||
return bit;
|
||||
}
|
||||
|
||||
if (quality == 10) {
|
||||
if ( bit && bit_p && c > b) {
|
||||
return 1;}
|
||||
if ( bit && !bit_p && d < b) {
|
||||
return 1;}
|
||||
if (!bit && bit_p && d > b) {
|
||||
return 0;}
|
||||
if (!bit && !bit_p && c < b) {
|
||||
return 0;}
|
||||
return BADSAMPLE;
|
||||
}
|
||||
|
||||
if ( bit && bit_p && c > b && d < a) {
|
||||
return 1;}
|
||||
if ( bit && !bit_p && c > a && d < b) {
|
||||
return 1;}
|
||||
if (!bit && bit_p && c < a && d > b) {
|
||||
return 0;}
|
||||
if (!bit && !bit_p && c < b && d > a) {
|
||||
return 0;}
|
||||
return BADSAMPLE;
|
||||
}
|
||||
|
||||
inline uint16_t min16(uint16_t a, uint16_t b)
|
||||
{
|
||||
return a<b ? a : b;
|
||||
}
|
||||
|
||||
inline uint16_t max16(uint16_t a, uint16_t b)
|
||||
{
|
||||
return a>b ? a : b;
|
||||
}
|
||||
|
||||
inline int preamble(uint16_t *buf, int i)
|
||||
/* returns 0/1 for preamble at index i */
|
||||
{
|
||||
int i2;
|
||||
uint16_t low = 0;
|
||||
uint16_t high = 65535;
|
||||
for (i2=0; i2<preamble_len; i2++) {
|
||||
switch (i2) {
|
||||
case 0:
|
||||
case 2:
|
||||
case 7:
|
||||
case 9:
|
||||
//high = min16(high, buf[i+i2]);
|
||||
high = buf[i+i2];
|
||||
break;
|
||||
default:
|
||||
//low = max16(low, buf[i+i2]);
|
||||
low = buf[i+i2];
|
||||
break;
|
||||
}
|
||||
if (high <= low) {
|
||||
return 0;}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void manchester(uint16_t *buf, int len)
|
||||
/* overwrites magnitude buffer with valid bits (BADSAMPLE on errors) */
|
||||
{
|
||||
/* a and b hold old values to verify local manchester */
|
||||
uint16_t a=0, b=0;
|
||||
uint16_t bit;
|
||||
int i, i2, start, errors;
|
||||
int maximum_i = len - 1; // len-1 since we look at i and i+1
|
||||
// todo, allow wrap across buffers
|
||||
i = 0;
|
||||
while (i < maximum_i) {
|
||||
/* find preamble */
|
||||
for ( ; i < (len - preamble_len); i++) {
|
||||
if (!preamble(buf, i)) {
|
||||
continue;}
|
||||
a = buf[i];
|
||||
b = buf[i+1];
|
||||
for (i2=0; i2<preamble_len; i2++) {
|
||||
buf[i+i2] = MESSAGEGO;}
|
||||
i += preamble_len;
|
||||
break;
|
||||
}
|
||||
i2 = start = i;
|
||||
errors = 0;
|
||||
/* mark bits until encoding breaks */
|
||||
for ( ; i < maximum_i; i+=2, i2++) {
|
||||
bit = single_manchester(a, b, buf[i], buf[i+1]);
|
||||
a = buf[i];
|
||||
b = buf[i+1];
|
||||
if (bit == BADSAMPLE) {
|
||||
errors += 1;
|
||||
if (errors > allowed_errors) {
|
||||
buf[i2] = BADSAMPLE;
|
||||
break;
|
||||
} else {
|
||||
bit = a > b;
|
||||
/* these don't have to match the bit */
|
||||
a = 0;
|
||||
b = 65535;
|
||||
}
|
||||
}
|
||||
buf[i] = buf[i+1] = OVERWRITE;
|
||||
buf[i2] = bit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void messages(uint16_t *buf, int len)
|
||||
{
|
||||
int i, data_i, index, shift, frame_len;
|
||||
// todo, allow wrap across buffers
|
||||
for (i=0; i<len; i++) {
|
||||
if (buf[i] > 1) {
|
||||
continue;}
|
||||
frame_len = long_frame;
|
||||
data_i = 0;
|
||||
for (index=0; index<14; index++) {
|
||||
adsb_frame[index] = 0;}
|
||||
for(; i<len && buf[i]<=1 && data_i<frame_len; i++, data_i++) {
|
||||
if (buf[i]) {
|
||||
index = data_i / 8;
|
||||
shift = 7 - (data_i % 8);
|
||||
adsb_frame[index] |= (uint8_t)(1<<shift);
|
||||
}
|
||||
if (data_i == 7) {
|
||||
if (adsb_frame[0] == 0) {
|
||||
break;}
|
||||
if (adsb_frame[0] & 0x80) {
|
||||
frame_len = long_frame;}
|
||||
else {
|
||||
frame_len = short_frame;}
|
||||
}
|
||||
}
|
||||
if (data_i < (frame_len-1)) {
|
||||
continue;}
|
||||
display(adsb_frame, frame_len);
|
||||
fflush(file);
|
||||
}
|
||||
}
|
||||
|
||||
static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
|
||||
{
|
||||
if (do_exit) {
|
||||
return;}
|
||||
memcpy(buffer, buf, len);
|
||||
safe_cond_signal(&ready, &ready_m);
|
||||
}
|
||||
|
||||
static void *demod_thread_fn(void *arg)
|
||||
{
|
||||
int len;
|
||||
while (!do_exit) {
|
||||
safe_cond_wait(&ready, &ready_m);
|
||||
len = magnitute(buffer, DEFAULT_BUF_LENGTH);
|
||||
manchester((uint16_t*)buffer, len);
|
||||
messages((uint16_t*)buffer, len);
|
||||
}
|
||||
rtlsdr_cancel_async(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
struct sigaction sigact;
|
||||
#endif
|
||||
char *filename = NULL;
|
||||
int r, opt;
|
||||
int gain = AUTO_GAIN; /* tenths of a dB */
|
||||
int dev_index = 0;
|
||||
int dev_given = 0;
|
||||
int ppm_error = 0;
|
||||
pthread_cond_init(&ready, NULL);
|
||||
pthread_mutex_init(&ready_m, NULL);
|
||||
squares_precompute();
|
||||
|
||||
while ((opt = getopt(argc, argv, "d:g:p:e:Q:VS")) != -1)
|
||||
{
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
dev_index = verbose_device_search(optarg);
|
||||
dev_given = 1;
|
||||
break;
|
||||
case 'g':
|
||||
gain = (int)(atof(optarg) * 10);
|
||||
break;
|
||||
case 'p':
|
||||
ppm_error = atoi(optarg);
|
||||
break;
|
||||
case 'V':
|
||||
verbose_output = 1;
|
||||
break;
|
||||
case 'S':
|
||||
short_output = 1;
|
||||
break;
|
||||
case 'e':
|
||||
allowed_errors = atoi(optarg);
|
||||
break;
|
||||
case 'Q':
|
||||
quality = (int)(atof(optarg) * 10);
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc <= optind) {
|
||||
filename = "-";
|
||||
} else {
|
||||
filename = argv[optind];
|
||||
}
|
||||
|
||||
buffer = malloc(DEFAULT_BUF_LENGTH * sizeof(uint8_t));
|
||||
|
||||
if (!dev_given) {
|
||||
dev_index = verbose_device_search("0");
|
||||
}
|
||||
|
||||
if (dev_index < 0) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
r = rtlsdr_open(&dev, (uint32_t)dev_index);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "Failed to open rtlsdr device #%d.\n", dev_index);
|
||||
exit(1);
|
||||
}
|
||||
#ifndef _WIN32
|
||||
sigact.sa_handler = sighandler;
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = 0;
|
||||
sigaction(SIGINT, &sigact, NULL);
|
||||
sigaction(SIGTERM, &sigact, NULL);
|
||||
sigaction(SIGQUIT, &sigact, NULL);
|
||||
sigaction(SIGPIPE, &sigact, NULL);
|
||||
#else
|
||||
SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE );
|
||||
#endif
|
||||
|
||||
if (strcmp(filename, "-") == 0) { /* Write samples to stdout */
|
||||
file = stdout;
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
#ifdef _WIN32
|
||||
_setmode(_fileno(file), _O_BINARY);
|
||||
#endif
|
||||
} else {
|
||||
file = fopen(filename, "wb");
|
||||
if (!file) {
|
||||
fprintf(stderr, "Failed to open %s\n", filename);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the tuner gain */
|
||||
if (gain == AUTO_GAIN) {
|
||||
verbose_auto_gain(dev);
|
||||
} else {
|
||||
gain = nearest_gain(dev, gain);
|
||||
verbose_gain_set(dev, gain);
|
||||
}
|
||||
|
||||
verbose_ppm_set(dev, ppm_error);
|
||||
r = rtlsdr_set_agc_mode(dev, 1);
|
||||
|
||||
/* Set the tuner frequency */
|
||||
verbose_set_frequency(dev, ADSB_FREQ);
|
||||
|
||||
/* Set the sample rate */
|
||||
verbose_set_sample_rate(dev, ADSB_RATE);
|
||||
|
||||
/* Reset endpoint before we start reading from it (mandatory) */
|
||||
verbose_reset_buffer(dev);
|
||||
|
||||
pthread_create(&demod_thread, NULL, demod_thread_fn, (void *)(NULL));
|
||||
rtlsdr_read_async(dev, rtlsdr_callback, (void *)(NULL),
|
||||
DEFAULT_ASYNC_BUF_NUMBER,
|
||||
DEFAULT_BUF_LENGTH);
|
||||
|
||||
if (do_exit) {
|
||||
fprintf(stderr, "\nUser cancel, exiting...\n");}
|
||||
else {
|
||||
fprintf(stderr, "\nLibrary error %d, exiting...\n", r);}
|
||||
rtlsdr_cancel_async(dev);
|
||||
pthread_cond_destroy(&ready);
|
||||
pthread_mutex_destroy(&ready_m);
|
||||
|
||||
if (file != stdout) {
|
||||
fclose(file);}
|
||||
|
||||
rtlsdr_close(dev);
|
||||
free(buffer);
|
||||
return r >= 0 ? r : -r;
|
||||
}
|
||||
|
|
@ -0,0 +1,425 @@
|
|||
/*
|
||||
* rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver
|
||||
* rtl_eeprom, EEPROM modification tool
|
||||
* Copyright (C) 2012 by Steve Markgraf <steve@steve-m.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include "getopt/getopt.h"
|
||||
#endif
|
||||
|
||||
#include "rtl-sdr.h"
|
||||
|
||||
#define EEPROM_SIZE 256
|
||||
#define MAX_STR_SIZE 256
|
||||
#define STR_OFFSET 0x09
|
||||
|
||||
static rtlsdr_dev_t *dev = NULL;
|
||||
|
||||
typedef struct rtlsdr_config {
|
||||
uint16_t vendor_id;
|
||||
uint16_t product_id;
|
||||
char manufacturer[MAX_STR_SIZE];
|
||||
char product[MAX_STR_SIZE];
|
||||
char serial[MAX_STR_SIZE];
|
||||
int have_serial;
|
||||
int enable_ir;
|
||||
int remote_wakeup;
|
||||
} rtlsdr_config_t;
|
||||
|
||||
void dump_config(rtlsdr_config_t *conf)
|
||||
{
|
||||
fprintf(stderr, "__________________________________________\n");
|
||||
fprintf(stderr, "Vendor ID:\t\t0x%04x\n", conf->vendor_id);
|
||||
fprintf(stderr, "Product ID:\t\t0x%04x\n", conf->product_id);
|
||||
fprintf(stderr, "Manufacturer:\t\t%s\n", conf->manufacturer);
|
||||
fprintf(stderr, "Product:\t\t%s\n", conf->product);
|
||||
fprintf(stderr, "Serial number:\t\t%s\n", conf->serial);
|
||||
fprintf(stderr, "Serial number enabled:\t");
|
||||
fprintf(stderr, conf->have_serial ? "yes\n": "no\n");
|
||||
fprintf(stderr, "IR endpoint enabled:\t");
|
||||
fprintf(stderr, conf->enable_ir ? "yes\n": "no\n");
|
||||
fprintf(stderr, "Remote wakeup enabled:\t");
|
||||
fprintf(stderr, conf->remote_wakeup ? "yes\n": "no\n");
|
||||
fprintf(stderr, "__________________________________________\n");
|
||||
}
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"rtl_eeprom, an EEPROM programming tool for "
|
||||
"RTL2832 based DVB-T receivers\n\n"
|
||||
"Usage:\n"
|
||||
"\t[-d device_index (default: 0)]\n"
|
||||
"\t[-m <str> set manufacturer string]\n"
|
||||
"\t[-p <str> set product string]\n"
|
||||
"\t[-s <str> set serial number string]\n"
|
||||
"\t[-i <0,1> disable/enable IR-endpoint]\n"
|
||||
"\t[-g <conf> generate default config and write to device]\n"
|
||||
"\t[ <conf> can be one of:]\n"
|
||||
"\t[ realtek\t\tRealtek default (as without EEPROM)]\n"
|
||||
"\t[ realtek_oem\t\tRealtek default OEM with EEPROM]\n"
|
||||
"\t[ noxon\t\tTerratec NOXON DAB Stick]\n"
|
||||
"\t[ terratec_black\tTerratec T Stick Black]\n"
|
||||
"\t[ terratec_plus\tTerratec T Stick+ (DVB-T/DAB)]\n"
|
||||
"\t[-w <filename> write dumped file to device]\n"
|
||||
"\t[-r <filename> dump EEPROM to file]\n"
|
||||
"\t[-h display this help text]\n"
|
||||
"\nUse on your own risk, especially -w!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int get_string_descriptor(int pos, uint8_t *data, char *str)
|
||||
{
|
||||
int len, i, j = 0;
|
||||
|
||||
len = data[pos];
|
||||
|
||||
if (data[pos + 1] != 0x03)
|
||||
fprintf(stderr, "Error: invalid string descriptor!\n");
|
||||
|
||||
for (i = 2; i < len; i += 2)
|
||||
str[j++] = data[pos + i];
|
||||
|
||||
str[j] = 0x00;
|
||||
|
||||
return pos + i;
|
||||
}
|
||||
|
||||
int set_string_descriptor(int pos, uint8_t *data, char *str)
|
||||
{
|
||||
int i = 0, j = 2;
|
||||
|
||||
if (pos < 0)
|
||||
return -1;
|
||||
|
||||
data[pos + 1] = 0x03;
|
||||
|
||||
while (str[i] != 0x00) {
|
||||
if ((pos + j) >= 78) {
|
||||
fprintf(stderr, "Error: string too long, truncated!\n");
|
||||
return -1;
|
||||
}
|
||||
data[pos + j++] = str[i++];
|
||||
data[pos + j++] = 0x00;
|
||||
}
|
||||
|
||||
data[pos] = j;
|
||||
|
||||
return pos + j;
|
||||
}
|
||||
|
||||
int parse_eeprom_to_conf(rtlsdr_config_t *conf, uint8_t *dat)
|
||||
{
|
||||
int pos;
|
||||
|
||||
if ((dat[0] != 0x28) || (dat[1] != 0x32))
|
||||
fprintf(stderr, "Error: invalid RTL2832 EEPROM header!\n");
|
||||
|
||||
conf->vendor_id = dat[2] | (dat[3] << 8);
|
||||
conf->product_id = dat[4] | (dat[5] << 8);
|
||||
conf->have_serial = (dat[6] == 0xa5) ? 1 : 0;
|
||||
conf->remote_wakeup = (dat[7] & 0x01) ? 1 : 0;
|
||||
conf->enable_ir = (dat[7] & 0x02) ? 1 : 0;
|
||||
|
||||
pos = get_string_descriptor(STR_OFFSET, dat, conf->manufacturer);
|
||||
pos = get_string_descriptor(pos, dat, conf->product);
|
||||
get_string_descriptor(pos, dat, conf->serial);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gen_eeprom_from_conf(rtlsdr_config_t *conf, uint8_t *dat)
|
||||
{
|
||||
int pos;
|
||||
|
||||
dat[0] = 0x28;
|
||||
dat[1] = 0x32;
|
||||
dat[2] = conf->vendor_id & 0xff;
|
||||
dat[3] = (conf->vendor_id >> 8) & 0xff ;
|
||||
dat[4] = conf->product_id & 0xff;
|
||||
dat[5] = (conf->product_id >> 8) & 0xff;
|
||||
dat[6] = conf->have_serial ? 0xa5 : 0x00;
|
||||
dat[7] = 0x14;
|
||||
dat[7] |= conf->remote_wakeup ? 0x01 : 0x00;
|
||||
dat[7] |= conf->enable_ir ? 0x02 : 0x00;
|
||||
dat[8] = 0x02;
|
||||
|
||||
pos = set_string_descriptor(STR_OFFSET, dat, conf->manufacturer);
|
||||
pos = set_string_descriptor(pos, dat, conf->product);
|
||||
pos = set_string_descriptor(pos, dat, conf->serial);
|
||||
|
||||
dat[78] = 0x00; /* length of IR config */
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
enum configs {
|
||||
CONF_NONE = 0,
|
||||
REALTEK,
|
||||
REALTEK_EEPROM,
|
||||
TERRATEC_NOXON,
|
||||
TERRATEC_T_BLACK,
|
||||
TERRATEC_T_PLUS,
|
||||
};
|
||||
|
||||
void gen_default_conf(rtlsdr_config_t *conf, int config)
|
||||
{
|
||||
switch (config) {
|
||||
case REALTEK:
|
||||
fprintf(stderr, "Realtek default (as without EEPROM)\n");
|
||||
conf->vendor_id = 0x0bda;
|
||||
conf->product_id = 0x2832;
|
||||
strcpy(conf->manufacturer, "Generic");
|
||||
strcpy(conf->product, "RTL2832U DVB-T");
|
||||
strcpy(conf->serial, "0");
|
||||
conf->have_serial = 1;
|
||||
conf->enable_ir = 0;
|
||||
conf->remote_wakeup = 1;
|
||||
break;
|
||||
case REALTEK_EEPROM:
|
||||
fprintf(stderr, "Realtek default OEM with EEPROM\n");
|
||||
conf->vendor_id = 0x0bda;
|
||||
conf->product_id = 0x2838;
|
||||
strcpy(conf->manufacturer, "Realtek");
|
||||
strcpy(conf->product, "RTL2838UHIDIR");
|
||||
strcpy(conf->serial, "00000001");
|
||||
conf->have_serial = 1;
|
||||
conf->enable_ir = 1;
|
||||
conf->remote_wakeup = 0;
|
||||
break;
|
||||
case TERRATEC_NOXON:
|
||||
fprintf(stderr, "Terratec NOXON DAB Stick\n");
|
||||
conf->vendor_id = 0x0ccd;
|
||||
conf->product_id = 0x00b3;
|
||||
strcpy(conf->manufacturer, "NOXON");
|
||||
strcpy(conf->product, "DAB Stick");
|
||||
strcpy(conf->serial, "0");
|
||||
conf->have_serial = 1;
|
||||
conf->enable_ir = 0;
|
||||
conf->remote_wakeup = 1;
|
||||
break;
|
||||
case TERRATEC_T_BLACK:
|
||||
fprintf(stderr, "Terratec T Stick Black\n");
|
||||
conf->vendor_id = 0x0ccd;
|
||||
conf->product_id = 0x00a9;
|
||||
strcpy(conf->manufacturer, "Realtek");
|
||||
strcpy(conf->product, "RTL2838UHIDIR");
|
||||
strcpy(conf->serial, "00000001");
|
||||
conf->have_serial = 1;
|
||||
conf->enable_ir = 1;
|
||||
conf->remote_wakeup = 0;
|
||||
break;
|
||||
case TERRATEC_T_PLUS:
|
||||
fprintf(stderr, "Terratec ran T Stick+\n");
|
||||
conf->vendor_id = 0x0ccd;
|
||||
conf->product_id = 0x00d7;
|
||||
strcpy(conf->manufacturer, "Realtek");
|
||||
strcpy(conf->product, "RTL2838UHIDIR");
|
||||
strcpy(conf->serial, "00000001");
|
||||
conf->have_serial = 1;
|
||||
conf->enable_ir = 1;
|
||||
conf->remote_wakeup = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, r, opt;
|
||||
uint32_t dev_index = 0;
|
||||
int device_count;
|
||||
char *filename = NULL;
|
||||
FILE *file = NULL;
|
||||
char *manuf_str = NULL;
|
||||
char *product_str = NULL;
|
||||
char *serial_str = NULL;
|
||||
uint8_t buf[EEPROM_SIZE];
|
||||
rtlsdr_config_t conf;
|
||||
int flash_file = 0;
|
||||
int default_config = 0;
|
||||
int change = 0;
|
||||
int ir_endpoint = 0;
|
||||
char ch;
|
||||
|
||||
while ((opt = getopt(argc, argv, "d:m:p:s:i:g:w:r:h?")) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
dev_index = atoi(optarg);
|
||||
break;
|
||||
case 'm':
|
||||
manuf_str = optarg;
|
||||
change = 1;
|
||||
break;
|
||||
case 'p':
|
||||
product_str = optarg;
|
||||
change = 1;
|
||||
break;
|
||||
case 's':
|
||||
serial_str = optarg;
|
||||
change = 1;
|
||||
break;
|
||||
case 'i':
|
||||
ir_endpoint = (atoi(optarg) > 0) ? 1 : -1;
|
||||
change = 1;
|
||||
break;
|
||||
case 'g':
|
||||
if (!strcmp(optarg, "realtek"))
|
||||
default_config = REALTEK;
|
||||
else if (!strcmp(optarg, "realtek_oem"))
|
||||
default_config = REALTEK_EEPROM;
|
||||
else if (!strcmp(optarg, "noxon"))
|
||||
default_config = TERRATEC_NOXON;
|
||||
else if (!strcmp(optarg, "terratec_black"))
|
||||
default_config = TERRATEC_T_BLACK;
|
||||
else if (!strcmp(optarg, "terratec_plus"))
|
||||
default_config = TERRATEC_T_PLUS;
|
||||
|
||||
if (default_config != CONF_NONE)
|
||||
change = 1;
|
||||
break;
|
||||
case 'w':
|
||||
flash_file = 1;
|
||||
change = 1;
|
||||
case 'r':
|
||||
filename = optarg;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
device_count = rtlsdr_get_device_count();
|
||||
if (!device_count) {
|
||||
fprintf(stderr, "No supported devices found.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fprintf(stderr, "Found %d device(s):\n", device_count);
|
||||
for (i = 0; i < device_count; i++)
|
||||
fprintf(stderr, " %d: %s\n", i, rtlsdr_get_device_name(i));
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
fprintf(stderr, "Using device %d: %s\n",
|
||||
dev_index,
|
||||
rtlsdr_get_device_name(dev_index));
|
||||
|
||||
r = rtlsdr_open(&dev, dev_index);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "Failed to open rtlsdr device #%d.\n", dev_index);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
r = rtlsdr_read_eeprom(dev, buf, 0, EEPROM_SIZE);
|
||||
if (r < 0) {
|
||||
if (r == -3)
|
||||
fprintf(stderr, "No EEPROM has been found.\n");
|
||||
else
|
||||
fprintf(stderr, "Failed to read EEPROM, err %i.\n", r);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (r < 0)
|
||||
return -1;
|
||||
|
||||
fprintf(stderr, "Current configuration:\n");
|
||||
parse_eeprom_to_conf(&conf, buf);
|
||||
dump_config(&conf);
|
||||
|
||||
if (filename) {
|
||||
file = fopen(filename, flash_file ? "rb" : "wb");
|
||||
if (!file) {
|
||||
fprintf(stderr, "Error opening file!\n");
|
||||
goto exit;
|
||||
}
|
||||
if (flash_file) {
|
||||
if (fread(buf, 1, sizeof(buf), file) != sizeof(buf))
|
||||
fprintf(stderr, "Error reading file!\n");
|
||||
} else {
|
||||
if (fwrite(buf, 1, sizeof(buf), file) != sizeof(buf))
|
||||
fprintf(stderr, "Short write, exiting!\n");
|
||||
else
|
||||
fprintf(stderr, "\nDump to %s successful.\n", filename);
|
||||
}
|
||||
}
|
||||
|
||||
if (manuf_str)
|
||||
strncpy((char*)&conf.manufacturer, manuf_str, MAX_STR_SIZE);
|
||||
|
||||
if (product_str)
|
||||
strncpy((char*)&conf.product, product_str, MAX_STR_SIZE);
|
||||
|
||||
if (serial_str) {
|
||||
conf.have_serial = 1;
|
||||
strncpy((char*)&conf.serial, serial_str, MAX_STR_SIZE);
|
||||
}
|
||||
|
||||
if (ir_endpoint != 0)
|
||||
conf.enable_ir = (ir_endpoint > 0) ? 1 : 0;
|
||||
|
||||
if (!change)
|
||||
goto exit;
|
||||
|
||||
fprintf(stderr, "\nNew configuration:\n");
|
||||
|
||||
if (default_config != CONF_NONE)
|
||||
gen_default_conf(&conf, default_config);
|
||||
|
||||
if (!flash_file) {
|
||||
if (gen_eeprom_from_conf(&conf, buf) < 0)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
parse_eeprom_to_conf(&conf, buf);
|
||||
dump_config(&conf);
|
||||
|
||||
fprintf(stderr, "Write new configuration to device [y/n]? ");
|
||||
|
||||
while ((ch = getchar())) {
|
||||
if (ch != 'y')
|
||||
goto exit;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
r = rtlsdr_write_eeprom(dev, buf, 0, flash_file ? EEPROM_SIZE : 128);
|
||||
if (r < 0)
|
||||
fprintf(stderr, "Error while writing EEPROM: %i\n", r);
|
||||
else
|
||||
fprintf(stderr, "\nConfiguration successfully written.\n"
|
||||
"Please replug the device for changes"
|
||||
" to take effect.\n");
|
||||
|
||||
exit:
|
||||
if (file)
|
||||
fclose(file);
|
||||
|
||||
rtlsdr_close(dev);
|
||||
|
||||
return r >= 0 ? r : -r;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,998 @@
|
|||
/*
|
||||
* rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver
|
||||
* Copyright (C) 2012 by Steve Markgraf <steve@steve-m.de>
|
||||
* Copyright (C) 2012 by Hoernchen <la@tfc-server.de>
|
||||
* Copyright (C) 2012 by Kyle Keen <keenerd@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* rtl_power: general purpose FFT integrator
|
||||
* -f low_freq:high_freq:max_bin_size
|
||||
* -i seconds
|
||||
* outputs CSV
|
||||
* time, low, high, step, db, db, db ...
|
||||
* db optional? raw output might be better for noise correction
|
||||
* todo:
|
||||
* threading
|
||||
* randomized hopping
|
||||
* noise correction
|
||||
* continuous IIR
|
||||
* general astronomy usefulness
|
||||
* multiple dongles
|
||||
* multiple FFT workers
|
||||
* check edge cropping for off-by-one and rounding errors
|
||||
* 1.8MS/s for hiding xtal harmonics
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
#include "getopt/getopt.h"
|
||||
#define usleep(x) Sleep(x/1000)
|
||||
#ifdef _MSC_VER
|
||||
#define round(x) (x > 0.0 ? floor(x + 0.5): ceil(x - 0.5))
|
||||
#endif
|
||||
#define _USE_MATH_DEFINES
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
#include <pthread.h>
|
||||
#include <libusb.h>
|
||||
|
||||
#include "rtl-sdr.h"
|
||||
#include "convenience/convenience.h"
|
||||
|
||||
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
|
||||
|
||||
#define DEFAULT_BUF_LENGTH (1 * 16384)
|
||||
#define AUTO_GAIN -100
|
||||
#define BUFFER_DUMP (1<<12)
|
||||
|
||||
#define MAXIMUM_RATE 2800000
|
||||
#define MINIMUM_RATE 1000000
|
||||
|
||||
static volatile int do_exit = 0;
|
||||
static rtlsdr_dev_t *dev = NULL;
|
||||
FILE *file;
|
||||
|
||||
int16_t* Sinewave;
|
||||
double* power_table;
|
||||
int N_WAVE, LOG2_N_WAVE;
|
||||
int next_power;
|
||||
int16_t *fft_buf;
|
||||
int *window_coefs;
|
||||
|
||||
struct tuning_state
|
||||
/* one per tuning range */
|
||||
{
|
||||
int freq;
|
||||
int rate;
|
||||
int bin_e;
|
||||
long *avg; /* length == 2^bin_e */
|
||||
int samples;
|
||||
int downsample;
|
||||
int downsample_passes; /* for the recursive filter */
|
||||
double crop;
|
||||
//pthread_rwlock_t avg_lock;
|
||||
//pthread_mutex_t avg_mutex;
|
||||
/* having the iq buffer here is wasteful, but will avoid contention */
|
||||
uint8_t *buf8;
|
||||
int buf_len;
|
||||
//int *comp_fir;
|
||||
//pthread_rwlock_t buf_lock;
|
||||
//pthread_mutex_t buf_mutex;
|
||||
};
|
||||
|
||||
/* 3000 is enough for 3GHz b/w worst case */
|
||||
#define MAX_TUNES 3000
|
||||
struct tuning_state tunes[MAX_TUNES];
|
||||
int tune_count = 0;
|
||||
|
||||
int boxcar = 1;
|
||||
int comp_fir_size = 0;
|
||||
int peak_hold = 0;
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"rtl_power, a simple FFT logger for RTL2832 based DVB-T receivers\n\n"
|
||||
"Use:\trtl_power -f freq_range [-options] [filename]\n"
|
||||
"\t-f lower:upper:bin_size [Hz]\n"
|
||||
"\t (bin size is a maximum, smaller more convenient bins\n"
|
||||
"\t will be used. valid range 1Hz - 2.8MHz)\n"
|
||||
"\t[-i integration_interval (default: 10 seconds)]\n"
|
||||
"\t (buggy if a full sweep takes longer than the interval)\n"
|
||||
"\t[-1 enables single-shot mode (default: off)]\n"
|
||||
"\t[-e exit_timer (default: off/0)]\n"
|
||||
//"\t[-s avg/iir smoothing (default: avg)]\n"
|
||||
//"\t[-t threads (default: 1)]\n"
|
||||
"\t[-d device_index (default: 0)]\n"
|
||||
"\t[-g tuner_gain (default: automatic)]\n"
|
||||
"\t[-p ppm_error (default: 0)]\n"
|
||||
"\tfilename (a '-' dumps samples to stdout)\n"
|
||||
"\t (omitting the filename also uses stdout)\n"
|
||||
"\n"
|
||||
"Experimental options:\n"
|
||||
"\t[-w window (default: rectangle)]\n"
|
||||
"\t (hamming, blackman, blackman-harris, hann-poisson, bartlett, youssef)\n"
|
||||
// kaiser
|
||||
"\t[-c crop_percent (default: 0%%, recommended: 20%%-50%%)]\n"
|
||||
"\t (discards data at the edges, 100%% discards everything)\n"
|
||||
"\t (has no effect for bins larger than 1MHz)\n"
|
||||
"\t[-F fir_size (default: disabled)]\n"
|
||||
"\t (enables low-leakage downsample filter,\n"
|
||||
"\t fir_size can be 0 or 9. 0 has bad roll off,\n"
|
||||
"\t try with '-c 50%%')\n"
|
||||
"\t[-P enables peak hold (default: off)]\n"
|
||||
"\t[-D enable direct sampling (default: off)]\n"
|
||||
"\t[-O enable offset tuning (default: off)]\n"
|
||||
"\n"
|
||||
"CSV FFT output columns:\n"
|
||||
"\tdate, time, Hz low, Hz high, Hz step, samples, dbm, dbm, ...\n\n"
|
||||
"Examples:\n"
|
||||
"\trtl_power -f 88M:108M:125k fm_stations.csv\n"
|
||||
"\t (creates 160 bins across the FM band,\n"
|
||||
"\t individual stations should be visible)\n"
|
||||
"\trtl_power -f 100M:1G:1M -i 5m -1 survey.csv\n"
|
||||
"\t (a five minute low res scan of nearly everything)\n"
|
||||
"\trtl_power -f ... -i 15m -1 log.csv\n"
|
||||
"\t (integrate for 15 minutes and exit afterwards)\n"
|
||||
"\trtl_power -f ... -e 1h | gzip > log.csv.gz\n"
|
||||
"\t (collect data for one hour and compress it on the fly)\n\n"
|
||||
"Convert CSV to a waterfall graphic with:\n"
|
||||
"\t http://kmkeen.com/tmp/heatmap.py.txt \n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void multi_bail(void)
|
||||
{
|
||||
if (do_exit == 1)
|
||||
{
|
||||
fprintf(stderr, "Signal caught, finishing scan pass.\n");
|
||||
}
|
||||
if (do_exit >= 2)
|
||||
{
|
||||
fprintf(stderr, "Signal caught, aborting immediately.\n");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
BOOL WINAPI
|
||||
sighandler(int signum)
|
||||
{
|
||||
if (CTRL_C_EVENT == signum) {
|
||||
do_exit++;
|
||||
multi_bail();
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
#else
|
||||
static void sighandler(int signum)
|
||||
{
|
||||
do_exit++;
|
||||
multi_bail();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* more cond dumbness */
|
||||
#define safe_cond_signal(n, m) pthread_mutex_lock(m); pthread_cond_signal(n); pthread_mutex_unlock(m)
|
||||
#define safe_cond_wait(n, m) pthread_mutex_lock(m); pthread_cond_wait(n, m); pthread_mutex_unlock(m)
|
||||
|
||||
/* {length, coef, coef, coef} and scaled by 2^15
|
||||
for now, only length 9, optimal way to get +85% bandwidth */
|
||||
#define CIC_TABLE_MAX 10
|
||||
int cic_9_tables[][10] = {
|
||||
{0,},
|
||||
{9, -156, -97, 2798, -15489, 61019, -15489, 2798, -97, -156},
|
||||
{9, -128, -568, 5593, -24125, 74126, -24125, 5593, -568, -128},
|
||||
{9, -129, -639, 6187, -26281, 77511, -26281, 6187, -639, -129},
|
||||
{9, -122, -612, 6082, -26353, 77818, -26353, 6082, -612, -122},
|
||||
{9, -120, -602, 6015, -26269, 77757, -26269, 6015, -602, -120},
|
||||
{9, -120, -582, 5951, -26128, 77542, -26128, 5951, -582, -120},
|
||||
{9, -119, -580, 5931, -26094, 77505, -26094, 5931, -580, -119},
|
||||
{9, -119, -578, 5921, -26077, 77484, -26077, 5921, -578, -119},
|
||||
{9, -119, -577, 5917, -26067, 77473, -26067, 5917, -577, -119},
|
||||
{9, -199, -362, 5303, -25505, 77489, -25505, 5303, -362, -199},
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
double log2(double n)
|
||||
{
|
||||
return log(n) / log(2.0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* FFT based on fix_fft.c by Roberts, Slaney and Bouras
|
||||
http://www.jjj.de/fft/fftpage.html
|
||||
16 bit ints for everything
|
||||
-32768..+32768 maps to -1.0..+1.0
|
||||
*/
|
||||
|
||||
void sine_table(int size)
|
||||
{
|
||||
int i;
|
||||
double d;
|
||||
LOG2_N_WAVE = size;
|
||||
N_WAVE = 1 << LOG2_N_WAVE;
|
||||
Sinewave = malloc(sizeof(int16_t) * N_WAVE*3/4);
|
||||
power_table = malloc(sizeof(double) * N_WAVE);
|
||||
for (i=0; i<N_WAVE*3/4; i++)
|
||||
{
|
||||
d = (double)i * 2.0 * M_PI / N_WAVE;
|
||||
Sinewave[i] = (int)round(32767*sin(d));
|
||||
//printf("%i\n", Sinewave[i]);
|
||||
}
|
||||
}
|
||||
|
||||
inline int16_t FIX_MPY(int16_t a, int16_t b)
|
||||
/* fixed point multiply and scale */
|
||||
{
|
||||
int c = ((int)a * (int)b) >> 14;
|
||||
b = c & 0x01;
|
||||
return (c >> 1) + b;
|
||||
}
|
||||
|
||||
int fix_fft(int16_t iq[], int m)
|
||||
/* interleaved iq[], 0 <= n < 2**m, changes in place */
|
||||
{
|
||||
int mr, nn, i, j, l, k, istep, n, shift;
|
||||
int16_t qr, qi, tr, ti, wr, wi;
|
||||
n = 1 << m;
|
||||
if (n > N_WAVE)
|
||||
{return -1;}
|
||||
mr = 0;
|
||||
nn = n - 1;
|
||||
/* decimation in time - re-order data */
|
||||
for (m=1; m<=nn; ++m) {
|
||||
l = n;
|
||||
do
|
||||
{l >>= 1;}
|
||||
while (mr+l > nn);
|
||||
mr = (mr & (l-1)) + l;
|
||||
if (mr <= m)
|
||||
{continue;}
|
||||
// real = 2*m, imag = 2*m+1
|
||||
tr = iq[2*m];
|
||||
iq[2*m] = iq[2*mr];
|
||||
iq[2*mr] = tr;
|
||||
ti = iq[2*m+1];
|
||||
iq[2*m+1] = iq[2*mr+1];
|
||||
iq[2*mr+1] = ti;
|
||||
}
|
||||
l = 1;
|
||||
k = LOG2_N_WAVE-1;
|
||||
while (l < n) {
|
||||
shift = 1;
|
||||
istep = l << 1;
|
||||
for (m=0; m<l; ++m) {
|
||||
j = m << k;
|
||||
wr = Sinewave[j+N_WAVE/4];
|
||||
wi = -Sinewave[j];
|
||||
if (shift) {
|
||||
wr >>= 1; wi >>= 1;}
|
||||
for (i=m; i<n; i+=istep) {
|
||||
j = i + l;
|
||||
tr = FIX_MPY(wr,iq[2*j]) - FIX_MPY(wi,iq[2*j+1]);
|
||||
ti = FIX_MPY(wr,iq[2*j+1]) + FIX_MPY(wi,iq[2*j]);
|
||||
qr = iq[2*i];
|
||||
qi = iq[2*i+1];
|
||||
if (shift) {
|
||||
qr >>= 1; qi >>= 1;}
|
||||
iq[2*j] = qr - tr;
|
||||
iq[2*j+1] = qi - ti;
|
||||
iq[2*i] = qr + tr;
|
||||
iq[2*i+1] = qi + ti;
|
||||
}
|
||||
}
|
||||
--k;
|
||||
l = istep;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
double rectangle(int i, int length)
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
double hamming(int i, int length)
|
||||
{
|
||||
double a, b, w, N1;
|
||||
a = 25.0/46.0;
|
||||
b = 21.0/46.0;
|
||||
N1 = (double)(length-1);
|
||||
w = a - b*cos(2*i*M_PI/N1);
|
||||
return w;
|
||||
}
|
||||
|
||||
double blackman(int i, int length)
|
||||
{
|
||||
double a0, a1, a2, w, N1;
|
||||
a0 = 7938.0/18608.0;
|
||||
a1 = 9240.0/18608.0;
|
||||
a2 = 1430.0/18608.0;
|
||||
N1 = (double)(length-1);
|
||||
w = a0 - a1*cos(2*i*M_PI/N1) + a2*cos(4*i*M_PI/N1);
|
||||
return w;
|
||||
}
|
||||
|
||||
double blackman_harris(int i, int length)
|
||||
{
|
||||
double a0, a1, a2, a3, w, N1;
|
||||
a0 = 0.35875;
|
||||
a1 = 0.48829;
|
||||
a2 = 0.14128;
|
||||
a3 = 0.01168;
|
||||
N1 = (double)(length-1);
|
||||
w = a0 - a1*cos(2*i*M_PI/N1) + a2*cos(4*i*M_PI/N1) - a3*cos(6*i*M_PI/N1);
|
||||
return w;
|
||||
}
|
||||
|
||||
double hann_poisson(int i, int length)
|
||||
{
|
||||
double a, N1, w;
|
||||
a = 2.0;
|
||||
N1 = (double)(length-1);
|
||||
w = 0.5 * (1 - cos(2*M_PI*i/N1)) * \
|
||||
pow(M_E, (-a*(double)abs((int)(N1-1-2*i)))/N1);
|
||||
return w;
|
||||
}
|
||||
|
||||
double youssef(int i, int length)
|
||||
/* really a blackman-harris-poisson window, but that is a mouthful */
|
||||
{
|
||||
double a, a0, a1, a2, a3, w, N1;
|
||||
a0 = 0.35875;
|
||||
a1 = 0.48829;
|
||||
a2 = 0.14128;
|
||||
a3 = 0.01168;
|
||||
N1 = (double)(length-1);
|
||||
w = a0 - a1*cos(2*i*M_PI/N1) + a2*cos(4*i*M_PI/N1) - a3*cos(6*i*M_PI/N1);
|
||||
a = 0.0025;
|
||||
w *= pow(M_E, (-a*(double)abs((int)(N1-1-2*i)))/N1);
|
||||
return w;
|
||||
}
|
||||
|
||||
double kaiser(int i, int length)
|
||||
// todo, become more smart
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
double bartlett(int i, int length)
|
||||
{
|
||||
double N1, L, w;
|
||||
L = (double)length;
|
||||
N1 = L - 1;
|
||||
w = (i - N1/2) / (L/2);
|
||||
if (w < 0) {
|
||||
w = -w;}
|
||||
w = 1 - w;
|
||||
return w;
|
||||
}
|
||||
|
||||
void rms_power(struct tuning_state *ts)
|
||||
/* for bins between 1MHz and 2MHz */
|
||||
{
|
||||
int i, s;
|
||||
uint8_t *buf = ts->buf8;
|
||||
int buf_len = ts->buf_len;
|
||||
long p, t;
|
||||
double dc, err;
|
||||
|
||||
p = t = 0L;
|
||||
for (i=0; i<buf_len; i++) {
|
||||
s = (int)buf[i] - 127;
|
||||
t += (long)s;
|
||||
p += (long)(s * s);
|
||||
}
|
||||
/* correct for dc offset in squares */
|
||||
dc = (double)t / (double)buf_len;
|
||||
err = t * 2 * dc - dc * dc * buf_len;
|
||||
p -= (long)round(err);
|
||||
|
||||
if (!peak_hold) {
|
||||
ts->avg[0] += p;
|
||||
} else {
|
||||
ts->avg[0] = MAX(ts->avg[0], p);
|
||||
}
|
||||
ts->samples += 1;
|
||||
}
|
||||
|
||||
void frequency_range(char *arg, double crop)
|
||||
/* flesh out the tunes[] for scanning */
|
||||
// do we want the fewest ranges (easy) or the fewest bins (harder)?
|
||||
{
|
||||
char *start, *stop, *step;
|
||||
int i, j, upper, lower, max_size, bw_seen, bw_used, bin_e, buf_len;
|
||||
int downsample, downsample_passes;
|
||||
double bin_size;
|
||||
struct tuning_state *ts;
|
||||
/* hacky string parsing */
|
||||
start = arg;
|
||||
stop = strchr(start, ':') + 1;
|
||||
stop[-1] = '\0';
|
||||
step = strchr(stop, ':') + 1;
|
||||
step[-1] = '\0';
|
||||
lower = (int)atofs(start);
|
||||
upper = (int)atofs(stop);
|
||||
max_size = (int)atofs(step);
|
||||
stop[-1] = ':';
|
||||
step[-1] = ':';
|
||||
downsample = 1;
|
||||
downsample_passes = 0;
|
||||
/* evenly sized ranges, as close to MAXIMUM_RATE as possible */
|
||||
// todo, replace loop with algebra
|
||||
for (i=1; i<1500; i++) {
|
||||
bw_seen = (upper - lower) / i;
|
||||
bw_used = (int)((double)(bw_seen) / (1.0 - crop));
|
||||
if (bw_used > MAXIMUM_RATE) {
|
||||
continue;}
|
||||
tune_count = i;
|
||||
break;
|
||||
}
|
||||
/* unless small bandwidth */
|
||||
if (bw_used < MINIMUM_RATE) {
|
||||
tune_count = 1;
|
||||
downsample = MAXIMUM_RATE / bw_used;
|
||||
bw_used = bw_used * downsample;
|
||||
}
|
||||
if (!boxcar && downsample > 1) {
|
||||
downsample_passes = (int)log2(downsample);
|
||||
downsample = 1 << downsample_passes;
|
||||
bw_used = (int)((double)(bw_seen * downsample) / (1.0 - crop));
|
||||
}
|
||||
/* number of bins is power-of-two, bin size is under limit */
|
||||
// todo, replace loop with log2
|
||||
for (i=1; i<=21; i++) {
|
||||
bin_e = i;
|
||||
bin_size = (double)bw_used / (double)((1<<i) * downsample);
|
||||
if (bin_size <= (double)max_size) {
|
||||
break;}
|
||||
}
|
||||
/* unless giant bins */
|
||||
if (max_size >= MINIMUM_RATE) {
|
||||
bw_seen = max_size;
|
||||
bw_used = max_size;
|
||||
tune_count = (upper - lower) / bw_seen;
|
||||
bin_e = 0;
|
||||
crop = 0;
|
||||
}
|
||||
if (tune_count > MAX_TUNES) {
|
||||
fprintf(stderr, "Error: bandwidth too wide.\n");
|
||||
exit(1);
|
||||
}
|
||||
buf_len = 2 * (1<<bin_e) * downsample;
|
||||
if (buf_len < DEFAULT_BUF_LENGTH) {
|
||||
buf_len = DEFAULT_BUF_LENGTH;
|
||||
}
|
||||
/* build the array */
|
||||
for (i=0; i<tune_count; i++) {
|
||||
ts = &tunes[i];
|
||||
ts->freq = lower + i*bw_seen + bw_seen/2;
|
||||
ts->rate = bw_used;
|
||||
ts->bin_e = bin_e;
|
||||
ts->samples = 0;
|
||||
ts->crop = crop;
|
||||
ts->downsample = downsample;
|
||||
ts->downsample_passes = downsample_passes;
|
||||
ts->avg = (long*)malloc((1<<bin_e) * sizeof(long));
|
||||
if (!ts->avg) {
|
||||
fprintf(stderr, "Error: malloc.\n");
|
||||
exit(1);
|
||||
}
|
||||
for (j=0; j<(1<<bin_e); j++) {
|
||||
ts->avg[j] = 0L;
|
||||
}
|
||||
ts->buf8 = (uint8_t*)malloc(buf_len * sizeof(uint8_t));
|
||||
if (!ts->buf8) {
|
||||
fprintf(stderr, "Error: malloc.\n");
|
||||
exit(1);
|
||||
}
|
||||
ts->buf_len = buf_len;
|
||||
}
|
||||
/* report */
|
||||
fprintf(stderr, "Number of frequency hops: %i\n", tune_count);
|
||||
fprintf(stderr, "Dongle bandwidth: %iHz\n", bw_used);
|
||||
fprintf(stderr, "Downsampling by: %ix\n", downsample);
|
||||
fprintf(stderr, "Cropping by: %0.2f%%\n", crop*100);
|
||||
fprintf(stderr, "Total FFT bins: %i\n", tune_count * (1<<bin_e));
|
||||
fprintf(stderr, "Logged FFT bins: %i\n", \
|
||||
(int)((double)(tune_count * (1<<bin_e)) * (1.0-crop)));
|
||||
fprintf(stderr, "FFT bin size: %0.2fHz\n", bin_size);
|
||||
fprintf(stderr, "Buffer size: %i bytes (%0.2fms)\n", buf_len, 1000 * 0.5 * (float)buf_len / (float)bw_used);
|
||||
}
|
||||
|
||||
void retune(rtlsdr_dev_t *d, int freq)
|
||||
{
|
||||
uint8_t dump[BUFFER_DUMP];
|
||||
int n_read;
|
||||
rtlsdr_set_center_freq(d, (uint32_t)freq);
|
||||
/* wait for settling and flush buffer */
|
||||
usleep(5000);
|
||||
rtlsdr_read_sync(d, &dump, BUFFER_DUMP, &n_read);
|
||||
if (n_read != BUFFER_DUMP) {
|
||||
fprintf(stderr, "Error: bad retune.\n");}
|
||||
}
|
||||
|
||||
void fifth_order(int16_t *data, int length)
|
||||
/* for half of interleaved data */
|
||||
{
|
||||
int i;
|
||||
int a, b, c, d, e, f;
|
||||
a = data[0];
|
||||
b = data[2];
|
||||
c = data[4];
|
||||
d = data[6];
|
||||
e = data[8];
|
||||
f = data[10];
|
||||
/* a downsample should improve resolution, so don't fully shift */
|
||||
/* ease in instead of being stateful */
|
||||
data[0] = ((a+b)*10 + (c+d)*5 + d + f) >> 4;
|
||||
data[2] = ((b+c)*10 + (a+d)*5 + e + f) >> 4;
|
||||
data[4] = (a + (b+e)*5 + (c+d)*10 + f) >> 4;
|
||||
for (i=12; i<length; i+=4) {
|
||||
a = c;
|
||||
b = d;
|
||||
c = e;
|
||||
d = f;
|
||||
e = data[i-2];
|
||||
f = data[i];
|
||||
data[i/2] = (a + (b+e)*5 + (c+d)*10 + f) >> 4;
|
||||
}
|
||||
}
|
||||
|
||||
void remove_dc(int16_t *data, int length)
|
||||
/* works on interleaved data */
|
||||
{
|
||||
int i;
|
||||
int16_t ave;
|
||||
long sum = 0L;
|
||||
for (i=0; i < length; i+=2) {
|
||||
sum += data[i];
|
||||
}
|
||||
ave = (int16_t)(sum / (long)(length));
|
||||
if (ave == 0) {
|
||||
return;}
|
||||
for (i=0; i < length; i+=2) {
|
||||
data[i] -= ave;
|
||||
}
|
||||
}
|
||||
|
||||
void generic_fir(int16_t *data, int length, int *fir)
|
||||
/* Okay, not at all generic. Assumes length 9, fix that eventually. */
|
||||
{
|
||||
int d, temp, sum;
|
||||
int hist[9] = {0,};
|
||||
/* cheat on the beginning, let it go unfiltered */
|
||||
for (d=0; d<18; d+=2) {
|
||||
hist[d/2] = data[d];
|
||||
}
|
||||
for (d=18; d<length; d+=2) {
|
||||
temp = data[d];
|
||||
sum = 0;
|
||||
sum += (hist[0] + hist[8]) * fir[1];
|
||||
sum += (hist[1] + hist[7]) * fir[2];
|
||||
sum += (hist[2] + hist[6]) * fir[3];
|
||||
sum += (hist[3] + hist[5]) * fir[4];
|
||||
sum += hist[4] * fir[5];
|
||||
data[d] = (int16_t)(sum >> 15) ;
|
||||
hist[0] = hist[1];
|
||||
hist[1] = hist[2];
|
||||
hist[2] = hist[3];
|
||||
hist[3] = hist[4];
|
||||
hist[4] = hist[5];
|
||||
hist[5] = hist[6];
|
||||
hist[6] = hist[7];
|
||||
hist[7] = hist[8];
|
||||
hist[8] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
void downsample_iq(int16_t *data, int length)
|
||||
{
|
||||
fifth_order(data, length);
|
||||
//remove_dc(data, length);
|
||||
fifth_order(data+1, length-1);
|
||||
//remove_dc(data+1, length-1);
|
||||
}
|
||||
|
||||
long real_conj(int16_t real, int16_t imag)
|
||||
/* real(n * conj(n)) */
|
||||
{
|
||||
return ((long)real*(long)real + (long)imag*(long)imag);
|
||||
}
|
||||
|
||||
void scanner(void)
|
||||
{
|
||||
int i, j, j2, f, n_read, offset, bin_e, bin_len, buf_len, ds, ds_p;
|
||||
int32_t w;
|
||||
struct tuning_state *ts;
|
||||
bin_e = tunes[0].bin_e;
|
||||
bin_len = 1 << bin_e;
|
||||
buf_len = tunes[0].buf_len;
|
||||
for (i=0; i<tune_count; i++) {
|
||||
if (do_exit >= 2)
|
||||
{return;}
|
||||
ts = &tunes[i];
|
||||
f = (int)rtlsdr_get_center_freq(dev);
|
||||
if (f != ts->freq) {
|
||||
retune(dev, ts->freq);}
|
||||
rtlsdr_read_sync(dev, ts->buf8, buf_len, &n_read);
|
||||
if (n_read != buf_len) {
|
||||
fprintf(stderr, "Error: dropped samples.\n");}
|
||||
/* rms */
|
||||
if (bin_len == 1) {
|
||||
rms_power(ts);
|
||||
continue;
|
||||
}
|
||||
/* prep for fft */
|
||||
for (j=0; j<buf_len; j++) {
|
||||
fft_buf[j] = (int16_t)ts->buf8[j] - 127;
|
||||
}
|
||||
ds = ts->downsample;
|
||||
ds_p = ts->downsample_passes;
|
||||
if (boxcar && ds > 1) {
|
||||
j=2, j2=0;
|
||||
while (j < buf_len) {
|
||||
fft_buf[j2] += fft_buf[j];
|
||||
fft_buf[j2+1] += fft_buf[j+1];
|
||||
fft_buf[j] = 0;
|
||||
fft_buf[j+1] = 0;
|
||||
j += 2;
|
||||
if (j % (ds*2) == 0) {
|
||||
j2 += 2;}
|
||||
}
|
||||
} else if (ds_p) { /* recursive */
|
||||
for (j=0; j < ds_p; j++) {
|
||||
downsample_iq(fft_buf, buf_len >> j);
|
||||
}
|
||||
/* droop compensation */
|
||||
if (comp_fir_size == 9 && ds_p <= CIC_TABLE_MAX) {
|
||||
generic_fir(fft_buf, buf_len >> j, cic_9_tables[ds_p]);
|
||||
generic_fir(fft_buf+1, (buf_len >> j)-1, cic_9_tables[ds_p]);
|
||||
}
|
||||
}
|
||||
remove_dc(fft_buf, buf_len / ds);
|
||||
remove_dc(fft_buf+1, (buf_len / ds) - 1);
|
||||
/* window function and fft */
|
||||
for (offset=0; offset<(buf_len/ds); offset+=(2*bin_len)) {
|
||||
// todo, let rect skip this
|
||||
for (j=0; j<bin_len; j++) {
|
||||
w = (int32_t)fft_buf[offset+j*2];
|
||||
w *= (int32_t)(window_coefs[j]);
|
||||
//w /= (int32_t)(ds);
|
||||
fft_buf[offset+j*2] = (int16_t)w;
|
||||
w = (int32_t)fft_buf[offset+j*2+1];
|
||||
w *= (int32_t)(window_coefs[j]);
|
||||
//w /= (int32_t)(ds);
|
||||
fft_buf[offset+j*2+1] = (int16_t)w;
|
||||
}
|
||||
fix_fft(fft_buf+offset, bin_e);
|
||||
if (!peak_hold) {
|
||||
for (j=0; j<bin_len; j++) {
|
||||
ts->avg[j] += real_conj(fft_buf[offset+j*2], fft_buf[offset+j*2+1]);
|
||||
}
|
||||
} else {
|
||||
for (j=0; j<bin_len; j++) {
|
||||
ts->avg[j] = MAX(real_conj(fft_buf[offset+j*2], fft_buf[offset+j*2+1]), ts->avg[j]);
|
||||
}
|
||||
}
|
||||
ts->samples += ds;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void csv_dbm(struct tuning_state *ts)
|
||||
{
|
||||
int i, len, ds, i1, i2, bw2, bin_count;
|
||||
long tmp;
|
||||
double dbm;
|
||||
len = 1 << ts->bin_e;
|
||||
ds = ts->downsample;
|
||||
/* fix FFT stuff quirks */
|
||||
if (ts->bin_e > 0) {
|
||||
/* nuke DC component (not effective for all windows) */
|
||||
ts->avg[0] = ts->avg[1];
|
||||
/* FFT is translated by 180 degrees */
|
||||
for (i=0; i<len/2; i++) {
|
||||
tmp = ts->avg[i];
|
||||
ts->avg[i] = ts->avg[i+len/2];
|
||||
ts->avg[i+len/2] = tmp;
|
||||
}
|
||||
}
|
||||
/* Hz low, Hz high, Hz step, samples, dbm, dbm, ... */
|
||||
bin_count = (int)((double)len * (1.0 - ts->crop));
|
||||
bw2 = (int)(((double)ts->rate * (double)bin_count) / (len * 2 * ds));
|
||||
fprintf(file, "%i, %i, %.2f, %i, ", ts->freq - bw2, ts->freq + bw2,
|
||||
(double)ts->rate / (double)(len*ds), ts->samples);
|
||||
// something seems off with the dbm math
|
||||
i1 = 0 + (int)((double)len * ts->crop * 0.5);
|
||||
i2 = (len-1) - (int)((double)len * ts->crop * 0.5);
|
||||
for (i=i1; i<=i2; i++) {
|
||||
dbm = (double)ts->avg[i];
|
||||
dbm /= (double)ts->rate;
|
||||
dbm /= (double)ts->samples;
|
||||
dbm = 10 * log10(dbm);
|
||||
fprintf(file, "%.2f, ", dbm);
|
||||
}
|
||||
dbm = (double)ts->avg[i2] / ((double)ts->rate * (double)ts->samples);
|
||||
if (ts->bin_e == 0) {
|
||||
dbm = ((double)ts->avg[0] / \
|
||||
((double)ts->rate * (double)ts->samples));}
|
||||
dbm = 10 * log10(dbm);
|
||||
fprintf(file, "%.2f\n", dbm);
|
||||
for (i=0; i<len; i++) {
|
||||
ts->avg[i] = 0L;
|
||||
}
|
||||
ts->samples = 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
struct sigaction sigact;
|
||||
#endif
|
||||
char *filename = NULL;
|
||||
int i, length, r, opt, wb_mode = 0;
|
||||
int f_set = 0;
|
||||
int gain = AUTO_GAIN; // tenths of a dB
|
||||
int dev_index = 0;
|
||||
int dev_given = 0;
|
||||
int ppm_error = 0;
|
||||
int interval = 10;
|
||||
int fft_threads = 1;
|
||||
int smoothing = 0;
|
||||
int single = 0;
|
||||
int direct_sampling = 0;
|
||||
int offset_tuning = 0;
|
||||
double crop = 0.0;
|
||||
char *freq_optarg;
|
||||
time_t next_tick;
|
||||
time_t time_now;
|
||||
time_t exit_time = 0;
|
||||
char t_str[50];
|
||||
struct tm *cal_time;
|
||||
double (*window_fn)(int, int) = rectangle;
|
||||
freq_optarg = "";
|
||||
|
||||
while ((opt = getopt(argc, argv, "f:i:s:t:d:g:p:e:w:c:F:1PDOh")) != -1) {
|
||||
switch (opt) {
|
||||
case 'f': // lower:upper:bin_size
|
||||
freq_optarg = strdup(optarg);
|
||||
f_set = 1;
|
||||
break;
|
||||
case 'd':
|
||||
dev_index = verbose_device_search(optarg);
|
||||
dev_given = 1;
|
||||
break;
|
||||
case 'g':
|
||||
gain = (int)(atof(optarg) * 10);
|
||||
break;
|
||||
case 'c':
|
||||
crop = atofp(optarg);
|
||||
break;
|
||||
case 'i':
|
||||
interval = (int)round(atoft(optarg));
|
||||
break;
|
||||
case 'e':
|
||||
exit_time = (time_t)((int)round(atoft(optarg)));
|
||||
break;
|
||||
case 's':
|
||||
if (strcmp("avg", optarg) == 0) {
|
||||
smoothing = 0;}
|
||||
if (strcmp("iir", optarg) == 0) {
|
||||
smoothing = 1;}
|
||||
break;
|
||||
case 'w':
|
||||
if (strcmp("rectangle", optarg) == 0) {
|
||||
window_fn = rectangle;}
|
||||
if (strcmp("hamming", optarg) == 0) {
|
||||
window_fn = hamming;}
|
||||
if (strcmp("blackman", optarg) == 0) {
|
||||
window_fn = blackman;}
|
||||
if (strcmp("blackman-harris", optarg) == 0) {
|
||||
window_fn = blackman_harris;}
|
||||
if (strcmp("hann-poisson", optarg) == 0) {
|
||||
window_fn = hann_poisson;}
|
||||
if (strcmp("youssef", optarg) == 0) {
|
||||
window_fn = youssef;}
|
||||
if (strcmp("kaiser", optarg) == 0) {
|
||||
window_fn = kaiser;}
|
||||
if (strcmp("bartlett", optarg) == 0) {
|
||||
window_fn = bartlett;}
|
||||
break;
|
||||
case 't':
|
||||
fft_threads = atoi(optarg);
|
||||
break;
|
||||
case 'p':
|
||||
ppm_error = atoi(optarg);
|
||||
break;
|
||||
case '1':
|
||||
single = 1;
|
||||
break;
|
||||
case 'P':
|
||||
peak_hold = 1;
|
||||
break;
|
||||
case 'D':
|
||||
direct_sampling = 1;
|
||||
break;
|
||||
case 'O':
|
||||
offset_tuning = 1;
|
||||
break;
|
||||
case 'F':
|
||||
boxcar = 0;
|
||||
comp_fir_size = atoi(optarg);
|
||||
break;
|
||||
case 'h':
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!f_set) {
|
||||
fprintf(stderr, "No frequency range provided.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((crop < 0.0) || (crop > 1.0)) {
|
||||
fprintf(stderr, "Crop value outside of 0 to 1.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
frequency_range(freq_optarg, crop);
|
||||
|
||||
if (tune_count == 0) {
|
||||
usage();}
|
||||
|
||||
if (argc <= optind) {
|
||||
filename = "-";
|
||||
} else {
|
||||
filename = argv[optind];
|
||||
}
|
||||
|
||||
if (interval < 1) {
|
||||
interval = 1;}
|
||||
|
||||
fprintf(stderr, "Reporting every %i seconds\n", interval);
|
||||
|
||||
if (!dev_given) {
|
||||
dev_index = verbose_device_search("0");
|
||||
}
|
||||
|
||||
if (dev_index < 0) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
r = rtlsdr_open(&dev, (uint32_t)dev_index);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "Failed to open rtlsdr device #%d.\n", dev_index);
|
||||
exit(1);
|
||||
}
|
||||
#ifndef _WIN32
|
||||
sigact.sa_handler = sighandler;
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = 0;
|
||||
sigaction(SIGINT, &sigact, NULL);
|
||||
sigaction(SIGTERM, &sigact, NULL);
|
||||
sigaction(SIGQUIT, &sigact, NULL);
|
||||
sigaction(SIGPIPE, &sigact, NULL);
|
||||
#else
|
||||
SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE );
|
||||
#endif
|
||||
|
||||
if (direct_sampling) {
|
||||
verbose_direct_sampling(dev, 1);
|
||||
}
|
||||
|
||||
if (offset_tuning) {
|
||||
verbose_offset_tuning(dev);
|
||||
}
|
||||
|
||||
/* Set the tuner gain */
|
||||
if (gain == AUTO_GAIN) {
|
||||
verbose_auto_gain(dev);
|
||||
} else {
|
||||
gain = nearest_gain(dev, gain);
|
||||
verbose_gain_set(dev, gain);
|
||||
}
|
||||
|
||||
verbose_ppm_set(dev, ppm_error);
|
||||
|
||||
if (strcmp(filename, "-") == 0) { /* Write log to stdout */
|
||||
file = stdout;
|
||||
#ifdef _WIN32
|
||||
// Is this necessary? Output is ascii.
|
||||
_setmode(_fileno(file), _O_BINARY);
|
||||
#endif
|
||||
} else {
|
||||
file = fopen(filename, "wb");
|
||||
if (!file) {
|
||||
fprintf(stderr, "Failed to open %s\n", filename);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset endpoint before we start reading from it (mandatory) */
|
||||
verbose_reset_buffer(dev);
|
||||
|
||||
/* actually do stuff */
|
||||
rtlsdr_set_sample_rate(dev, (uint32_t)tunes[0].rate);
|
||||
sine_table(tunes[0].bin_e);
|
||||
next_tick = time(NULL) + interval;
|
||||
if (exit_time) {
|
||||
exit_time = time(NULL) + exit_time;}
|
||||
fft_buf = malloc(tunes[0].buf_len * sizeof(int16_t));
|
||||
length = 1 << tunes[0].bin_e;
|
||||
window_coefs = malloc(length * sizeof(int));
|
||||
for (i=0; i<length; i++) {
|
||||
window_coefs[i] = (int)(256*window_fn(i, length));
|
||||
}
|
||||
while (!do_exit) {
|
||||
scanner();
|
||||
time_now = time(NULL);
|
||||
if (time_now < next_tick) {
|
||||
continue;}
|
||||
// time, Hz low, Hz high, Hz step, samples, dbm, dbm, ...
|
||||
cal_time = localtime(&time_now);
|
||||
strftime(t_str, 50, "%Y-%m-%d, %H:%M:%S", cal_time);
|
||||
for (i=0; i<tune_count; i++) {
|
||||
fprintf(file, "%s, ", t_str);
|
||||
csv_dbm(&tunes[i]);
|
||||
}
|
||||
fflush(file);
|
||||
while (time(NULL) >= next_tick) {
|
||||
next_tick += interval;}
|
||||
if (single) {
|
||||
do_exit = 1;}
|
||||
if (exit_time && time(NULL) >= exit_time) {
|
||||
do_exit = 1;}
|
||||
}
|
||||
|
||||
/* clean up */
|
||||
|
||||
if (do_exit) {
|
||||
fprintf(stderr, "\nUser cancel, exiting...\n");}
|
||||
else {
|
||||
fprintf(stderr, "\nLibrary error %d, exiting...\n", r);}
|
||||
|
||||
if (file != stdout) {
|
||||
fclose(file);}
|
||||
|
||||
rtlsdr_close(dev);
|
||||
free(fft_buf);
|
||||
free(window_coefs);
|
||||
//for (i=0; i<tune_count; i++) {
|
||||
// free(tunes[i].avg);
|
||||
// free(tunes[i].buf8);
|
||||
//}
|
||||
return r >= 0 ? r : -r;
|
||||
}
|
||||
|
||||
// vim: tabstop=8:softtabstop=8:shiftwidth=8:noexpandtab
|
|
@ -0,0 +1,285 @@
|
|||
/*
|
||||
* rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver
|
||||
* Copyright (C) 2012 by Steve Markgraf <steve@steve-m.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
#include "getopt/getopt.h"
|
||||
#endif
|
||||
|
||||
#include "rtl-sdr.h"
|
||||
#include "convenience/convenience.h"
|
||||
|
||||
#define DEFAULT_SAMPLE_RATE 2048000
|
||||
#define DEFAULT_BUF_LENGTH (16 * 16384)
|
||||
#define MINIMAL_BUF_LENGTH 512
|
||||
#define MAXIMAL_BUF_LENGTH (256 * 16384)
|
||||
|
||||
static int do_exit = 0;
|
||||
static uint32_t bytes_to_read = 0;
|
||||
static rtlsdr_dev_t *dev = NULL;
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"rtl_sdr, an I/Q recorder for RTL2832 based DVB-T receivers\n\n"
|
||||
"Usage:\t -f frequency_to_tune_to [Hz]\n"
|
||||
"\t[-q x] enable direct sampling (input I:1, Q:2)\n"
|
||||
"\t[-s samplerate (default: 2048000 Hz)]\n"
|
||||
"\t[-d device_index (default: 0)]\n"
|
||||
"\t[-g gain (default: 0 for auto)]\n"
|
||||
"\t[-p ppm_error (default: 0)]\n"
|
||||
"\t[-b output_block_size (default: 16 * 16384)]\n"
|
||||
"\t[-n number of samples to read (default: 0, infinite)]\n"
|
||||
"\t[-S force sync output (default: async)]\n"
|
||||
"\tfilename (a '-' dumps samples to stdout)\n\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
BOOL WINAPI
|
||||
sighandler(int signum)
|
||||
{
|
||||
if (CTRL_C_EVENT == signum) {
|
||||
fprintf(stderr, "Signal caught, exiting!\n");
|
||||
do_exit = 1;
|
||||
rtlsdr_cancel_async(dev);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
#else
|
||||
static void sighandler(int signum)
|
||||
{
|
||||
fprintf(stderr, "Signal caught, exiting!\n");
|
||||
do_exit = 1;
|
||||
rtlsdr_cancel_async(dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
|
||||
{
|
||||
if (ctx) {
|
||||
if (do_exit)
|
||||
return;
|
||||
|
||||
if ((bytes_to_read > 0) && (bytes_to_read < len)) {
|
||||
len = bytes_to_read;
|
||||
do_exit = 1;
|
||||
rtlsdr_cancel_async(dev);
|
||||
}
|
||||
|
||||
if (fwrite(buf, 1, len, (FILE*)ctx) != len) {
|
||||
fprintf(stderr, "Short write, samples lost, exiting!\n");
|
||||
rtlsdr_cancel_async(dev);
|
||||
}
|
||||
|
||||
if (bytes_to_read > 0)
|
||||
bytes_to_read -= len;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
struct sigaction sigact;
|
||||
#endif
|
||||
char *filename = NULL;
|
||||
int n_read;
|
||||
int r, opt;
|
||||
int gain = 0;
|
||||
int ppm_error = 0;
|
||||
int sync_mode = 0;
|
||||
int direct_sp = 0;
|
||||
FILE *file;
|
||||
uint8_t *buffer;
|
||||
int dev_index = 0;
|
||||
int dev_given = 0;
|
||||
uint32_t frequency = 100000000;
|
||||
uint32_t samp_rate = DEFAULT_SAMPLE_RATE;
|
||||
uint32_t out_block_size = DEFAULT_BUF_LENGTH;
|
||||
|
||||
while ((opt = getopt(argc, argv, "d:f:g:s:b:n:p:S:q")) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
dev_index = verbose_device_search(optarg);
|
||||
dev_given = 1;
|
||||
break;
|
||||
case 'f':
|
||||
frequency = (uint32_t)atofs(optarg);
|
||||
break;
|
||||
case 'g':
|
||||
gain = (int)(atof(optarg) * 10); /* tenths of a dB */
|
||||
break;
|
||||
case 's':
|
||||
samp_rate = (uint32_t)atofs(optarg);
|
||||
break;
|
||||
case 'p':
|
||||
ppm_error = atoi(optarg);
|
||||
break;
|
||||
case 'b':
|
||||
out_block_size = (uint32_t)atof(optarg);
|
||||
break;
|
||||
case 'n':
|
||||
bytes_to_read = (uint32_t)atof(optarg) * 2;
|
||||
break;
|
||||
case 'S':
|
||||
sync_mode = 1;
|
||||
break;
|
||||
case 'q':
|
||||
direct_sampling = atoi(optarg);
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc <= optind) {
|
||||
usage();
|
||||
} else {
|
||||
filename = argv[optind];
|
||||
}
|
||||
|
||||
if(out_block_size < MINIMAL_BUF_LENGTH ||
|
||||
out_block_size > MAXIMAL_BUF_LENGTH ){
|
||||
fprintf(stderr,
|
||||
"Output block size wrong value, falling back to default\n");
|
||||
fprintf(stderr,
|
||||
"Minimal length: %u\n", MINIMAL_BUF_LENGTH);
|
||||
fprintf(stderr,
|
||||
"Maximal length: %u\n", MAXIMAL_BUF_LENGTH);
|
||||
out_block_size = DEFAULT_BUF_LENGTH;
|
||||
}
|
||||
|
||||
buffer = malloc(out_block_size * sizeof(uint8_t));
|
||||
|
||||
if (!dev_given) {
|
||||
dev_index = verbose_device_search("0");
|
||||
}
|
||||
|
||||
if (dev_index < 0) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
r = rtlsdr_open(&dev, (uint32_t)dev_index);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "Failed to open rtlsdr device #%d.\n", dev_index);
|
||||
exit(1);
|
||||
}
|
||||
#ifndef _WIN32
|
||||
sigact.sa_handler = sighandler;
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = 0;
|
||||
sigaction(SIGINT, &sigact, NULL);
|
||||
sigaction(SIGTERM, &sigact, NULL);
|
||||
sigaction(SIGQUIT, &sigact, NULL);
|
||||
sigaction(SIGPIPE, &sigact, NULL);
|
||||
#else
|
||||
SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE );
|
||||
#endif
|
||||
/* Set the sample rate */
|
||||
verbose_set_sample_rate(dev, samp_rate);
|
||||
|
||||
/* Set the frequency */
|
||||
verbose_set_frequency(dev, frequency);
|
||||
/* Direct Sampling */
|
||||
verbose_set_direct_sampling(dev, direct_sampling);
|
||||
/* Set gain */
|
||||
if (0 == gain) {
|
||||
/* Enable automatic gain */
|
||||
verbose_auto_gain(dev);
|
||||
} else {
|
||||
/* Enable manual gain */
|
||||
gain = nearest_gain(dev, gain);
|
||||
verbose_gain_set(dev, gain);
|
||||
}
|
||||
|
||||
verbose_ppm_set(dev, ppm_error);
|
||||
|
||||
if(strcmp(filename, "-") == 0) { /* Write samples to stdout */
|
||||
file = stdout;
|
||||
#ifdef _WIN32
|
||||
_setmode(_fileno(stdin), _O_BINARY);
|
||||
#endif
|
||||
} else {
|
||||
file = fopen(filename, "wb");
|
||||
if (!file) {
|
||||
fprintf(stderr, "Failed to open %s\n", filename);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset endpoint before we start reading from it (mandatory) */
|
||||
verbose_reset_buffer(dev);
|
||||
|
||||
if (sync_mode) {
|
||||
fprintf(stderr, "Reading samples in sync mode...\n");
|
||||
while (!do_exit) {
|
||||
r = rtlsdr_read_sync(dev, buffer, out_block_size, &n_read);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "WARNING: sync read failed.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if ((bytes_to_read > 0) && (bytes_to_read < (uint32_t)n_read)) {
|
||||
n_read = bytes_to_read;
|
||||
do_exit = 1;
|
||||
}
|
||||
|
||||
if (fwrite(buffer, 1, n_read, file) != (size_t)n_read) {
|
||||
fprintf(stderr, "Short write, samples lost, exiting!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if ((uint32_t)n_read < out_block_size) {
|
||||
fprintf(stderr, "Short read, samples lost, exiting!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (bytes_to_read > 0)
|
||||
bytes_to_read -= n_read;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Reading samples in async mode...\n");
|
||||
r = rtlsdr_read_async(dev, rtlsdr_callback, (void *)file,
|
||||
0, out_block_size);
|
||||
}
|
||||
|
||||
if (do_exit)
|
||||
fprintf(stderr, "\nUser cancel, exiting...\n");
|
||||
else
|
||||
fprintf(stderr, "\nLibrary error %d, exiting...\n", r);
|
||||
|
||||
if (file != stdout)
|
||||
fclose(file);
|
||||
|
||||
rtlsdr_close(dev);
|
||||
free (buffer);
|
||||
out:
|
||||
return r >= 0 ? r : -r;
|
||||
}
|
|
@ -0,0 +1,626 @@
|
|||
/*
|
||||
* rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver
|
||||
* Copyright (C) 2012 by Steve Markgraf <steve@steve-m.de>
|
||||
* Copyright (C) 2012-2013 by Hoernchen <la@tfc-server.de>
|
||||
* Frequency Lock [-l] Copyright (C) 2014 by Mario Rößler
|
||||
* Direct Sampling Flag [-q] by Phil Crump <phil@philcrump.co.uk>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <netinet/in.h>
|
||||
#include <fcntl.h>
|
||||
#else
|
||||
#include <winsock2.h>
|
||||
#include "getopt/getopt.h"
|
||||
#endif
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "rtl-sdr.h"
|
||||
#include "convenience/convenience.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
|
||||
typedef int socklen_t;
|
||||
|
||||
#else
|
||||
#define closesocket close
|
||||
#define SOCKADDR struct sockaddr
|
||||
#define SOCKET int
|
||||
#define SOCKET_ERROR -1
|
||||
#endif
|
||||
|
||||
static SOCKET s;
|
||||
|
||||
static pthread_t tcp_worker_thread;
|
||||
static pthread_t command_thread;
|
||||
static pthread_cond_t exit_cond;
|
||||
static pthread_mutex_t exit_cond_lock;
|
||||
|
||||
static pthread_mutex_t ll_mutex;
|
||||
static pthread_cond_t cond;
|
||||
|
||||
struct llist {
|
||||
char *data;
|
||||
size_t len;
|
||||
struct llist *next;
|
||||
};
|
||||
|
||||
typedef struct { /* structure size must be multiple of 2 bytes */
|
||||
char magic[4];
|
||||
uint32_t tuner_type;
|
||||
uint32_t tuner_gain_count;
|
||||
} dongle_info_t;
|
||||
|
||||
static rtlsdr_dev_t *dev = NULL;
|
||||
|
||||
static int global_numq = 0;
|
||||
static struct llist *ll_buffers = 0;
|
||||
static int llbuf_num = 500;
|
||||
|
||||
static volatile int do_exit = 0;
|
||||
|
||||
int freq_lock = 0;
|
||||
int direct_sampling = 0;
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
printf("rtl_tcp, an I/Q spectrum server for RTL2832 based DVB-T receivers\n\n"
|
||||
"Usage:\t[-a listen address]\n"
|
||||
"\t[-p listen port (default: 1234)]\n"
|
||||
"\t[-f frequency to tune to [Hz]]\n"
|
||||
"\t[-l 1] lock frequency against tcp command\n"
|
||||
"\t[-q x] enable direct sampling (input I:1, Q:2)\n"
|
||||
"\t[-g gain (default: 0 for auto)]\n"
|
||||
"\t[-s samplerate in Hz (default: 2048000 Hz)]\n"
|
||||
"\t[-b number of buffers (default: 15, set by library)]\n"
|
||||
"\t[-n max number of linked list buffers to keep (default: 500)]\n"
|
||||
"\t[-d device index (default: 0)]\n"
|
||||
"\t[-P ppm_error (default: 0)]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
int gettimeofday(struct timeval *tv, void* ignored)
|
||||
{
|
||||
FILETIME ft;
|
||||
unsigned __int64 tmp = 0;
|
||||
if (NULL != tv) {
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
tmp |= ft.dwHighDateTime;
|
||||
tmp <<= 32;
|
||||
tmp |= ft.dwLowDateTime;
|
||||
tmp /= 10;
|
||||
#ifdef _MSC_VER
|
||||
tmp -= 11644473600000000Ui64;
|
||||
#else
|
||||
tmp -= 11644473600000000ULL;
|
||||
#endif
|
||||
tv->tv_sec = (long)(tmp / 1000000UL);
|
||||
tv->tv_usec = (long)(tmp % 1000000UL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL WINAPI
|
||||
sighandler(int signum)
|
||||
{
|
||||
if (CTRL_C_EVENT == signum) {
|
||||
fprintf(stderr, "Signal caught, exiting!\n");
|
||||
do_exit = 1;
|
||||
rtlsdr_cancel_async(dev);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
#else
|
||||
static void sighandler(int signum)
|
||||
{
|
||||
fprintf(stderr, "Signal caught, exiting!\n");
|
||||
rtlsdr_cancel_async(dev);
|
||||
do_exit = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
|
||||
{
|
||||
if(!do_exit) {
|
||||
struct llist *rpt = (struct llist*)malloc(sizeof(struct llist));
|
||||
rpt->data = (char*)malloc(len);
|
||||
memcpy(rpt->data, buf, len);
|
||||
rpt->len = len;
|
||||
rpt->next = NULL;
|
||||
|
||||
pthread_mutex_lock(&ll_mutex);
|
||||
|
||||
if (ll_buffers == NULL) {
|
||||
ll_buffers = rpt;
|
||||
} else {
|
||||
struct llist *cur = ll_buffers;
|
||||
int num_queued = 0;
|
||||
|
||||
while (cur->next != NULL) {
|
||||
cur = cur->next;
|
||||
num_queued++;
|
||||
}
|
||||
|
||||
if(llbuf_num && llbuf_num == num_queued-2){
|
||||
struct llist *curelem;
|
||||
|
||||
free(ll_buffers->data);
|
||||
curelem = ll_buffers->next;
|
||||
free(ll_buffers);
|
||||
ll_buffers = curelem;
|
||||
}
|
||||
|
||||
cur->next = rpt;
|
||||
|
||||
if (num_queued > global_numq)
|
||||
printf("ll+, now %d\n", num_queued);
|
||||
else if (num_queued < global_numq)
|
||||
printf("ll-, now %d\n", num_queued);
|
||||
|
||||
global_numq = num_queued;
|
||||
}
|
||||
pthread_cond_signal(&cond);
|
||||
pthread_mutex_unlock(&ll_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
static void *tcp_worker(void *arg)
|
||||
{
|
||||
struct llist *curelem,*prev;
|
||||
int bytesleft,bytessent, index;
|
||||
struct timeval tv= {1,0};
|
||||
struct timespec ts;
|
||||
struct timeval tp;
|
||||
fd_set writefds;
|
||||
int r = 0;
|
||||
|
||||
while(1) {
|
||||
if(do_exit)
|
||||
pthread_exit(0);
|
||||
|
||||
pthread_mutex_lock(&ll_mutex);
|
||||
gettimeofday(&tp, NULL);
|
||||
ts.tv_sec = tp.tv_sec+5;
|
||||
ts.tv_nsec = tp.tv_usec * 1000;
|
||||
r = pthread_cond_timedwait(&cond, &ll_mutex, &ts);
|
||||
if(r == ETIMEDOUT) {
|
||||
pthread_mutex_unlock(&ll_mutex);
|
||||
printf("worker cond timeout\n");
|
||||
sighandler(0);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
curelem = ll_buffers;
|
||||
ll_buffers = 0;
|
||||
pthread_mutex_unlock(&ll_mutex);
|
||||
|
||||
while(curelem != 0) {
|
||||
bytesleft = curelem->len;
|
||||
index = 0;
|
||||
bytessent = 0;
|
||||
while(bytesleft > 0) {
|
||||
FD_ZERO(&writefds);
|
||||
FD_SET(s, &writefds);
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_usec = 0;
|
||||
r = select(s+1, NULL, &writefds, NULL, &tv);
|
||||
if(r) {
|
||||
bytessent = send(s, &curelem->data[index], bytesleft, 0);
|
||||
bytesleft -= bytessent;
|
||||
index += bytessent;
|
||||
}
|
||||
if(bytessent == SOCKET_ERROR || do_exit) {
|
||||
printf("worker socket bye\n");
|
||||
sighandler(0);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
}
|
||||
prev = curelem;
|
||||
curelem = curelem->next;
|
||||
free(prev->data);
|
||||
free(prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int set_gain_by_index(rtlsdr_dev_t *_dev, unsigned int index)
|
||||
{
|
||||
int res = 0;
|
||||
int* gains;
|
||||
int count = rtlsdr_get_tuner_gains(_dev, NULL);
|
||||
|
||||
if (count > 0 && (unsigned int)count > index) {
|
||||
gains = malloc(sizeof(int) * count);
|
||||
count = rtlsdr_get_tuner_gains(_dev, gains);
|
||||
|
||||
res = rtlsdr_set_tuner_gain(_dev, gains[index]);
|
||||
|
||||
free(gains);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#define __attribute__(x)
|
||||
#pragma pack(push, 1)
|
||||
#endif
|
||||
struct command{
|
||||
unsigned char cmd;
|
||||
unsigned int param;
|
||||
}__attribute__((packed));
|
||||
#ifdef _WIN32
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
static void *command_worker(void *arg)
|
||||
{
|
||||
int left, received = 0;
|
||||
fd_set readfds;
|
||||
struct command cmd={0, 0};
|
||||
struct timeval tv= {1, 0};
|
||||
int r = 0;
|
||||
uint32_t tmp;
|
||||
|
||||
while(1) {
|
||||
left=sizeof(cmd);
|
||||
while(left >0) {
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(s, &readfds);
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_usec = 0;
|
||||
r = select(s+1, &readfds, NULL, NULL, &tv);
|
||||
if(r) {
|
||||
received = recv(s, (char*)&cmd+(sizeof(cmd)-left), left, 0);
|
||||
left -= received;
|
||||
}
|
||||
if(received == SOCKET_ERROR || do_exit) {
|
||||
printf("comm recv bye\n");
|
||||
sighandler(0);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
}
|
||||
switch(cmd.cmd) {
|
||||
case 0x01:
|
||||
printf("set freq %d\n", ntohl(cmd.param));
|
||||
if(!freq_lock) {
|
||||
rtlsdr_set_center_freq(dev,ntohl(cmd.param));
|
||||
}
|
||||
break;
|
||||
case 0x02:
|
||||
printf("set sample rate %d\n", ntohl(cmd.param));
|
||||
rtlsdr_set_sample_rate(dev, ntohl(cmd.param));
|
||||
break;
|
||||
case 0x03:
|
||||
printf("set gain mode %d\n", ntohl(cmd.param));
|
||||
rtlsdr_set_tuner_gain_mode(dev, ntohl(cmd.param));
|
||||
break;
|
||||
case 0x04:
|
||||
printf("set gain %d\n", ntohl(cmd.param));
|
||||
rtlsdr_set_tuner_gain(dev, ntohl(cmd.param));
|
||||
break;
|
||||
case 0x05:
|
||||
printf("set freq correction %d\n", ntohl(cmd.param));
|
||||
rtlsdr_set_freq_correction(dev, ntohl(cmd.param));
|
||||
break;
|
||||
case 0x06:
|
||||
tmp = ntohl(cmd.param);
|
||||
printf("set if stage %d gain %d\n", tmp >> 16, (short)(tmp & 0xffff));
|
||||
rtlsdr_set_tuner_if_gain(dev, tmp >> 16, (short)(tmp & 0xffff));
|
||||
break;
|
||||
case 0x07:
|
||||
printf("set test mode %d\n", ntohl(cmd.param));
|
||||
rtlsdr_set_testmode(dev, ntohl(cmd.param));
|
||||
break;
|
||||
case 0x08:
|
||||
printf("set agc mode %d\n", ntohl(cmd.param));
|
||||
rtlsdr_set_agc_mode(dev, ntohl(cmd.param));
|
||||
break;
|
||||
case 0x09:
|
||||
printf("set direct sampling %d\n", ntohl(cmd.param));
|
||||
/* Pass through unless we've set it manually */
|
||||
if(!direct_sampling) {
|
||||
rtlsdr_set_direct_sampling(dev, ntohl(cmd.param));
|
||||
}
|
||||
break;
|
||||
case 0x0a:
|
||||
printf("set offset tuning %d\n", ntohl(cmd.param));
|
||||
rtlsdr_set_offset_tuning(dev, ntohl(cmd.param));
|
||||
break;
|
||||
case 0x0b:
|
||||
printf("set rtl xtal %d\n", ntohl(cmd.param));
|
||||
rtlsdr_set_xtal_freq(dev, ntohl(cmd.param), 0);
|
||||
break;
|
||||
case 0x0c:
|
||||
printf("set tuner xtal %d\n", ntohl(cmd.param));
|
||||
rtlsdr_set_xtal_freq(dev, 0, ntohl(cmd.param));
|
||||
break;
|
||||
case 0x0d:
|
||||
printf("set tuner gain by index %d\n", ntohl(cmd.param));
|
||||
set_gain_by_index(dev, ntohl(cmd.param));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
cmd.cmd = 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int r, opt, i;
|
||||
char* addr = "127.0.0.1";
|
||||
int port = 1234;
|
||||
uint32_t frequency = 100000000, samp_rate = 2048000;
|
||||
struct sockaddr_in local, remote;
|
||||
uint32_t buf_num = 0;
|
||||
int dev_index = 0;
|
||||
int dev_given = 0;
|
||||
int gain = 0;
|
||||
int ppm_error = 0;
|
||||
struct llist *curelem,*prev;
|
||||
pthread_attr_t attr;
|
||||
void *status;
|
||||
struct timeval tv = {1,0};
|
||||
struct linger ling = {1,0};
|
||||
SOCKET listensocket;
|
||||
socklen_t rlen;
|
||||
fd_set readfds;
|
||||
u_long blockmode = 1;
|
||||
dongle_info_t dongle_info;
|
||||
#ifdef _WIN32
|
||||
WSADATA wsd;
|
||||
i = WSAStartup(MAKEWORD(2,2), &wsd);
|
||||
#else
|
||||
struct sigaction sigact, sigign;
|
||||
#endif
|
||||
|
||||
while ((opt = getopt(argc, argv, "a:p:f:g:s:b:n:d:P:l:q:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
dev_index = verbose_device_search(optarg);
|
||||
dev_given = 1;
|
||||
break;
|
||||
case 'f':
|
||||
frequency = (uint32_t)atofs(optarg);
|
||||
break;
|
||||
case 'g':
|
||||
gain = (int)(atof(optarg) * 10); /* tenths of a dB */
|
||||
break;
|
||||
case 's':
|
||||
samp_rate = (uint32_t)atofs(optarg);
|
||||
break;
|
||||
case 'a':
|
||||
addr = optarg;
|
||||
break;
|
||||
case 'p':
|
||||
port = atoi(optarg);
|
||||
break;
|
||||
case 'b':
|
||||
buf_num = atoi(optarg);
|
||||
break;
|
||||
case 'n':
|
||||
llbuf_num = atoi(optarg);
|
||||
break;
|
||||
case 'P':
|
||||
ppm_error = atoi(optarg);
|
||||
break;
|
||||
case 'l':
|
||||
freq_lock = atoi(optarg);
|
||||
break;
|
||||
case 'q':
|
||||
direct_sampling = atoi(optarg);
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc < optind)
|
||||
usage();
|
||||
|
||||
if (!dev_given) {
|
||||
dev_index = verbose_device_search("0");
|
||||
}
|
||||
|
||||
if (dev_index < 0) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
rtlsdr_open(&dev, (uint32_t)dev_index);
|
||||
if (NULL == dev) {
|
||||
fprintf(stderr, "Failed to open rtlsdr device #%d.\n", dev_index);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
sigact.sa_handler = sighandler;
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = 0;
|
||||
sigign.sa_handler = SIG_IGN;
|
||||
sigaction(SIGINT, &sigact, NULL);
|
||||
sigaction(SIGTERM, &sigact, NULL);
|
||||
sigaction(SIGQUIT, &sigact, NULL);
|
||||
sigaction(SIGPIPE, &sigign, NULL);
|
||||
#else
|
||||
SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE );
|
||||
#endif
|
||||
|
||||
/* Set the tuner error */
|
||||
verbose_ppm_set(dev, ppm_error);
|
||||
|
||||
/* Set the sample rate */
|
||||
r = rtlsdr_set_sample_rate(dev, samp_rate);
|
||||
if (r < 0)
|
||||
fprintf(stderr, "WARNING: Failed to set sample rate.\n");
|
||||
|
||||
/* Set the frequency */
|
||||
r = rtlsdr_set_center_freq(dev, frequency);
|
||||
if (r < 0)
|
||||
fprintf(stderr, "WARNING: Failed to set center freq.\n");
|
||||
else
|
||||
fprintf(stderr, "Tuned to %i Hz.\n", frequency);
|
||||
|
||||
if (0 != direct_sampling) {
|
||||
/* Set direct sampling */
|
||||
rtlsdr_set_direct_sampling(dev, direct_sampling);
|
||||
}
|
||||
|
||||
if (0 == gain) {
|
||||
/* Enable automatic gain */
|
||||
r = rtlsdr_set_tuner_gain_mode(dev, 0);
|
||||
if (r < 0)
|
||||
fprintf(stderr, "WARNING: Failed to enable automatic gain.\n");
|
||||
} else {
|
||||
/* Enable manual gain */
|
||||
r = rtlsdr_set_tuner_gain_mode(dev, 1);
|
||||
if (r < 0)
|
||||
fprintf(stderr, "WARNING: Failed to enable manual gain.\n");
|
||||
|
||||
/* Set the tuner gain */
|
||||
r = rtlsdr_set_tuner_gain(dev, gain);
|
||||
if (r < 0)
|
||||
fprintf(stderr, "WARNING: Failed to set tuner gain.\n");
|
||||
else
|
||||
fprintf(stderr, "Tuner gain set to %f dB.\n", gain/10.0);
|
||||
}
|
||||
|
||||
/* Reset endpoint before we start reading from it (mandatory) */
|
||||
r = rtlsdr_reset_buffer(dev);
|
||||
if (r < 0)
|
||||
fprintf(stderr, "WARNING: Failed to reset buffers.\n");
|
||||
|
||||
pthread_mutex_init(&exit_cond_lock, NULL);
|
||||
pthread_mutex_init(&ll_mutex, NULL);
|
||||
pthread_mutex_init(&exit_cond_lock, NULL);
|
||||
pthread_cond_init(&cond, NULL);
|
||||
pthread_cond_init(&exit_cond, NULL);
|
||||
|
||||
memset(&local,0,sizeof(local));
|
||||
local.sin_family = AF_INET;
|
||||
local.sin_port = htons(port);
|
||||
local.sin_addr.s_addr = inet_addr(addr);
|
||||
|
||||
listensocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
r = 1;
|
||||
setsockopt(listensocket, SOL_SOCKET, SO_REUSEADDR, (char *)&r, sizeof(int));
|
||||
setsockopt(listensocket, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling));
|
||||
bind(listensocket,(struct sockaddr *)&local,sizeof(local));
|
||||
|
||||
#ifdef _WIN32
|
||||
ioctlsocket(listensocket, FIONBIO, &blockmode);
|
||||
#else
|
||||
r = fcntl(listensocket, F_GETFL, 0);
|
||||
r = fcntl(listensocket, F_SETFL, r | O_NONBLOCK);
|
||||
#endif
|
||||
|
||||
while(1) {
|
||||
printf("listening...\n");
|
||||
printf("Use the device argument 'rtl_tcp=%s:%d' in OsmoSDR "
|
||||
"(gr-osmosdr) source\n"
|
||||
"to receive samples in GRC and control "
|
||||
"rtl_tcp parameters (frequency, gain, ...).\n",
|
||||
addr, port);
|
||||
listen(listensocket,1);
|
||||
|
||||
while(1) {
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(listensocket, &readfds);
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_usec = 0;
|
||||
r = select(listensocket+1, &readfds, NULL, NULL, &tv);
|
||||
if(do_exit) {
|
||||
goto out;
|
||||
} else if(r) {
|
||||
rlen = sizeof(remote);
|
||||
s = accept(listensocket,(struct sockaddr *)&remote, &rlen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
setsockopt(s, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling));
|
||||
|
||||
printf("client accepted!\n");
|
||||
|
||||
memset(&dongle_info, 0, sizeof(dongle_info));
|
||||
memcpy(&dongle_info.magic, "RTL0", 4);
|
||||
|
||||
r = rtlsdr_get_tuner_type(dev);
|
||||
if (r >= 0)
|
||||
dongle_info.tuner_type = htonl(r);
|
||||
|
||||
r = rtlsdr_get_tuner_gains(dev, NULL);
|
||||
if (r >= 0)
|
||||
dongle_info.tuner_gain_count = htonl(r);
|
||||
|
||||
r = send(s, (const char *)&dongle_info, sizeof(dongle_info), 0);
|
||||
if (sizeof(dongle_info) != r)
|
||||
printf("failed to send dongle information\n");
|
||||
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
|
||||
r = pthread_create(&tcp_worker_thread, &attr, tcp_worker, NULL);
|
||||
r = pthread_create(&command_thread, &attr, command_worker, NULL);
|
||||
pthread_attr_destroy(&attr);
|
||||
|
||||
r = rtlsdr_read_async(dev, rtlsdr_callback, NULL, buf_num, 0);
|
||||
|
||||
pthread_join(tcp_worker_thread, &status);
|
||||
pthread_join(command_thread, &status);
|
||||
|
||||
closesocket(s);
|
||||
|
||||
printf("all threads dead..\n");
|
||||
curelem = ll_buffers;
|
||||
ll_buffers = 0;
|
||||
|
||||
while(curelem != 0) {
|
||||
prev = curelem;
|
||||
curelem = curelem->next;
|
||||
free(prev->data);
|
||||
free(prev);
|
||||
}
|
||||
|
||||
do_exit = 0;
|
||||
global_numq = 0;
|
||||
}
|
||||
|
||||
out:
|
||||
rtlsdr_close(dev);
|
||||
closesocket(listensocket);
|
||||
closesocket(s);
|
||||
#ifdef _WIN32
|
||||
WSACleanup();
|
||||
#endif
|
||||
printf("bye!\n");
|
||||
return r >= 0 ? r : -r;
|
||||
}
|
|
@ -0,0 +1,423 @@
|
|||
/*
|
||||
* rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver
|
||||
* rtl_test, test and benchmark tool
|
||||
*
|
||||
* Copyright (C) 2012-2014 by Steve Markgraf <steve@steve-m.de>
|
||||
* Copyright (C) 2012-2014 by Kyle Keen <keenerd@gmail.com>
|
||||
* Copyright (C) 2014 by Michael Tatarinov <kukabu@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include "getopt/getopt.h"
|
||||
#endif
|
||||
|
||||
#include "rtl-sdr.h"
|
||||
#include "convenience/convenience.h"
|
||||
|
||||
#define DEFAULT_SAMPLE_RATE 2048000
|
||||
#define DEFAULT_BUF_LENGTH (16 * 16384)
|
||||
#define MINIMAL_BUF_LENGTH 512
|
||||
#define MAXIMAL_BUF_LENGTH (256 * 16384)
|
||||
|
||||
#define MHZ(x) ((x)*1000*1000)
|
||||
|
||||
#define PPM_DURATION 10
|
||||
#define PPM_DUMP_TIME 5
|
||||
|
||||
static enum {
|
||||
NO_BENCHMARK,
|
||||
TUNER_BENCHMARK,
|
||||
PPM_BENCHMARK
|
||||
} test_mode = NO_BENCHMARK;
|
||||
|
||||
static int do_exit = 0;
|
||||
static rtlsdr_dev_t *dev = NULL;
|
||||
|
||||
static uint32_t samp_rate = DEFAULT_SAMPLE_RATE;
|
||||
|
||||
static uint32_t total_samples = 0;
|
||||
static uint32_t dropped_samples = 0;
|
||||
|
||||
static unsigned int ppm_duration = PPM_DURATION;
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"rtl_test, a benchmark tool for RTL2832 based DVB-T receivers\n\n"
|
||||
"Usage:\n"
|
||||
"\t[-s samplerate (default: 2048000 Hz)]\n"
|
||||
"\t[-d device_index (default: 0)]\n"
|
||||
"\t[-t enable Elonics E4000 tuner benchmark]\n"
|
||||
#ifndef _WIN32
|
||||
"\t[-p[seconds] enable PPM error measurement (default: 10 seconds)]\n"
|
||||
#endif
|
||||
"\t[-b output_block_size (default: 16 * 16384)]\n"
|
||||
"\t[-S force sync output (default: async)]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
BOOL WINAPI
|
||||
sighandler(int signum)
|
||||
{
|
||||
if (CTRL_C_EVENT == signum) {
|
||||
fprintf(stderr, "Signal caught, exiting!\n");
|
||||
do_exit = 1;
|
||||
rtlsdr_cancel_async(dev);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
#else
|
||||
static void sighandler(int signum)
|
||||
{
|
||||
fprintf(stderr, "Signal caught, exiting!\n");
|
||||
do_exit = 1;
|
||||
rtlsdr_cancel_async(dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void underrun_test(unsigned char *buf, uint32_t len, int mute)
|
||||
{
|
||||
uint32_t i, lost = 0;
|
||||
static uint8_t bcnt, uninit = 1;
|
||||
|
||||
if (uninit) {
|
||||
bcnt = buf[0];
|
||||
uninit = 0;
|
||||
}
|
||||
for (i = 0; i < len; i++) {
|
||||
if(bcnt != buf[i]) {
|
||||
lost += (buf[i] > bcnt) ? (buf[i] - bcnt) : (bcnt - buf[i]);
|
||||
bcnt = buf[i];
|
||||
}
|
||||
|
||||
bcnt++;
|
||||
}
|
||||
|
||||
total_samples += len;
|
||||
dropped_samples += lost;
|
||||
if (mute)
|
||||
return;
|
||||
if (lost)
|
||||
printf("lost at least %d bytes\n", lost);
|
||||
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
static int ppm_gettime(struct timespec *ts)
|
||||
{
|
||||
int rv = ENOSYS;
|
||||
|
||||
#ifdef __unix__
|
||||
rv = clock_gettime(CLOCK_MONOTONIC, ts);
|
||||
#elif __APPLE__
|
||||
struct timeval tv;
|
||||
|
||||
rv = gettimeofday(&tv, NULL);
|
||||
ts->tv_sec = tv.tv_sec;
|
||||
ts->tv_nsec = tv.tv_usec * 1000;
|
||||
#endif
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int ppm_report(uint64_t nsamples, uint64_t interval)
|
||||
{
|
||||
double real_rate, ppm;
|
||||
|
||||
real_rate = nsamples * 1e9 / interval;
|
||||
ppm = 1e6 * (real_rate / (double)samp_rate - 1.);
|
||||
return (int)round(ppm);
|
||||
}
|
||||
|
||||
static void ppm_test(uint32_t len)
|
||||
{
|
||||
static uint64_t nsamples = 0;
|
||||
static uint64_t interval = 0;
|
||||
static uint64_t nsamples_total = 0;
|
||||
static uint64_t interval_total = 0;
|
||||
struct timespec ppm_now;
|
||||
static struct timespec ppm_recent;
|
||||
static enum {
|
||||
PPM_INIT_NO,
|
||||
PPM_INIT_DUMP,
|
||||
PPM_INIT_RUN
|
||||
} ppm_init = PPM_INIT_NO;
|
||||
|
||||
ppm_gettime(&ppm_now);
|
||||
if (ppm_init != PPM_INIT_RUN) {
|
||||
/*
|
||||
* Kyle Keen wrote:
|
||||
* PPM_DUMP_TIME throws out the first N seconds of data.
|
||||
* The dongle's PPM is usually very bad when first starting up,
|
||||
* typically incorrect by more than twice the final value.
|
||||
* Discarding the first few seconds allows the value to stabilize much faster.
|
||||
*/
|
||||
if (ppm_init == PPM_INIT_NO) {
|
||||
ppm_recent.tv_sec = ppm_now.tv_sec + PPM_DUMP_TIME;
|
||||
ppm_init = PPM_INIT_DUMP;
|
||||
return;
|
||||
}
|
||||
if (ppm_init == PPM_INIT_DUMP && ppm_recent.tv_sec < ppm_now.tv_sec)
|
||||
return;
|
||||
ppm_recent.tv_sec = ppm_now.tv_sec;
|
||||
ppm_recent.tv_nsec = ppm_now.tv_nsec;
|
||||
ppm_init = PPM_INIT_RUN;
|
||||
return;
|
||||
}
|
||||
nsamples += (uint64_t)(len / 2UL);
|
||||
interval = (uint64_t)(ppm_now.tv_sec - ppm_recent.tv_sec);
|
||||
if (interval < ppm_duration)
|
||||
return;
|
||||
interval *= 1000000000UL;
|
||||
interval += (int64_t)(ppm_now.tv_nsec - ppm_recent.tv_nsec);
|
||||
nsamples_total += nsamples;
|
||||
interval_total += interval;
|
||||
printf("real sample rate: %i current PPM: %i cumulative PPM: %i\n",
|
||||
(int)((1000000000UL * nsamples) / interval),
|
||||
ppm_report(nsamples, interval),
|
||||
ppm_report(nsamples_total, interval_total));
|
||||
ppm_recent.tv_sec = ppm_now.tv_sec;
|
||||
ppm_recent.tv_nsec = ppm_now.tv_nsec;
|
||||
nsamples = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
|
||||
{
|
||||
underrun_test(buf, len, 0);
|
||||
#ifndef _WIN32
|
||||
if (test_mode == PPM_BENCHMARK)
|
||||
ppm_test(len);
|
||||
#endif
|
||||
}
|
||||
|
||||
void e4k_benchmark(void)
|
||||
{
|
||||
uint32_t freq, gap_start = 0, gap_end = 0;
|
||||
uint32_t range_start = 0, range_end = 0;
|
||||
|
||||
fprintf(stderr, "Benchmarking E4000 PLL...\n");
|
||||
|
||||
/* find tuner range start */
|
||||
for (freq = MHZ(70); freq > MHZ(1); freq -= MHZ(1)) {
|
||||
if (rtlsdr_set_center_freq(dev, freq) < 0) {
|
||||
range_start = freq;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* find tuner range end */
|
||||
for (freq = MHZ(2000); freq < MHZ(2300UL); freq += MHZ(1)) {
|
||||
if (rtlsdr_set_center_freq(dev, freq) < 0) {
|
||||
range_end = freq;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* find start of L-band gap */
|
||||
for (freq = MHZ(1000); freq < MHZ(1300); freq += MHZ(1)) {
|
||||
if (rtlsdr_set_center_freq(dev, freq) < 0) {
|
||||
gap_start = freq;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* find end of L-band gap */
|
||||
for (freq = MHZ(1300); freq > MHZ(1000); freq -= MHZ(1)) {
|
||||
if (rtlsdr_set_center_freq(dev, freq) < 0) {
|
||||
gap_end = freq;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "E4K range: %i to %i MHz\n",
|
||||
range_start/MHZ(1) + 1, range_end/MHZ(1) - 1);
|
||||
|
||||
fprintf(stderr, "E4K L-band gap: %i to %i MHz\n",
|
||||
gap_start/MHZ(1), gap_end/MHZ(1));
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
struct sigaction sigact;
|
||||
#endif
|
||||
int n_read, r, opt, i;
|
||||
int sync_mode = 0;
|
||||
uint8_t *buffer;
|
||||
int dev_index = 0;
|
||||
int dev_given = 0;
|
||||
uint32_t out_block_size = DEFAULT_BUF_LENGTH;
|
||||
int count;
|
||||
int gains[100];
|
||||
|
||||
while ((opt = getopt(argc, argv, "d:s:b:tp::Sh")) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
dev_index = verbose_device_search(optarg);
|
||||
dev_given = 1;
|
||||
break;
|
||||
case 's':
|
||||
samp_rate = (uint32_t)atof(optarg);
|
||||
break;
|
||||
case 'b':
|
||||
out_block_size = (uint32_t)atof(optarg);
|
||||
break;
|
||||
case 't':
|
||||
test_mode = TUNER_BENCHMARK;
|
||||
break;
|
||||
case 'p':
|
||||
test_mode = PPM_BENCHMARK;
|
||||
if (optarg)
|
||||
ppm_duration = atoi(optarg);
|
||||
break;
|
||||
case 'S':
|
||||
sync_mode = 1;
|
||||
break;
|
||||
case 'h':
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(out_block_size < MINIMAL_BUF_LENGTH ||
|
||||
out_block_size > MAXIMAL_BUF_LENGTH ){
|
||||
fprintf(stderr,
|
||||
"Output block size wrong value, falling back to default\n");
|
||||
fprintf(stderr,
|
||||
"Minimal length: %u\n", MINIMAL_BUF_LENGTH);
|
||||
fprintf(stderr,
|
||||
"Maximal length: %u\n", MAXIMAL_BUF_LENGTH);
|
||||
out_block_size = DEFAULT_BUF_LENGTH;
|
||||
}
|
||||
|
||||
buffer = malloc(out_block_size * sizeof(uint8_t));
|
||||
|
||||
if (!dev_given) {
|
||||
dev_index = verbose_device_search("0");
|
||||
}
|
||||
|
||||
if (dev_index < 0) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
r = rtlsdr_open(&dev, (uint32_t)dev_index);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "Failed to open rtlsdr device #%d.\n", dev_index);
|
||||
exit(1);
|
||||
}
|
||||
#ifndef _WIN32
|
||||
sigact.sa_handler = sighandler;
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = 0;
|
||||
sigaction(SIGINT, &sigact, NULL);
|
||||
sigaction(SIGTERM, &sigact, NULL);
|
||||
sigaction(SIGQUIT, &sigact, NULL);
|
||||
sigaction(SIGPIPE, &sigact, NULL);
|
||||
#else
|
||||
SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE );
|
||||
#endif
|
||||
count = rtlsdr_get_tuner_gains(dev, NULL);
|
||||
fprintf(stderr, "Supported gain values (%d): ", count);
|
||||
|
||||
count = rtlsdr_get_tuner_gains(dev, gains);
|
||||
for (i = 0; i < count; i++)
|
||||
fprintf(stderr, "%.1f ", gains[i] / 10.0);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
/* Set the sample rate */
|
||||
verbose_set_sample_rate(dev, samp_rate);
|
||||
|
||||
if (test_mode == TUNER_BENCHMARK) {
|
||||
if (rtlsdr_get_tuner_type(dev) == RTLSDR_TUNER_E4000)
|
||||
e4k_benchmark();
|
||||
else
|
||||
fprintf(stderr, "No E4000 tuner found, aborting.\n");
|
||||
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Enable test mode */
|
||||
r = rtlsdr_set_testmode(dev, 1);
|
||||
|
||||
/* Reset endpoint before we start reading from it (mandatory) */
|
||||
verbose_reset_buffer(dev);
|
||||
|
||||
if ((test_mode == PPM_BENCHMARK) && !sync_mode) {
|
||||
fprintf(stderr, "Reporting PPM error measurement every %i seconds...\n", ppm_duration);
|
||||
fprintf(stderr, "Press ^C after a few minutes.\n");
|
||||
}
|
||||
|
||||
if (test_mode == NO_BENCHMARK) {
|
||||
fprintf(stderr, "\nInfo: This tool will continuously"
|
||||
" read from the device, and report if\n"
|
||||
"samples get lost. If you observe no "
|
||||
"further output, everything is fine.\n\n");
|
||||
}
|
||||
|
||||
if (sync_mode) {
|
||||
fprintf(stderr, "Reading samples in sync mode...\n");
|
||||
fprintf(stderr, "(Samples are being lost but not reported.)\n");
|
||||
while (!do_exit) {
|
||||
r = rtlsdr_read_sync(dev, buffer, out_block_size, &n_read);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "WARNING: sync read failed.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if ((uint32_t)n_read < out_block_size) {
|
||||
fprintf(stderr, "Short read, samples lost, exiting!\n");
|
||||
break;
|
||||
}
|
||||
underrun_test(buffer, n_read, 1);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Reading samples in async mode...\n");
|
||||
r = rtlsdr_read_async(dev, rtlsdr_callback, NULL,
|
||||
0, out_block_size);
|
||||
}
|
||||
|
||||
if (do_exit) {
|
||||
fprintf(stderr, "\nUser cancel, exiting...\n");
|
||||
fprintf(stderr, "Samples per million lost (minimum): %i\n", (int)(1000000L * dropped_samples / total_samples));
|
||||
}
|
||||
else
|
||||
fprintf(stderr, "\nLibrary error %d, exiting...\n", r);
|
||||
|
||||
exit:
|
||||
rtlsdr_close(dev);
|
||||
free (buffer);
|
||||
|
||||
return r >= 0 ? r : -r;
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
|
||||
#include <afxres.h>
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 0,0,0,0
|
||||
PRODUCTVERSION 0,0,0,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifndef NDEBUG
|
||||
FILEFLAGS 0x0L
|
||||
#else
|
||||
FILEFLAGS 0x1L
|
||||
#endif
|
||||
FILEOS VOS__WINDOWS32
|
||||
FILETYPE VFT_DLL
|
||||
FILESUBTYPE VFT2_DRV_INSTALLABLE
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "FileDescription", "osmocom rtl-sdr"
|
||||
VALUE "FileVersion", "@VERSION@"
|
||||
VALUE "InternalName", "rtl-sdr.dll"
|
||||
VALUE "LegalCopyright", "Licensed under GPLv2"
|
||||
VALUE "OriginalFilename", "rtl-sdr.dll"
|
||||
VALUE "ProductName", "osmocom rtl-sdr"
|
||||
VALUE "ProductVersion", "@VERSION@"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,345 @@
|
|||
/*
|
||||
* Fitipower FC0012 tuner driver
|
||||
*
|
||||
* Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net>
|
||||
*
|
||||
* modified for use in librtlsdr
|
||||
* Copyright (C) 2012 Steve Markgraf <steve@steve-m.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "rtlsdr_i2c.h"
|
||||
#include "tuner_fc0012.h"
|
||||
|
||||
static int fc0012_writereg(void *dev, uint8_t reg, uint8_t val)
|
||||
{
|
||||
uint8_t data[2];
|
||||
data[0] = reg;
|
||||
data[1] = val;
|
||||
|
||||
if (rtlsdr_i2c_write_fn(dev, FC0012_I2C_ADDR, data, 2) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fc0012_readreg(void *dev, uint8_t reg, uint8_t *val)
|
||||
{
|
||||
uint8_t data = reg;
|
||||
|
||||
if (rtlsdr_i2c_write_fn(dev, FC0012_I2C_ADDR, &data, 1) < 0)
|
||||
return -1;
|
||||
|
||||
if (rtlsdr_i2c_read_fn(dev, FC0012_I2C_ADDR, &data, 1) < 0)
|
||||
return -1;
|
||||
|
||||
*val = data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Incomplete list of register settings:
|
||||
*
|
||||
* Name Reg Bits Desc
|
||||
* CHIP_ID 0x00 0-7 Chip ID (constant 0xA1)
|
||||
* RF_A 0x01 0-3 Number of count-to-9 cycles in RF
|
||||
* divider (suggested: 2..9)
|
||||
* RF_M 0x02 0-7 Total number of cycles (to-8 and to-9)
|
||||
* in RF divider
|
||||
* RF_K_HIGH 0x03 0-6 Bits 8..14 of fractional divider
|
||||
* RF_K_LOW 0x04 0-7 Bits 0..7 of fractional RF divider
|
||||
* RF_OUTDIV_A 0x05 3-7 Power of two required?
|
||||
* LNA_POWER_DOWN 0x06 0 Set to 1 to switch off low noise amp
|
||||
* RF_OUTDIV_B 0x06 1 Set to select 3 instead of 2 for the
|
||||
* RF output divider
|
||||
* VCO_SPEED 0x06 3 Select tuning range of VCO:
|
||||
* 0 = Low range, (ca. 1.1 - 1.5GHz)
|
||||
* 1 = High range (ca. 1.4 - 1.8GHz)
|
||||
* BANDWIDTH 0x06 6-7 Set bandwidth. 6MHz = 0x80, 7MHz=0x40
|
||||
* 8MHz=0x00
|
||||
* XTAL_SPEED 0x07 5 Set to 1 for 28.8MHz Crystal input
|
||||
* or 0 for 36MHz
|
||||
* <agc params> 0x08 0-7
|
||||
* EN_CAL_RSSI 0x09 4 Enable calibrate RSSI
|
||||
* (Receive Signal Strength Indicator)
|
||||
* LNA_FORCE 0x0d 0
|
||||
* AGC_FORCE 0x0d ?
|
||||
* LNA_GAIN 0x13 3-4 Low noise amp gain
|
||||
* LNA_COMPS 0x15 3 ?
|
||||
* VCO_CALIB 0x0e 7 Set high then low to calibrate VCO
|
||||
* (fast lock?)
|
||||
* VCO_VOLTAGE 0x0e 0-6 Read Control voltage of VCO
|
||||
* (big value -> low freq)
|
||||
*/
|
||||
|
||||
int fc0012_init(void *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned int i;
|
||||
uint8_t reg[] = {
|
||||
0x00, /* dummy reg. 0 */
|
||||
0x05, /* reg. 0x01 */
|
||||
0x10, /* reg. 0x02 */
|
||||
0x00, /* reg. 0x03 */
|
||||
0x00, /* reg. 0x04 */
|
||||
0x0f, /* reg. 0x05: may also be 0x0a */
|
||||
0x00, /* reg. 0x06: divider 2, VCO slow */
|
||||
0x00, /* reg. 0x07: may also be 0x0f */
|
||||
0xff, /* reg. 0x08: AGC Clock divide by 256, AGC gain 1/256,
|
||||
Loop Bw 1/8 */
|
||||
0x6e, /* reg. 0x09: Disable LoopThrough, Enable LoopThrough: 0x6f */
|
||||
0xb8, /* reg. 0x0a: Disable LO Test Buffer */
|
||||
0x82, /* reg. 0x0b: Output Clock is same as clock frequency,
|
||||
may also be 0x83 */
|
||||
0xfc, /* reg. 0x0c: depending on AGC Up-Down mode, may need 0xf8 */
|
||||
0x02, /* reg. 0x0d: AGC Not Forcing & LNA Forcing, 0x02 for DVB-T */
|
||||
0x00, /* reg. 0x0e */
|
||||
0x00, /* reg. 0x0f */
|
||||
0x00, /* reg. 0x10: may also be 0x0d */
|
||||
0x00, /* reg. 0x11 */
|
||||
0x1f, /* reg. 0x12: Set to maximum gain */
|
||||
0x08, /* reg. 0x13: Set to Middle Gain: 0x08,
|
||||
Low Gain: 0x00, High Gain: 0x10, enable IX2: 0x80 */
|
||||
0x00, /* reg. 0x14 */
|
||||
0x04, /* reg. 0x15: Enable LNA COMPS */
|
||||
};
|
||||
|
||||
#if 0
|
||||
switch (rtlsdr_get_tuner_clock(dev)) {
|
||||
case FC_XTAL_27_MHZ:
|
||||
case FC_XTAL_28_8_MHZ:
|
||||
reg[0x07] |= 0x20;
|
||||
break;
|
||||
case FC_XTAL_36_MHZ:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
reg[0x07] |= 0x20;
|
||||
|
||||
// if (priv->dual_master)
|
||||
reg[0x0c] |= 0x02;
|
||||
|
||||
for (i = 1; i < sizeof(reg); i++) {
|
||||
ret = fc0012_writereg(dev, i, reg[i]);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fc0012_set_params(void *dev, uint32_t freq, uint32_t bandwidth)
|
||||
{
|
||||
int i, ret = 0;
|
||||
uint8_t reg[7], am, pm, multi, tmp;
|
||||
uint64_t f_vco;
|
||||
uint32_t xtal_freq_div_2;
|
||||
uint16_t xin, xdiv;
|
||||
int vco_select = 0;
|
||||
|
||||
xtal_freq_div_2 = rtlsdr_get_tuner_clock(dev) / 2;
|
||||
|
||||
/* select frequency divider and the frequency of VCO */
|
||||
if (freq < 37084000) { /* freq * 96 < 3560000000 */
|
||||
multi = 96;
|
||||
reg[5] = 0x82;
|
||||
reg[6] = 0x00;
|
||||
} else if (freq < 55625000) { /* freq * 64 < 3560000000 */
|
||||
multi = 64;
|
||||
reg[5] = 0x82;
|
||||
reg[6] = 0x02;
|
||||
} else if (freq < 74167000) { /* freq * 48 < 3560000000 */
|
||||
multi = 48;
|
||||
reg[5] = 0x42;
|
||||
reg[6] = 0x00;
|
||||
} else if (freq < 111250000) { /* freq * 32 < 3560000000 */
|
||||
multi = 32;
|
||||
reg[5] = 0x42;
|
||||
reg[6] = 0x02;
|
||||
} else if (freq < 148334000) { /* freq * 24 < 3560000000 */
|
||||
multi = 24;
|
||||
reg[5] = 0x22;
|
||||
reg[6] = 0x00;
|
||||
} else if (freq < 222500000) { /* freq * 16 < 3560000000 */
|
||||
multi = 16;
|
||||
reg[5] = 0x22;
|
||||
reg[6] = 0x02;
|
||||
} else if (freq < 296667000) { /* freq * 12 < 3560000000 */
|
||||
multi = 12;
|
||||
reg[5] = 0x12;
|
||||
reg[6] = 0x00;
|
||||
} else if (freq < 445000000) { /* freq * 8 < 3560000000 */
|
||||
multi = 8;
|
||||
reg[5] = 0x12;
|
||||
reg[6] = 0x02;
|
||||
} else if (freq < 593334000) { /* freq * 6 < 3560000000 */
|
||||
multi = 6;
|
||||
reg[5] = 0x0a;
|
||||
reg[6] = 0x00;
|
||||
} else {
|
||||
multi = 4;
|
||||
reg[5] = 0x0a;
|
||||
reg[6] = 0x02;
|
||||
}
|
||||
|
||||
f_vco = freq * multi;
|
||||
|
||||
if (f_vco >= 3060000000U) {
|
||||
reg[6] |= 0x08;
|
||||
vco_select = 1;
|
||||
}
|
||||
|
||||
/* From divided value (XDIV) determined the FA and FP value */
|
||||
xdiv = (uint16_t)(f_vco / xtal_freq_div_2);
|
||||
if ((f_vco - xdiv * xtal_freq_div_2) >= (xtal_freq_div_2 / 2))
|
||||
xdiv++;
|
||||
|
||||
pm = (uint8_t)(xdiv / 8);
|
||||
am = (uint8_t)(xdiv - (8 * pm));
|
||||
|
||||
if (am < 2) {
|
||||
am += 8;
|
||||
pm--;
|
||||
}
|
||||
|
||||
if (pm > 31) {
|
||||
reg[1] = am + (8 * (pm - 31));
|
||||
reg[2] = 31;
|
||||
} else {
|
||||
reg[1] = am;
|
||||
reg[2] = pm;
|
||||
}
|
||||
|
||||
if ((reg[1] > 15) || (reg[2] < 0x0b)) {
|
||||
fprintf(stderr, "[FC0012] no valid PLL combination "
|
||||
"found for %u Hz!\n", freq);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* fix clock out */
|
||||
reg[6] |= 0x20;
|
||||
|
||||
/* From VCO frequency determines the XIN ( fractional part of Delta
|
||||
Sigma PLL) and divided value (XDIV) */
|
||||
xin = (uint16_t)((f_vco - (f_vco / xtal_freq_div_2) * xtal_freq_div_2) / 1000);
|
||||
xin = (xin << 15) / (xtal_freq_div_2 / 1000);
|
||||
if (xin >= 16384)
|
||||
xin += 32768;
|
||||
|
||||
reg[3] = xin >> 8; /* xin with 9 bit resolution */
|
||||
reg[4] = xin & 0xff;
|
||||
|
||||
reg[6] &= 0x3f; /* bits 6 and 7 describe the bandwidth */
|
||||
switch (bandwidth) {
|
||||
case 6000000:
|
||||
reg[6] |= 0x80;
|
||||
break;
|
||||
case 7000000:
|
||||
reg[6] |= 0x40;
|
||||
break;
|
||||
case 8000000:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* modified for Realtek demod */
|
||||
reg[5] |= 0x07;
|
||||
|
||||
for (i = 1; i <= 6; i++) {
|
||||
ret = fc0012_writereg(dev, i, reg[i]);
|
||||
if (ret)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* VCO Calibration */
|
||||
ret = fc0012_writereg(dev, 0x0e, 0x80);
|
||||
if (!ret)
|
||||
ret = fc0012_writereg(dev, 0x0e, 0x00);
|
||||
|
||||
/* VCO Re-Calibration if needed */
|
||||
if (!ret)
|
||||
ret = fc0012_writereg(dev, 0x0e, 0x00);
|
||||
|
||||
if (!ret) {
|
||||
// msleep(10);
|
||||
ret = fc0012_readreg(dev, 0x0e, &tmp);
|
||||
}
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
/* vco selection */
|
||||
tmp &= 0x3f;
|
||||
|
||||
if (vco_select) {
|
||||
if (tmp > 0x3c) {
|
||||
reg[6] &= ~0x08;
|
||||
ret = fc0012_writereg(dev, 0x06, reg[6]);
|
||||
if (!ret)
|
||||
ret = fc0012_writereg(dev, 0x0e, 0x80);
|
||||
if (!ret)
|
||||
ret = fc0012_writereg(dev, 0x0e, 0x00);
|
||||
}
|
||||
} else {
|
||||
if (tmp < 0x02) {
|
||||
reg[6] |= 0x08;
|
||||
ret = fc0012_writereg(dev, 0x06, reg[6]);
|
||||
if (!ret)
|
||||
ret = fc0012_writereg(dev, 0x0e, 0x80);
|
||||
if (!ret)
|
||||
ret = fc0012_writereg(dev, 0x0e, 0x00);
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fc0012_set_gain(void *dev, int gain)
|
||||
{
|
||||
int ret;
|
||||
uint8_t tmp = 0;
|
||||
|
||||
ret = fc0012_readreg(dev, 0x13, &tmp);
|
||||
|
||||
/* mask bits off */
|
||||
tmp &= 0xe0;
|
||||
|
||||
switch (gain) {
|
||||
case -99: /* -9.9 dB */
|
||||
tmp |= 0x02;
|
||||
break;
|
||||
case -40: /* -4 dB */
|
||||
break;
|
||||
case 71:
|
||||
tmp |= 0x08; /* 7.1 dB */
|
||||
break;
|
||||
case 179:
|
||||
tmp |= 0x17; /* 17.9 dB */
|
||||
break;
|
||||
case 192:
|
||||
default:
|
||||
tmp |= 0x10; /* 19.2 dB */
|
||||
break;
|
||||
}
|
||||
|
||||
ret = fc0012_writereg(dev, 0x13, tmp);
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,500 @@
|
|||
/*
|
||||
* Fitipower FC0013 tuner driver
|
||||
*
|
||||
* Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net>
|
||||
* partially based on driver code from Fitipower
|
||||
* Copyright (C) 2010 Fitipower Integrated Technology Inc
|
||||
*
|
||||
* modified for use in librtlsdr
|
||||
* Copyright (C) 2012 Steve Markgraf <steve@steve-m.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "rtlsdr_i2c.h"
|
||||
#include "tuner_fc0013.h"
|
||||
|
||||
static int fc0013_writereg(void *dev, uint8_t reg, uint8_t val)
|
||||
{
|
||||
uint8_t data[2];
|
||||
data[0] = reg;
|
||||
data[1] = val;
|
||||
|
||||
if (rtlsdr_i2c_write_fn(dev, FC0013_I2C_ADDR, data, 2) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fc0013_readreg(void *dev, uint8_t reg, uint8_t *val)
|
||||
{
|
||||
uint8_t data = reg;
|
||||
|
||||
if (rtlsdr_i2c_write_fn(dev, FC0013_I2C_ADDR, &data, 1) < 0)
|
||||
return -1;
|
||||
|
||||
if (rtlsdr_i2c_read_fn(dev, FC0013_I2C_ADDR, &data, 1) < 0)
|
||||
return -1;
|
||||
|
||||
*val = data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fc0013_init(void *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned int i;
|
||||
uint8_t reg[] = {
|
||||
0x00, /* reg. 0x00: dummy */
|
||||
0x09, /* reg. 0x01 */
|
||||
0x16, /* reg. 0x02 */
|
||||
0x00, /* reg. 0x03 */
|
||||
0x00, /* reg. 0x04 */
|
||||
0x17, /* reg. 0x05 */
|
||||
0x02, /* reg. 0x06: LPF bandwidth */
|
||||
0x0a, /* reg. 0x07: CHECK */
|
||||
0xff, /* reg. 0x08: AGC Clock divide by 256, AGC gain 1/256,
|
||||
Loop Bw 1/8 */
|
||||
0x6e, /* reg. 0x09: Disable LoopThrough, Enable LoopThrough: 0x6f */
|
||||
0xb8, /* reg. 0x0a: Disable LO Test Buffer */
|
||||
0x82, /* reg. 0x0b: CHECK */
|
||||
0xfc, /* reg. 0x0c: depending on AGC Up-Down mode, may need 0xf8 */
|
||||
0x01, /* reg. 0x0d: AGC Not Forcing & LNA Forcing, may need 0x02 */
|
||||
0x00, /* reg. 0x0e */
|
||||
0x00, /* reg. 0x0f */
|
||||
0x00, /* reg. 0x10 */
|
||||
0x00, /* reg. 0x11 */
|
||||
0x00, /* reg. 0x12 */
|
||||
0x00, /* reg. 0x13 */
|
||||
0x50, /* reg. 0x14: DVB-t High Gain, UHF.
|
||||
Middle Gain: 0x48, Low Gain: 0x40 */
|
||||
0x01, /* reg. 0x15 */
|
||||
};
|
||||
#if 0
|
||||
switch (rtlsdr_get_tuner_clock(dev)) {
|
||||
case FC_XTAL_27_MHZ:
|
||||
case FC_XTAL_28_8_MHZ:
|
||||
reg[0x07] |= 0x20;
|
||||
break;
|
||||
case FC_XTAL_36_MHZ:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
reg[0x07] |= 0x20;
|
||||
|
||||
// if (dev->dual_master)
|
||||
reg[0x0c] |= 0x02;
|
||||
|
||||
for (i = 1; i < sizeof(reg); i++) {
|
||||
ret = fc0013_writereg(dev, i, reg[i]);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fc0013_rc_cal_add(void *dev, int rc_val)
|
||||
{
|
||||
int ret;
|
||||
uint8_t rc_cal;
|
||||
int val;
|
||||
|
||||
/* push rc_cal value, get rc_cal value */
|
||||
ret = fc0013_writereg(dev, 0x10, 0x00);
|
||||
if (ret)
|
||||
goto error_out;
|
||||
|
||||
/* get rc_cal value */
|
||||
ret = fc0013_readreg(dev, 0x10, &rc_cal);
|
||||
if (ret)
|
||||
goto error_out;
|
||||
|
||||
rc_cal &= 0x0f;
|
||||
|
||||
val = (int)rc_cal + rc_val;
|
||||
|
||||
/* forcing rc_cal */
|
||||
ret = fc0013_writereg(dev, 0x0d, 0x11);
|
||||
if (ret)
|
||||
goto error_out;
|
||||
|
||||
/* modify rc_cal value */
|
||||
if (val > 15)
|
||||
ret = fc0013_writereg(dev, 0x10, 0x0f);
|
||||
else if (val < 0)
|
||||
ret = fc0013_writereg(dev, 0x10, 0x00);
|
||||
else
|
||||
ret = fc0013_writereg(dev, 0x10, (uint8_t)val);
|
||||
|
||||
error_out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fc0013_rc_cal_reset(void *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = fc0013_writereg(dev, 0x0d, 0x01);
|
||||
if (!ret)
|
||||
ret = fc0013_writereg(dev, 0x10, 0x00);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fc0013_set_vhf_track(void *dev, uint32_t freq)
|
||||
{
|
||||
int ret;
|
||||
uint8_t tmp;
|
||||
|
||||
ret = fc0013_readreg(dev, 0x1d, &tmp);
|
||||
if (ret)
|
||||
goto error_out;
|
||||
tmp &= 0xe3;
|
||||
if (freq <= 177500000) { /* VHF Track: 7 */
|
||||
ret = fc0013_writereg(dev, 0x1d, tmp | 0x1c);
|
||||
} else if (freq <= 184500000) { /* VHF Track: 6 */
|
||||
ret = fc0013_writereg(dev, 0x1d, tmp | 0x18);
|
||||
} else if (freq <= 191500000) { /* VHF Track: 5 */
|
||||
ret = fc0013_writereg(dev, 0x1d, tmp | 0x14);
|
||||
} else if (freq <= 198500000) { /* VHF Track: 4 */
|
||||
ret = fc0013_writereg(dev, 0x1d, tmp | 0x10);
|
||||
} else if (freq <= 205500000) { /* VHF Track: 3 */
|
||||
ret = fc0013_writereg(dev, 0x1d, tmp | 0x0c);
|
||||
} else if (freq <= 219500000) { /* VHF Track: 2 */
|
||||
ret = fc0013_writereg(dev, 0x1d, tmp | 0x08);
|
||||
} else if (freq < 300000000) { /* VHF Track: 1 */
|
||||
ret = fc0013_writereg(dev, 0x1d, tmp | 0x04);
|
||||
} else { /* UHF and GPS */
|
||||
ret = fc0013_writereg(dev, 0x1d, tmp | 0x1c);
|
||||
}
|
||||
|
||||
error_out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fc0013_set_params(void *dev, uint32_t freq, uint32_t bandwidth)
|
||||
{
|
||||
int i, ret = 0;
|
||||
uint8_t reg[7], am, pm, multi, tmp;
|
||||
uint64_t f_vco;
|
||||
uint32_t xtal_freq_div_2;
|
||||
uint16_t xin, xdiv;
|
||||
int vco_select = 0;
|
||||
|
||||
xtal_freq_div_2 = rtlsdr_get_tuner_clock(dev) / 2;
|
||||
|
||||
/* set VHF track */
|
||||
ret = fc0013_set_vhf_track(dev, freq);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
if (freq < 300000000) {
|
||||
/* enable VHF filter */
|
||||
ret = fc0013_readreg(dev, 0x07, &tmp);
|
||||
if (ret)
|
||||
goto exit;
|
||||
ret = fc0013_writereg(dev, 0x07, tmp | 0x10);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
/* disable UHF & disable GPS */
|
||||
ret = fc0013_readreg(dev, 0x14, &tmp);
|
||||
if (ret)
|
||||
goto exit;
|
||||
ret = fc0013_writereg(dev, 0x14, tmp & 0x1f);
|
||||
if (ret)
|
||||
goto exit;
|
||||
} else if (freq <= 862000000) {
|
||||
/* disable VHF filter */
|
||||
ret = fc0013_readreg(dev, 0x07, &tmp);
|
||||
if (ret)
|
||||
goto exit;
|
||||
ret = fc0013_writereg(dev, 0x07, tmp & 0xef);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
/* enable UHF & disable GPS */
|
||||
ret = fc0013_readreg(dev, 0x14, &tmp);
|
||||
if (ret)
|
||||
goto exit;
|
||||
ret = fc0013_writereg(dev, 0x14, (tmp & 0x1f) | 0x40);
|
||||
if (ret)
|
||||
goto exit;
|
||||
} else {
|
||||
/* disable VHF filter */
|
||||
ret = fc0013_readreg(dev, 0x07, &tmp);
|
||||
if (ret)
|
||||
goto exit;
|
||||
ret = fc0013_writereg(dev, 0x07, tmp & 0xef);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
/* disable UHF & enable GPS */
|
||||
ret = fc0013_readreg(dev, 0x14, &tmp);
|
||||
if (ret)
|
||||
goto exit;
|
||||
ret = fc0013_writereg(dev, 0x14, (tmp & 0x1f) | 0x20);
|
||||
if (ret)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* select frequency divider and the frequency of VCO */
|
||||
if (freq < 37084000) { /* freq * 96 < 3560000000 */
|
||||
multi = 96;
|
||||
reg[5] = 0x82;
|
||||
reg[6] = 0x00;
|
||||
} else if (freq < 55625000) { /* freq * 64 < 3560000000 */
|
||||
multi = 64;
|
||||
reg[5] = 0x02;
|
||||
reg[6] = 0x02;
|
||||
} else if (freq < 74167000) { /* freq * 48 < 3560000000 */
|
||||
multi = 48;
|
||||
reg[5] = 0x42;
|
||||
reg[6] = 0x00;
|
||||
} else if (freq < 111250000) { /* freq * 32 < 3560000000 */
|
||||
multi = 32;
|
||||
reg[5] = 0x82;
|
||||
reg[6] = 0x02;
|
||||
} else if (freq < 148334000) { /* freq * 24 < 3560000000 */
|
||||
multi = 24;
|
||||
reg[5] = 0x22;
|
||||
reg[6] = 0x00;
|
||||
} else if (freq < 222500000) { /* freq * 16 < 3560000000 */
|
||||
multi = 16;
|
||||
reg[5] = 0x42;
|
||||
reg[6] = 0x02;
|
||||
} else if (freq < 296667000) { /* freq * 12 < 3560000000 */
|
||||
multi = 12;
|
||||
reg[5] = 0x12;
|
||||
reg[6] = 0x00;
|
||||
} else if (freq < 445000000) { /* freq * 8 < 3560000000 */
|
||||
multi = 8;
|
||||
reg[5] = 0x22;
|
||||
reg[6] = 0x02;
|
||||
} else if (freq < 593334000) { /* freq * 6 < 3560000000 */
|
||||
multi = 6;
|
||||
reg[5] = 0x0a;
|
||||
reg[6] = 0x00;
|
||||
} else if (freq < 950000000) { /* freq * 4 < 3800000000 */
|
||||
multi = 4;
|
||||
reg[5] = 0x12;
|
||||
reg[6] = 0x02;
|
||||
} else {
|
||||
multi = 2;
|
||||
reg[5] = 0x0a;
|
||||
reg[6] = 0x02;
|
||||
}
|
||||
|
||||
f_vco = freq * multi;
|
||||
|
||||
if (f_vco >= 3060000000U) {
|
||||
reg[6] |= 0x08;
|
||||
vco_select = 1;
|
||||
}
|
||||
|
||||
/* From divided value (XDIV) determined the FA and FP value */
|
||||
xdiv = (uint16_t)(f_vco / xtal_freq_div_2);
|
||||
if ((f_vco - xdiv * xtal_freq_div_2) >= (xtal_freq_div_2 / 2))
|
||||
xdiv++;
|
||||
|
||||
pm = (uint8_t)(xdiv / 8);
|
||||
am = (uint8_t)(xdiv - (8 * pm));
|
||||
|
||||
if (am < 2) {
|
||||
am += 8;
|
||||
pm--;
|
||||
}
|
||||
|
||||
if (pm > 31) {
|
||||
reg[1] = am + (8 * (pm - 31));
|
||||
reg[2] = 31;
|
||||
} else {
|
||||
reg[1] = am;
|
||||
reg[2] = pm;
|
||||
}
|
||||
|
||||
if ((reg[1] > 15) || (reg[2] < 0x0b)) {
|
||||
fprintf(stderr, "[FC0013] no valid PLL combination "
|
||||
"found for %u Hz!\n", freq);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* fix clock out */
|
||||
reg[6] |= 0x20;
|
||||
|
||||
/* From VCO frequency determines the XIN ( fractional part of Delta
|
||||
Sigma PLL) and divided value (XDIV) */
|
||||
xin = (uint16_t)((f_vco - (f_vco / xtal_freq_div_2) * xtal_freq_div_2) / 1000);
|
||||
xin = (xin << 15) / (xtal_freq_div_2 / 1000);
|
||||
if (xin >= 16384)
|
||||
xin += 32768;
|
||||
|
||||
reg[3] = xin >> 8;
|
||||
reg[4] = xin & 0xff;
|
||||
|
||||
reg[6] &= 0x3f; /* bits 6 and 7 describe the bandwidth */
|
||||
switch (bandwidth) {
|
||||
case 6000000:
|
||||
reg[6] |= 0x80;
|
||||
break;
|
||||
case 7000000:
|
||||
reg[6] |= 0x40;
|
||||
break;
|
||||
case 8000000:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* modified for Realtek demod */
|
||||
reg[5] |= 0x07;
|
||||
|
||||
for (i = 1; i <= 6; i++) {
|
||||
ret = fc0013_writereg(dev, i, reg[i]);
|
||||
if (ret)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = fc0013_readreg(dev, 0x11, &tmp);
|
||||
if (ret)
|
||||
goto exit;
|
||||
if (multi == 64)
|
||||
ret = fc0013_writereg(dev, 0x11, tmp | 0x04);
|
||||
else
|
||||
ret = fc0013_writereg(dev, 0x11, tmp & 0xfb);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
/* VCO Calibration */
|
||||
ret = fc0013_writereg(dev, 0x0e, 0x80);
|
||||
if (!ret)
|
||||
ret = fc0013_writereg(dev, 0x0e, 0x00);
|
||||
|
||||
/* VCO Re-Calibration if needed */
|
||||
if (!ret)
|
||||
ret = fc0013_writereg(dev, 0x0e, 0x00);
|
||||
|
||||
if (!ret) {
|
||||
// msleep(10);
|
||||
ret = fc0013_readreg(dev, 0x0e, &tmp);
|
||||
}
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
/* vco selection */
|
||||
tmp &= 0x3f;
|
||||
|
||||
if (vco_select) {
|
||||
if (tmp > 0x3c) {
|
||||
reg[6] &= ~0x08;
|
||||
ret = fc0013_writereg(dev, 0x06, reg[6]);
|
||||
if (!ret)
|
||||
ret = fc0013_writereg(dev, 0x0e, 0x80);
|
||||
if (!ret)
|
||||
ret = fc0013_writereg(dev, 0x0e, 0x00);
|
||||
}
|
||||
} else {
|
||||
if (tmp < 0x02) {
|
||||
reg[6] |= 0x08;
|
||||
ret = fc0013_writereg(dev, 0x06, reg[6]);
|
||||
if (!ret)
|
||||
ret = fc0013_writereg(dev, 0x0e, 0x80);
|
||||
if (!ret)
|
||||
ret = fc0013_writereg(dev, 0x0e, 0x00);
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fc0013_set_gain_mode(void *dev, int manual)
|
||||
{
|
||||
int ret = 0;
|
||||
uint8_t tmp = 0;
|
||||
|
||||
ret |= fc0013_readreg(dev, 0x0d, &tmp);
|
||||
|
||||
if (manual)
|
||||
tmp |= (1 << 3);
|
||||
else
|
||||
tmp &= ~(1 << 3);
|
||||
|
||||
ret |= fc0013_writereg(dev, 0x0d, tmp);
|
||||
|
||||
/* set a fixed IF-gain for now */
|
||||
ret |= fc0013_writereg(dev, 0x13, 0x0a);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fc0013_lna_gains[] ={
|
||||
-99, 0x02,
|
||||
-73, 0x03,
|
||||
-65, 0x05,
|
||||
-63, 0x04,
|
||||
-63, 0x00,
|
||||
-60, 0x07,
|
||||
-58, 0x01,
|
||||
-54, 0x06,
|
||||
58, 0x0f,
|
||||
61, 0x0e,
|
||||
63, 0x0d,
|
||||
65, 0x0c,
|
||||
67, 0x0b,
|
||||
68, 0x0a,
|
||||
70, 0x09,
|
||||
71, 0x08,
|
||||
179, 0x17,
|
||||
181, 0x16,
|
||||
182, 0x15,
|
||||
184, 0x14,
|
||||
186, 0x13,
|
||||
188, 0x12,
|
||||
191, 0x11,
|
||||
197, 0x10
|
||||
};
|
||||
|
||||
#define GAIN_CNT (sizeof(fc0013_lna_gains) / sizeof(int) / 2)
|
||||
|
||||
int fc0013_set_lna_gain(void *dev, int gain)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned int i;
|
||||
uint8_t tmp = 0;
|
||||
|
||||
ret |= fc0013_readreg(dev, 0x14, &tmp);
|
||||
|
||||
/* mask bits off */
|
||||
tmp &= 0xe0;
|
||||
|
||||
for (i = 0; i < GAIN_CNT; i++) {
|
||||
if ((fc0013_lna_gains[i*2] >= gain) || (i+1 == GAIN_CNT)) {
|
||||
tmp |= fc0013_lna_gains[i*2 + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* set gain */
|
||||
ret |= fc0013_writereg(dev, 0x14, tmp);
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,494 @@
|
|||
/*
|
||||
* FCI FC2580 tuner driver, taken from the kernel driver that can be found
|
||||
* on http://linux.terratec.de/tv_en.html
|
||||
*
|
||||
* This driver is a mess, and should be cleaned up/rewritten.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "rtlsdr_i2c.h"
|
||||
#include "tuner_fc2580.h"
|
||||
|
||||
/* 16.384 MHz (at least on the Logilink VG0002A) */
|
||||
#define CRYSTAL_FREQ 16384000
|
||||
|
||||
/* glue functions to rtl-sdr code */
|
||||
|
||||
fc2580_fci_result_type fc2580_i2c_write(void *pTuner, unsigned char reg, unsigned char val)
|
||||
{
|
||||
uint8_t data[2];
|
||||
|
||||
data[0] = reg;
|
||||
data[1] = val;
|
||||
|
||||
if (rtlsdr_i2c_write_fn(pTuner, FC2580_I2C_ADDR, data, 2) < 0)
|
||||
return FC2580_FCI_FAIL;
|
||||
|
||||
return FC2580_FCI_SUCCESS;
|
||||
}
|
||||
|
||||
fc2580_fci_result_type fc2580_i2c_read(void *pTuner, unsigned char reg, unsigned char *read_data)
|
||||
{
|
||||
uint8_t data = reg;
|
||||
|
||||
if (rtlsdr_i2c_write_fn(pTuner, FC2580_I2C_ADDR, &data, 1) < 0)
|
||||
return FC2580_FCI_FAIL;
|
||||
|
||||
if (rtlsdr_i2c_read_fn(pTuner, FC2580_I2C_ADDR, &data, 1) < 0)
|
||||
return FC2580_FCI_FAIL;
|
||||
|
||||
*read_data = data;
|
||||
|
||||
return FC2580_FCI_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
fc2580_Initialize(
|
||||
void *pTuner
|
||||
)
|
||||
{
|
||||
int AgcMode;
|
||||
unsigned int CrystalFreqKhz;
|
||||
|
||||
//TODO set AGC mode
|
||||
AgcMode = FC2580_AGC_EXTERNAL;
|
||||
|
||||
// Initialize tuner with AGC mode.
|
||||
// Note: CrystalFreqKhz = round(CrystalFreqHz / 1000)
|
||||
CrystalFreqKhz = (unsigned int)((CRYSTAL_FREQ + 500) / 1000);
|
||||
|
||||
if(fc2580_set_init(pTuner, AgcMode, CrystalFreqKhz) != FC2580_FCI_SUCCESS)
|
||||
goto error_status_initialize_tuner;
|
||||
|
||||
|
||||
return FUNCTION_SUCCESS;
|
||||
|
||||
|
||||
error_status_initialize_tuner:
|
||||
return FUNCTION_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
fc2580_SetRfFreqHz(
|
||||
void *pTuner,
|
||||
unsigned long RfFreqHz
|
||||
)
|
||||
{
|
||||
unsigned int RfFreqKhz;
|
||||
unsigned int CrystalFreqKhz;
|
||||
|
||||
// Set tuner RF frequency in KHz.
|
||||
// Note: RfFreqKhz = round(RfFreqHz / 1000)
|
||||
// CrystalFreqKhz = round(CrystalFreqHz / 1000)
|
||||
RfFreqKhz = (unsigned int)((RfFreqHz + 500) / 1000);
|
||||
CrystalFreqKhz = (unsigned int)((CRYSTAL_FREQ + 500) / 1000);
|
||||
|
||||
if(fc2580_set_freq(pTuner, RfFreqKhz, CrystalFreqKhz) != FC2580_FCI_SUCCESS)
|
||||
goto error_status_set_tuner_rf_frequency;
|
||||
|
||||
return FUNCTION_SUCCESS;
|
||||
|
||||
error_status_set_tuner_rf_frequency:
|
||||
return FUNCTION_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@brief Set FC2580 tuner bandwidth mode.
|
||||
|
||||
*/
|
||||
int
|
||||
fc2580_SetBandwidthMode(
|
||||
void *pTuner,
|
||||
int BandwidthMode
|
||||
)
|
||||
{
|
||||
unsigned int CrystalFreqKhz;
|
||||
|
||||
// Set tuner bandwidth mode.
|
||||
// Note: CrystalFreqKhz = round(CrystalFreqHz / 1000)
|
||||
CrystalFreqKhz = (unsigned int)((CRYSTAL_FREQ + 500) / 1000);
|
||||
|
||||
if(fc2580_set_filter(pTuner, (unsigned char)BandwidthMode, CrystalFreqKhz) != FC2580_FCI_SUCCESS)
|
||||
goto error_status_set_tuner_bandwidth_mode;
|
||||
|
||||
return FUNCTION_SUCCESS;
|
||||
|
||||
|
||||
error_status_set_tuner_bandwidth_mode:
|
||||
return FUNCTION_ERROR;
|
||||
}
|
||||
|
||||
void fc2580_wait_msec(void *pTuner, int a)
|
||||
{
|
||||
/* USB latency is enough for now ;) */
|
||||
// usleep(a * 1000);
|
||||
return;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
fc2580 initial setting
|
||||
|
||||
This function is a generic function which gets called to initialize
|
||||
|
||||
fc2580 in DVB-H mode or L-Band TDMB mode
|
||||
|
||||
<input parameter>
|
||||
|
||||
ifagc_mode
|
||||
type : integer
|
||||
1 : Internal AGC
|
||||
2 : Voltage Control Mode
|
||||
|
||||
==============================================================================*/
|
||||
fc2580_fci_result_type fc2580_set_init( void *pTuner, int ifagc_mode, unsigned int freq_xtal )
|
||||
{
|
||||
fc2580_fci_result_type result = FC2580_FCI_SUCCESS;
|
||||
|
||||
result &= fc2580_i2c_write(pTuner, 0x00, 0x00); /*** Confidential ***/
|
||||
result &= fc2580_i2c_write(pTuner, 0x12, 0x86);
|
||||
result &= fc2580_i2c_write(pTuner, 0x14, 0x5C);
|
||||
result &= fc2580_i2c_write(pTuner, 0x16, 0x3C);
|
||||
result &= fc2580_i2c_write(pTuner, 0x1F, 0xD2);
|
||||
result &= fc2580_i2c_write(pTuner, 0x09, 0xD7);
|
||||
result &= fc2580_i2c_write(pTuner, 0x0B, 0xD5);
|
||||
result &= fc2580_i2c_write(pTuner, 0x0C, 0x32);
|
||||
result &= fc2580_i2c_write(pTuner, 0x0E, 0x43);
|
||||
result &= fc2580_i2c_write(pTuner, 0x21, 0x0A);
|
||||
result &= fc2580_i2c_write(pTuner, 0x22, 0x82);
|
||||
if( ifagc_mode == 1 )
|
||||
{
|
||||
result &= fc2580_i2c_write(pTuner, 0x45, 0x10); //internal AGC
|
||||
result &= fc2580_i2c_write(pTuner, 0x4C, 0x00); //HOLD_AGC polarity
|
||||
}
|
||||
else if( ifagc_mode == 2 )
|
||||
{
|
||||
result &= fc2580_i2c_write(pTuner, 0x45, 0x20); //Voltage Control Mode
|
||||
result &= fc2580_i2c_write(pTuner, 0x4C, 0x02); //HOLD_AGC polarity
|
||||
}
|
||||
result &= fc2580_i2c_write(pTuner, 0x3F, 0x88);
|
||||
result &= fc2580_i2c_write(pTuner, 0x02, 0x0E);
|
||||
result &= fc2580_i2c_write(pTuner, 0x58, 0x14);
|
||||
result &= fc2580_set_filter(pTuner, 8, freq_xtal); //BW = 7.8MHz
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
fc2580 frequency setting
|
||||
|
||||
This function is a generic function which gets called to change LO Frequency
|
||||
|
||||
of fc2580 in DVB-H mode or L-Band TDMB mode
|
||||
|
||||
<input parameter>
|
||||
freq_xtal: kHz
|
||||
|
||||
f_lo
|
||||
Value of target LO Frequency in 'kHz' unit
|
||||
ex) 2.6GHz = 2600000
|
||||
|
||||
==============================================================================*/
|
||||
fc2580_fci_result_type fc2580_set_freq( void *pTuner, unsigned int f_lo, unsigned int freq_xtal )
|
||||
{
|
||||
unsigned int f_diff, f_diff_shifted, n_val, k_val;
|
||||
unsigned int f_vco, r_val, f_comp;
|
||||
unsigned char pre_shift_bits = 4;// number of preshift to prevent overflow in shifting f_diff to f_diff_shifted
|
||||
unsigned char data_0x18;
|
||||
unsigned char data_0x02 = (USE_EXT_CLK<<5)|0x0E;
|
||||
|
||||
fc2580_band_type band = ( f_lo > 1000000 )? FC2580_L_BAND : ( f_lo > 400000 )? FC2580_UHF_BAND : FC2580_VHF_BAND;
|
||||
|
||||
fc2580_fci_result_type result = FC2580_FCI_SUCCESS;
|
||||
|
||||
f_vco = ( band == FC2580_UHF_BAND )? f_lo * 4 : (( band == FC2580_L_BAND )? f_lo * 2 : f_lo * 12);
|
||||
r_val = ( f_vco >= 2*76*freq_xtal )? 1 : ( f_vco >= 76*freq_xtal )? 2 : 4;
|
||||
f_comp = freq_xtal/r_val;
|
||||
n_val = ( f_vco / 2 ) / f_comp;
|
||||
|
||||
f_diff = f_vco - 2* f_comp * n_val;
|
||||
f_diff_shifted = f_diff << ( 20 - pre_shift_bits );
|
||||
k_val = f_diff_shifted / ( ( 2* f_comp ) >> pre_shift_bits );
|
||||
|
||||
if( f_diff_shifted - k_val * ( ( 2* f_comp ) >> pre_shift_bits ) >= ( f_comp >> pre_shift_bits ) )
|
||||
k_val = k_val + 1;
|
||||
|
||||
if( f_vco >= BORDER_FREQ ) //Select VCO Band
|
||||
data_0x02 = data_0x02 | 0x08; //0x02[3] = 1;
|
||||
else
|
||||
data_0x02 = data_0x02 & 0xF7; //0x02[3] = 0;
|
||||
|
||||
// if( band != curr_band ) {
|
||||
switch(band)
|
||||
{
|
||||
case FC2580_UHF_BAND:
|
||||
data_0x02 = (data_0x02 & 0x3F);
|
||||
|
||||
result &= fc2580_i2c_write(pTuner, 0x25, 0xF0);
|
||||
result &= fc2580_i2c_write(pTuner, 0x27, 0x77);
|
||||
result &= fc2580_i2c_write(pTuner, 0x28, 0x53);
|
||||
result &= fc2580_i2c_write(pTuner, 0x29, 0x60);
|
||||
result &= fc2580_i2c_write(pTuner, 0x30, 0x09);
|
||||
result &= fc2580_i2c_write(pTuner, 0x50, 0x8C);
|
||||
result &= fc2580_i2c_write(pTuner, 0x53, 0x50);
|
||||
|
||||
if( f_lo < 538000 )
|
||||
result &= fc2580_i2c_write(pTuner, 0x5F, 0x13);
|
||||
else
|
||||
result &= fc2580_i2c_write(pTuner, 0x5F, 0x15);
|
||||
|
||||
if( f_lo < 538000 )
|
||||
{
|
||||
result &= fc2580_i2c_write(pTuner, 0x61, 0x07);
|
||||
result &= fc2580_i2c_write(pTuner, 0x62, 0x06);
|
||||
result &= fc2580_i2c_write(pTuner, 0x67, 0x06);
|
||||
result &= fc2580_i2c_write(pTuner, 0x68, 0x08);
|
||||
result &= fc2580_i2c_write(pTuner, 0x69, 0x10);
|
||||
result &= fc2580_i2c_write(pTuner, 0x6A, 0x12);
|
||||
}
|
||||
else if( f_lo < 794000 )
|
||||
{
|
||||
result &= fc2580_i2c_write(pTuner, 0x61, 0x03);
|
||||
result &= fc2580_i2c_write(pTuner, 0x62, 0x03);
|
||||
result &= fc2580_i2c_write(pTuner, 0x67, 0x03); //ACI improve
|
||||
result &= fc2580_i2c_write(pTuner, 0x68, 0x05); //ACI improve
|
||||
result &= fc2580_i2c_write(pTuner, 0x69, 0x0C);
|
||||
result &= fc2580_i2c_write(pTuner, 0x6A, 0x0E);
|
||||
}
|
||||
else
|
||||
{
|
||||
result &= fc2580_i2c_write(pTuner, 0x61, 0x07);
|
||||
result &= fc2580_i2c_write(pTuner, 0x62, 0x06);
|
||||
result &= fc2580_i2c_write(pTuner, 0x67, 0x07);
|
||||
result &= fc2580_i2c_write(pTuner, 0x68, 0x09);
|
||||
result &= fc2580_i2c_write(pTuner, 0x69, 0x10);
|
||||
result &= fc2580_i2c_write(pTuner, 0x6A, 0x12);
|
||||
}
|
||||
|
||||
result &= fc2580_i2c_write(pTuner, 0x63, 0x15);
|
||||
|
||||
result &= fc2580_i2c_write(pTuner, 0x6B, 0x0B);
|
||||
result &= fc2580_i2c_write(pTuner, 0x6C, 0x0C);
|
||||
result &= fc2580_i2c_write(pTuner, 0x6D, 0x78);
|
||||
result &= fc2580_i2c_write(pTuner, 0x6E, 0x32);
|
||||
result &= fc2580_i2c_write(pTuner, 0x6F, 0x14);
|
||||
result &= fc2580_set_filter(pTuner, 8, freq_xtal); //BW = 7.8MHz
|
||||
break;
|
||||
case FC2580_VHF_BAND:
|
||||
data_0x02 = (data_0x02 & 0x3F) | 0x80;
|
||||
result &= fc2580_i2c_write(pTuner, 0x27, 0x77);
|
||||
result &= fc2580_i2c_write(pTuner, 0x28, 0x33);
|
||||
result &= fc2580_i2c_write(pTuner, 0x29, 0x40);
|
||||
result &= fc2580_i2c_write(pTuner, 0x30, 0x09);
|
||||
result &= fc2580_i2c_write(pTuner, 0x50, 0x8C);
|
||||
result &= fc2580_i2c_write(pTuner, 0x53, 0x50);
|
||||
result &= fc2580_i2c_write(pTuner, 0x5F, 0x0F);
|
||||
result &= fc2580_i2c_write(pTuner, 0x61, 0x07);
|
||||
result &= fc2580_i2c_write(pTuner, 0x62, 0x00);
|
||||
result &= fc2580_i2c_write(pTuner, 0x63, 0x15);
|
||||
result &= fc2580_i2c_write(pTuner, 0x67, 0x03);
|
||||
result &= fc2580_i2c_write(pTuner, 0x68, 0x05);
|
||||
result &= fc2580_i2c_write(pTuner, 0x69, 0x10);
|
||||
result &= fc2580_i2c_write(pTuner, 0x6A, 0x12);
|
||||
result &= fc2580_i2c_write(pTuner, 0x6B, 0x08);
|
||||
result &= fc2580_i2c_write(pTuner, 0x6C, 0x0A);
|
||||
result &= fc2580_i2c_write(pTuner, 0x6D, 0x78);
|
||||
result &= fc2580_i2c_write(pTuner, 0x6E, 0x32);
|
||||
result &= fc2580_i2c_write(pTuner, 0x6F, 0x54);
|
||||
result &= fc2580_set_filter(pTuner, 7, freq_xtal); //BW = 6.8MHz
|
||||
break;
|
||||
case FC2580_L_BAND:
|
||||
data_0x02 = (data_0x02 & 0x3F) | 0x40;
|
||||
result &= fc2580_i2c_write(pTuner, 0x2B, 0x70);
|
||||
result &= fc2580_i2c_write(pTuner, 0x2C, 0x37);
|
||||
result &= fc2580_i2c_write(pTuner, 0x2D, 0xE7);
|
||||
result &= fc2580_i2c_write(pTuner, 0x30, 0x09);
|
||||
result &= fc2580_i2c_write(pTuner, 0x44, 0x20);
|
||||
result &= fc2580_i2c_write(pTuner, 0x50, 0x8C);
|
||||
result &= fc2580_i2c_write(pTuner, 0x53, 0x50);
|
||||
result &= fc2580_i2c_write(pTuner, 0x5F, 0x0F);
|
||||
result &= fc2580_i2c_write(pTuner, 0x61, 0x0F);
|
||||
result &= fc2580_i2c_write(pTuner, 0x62, 0x00);
|
||||
result &= fc2580_i2c_write(pTuner, 0x63, 0x13);
|
||||
result &= fc2580_i2c_write(pTuner, 0x67, 0x00);
|
||||
result &= fc2580_i2c_write(pTuner, 0x68, 0x02);
|
||||
result &= fc2580_i2c_write(pTuner, 0x69, 0x0C);
|
||||
result &= fc2580_i2c_write(pTuner, 0x6A, 0x0E);
|
||||
result &= fc2580_i2c_write(pTuner, 0x6B, 0x08);
|
||||
result &= fc2580_i2c_write(pTuner, 0x6C, 0x0A);
|
||||
result &= fc2580_i2c_write(pTuner, 0x6D, 0xA0);
|
||||
result &= fc2580_i2c_write(pTuner, 0x6E, 0x50);
|
||||
result &= fc2580_i2c_write(pTuner, 0x6F, 0x14);
|
||||
result &= fc2580_set_filter(pTuner, 1, freq_xtal); //BW = 1.53MHz
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// curr_band = band;
|
||||
// }
|
||||
|
||||
//A command about AGC clock's pre-divide ratio
|
||||
if( freq_xtal >= 28000 )
|
||||
result &= fc2580_i2c_write(pTuner, 0x4B, 0x22 );
|
||||
|
||||
//Commands about VCO Band and PLL setting.
|
||||
result &= fc2580_i2c_write(pTuner, 0x02, data_0x02);
|
||||
data_0x18 = ( ( r_val == 1 )? 0x00 : ( ( r_val == 2 )? 0x10 : 0x20 ) ) + (unsigned char)(k_val >> 16);
|
||||
result &= fc2580_i2c_write(pTuner, 0x18, data_0x18); //Load 'R' value and high part of 'K' values
|
||||
result &= fc2580_i2c_write(pTuner, 0x1A, (unsigned char)( k_val >> 8 ) ); //Load middle part of 'K' value
|
||||
result &= fc2580_i2c_write(pTuner, 0x1B, (unsigned char)( k_val ) ); //Load lower part of 'K' value
|
||||
result &= fc2580_i2c_write(pTuner, 0x1C, (unsigned char)( n_val ) ); //Load 'N' value
|
||||
|
||||
//A command about UHF LNA Load Cap
|
||||
if( band == FC2580_UHF_BAND )
|
||||
result &= fc2580_i2c_write(pTuner, 0x2D, ( f_lo <= (unsigned int)794000 )? 0x9F : 0x8F ); //LNA_OUT_CAP
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
fc2580 filter BW setting
|
||||
|
||||
This function is a generic function which gets called to change Bandwidth
|
||||
|
||||
frequency of fc2580's channel selection filter
|
||||
|
||||
<input parameter>
|
||||
freq_xtal: kHz
|
||||
|
||||
filter_bw
|
||||
1 : 1.53MHz(TDMB)
|
||||
6 : 6MHz (Bandwidth 6MHz)
|
||||
7 : 6.8MHz (Bandwidth 7MHz)
|
||||
8 : 7.8MHz (Bandwidth 8MHz)
|
||||
|
||||
|
||||
==============================================================================*/
|
||||
fc2580_fci_result_type fc2580_set_filter( void *pTuner, unsigned char filter_bw, unsigned int freq_xtal )
|
||||
{
|
||||
unsigned char cal_mon = 0, i;
|
||||
fc2580_fci_result_type result = FC2580_FCI_SUCCESS;
|
||||
|
||||
if(filter_bw == 1)
|
||||
{
|
||||
result &= fc2580_i2c_write(pTuner, 0x36, 0x1C);
|
||||
result &= fc2580_i2c_write(pTuner, 0x37, (unsigned char)(4151*freq_xtal/1000000) );
|
||||
result &= fc2580_i2c_write(pTuner, 0x39, 0x00);
|
||||
result &= fc2580_i2c_write(pTuner, 0x2E, 0x09);
|
||||
}
|
||||
if(filter_bw == 6)
|
||||
{
|
||||
result &= fc2580_i2c_write(pTuner, 0x36, 0x18);
|
||||
result &= fc2580_i2c_write(pTuner, 0x37, (unsigned char)(4400*freq_xtal/1000000) );
|
||||
result &= fc2580_i2c_write(pTuner, 0x39, 0x00);
|
||||
result &= fc2580_i2c_write(pTuner, 0x2E, 0x09);
|
||||
}
|
||||
else if(filter_bw == 7)
|
||||
{
|
||||
result &= fc2580_i2c_write(pTuner, 0x36, 0x18);
|
||||
result &= fc2580_i2c_write(pTuner, 0x37, (unsigned char)(3910*freq_xtal/1000000) );
|
||||
result &= fc2580_i2c_write(pTuner, 0x39, 0x80);
|
||||
result &= fc2580_i2c_write(pTuner, 0x2E, 0x09);
|
||||
}
|
||||
else if(filter_bw == 8)
|
||||
{
|
||||
result &= fc2580_i2c_write(pTuner, 0x36, 0x18);
|
||||
result &= fc2580_i2c_write(pTuner, 0x37, (unsigned char)(3300*freq_xtal/1000000) );
|
||||
result &= fc2580_i2c_write(pTuner, 0x39, 0x80);
|
||||
result &= fc2580_i2c_write(pTuner, 0x2E, 0x09);
|
||||
}
|
||||
|
||||
|
||||
for(i=0; i<5; i++)
|
||||
{
|
||||
fc2580_wait_msec(pTuner, 5);//wait 5ms
|
||||
result &= fc2580_i2c_read(pTuner, 0x2F, &cal_mon);
|
||||
if( (cal_mon & 0xC0) != 0xC0)
|
||||
{
|
||||
result &= fc2580_i2c_write(pTuner, 0x2E, 0x01);
|
||||
result &= fc2580_i2c_write(pTuner, 0x2E, 0x09);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
result &= fc2580_i2c_write(pTuner, 0x2E, 0x01);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
fc2580 RSSI function
|
||||
|
||||
This function is a generic function which returns fc2580's
|
||||
|
||||
current RSSI value.
|
||||
|
||||
<input parameter>
|
||||
none
|
||||
|
||||
<return value>
|
||||
int
|
||||
rssi : estimated input power.
|
||||
|
||||
==============================================================================*/
|
||||
//int fc2580_get_rssi(void) {
|
||||
//
|
||||
// unsigned char s_lna, s_rfvga, s_cfs, s_ifvga;
|
||||
// int ofs_lna, ofs_rfvga, ofs_csf, ofs_ifvga, rssi;
|
||||
//
|
||||
// fc2580_i2c_read(0x71, &s_lna );
|
||||
// fc2580_i2c_read(0x72, &s_rfvga );
|
||||
// fc2580_i2c_read(0x73, &s_cfs );
|
||||
// fc2580_i2c_read(0x74, &s_ifvga );
|
||||
//
|
||||
//
|
||||
// ofs_lna =
|
||||
// (curr_band==FC2580_UHF_BAND)?
|
||||
// (s_lna==0)? 0 :
|
||||
// (s_lna==1)? -6 :
|
||||
// (s_lna==2)? -17 :
|
||||
// (s_lna==3)? -22 : -30 :
|
||||
// (curr_band==FC2580_VHF_BAND)?
|
||||
// (s_lna==0)? 0 :
|
||||
// (s_lna==1)? -6 :
|
||||
// (s_lna==2)? -19 :
|
||||
// (s_lna==3)? -24 : -32 :
|
||||
// (curr_band==FC2580_L_BAND)?
|
||||
// (s_lna==0)? 0 :
|
||||
// (s_lna==1)? -6 :
|
||||
// (s_lna==2)? -11 :
|
||||
// (s_lna==3)? -16 : -34 :
|
||||
// 0;//FC2580_NO_BAND
|
||||
// ofs_rfvga = -s_rfvga+((s_rfvga>=11)? 1 : 0) + ((s_rfvga>=18)? 1 : 0);
|
||||
// ofs_csf = -6*s_cfs;
|
||||
// ofs_ifvga = s_ifvga/4;
|
||||
//
|
||||
// return rssi = ofs_lna+ofs_rfvga+ofs_csf+ofs_ifvga+OFS_RSSI;
|
||||
//
|
||||
//}
|
||||
|
||||
/*==============================================================================
|
||||
fc2580 Xtal frequency Setting
|
||||
|
||||
This function is a generic function which sets
|
||||
|
||||
the frequency of xtal.
|
||||
|
||||
<input parameter>
|
||||
|
||||
frequency
|
||||
frequency value of internal(external) Xtal(clock) in kHz unit.
|
||||
|
||||
==============================================================================*/
|
||||
//void fc2580_set_freq_xtal(unsigned int frequency) {
|
||||
//
|
||||
// freq_xtal = frequency;
|
||||
//
|
||||
//}
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue