Initial upload rtl_sdr direct SP

master
root 2016-03-19 22:10:00 +02:00
commit c30d3646af
48 changed files with 16229 additions and 0 deletions

41
.gitignore vendored 100644
View File

@ -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

10
.travis.yml 100644
View File

@ -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

4
AUTHORS 100644
View File

@ -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>

170
CMakeLists.txt 100644
View File

@ -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}")

339
COPYING 100644
View File

@ -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.

1716
Doxyfile.in 100644

File diff suppressed because it is too large Load Diff

49
Makefile.am 100644
View File

@ -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)

19
README 100644
View File

@ -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

View File

@ -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)

View File

@ -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()

View File

@ -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()

View File

@ -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)

86
configure.ac 100644
View 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
)

151
git-version-gen 100755
View File

@ -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:

View File

@ -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
)

View File

@ -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)

View File

@ -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

387
include/rtl-sdr.h 100644
View File

@ -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 */

View File

@ -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 */

View File

@ -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

222
include/tuner_e4k.h 100644
View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

11
librtlsdr.pc.in 100644
View File

@ -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@

2
m4/.gitignore vendored 100644
View File

@ -0,0 +1,2 @@
/libtool.m4
/lt*.m4

139
rtl-sdr.rules 100644
View File

@ -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"

158
src/CMakeLists.txt 100644
View File

@ -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
)

36
src/Makefile.am 100644
View 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)

View File

@ -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

View File

@ -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);

1059
src/getopt/getopt.c 100644

File diff suppressed because it is too large Load Diff

180
src/getopt/getopt.h 100644
View File

@ -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 */

1928
src/librtlsdr.c 100644

File diff suppressed because it is too large Load Diff

494
src/rtl_adsb.c 100644
View File

@ -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;
}

425
src/rtl_eeprom.c 100644
View File

@ -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;
}

1264
src/rtl_fm.c 100644

File diff suppressed because it is too large Load Diff

998
src/rtl_power.c 100644
View File

@ -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

285
src/rtl_sdr.c 100644
View File

@ -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;
}

626
src/rtl_tcp.c 100644
View File

@ -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;
}

423
src/rtl_test.c 100644
View File

@ -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;
}

34
src/rtlsdr.rc.in 100644
View File

@ -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

1000
src/tuner_e4k.c 100644

File diff suppressed because it is too large Load Diff

345
src/tuner_fc0012.c 100644
View File

@ -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;
}

500
src/tuner_fc0013.c 100644
View File

@ -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;
}

494
src/tuner_fc2580.c 100644
View File

@ -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;
//
//}

1328
src/tuner_r82xx.c 100644

File diff suppressed because it is too large Load Diff