removed rtl-sdr files and modified CMake and autotools configurations
This commit is contained in:
parent
7748f464cf
commit
50cfd95da1
37 changed files with 109 additions and 11853 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -17,6 +17,7 @@ config.log
|
|||
config.status
|
||||
config.guess
|
||||
configure
|
||||
compile
|
||||
depcomp
|
||||
missing
|
||||
ltmain.sh
|
||||
|
@ -24,7 +25,7 @@ install-sh
|
|||
stamp-h1
|
||||
libtool
|
||||
Doxyfile
|
||||
build
|
||||
.dirstamp
|
||||
|
||||
.tarball-version
|
||||
.version
|
||||
|
@ -37,9 +38,6 @@ src/rtl_sdr
|
|||
src/rtl_tcp
|
||||
|
||||
CMakeCache.txt
|
||||
*/CMakeFiles
|
||||
CMakeFiles
|
||||
*.cmake
|
||||
|
||||
build/
|
||||
.cproject
|
||||
|
|
24
AUTHORS
24
AUTHORS
|
@ -1,4 +1,20 @@
|
|||
Steve Markgraf <steve@steve-m.de>
|
||||
Dimitri Stolnikov <horiz0n@gmx.net>
|
||||
Hoernchen <la@tfc-server.de>
|
||||
Kyle Keen <keenerd@gmail.com>
|
||||
Benjamin Larsson <benjamin@southpole.se>
|
||||
Sven Killig <sven@killig.de>
|
||||
Benjamin Larsson <banan@ludd.ltu.se>
|
||||
rct <rct+github@r-t.org>
|
||||
johan <johan@E6410>
|
||||
Thomas Kerpe <toke@toke.de>
|
||||
Jens Jensen <zerog2k@yahoo.com>
|
||||
Sven <sonic@sonic-VGN-Z41WD-B.(none)>
|
||||
Martin Hauke <mardnh@gmx.de>
|
||||
magellannh <pi@raspberrypi.(none)>
|
||||
jules69350 <julien.sangouard@gmail.com>
|
||||
arantius <arantius@gmail.com>
|
||||
andreaaizza <andrea@andreaaizza.com>
|
||||
Trueffelwurm <jens@trueffelwurm.de>
|
||||
Tomasz Brzezina <tombrz@Bonawentura.brzezina.pl>
|
||||
Paul F-Y <pbfy00@gmail.com>
|
||||
Corné van Strien <github@atilas.nl>
|
||||
Baruch Even <baruch@ev-en.org>
|
||||
Andrea <andrea@andreaaizza.com>
|
||||
Helge Weissig <helgew@grajagan.org>
|
||||
|
|
|
@ -1,13 +1,4 @@
|
|||
# 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,
|
||||
# rtl_433 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.
|
||||
|
@ -22,7 +13,9 @@
|
|||
# Project setup
|
||||
########################################################################
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
project(rtlsdr C)
|
||||
project(rtl433 C)
|
||||
set (rtl433_VERSION_MAJOR 1)
|
||||
set (rtl433_VERSION_MINOR 0)
|
||||
|
||||
#select the release build type by default to get optimization flags
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
|
@ -50,32 +43,16 @@ endif()
|
|||
# Find build dependencies
|
||||
########################################################################
|
||||
find_package(PkgConfig)
|
||||
find_package(LibUSB)
|
||||
set(THREADS_USE_PTHREADS_WIN32 true)
|
||||
find_package(Threads)
|
||||
find_package(LibRTLSDR)
|
||||
|
||||
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}
|
||||
${LIBRTLSDR_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
#link_directories(
|
||||
# ...
|
||||
#)
|
||||
|
||||
# Set component parameters
|
||||
#set(INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include CACHE INTERNAL "" FORCE)
|
||||
|
||||
########################################################################
|
||||
# Create uninstall target
|
||||
########################################################################
|
||||
|
@ -88,45 +65,20 @@ 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)
|
||||
|
||||
########################################################################
|
||||
# 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}")
|
||||
STRING(REPLACE ";" " " RTL433_PC_CFLAGS "${RTL433_PC_CFLAGS}")
|
||||
STRING(REPLACE ";" " " RTL433_PC_LIBS "${RTL433_PC_LIBS}")
|
||||
|
||||
# unset these vars to avoid hard-coded paths to cross environment
|
||||
IF(CMAKE_CROSSCOMPILING)
|
||||
UNSET(RTLSDR_PC_CFLAGS)
|
||||
UNSET(RTLSDR_PC_LIBS)
|
||||
UNSET(RTL433_PC_CFLAGS)
|
||||
UNSET(RTL433_PC_LIBS)
|
||||
ENDIF(CMAKE_CROSSCOMPILING)
|
||||
|
||||
set(prefix ${CMAKE_INSTALL_PREFIX})
|
||||
|
@ -134,12 +86,7 @@ set(exec_prefix \${prefix})
|
|||
set(libdir \${exec_prefix}/lib)
|
||||
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
|
||||
FILES
|
||||
DESTINATION lib/pkgconfig
|
||||
)
|
||||
|
|
|
@ -25,7 +25,7 @@ DOXYFILE_ENCODING = UTF-8
|
|||
# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
|
||||
# by quotes) that should identify the project.
|
||||
|
||||
PROJECT_NAME = librtlsdr
|
||||
PROJECT_NAME = rtl433
|
||||
|
||||
# The PROJECT_NUMBER tag can be used to enter a project or revision number.
|
||||
# This could be handy for archiving the generated documentation or
|
||||
|
@ -37,7 +37,7 @@ PROJECT_NUMBER = @VERSION@
|
|||
# for a project that appears at the top of each page and should give viewer
|
||||
# a quick idea about the purpose of the project. Keep the description short.
|
||||
|
||||
PROJECT_BRIEF = "RTL-SDR library"
|
||||
PROJECT_BRIEF = "RTL-433 utility"
|
||||
|
||||
# With the PROJECT_LOGO tag one can specify an logo or icon that is
|
||||
# included in the documentation. The maximum height of the logo should not
|
||||
|
|
|
@ -5,7 +5,7 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include
|
|||
SUBDIRS = include src
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = librtlsdr.pc
|
||||
pkgconfig_DATA = rtl433.pc
|
||||
|
||||
BUILT_SOURCES = $(top_srcdir)/.version
|
||||
$(top_srcdir)/.version:
|
||||
|
@ -13,12 +13,6 @@ $(top_srcdir)/.version:
|
|||
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
|
||||
|
|
28
cmake/Modules/FindLibRTLSDR.cmake
Normal file
28
cmake/Modules/FindLibRTLSDR.cmake
Normal file
|
@ -0,0 +1,28 @@
|
|||
INCLUDE(FindPkgConfig)
|
||||
if(NOT LIBRTLSDR_FOUND)
|
||||
pkg_check_modules (LIBRTLSDR_PKG librtlsdr)
|
||||
find_path(LIBRTLSDR_INCLUDE_DIRS NAMES rtl-sdr.h
|
||||
PATHS
|
||||
${LIBRTLSDR_PKG_INCLUDE_DIRS}
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
)
|
||||
|
||||
find_library(LIBRTLSDR_LIBRARIES NAMES rtlsdr
|
||||
PATHS
|
||||
${LIBRTLSDR_PKG_LIBRARY_DIRS}
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
)
|
||||
|
||||
if(LIBRTLSDR_INCLUDE_DIRS AND LIBRTLSDR_LIBRARIES)
|
||||
set(LIBRTLSDR_FOUND TRUE CACHE INTERNAL "librtlsdr found")
|
||||
message(STATUS "Found librtlsdr: ${LIBRTLSDR_INCLUDE_DIRS}, ${LIBRTLSDR_LIBRARIES}")
|
||||
else(LIBRTLSDR_INCLUDE_DIRS AND LIBRTLSDR_LIBRARIES)
|
||||
set(LIBRTLSDR_FOUND FALSE CACHE INTERNAL "librtlsdr found")
|
||||
message(STATUS "librtlsdr not found.")
|
||||
endif(LIBRTLSDR_INCLUDE_DIRS AND LIBRTLSDR_LIBRARIES)
|
||||
|
||||
mark_as_advanced(LIBRTLSDR_LIBRARIES LIBRTLSDR_INCLUDE_DIRS)
|
||||
|
||||
endif(NOT LIBRTLSDR_FOUND)
|
|
@ -1,28 +0,0 @@
|
|||
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
|
||||
)
|
||||
|
||||
find_library(LIBUSB_LIBRARIES NAMES usb-1.0
|
||||
PATHS
|
||||
${LIBUSB_PKG_LIBRARY_DIRS}
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
)
|
||||
|
||||
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)
|
|
@ -1,246 +0,0 @@
|
|||
# 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()
|
26
configure.ac
26
configure.ac
|
@ -1,8 +1,8 @@
|
|||
AC_INIT([librtlsdr],
|
||||
AC_INIT([rtl433],
|
||||
m4_esyscmd([./git-version-gen .tarball-version]),
|
||||
[osmocom-sdr@lists.osmocom.org])
|
||||
[rtl_433@googlegroups.com])
|
||||
|
||||
AM_INIT_AUTOMAKE([dist-bzip2])
|
||||
AM_INIT_AUTOMAKE([dist-bzip2 subdir-objects])
|
||||
|
||||
dnl kernel style compile messages
|
||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
||||
|
@ -14,9 +14,9 @@ AC_PROG_INSTALL
|
|||
LT_INIT
|
||||
AC_PROG_LIBTOOL
|
||||
|
||||
PKG_CHECK_MODULES(LIBUSB, libusb-1.0 >= 1.0)
|
||||
LIBS="$LIBS $LIBUSB_LIBS"
|
||||
CFLAGS="$CFLAGS $LIBUSB_CFLAGS"
|
||||
PKG_CHECK_MODULES(LIBRTLSDR, librtlsdr)
|
||||
LIBS="$LIBS $LIBRTLSDR_LIBS"
|
||||
CFLAGS="$CFLAGS $LIBRTLSDR_CFLAGS"
|
||||
|
||||
AC_PATH_PROG(DOXYGEN,doxygen,false)
|
||||
AM_CONDITIONAL(HAVE_DOXYGEN, test $DOXYGEN != false)
|
||||
|
@ -26,24 +26,12 @@ 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 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"
|
||||
|
@ -68,7 +56,7 @@ dnl Generate the output
|
|||
AM_CONFIG_HEADER(config.h)
|
||||
|
||||
AC_OUTPUT(
|
||||
librtlsdr.pc
|
||||
rtl433.pc
|
||||
include/Makefile
|
||||
src/Makefile
|
||||
Makefile
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
# Install public header files
|
||||
########################################################################
|
||||
install(FILES
|
||||
rtl-sdr.h
|
||||
rtl-sdr_export.h
|
||||
rtl_433.h
|
||||
rtl_433_devices.h
|
||||
DESTINATION include
|
||||
)
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
rtlsdr_HEADERS = rtl-sdr.h rtl-sdr_export.h
|
||||
rtl433_HEADERS = rtl_433.h rtl_433_devices.h
|
||||
|
||||
noinst_HEADERS = reg_field.h rtlsdr_i2c.h tuner_e4k.h tuner_fc0012.h tuner_fc0013.h tuner_fc2580.h tuner_r820t.h
|
||||
|
||||
rtlsdrdir = $(includedir)
|
||||
rtl433dir = $(includedir)
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
#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
|
|
@ -1,366 +0,0 @@
|
|||
/*
|
||||
* 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 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
|
||||
};
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
/* this will select the baseband filters according to the requested sample 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 (32)
|
||||
* \param buf_len optional buffer length, must be multiple of 512,
|
||||
* 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 */
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* 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 */
|
|
@ -1,8 +0,0 @@
|
|||
#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
|
|
@ -1,224 +0,0 @@
|
|||
#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_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_reg_write(struct e4k_state *e4k, uint8_t reg, uint8_t val);
|
||||
uint8_t e4k_reg_read(struct e4k_state *e4k, uint8_t reg);
|
||||
|
||||
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 */
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* 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
|
|
@ -1,37 +0,0 @@
|
|||
/*
|
||||
* 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
|
|
@ -1,127 +0,0 @@
|
|||
#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
|
|
@ -1,196 +0,0 @@
|
|||
#ifndef _R820T_TUNER_H
|
||||
#define _R820T_TUNER_H
|
||||
|
||||
#define R820T_I2C_ADDR 0x34
|
||||
#define R820T_CHECK_ADDR 0x00
|
||||
#define R820T_CHECK_VAL 0x69
|
||||
|
||||
#define R820T_IF_FREQ 3570000
|
||||
|
||||
//***************************************************************
|
||||
//* INCLUDES.H
|
||||
//***************************************************************
|
||||
#define VERSION "R820T_v1.49_ASTRO"
|
||||
#define VER_NUM 49
|
||||
|
||||
#define USE_16M_XTAL FALSE
|
||||
#define R828_Xtal 28800
|
||||
|
||||
#define USE_DIPLEXER FALSE
|
||||
#define TUNER_CLK_OUT TRUE
|
||||
|
||||
#ifndef _UINT_X_
|
||||
#define _UINT_X_ 1
|
||||
typedef unsigned char UINT8;
|
||||
typedef unsigned short UINT16;
|
||||
typedef unsigned int UINT32;
|
||||
#endif
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
#define FUNCTION_SUCCESS 0
|
||||
#define FUNCTION_ERROR -1
|
||||
|
||||
typedef enum _R828_ErrCode
|
||||
{
|
||||
RT_Success,
|
||||
RT_Fail
|
||||
}R828_ErrCode;
|
||||
|
||||
typedef enum _Rafael_Chip_Type //Don't modify chip list
|
||||
{
|
||||
R828 = 0,
|
||||
R828D,
|
||||
R828S,
|
||||
R820T,
|
||||
R820C,
|
||||
R620D,
|
||||
R620S
|
||||
}Rafael_Chip_Type;
|
||||
//----------------------------------------------------------//
|
||||
// R828 Parameter //
|
||||
//----------------------------------------------------------//
|
||||
|
||||
extern UINT8 R828_ADDRESS;
|
||||
|
||||
#define DIP_FREQ 320000
|
||||
#define IMR_TRIAL 9
|
||||
#define VCO_pwr_ref 0x02
|
||||
|
||||
extern UINT32 R828_IF_khz;
|
||||
extern UINT32 R828_CAL_LO_khz;
|
||||
extern UINT8 R828_IMR_point_num;
|
||||
extern UINT8 R828_IMR_done_flag;
|
||||
extern UINT8 Rafael_Chip;
|
||||
|
||||
typedef enum _R828_Standard_Type //Don't remove standand list!!
|
||||
{
|
||||
NTSC_MN = 0,
|
||||
PAL_I,
|
||||
PAL_DK,
|
||||
PAL_B_7M, //no use
|
||||
PAL_BGH_8M, //for PAL B/G, PAL G/H
|
||||
SECAM_L,
|
||||
SECAM_L1_INV, //for SECAM L'
|
||||
SECAM_L1, //no use
|
||||
ATV_SIZE,
|
||||
DVB_T_6M = ATV_SIZE,
|
||||
DVB_T_7M,
|
||||
DVB_T_7M_2,
|
||||
DVB_T_8M,
|
||||
DVB_T2_6M,
|
||||
DVB_T2_7M,
|
||||
DVB_T2_7M_2,
|
||||
DVB_T2_8M,
|
||||
DVB_T2_1_7M,
|
||||
DVB_T2_10M,
|
||||
DVB_C_8M,
|
||||
DVB_C_6M,
|
||||
ISDB_T,
|
||||
DTMB,
|
||||
R828_ATSC,
|
||||
FM,
|
||||
STD_SIZE
|
||||
}R828_Standard_Type;
|
||||
|
||||
extern UINT8 R828_Fil_Cal_flag[STD_SIZE];
|
||||
|
||||
typedef enum _R828_SetFreq_Type
|
||||
{
|
||||
FAST_MODE = TRUE,
|
||||
NORMAL_MODE = FALSE
|
||||
}R828_SetFreq_Type;
|
||||
|
||||
typedef enum _R828_LoopThrough_Type
|
||||
{
|
||||
LOOP_THROUGH = TRUE,
|
||||
SIGLE_IN = FALSE
|
||||
}R828_LoopThrough_Type;
|
||||
|
||||
|
||||
typedef enum _R828_InputMode_Type
|
||||
{
|
||||
AIR_IN = 0,
|
||||
CABLE_IN_1,
|
||||
CABLE_IN_2
|
||||
}R828_InputMode_Type;
|
||||
|
||||
typedef enum _R828_IfAgc_Type
|
||||
{
|
||||
IF_AGC1 = 0,
|
||||
IF_AGC2
|
||||
}R828_IfAgc_Type;
|
||||
|
||||
typedef enum _R828_GPIO_Type
|
||||
{
|
||||
HI_SIG = TRUE,
|
||||
LO_SIG = FALSE
|
||||
}R828_GPIO_Type;
|
||||
|
||||
typedef struct _R828_Set_Info
|
||||
{
|
||||
UINT32 RF_Hz;
|
||||
UINT32 RF_KHz;
|
||||
R828_Standard_Type R828_Standard;
|
||||
R828_LoopThrough_Type RT_Input;
|
||||
R828_InputMode_Type RT_InputMode;
|
||||
R828_IfAgc_Type R828_IfAgc_Select;
|
||||
}R828_Set_Info;
|
||||
|
||||
typedef struct _R828_RF_Gain_Info
|
||||
{
|
||||
UINT8 RF_gain1;
|
||||
UINT8 RF_gain2;
|
||||
UINT8 RF_gain_comb;
|
||||
}R828_RF_Gain_Info;
|
||||
|
||||
typedef enum _R828_RF_Gain_TYPE
|
||||
{
|
||||
RF_AUTO = 0,
|
||||
RF_MANUAL
|
||||
}R828_RF_Gain_TYPE;
|
||||
|
||||
typedef struct _R828_I2C_LEN_TYPE
|
||||
{
|
||||
UINT8 RegAddr;
|
||||
UINT8 Data[50];
|
||||
UINT8 Len;
|
||||
}R828_I2C_LEN_TYPE;
|
||||
|
||||
typedef struct _R828_I2C_TYPE
|
||||
{
|
||||
UINT8 RegAddr;
|
||||
UINT8 Data;
|
||||
}R828_I2C_TYPE;
|
||||
//----------------------------------------------------------//
|
||||
// R828 Function //
|
||||
//----------------------------------------------------------//
|
||||
R828_ErrCode R828_Init(void *pTuner);
|
||||
R828_ErrCode R828_Standby(void *pTuner, R828_LoopThrough_Type R828_LoopSwitch);
|
||||
R828_ErrCode R828_GPIO(void *pTuner, R828_GPIO_Type R828_GPIO_Conrl);
|
||||
R828_ErrCode R828_SetStandard(void *pTuner, R828_Standard_Type RT_Standard);
|
||||
R828_ErrCode R828_SetFrequency(void *pTuner, R828_Set_Info R828_INFO, R828_SetFreq_Type R828_SetFreqMode);
|
||||
R828_ErrCode R828_GetRfGain(void *pTuner, R828_RF_Gain_Info *pR828_rf_gain);
|
||||
R828_ErrCode R828_SetRfGain(void *pTuner, int gain);
|
||||
R828_ErrCode R828_RfGainMode(void *pTuner, int manual);
|
||||
|
||||
int
|
||||
r820t_SetRfFreqHz(
|
||||
void *pTuner,
|
||||
unsigned long RfFreqHz
|
||||
);
|
||||
|
||||
int
|
||||
r820t_SetStandardMode(
|
||||
void *pTuner,
|
||||
int StandardMode
|
||||
);
|
||||
|
||||
int
|
||||
r820t_SetStandby(
|
||||
void *pTuner,
|
||||
int LoopThroughType
|
||||
);
|
||||
|
||||
#endif /* _R820T_TUNER_H */
|
|
@ -1,11 +0,0 @@
|
|||
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@
|
101
rtl-sdr.rules
101
rtl-sdr.rules
|
@ -1,101 +0,0 @@
|
|||
#
|
||||
# Copyright 2012 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"
|
||||
|
||||
# ezcap EzTV668 (E4000)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="2838", 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"
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00b4", MODE:="0666"
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00b7", MODE:="0666"
|
||||
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"
|
||||
|
||||
# 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"
|
||||
|
||||
# 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"
|
||||
|
||||
# Zaapa ZT-MINDVBZP (FC0012)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d398", MODE:="0666"
|
||||
|
||||
# Twintech UT-40 (FC0013)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d3a4", 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"
|
||||
|
||||
# Genius TVGo DVB-T03 USB dongle (Ver. B)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0458", ATTRS{idProduct}=="707f", 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"
|
||||
|
||||
# SVEON STV20 DVB-T USB & FM (FC0012)
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d39d", MODE:="0666"
|
||||
|
9
rtl433.pc.in
Normal file
9
rtl433.pc.in
Normal file
|
@ -0,0 +1,9 @@
|
|||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: RTL-433 Utility
|
||||
Description: C Utility
|
||||
Version: @VERSION@
|
||||
Cflags: -I${includedir}/ @RTL433_PC_CFLAGS@
|
|
@ -1,13 +1,9 @@
|
|||
# Copyright 2012 OSMOCOM Project
|
||||
#
|
||||
# This file is part of rtl-sdr
|
||||
#
|
||||
# GNU Radio is free software; you can redistribute it and/or modify
|
||||
# rtl_433 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,
|
||||
# rtl_433 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.
|
||||
|
@ -17,61 +13,9 @@
|
|||
# the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
########################################################################
|
||||
# Setup library
|
||||
########################################################################
|
||||
add_library(rtlsdr_shared SHARED
|
||||
librtlsdr.c
|
||||
tuner_e4k.c
|
||||
tuner_fc0012.c
|
||||
tuner_fc0013.c
|
||||
tuner_fc2580.c
|
||||
tuner_r820t.c
|
||||
)
|
||||
|
||||
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 0 VERSION 0.0.0)
|
||||
|
||||
add_library(rtlsdr_static STATIC
|
||||
librtlsdr.c
|
||||
tuner_e4k.c
|
||||
tuner_fc0012.c
|
||||
tuner_fc0013.c
|
||||
tuner_fc2580.c
|
||||
tuner_r820t.c
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
add_library(libgetopt_static STATIC
|
||||
getopt/getopt.c
|
||||
)
|
||||
endif()
|
||||
|
||||
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()
|
||||
|
||||
########################################################################
|
||||
# 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_433
|
||||
rtl_433.c
|
||||
devices/silvercrest.c
|
||||
|
@ -87,69 +31,21 @@ add_executable(rtl_433
|
|||
devices/intertechno.c
|
||||
devices/alecto.c
|
||||
devices/newkaku.c)
|
||||
|
||||
target_link_libraries(rtl_433
|
||||
${LIBRTLSDR_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
)
|
||||
|
||||
|
||||
set(INSTALL_TARGETS rtlsdr_shared rtlsdr_static rtl_sdr rtl_tcp rtl_test rtl_fm rtl_eeprom rtl_adsb rtl_433)
|
||||
|
||||
target_link_libraries(rtl_sdr rtlsdr_shared
|
||||
${LIBUSB_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
)
|
||||
target_link_libraries(rtl_tcp rtlsdr_shared
|
||||
${LIBUSB_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
)
|
||||
target_link_libraries(rtl_test rtlsdr_shared
|
||||
${LIBUSB_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
)
|
||||
target_link_libraries(rtl_fm rtlsdr_shared
|
||||
${LIBUSB_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
)
|
||||
target_link_libraries(rtl_433 rtlsdr_shared
|
||||
${LIBUSB_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
)
|
||||
target_link_libraries(rtl_eeprom rtlsdr_shared
|
||||
${LIBUSB_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
)
|
||||
target_link_libraries(rtl_adsb rtlsdr_shared
|
||||
${LIBUSB_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
)
|
||||
set(INSTALL_TARGETS rtl_433)
|
||||
if(UNIX)
|
||||
target_link_libraries(rtl_fm m)
|
||||
target_link_libraries(rtl_433 m)
|
||||
target_link_libraries(rtl_adsb 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 libgetopt_static)
|
||||
target_link_libraries(rtl_test libgetopt_static)
|
||||
target_link_libraries(rtl_fm libgetopt_static)
|
||||
target_link_libraries(rtl_433 libgetopt_static)
|
||||
target_link_libraries(rtl_eeprom libgetopt_static)
|
||||
target_link_libraries(rtl_adsb 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_433 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" )
|
||||
endif()
|
||||
########################################################################
|
||||
# Install built library files & utilities
|
||||
########################################################################
|
||||
install(TARGETS ${INSTALL_TARGETS}
|
||||
LIBRARY DESTINATION lib${LIB_SUFFIX} # .so/.dylib file
|
||||
ARCHIVE DESTINATION lib${LIB_SUFFIX} # .lib file
|
||||
RUNTIME DESTINATION bin # .dll file
|
||||
)
|
||||
|
|
|
@ -1,34 +1,21 @@
|
|||
# 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:0:0
|
||||
|
||||
INCLUDES = $(all_includes) -I$(top_srcdir)/include
|
||||
AM_CFLAGS = ${CFLAGS} -fPIC ${SYMBOL_VISIBILITY}
|
||||
|
||||
lib_LTLIBRARIES = librtlsdr.la
|
||||
bin_PROGRAMS = rtl_433
|
||||
|
||||
librtlsdr_la_SOURCES = librtlsdr.c tuner_e4k.c tuner_fc0012.c tuner_fc0013.c tuner_fc2580.c tuner_r820t.c
|
||||
librtlsdr_la_LDFLAGS = -version-info $(LIBVERSION)
|
||||
rtl_433_SOURCES = rtl_433.c \
|
||||
devices/acurite.c \
|
||||
devices/intertechno.c \
|
||||
devices/newkaku.c \
|
||||
devices/rubicson.c \
|
||||
devices/waveman.c \
|
||||
devices/alecto.c \
|
||||
devices/lacrosse.c \
|
||||
devices/oregon_scientific.c \
|
||||
devices/silvercrest.c \
|
||||
devices/elv.c \
|
||||
devices/mebus.c \
|
||||
devices/prologue.c \
|
||||
devices/steffen.c
|
||||
|
||||
bin_PROGRAMS = rtl_sdr rtl_tcp rtl_test rtl_fm rtl_eeprom rtl_adsb rtl_433
|
||||
|
||||
rtl_sdr_SOURCES = rtl_sdr.c
|
||||
rtl_sdr_LDADD = librtlsdr.la
|
||||
|
||||
rtl_tcp_SOURCES = rtl_tcp.c
|
||||
rtl_tcp_LDADD = librtlsdr.la
|
||||
|
||||
rtl_test_SOURCES = rtl_test.c
|
||||
rtl_test_LDADD = librtlsdr.la $(LIBM)
|
||||
|
||||
rtl_fm_SOURCES = rtl_fm.c
|
||||
rtl_fm_LDADD = librtlsdr.la $(LIBM)
|
||||
|
||||
rtl_eeprom_SOURCES = rtl_eeprom.c
|
||||
rtl_eeprom_LDADD = librtlsdr.la $(LIBM)
|
||||
|
||||
rtl_adsb_SOURCES = rtl_adsb.c
|
||||
rtl_adsb_LDADD = librtlsdr.la $(LIBM)
|
||||
|
||||
rtl_433_SOURCES = rtl_433.c
|
||||
rtl_433_LDADD = librtlsdr.la $(LIBM)
|
||||
rtl_433_LDADD = $(LIBRTLSDR) $(LIBM)
|
||||
|
|
1698
src/librtlsdr.c
1698
src/librtlsdr.c
File diff suppressed because it is too large
Load diff
512
src/rtl_adsb.c
512
src/rtl_adsb.c
|
@ -1,512 +0,0 @@
|
|||
/*
|
||||
* 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 <semaphore.h>
|
||||
#include <pthread.h>
|
||||
#include <libusb.h>
|
||||
|
||||
#include "rtl-sdr.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
|
||||
|
||||
static pthread_t demod_thread;
|
||||
static sem_t data_ready;
|
||||
static volatile int do_exit = 0;
|
||||
static rtlsdr_dev_t *dev = NULL;
|
||||
|
||||
/* look up table, could be made smaller */
|
||||
uint8_t pyth[129][129];
|
||||
|
||||
/* todo, bundle these up in a struct */
|
||||
uint8_t *buffer;
|
||||
int verbose_output = 0;
|
||||
int short_output = 0;
|
||||
double quality = 1.0;
|
||||
int allowed_errors = 5;
|
||||
FILE *file;
|
||||
int adsb_frame[14];
|
||||
#define preamble_len 16
|
||||
#define long_frame 112
|
||||
#define short_frame 56
|
||||
|
||||
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.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");
|
||||
}
|
||||
|
||||
void pyth_precompute(void)
|
||||
{
|
||||
int x, y;
|
||||
double scale = 1.408 ; /* use the full 8 bits */
|
||||
for (x=0; x<129; x++) {
|
||||
for (y=0; y<129; y++) {
|
||||
pyth[x][y] = (uint8_t)round(scale * sqrt(x*x + y*y));
|
||||
}}
|
||||
}
|
||||
|
||||
inline uint8_t abs8(uint8_t x)
|
||||
/* do not subtract 128 from the raw iq, this handles it */
|
||||
{
|
||||
if (x >= 128) {
|
||||
return x - 128;}
|
||||
return 128 - x;
|
||||
}
|
||||
|
||||
int magnitute(uint8_t *buf, int len)
|
||||
/* takes i/q, changes buf in place, returns new len */
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<len; i+=2) {
|
||||
buf[i/2] = pyth[abs8(buf[i])][abs8(buf[i+1])];
|
||||
}
|
||||
return len/2;
|
||||
}
|
||||
|
||||
inline uint8_t single_manchester(uint8_t a, uint8_t b, uint8_t c, uint8_t d)
|
||||
/* takes 4 consecutive real samples, return 0 or 1, 255 on error */
|
||||
{
|
||||
int bit, bit_p;
|
||||
bit_p = a > b;
|
||||
bit = c > d;
|
||||
|
||||
if (quality == 0.0) {
|
||||
return bit;}
|
||||
|
||||
if (quality == 0.5) {
|
||||
if ( bit && bit_p && b > c) {
|
||||
return 255;}
|
||||
if (!bit && !bit_p && b < c) {
|
||||
return 255;}
|
||||
return bit;
|
||||
}
|
||||
|
||||
if (quality == 1.0) {
|
||||
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 255;
|
||||
}
|
||||
|
||||
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 255;
|
||||
}
|
||||
|
||||
inline uint8_t min8(uint8_t a, uint8_t b)
|
||||
{
|
||||
return a<b ? a : b;
|
||||
}
|
||||
|
||||
inline uint8_t max8(uint8_t a, uint8_t b)
|
||||
{
|
||||
return a>b ? a : b;
|
||||
}
|
||||
|
||||
inline int preamble(uint8_t *buf, int len, int i)
|
||||
/* returns 0/1 for preamble at index i */
|
||||
{
|
||||
int i2;
|
||||
uint8_t low = 0;
|
||||
uint8_t high = 255;
|
||||
for (i2=0; i2<preamble_len; i2++) {
|
||||
switch (i2) {
|
||||
case 0:
|
||||
case 2:
|
||||
case 7:
|
||||
case 9:
|
||||
//high = min8(high, buf[i+i2]);
|
||||
high = buf[i+i2];
|
||||
break;
|
||||
default:
|
||||
//low = max8(low, buf[i+i2]);
|
||||
low = buf[i+i2];
|
||||
break;
|
||||
}
|
||||
if (high <= low) {
|
||||
return 0;}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void manchester(uint8_t *buf, int len)
|
||||
/* overwrites magnitude buffer with valid bits (255 on errors) */
|
||||
{
|
||||
/* a and b hold old values to verify local manchester */
|
||||
uint8_t a=0, b=0;
|
||||
uint8_t bit;
|
||||
int i, i2, start, errors;
|
||||
// todo, allow wrap across buffers
|
||||
i = 0;
|
||||
while (i < len) {
|
||||
/* find preamble */
|
||||
for ( ; i < (len - preamble_len); i++) {
|
||||
if (!preamble(buf, len, i)) {
|
||||
continue;}
|
||||
a = buf[i];
|
||||
b = buf[i+1];
|
||||
for (i2=0; i2<preamble_len; i2++) {
|
||||
buf[i+i2] = 253;}
|
||||
i += preamble_len;
|
||||
break;
|
||||
}
|
||||
i2 = start = i;
|
||||
errors = 0;
|
||||
/* mark bits until encoding breaks */
|
||||
for ( ; i < len; i+=2, i2++) {
|
||||
bit = single_manchester(a, b, buf[i], buf[i+1]);
|
||||
a = buf[i];
|
||||
b = buf[i+1];
|
||||
if (bit == 255) {
|
||||
errors += 1;
|
||||
if (errors > allowed_errors) {
|
||||
buf[i2] = 255;
|
||||
break;
|
||||
} else {
|
||||
bit = a > b;
|
||||
/* these don't have to match the bit */
|
||||
a = 0;
|
||||
b = 255;
|
||||
}
|
||||
}
|
||||
buf[i] = buf[i+1] = 254; /* to be overwritten */
|
||||
buf[i2] = bit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void messages(uint8_t *buf, int len)
|
||||
{
|
||||
int i, i2, start, preamble_found;
|
||||
int 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)
|
||||
{
|
||||
int dr_val;
|
||||
if (do_exit) {
|
||||
return;}
|
||||
memcpy(buffer, buf, len);
|
||||
sem_getvalue(&data_ready, &dr_val);
|
||||
if (dr_val <= 0) {
|
||||
sem_post(&data_ready);}
|
||||
}
|
||||
|
||||
static void *demod_thread_fn(void *arg)
|
||||
{
|
||||
int len;
|
||||
while (!do_exit) {
|
||||
sem_wait(&data_ready);
|
||||
len = magnitute(buffer, DEFAULT_BUF_LENGTH);
|
||||
manchester(buffer, len);
|
||||
messages(buffer, len);
|
||||
}
|
||||
rtlsdr_cancel_async(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
struct sigaction sigact;
|
||||
#endif
|
||||
char *filename = NULL;
|
||||
int n_read, r, opt;
|
||||
int i, gain = AUTO_GAIN; /* tenths of a dB */
|
||||
uint32_t dev_index = 0;
|
||||
int device_count;
|
||||
int ppm_error = 0;
|
||||
char vendor[256], product[256], serial[256];
|
||||
sem_init(&data_ready, 0, 0);
|
||||
pyth_precompute();
|
||||
|
||||
while ((opt = getopt(argc, argv, "d:g:p:e:Q:VS")) != -1)
|
||||
{
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
dev_index = atoi(optarg);
|
||||
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 = atof(optarg);
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc <= optind) {
|
||||
filename = "-";
|
||||
} else {
|
||||
filename = argv[optind];
|
||||
}
|
||||
|
||||
buffer = malloc(DEFAULT_BUF_LENGTH * sizeof(uint8_t));
|
||||
|
||||
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++) {
|
||||
rtlsdr_get_device_usb_strings(i, vendor, product, serial);
|
||||
fprintf(stderr, " %d: %s, %s, SN: %s\n", i, vendor, product, serial);
|
||||
}
|
||||
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);
|
||||
}
|
||||
#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) {
|
||||
r = rtlsdr_set_tuner_gain_mode(dev, 0);
|
||||
} else {
|
||||
r = rtlsdr_set_tuner_gain_mode(dev, 1);
|
||||
r = rtlsdr_set_tuner_gain(dev, gain);
|
||||
}
|
||||
if (r != 0) {
|
||||
fprintf(stderr, "WARNING: Failed to set tuner gain.\n");
|
||||
} else if (gain == AUTO_GAIN) {
|
||||
fprintf(stderr, "Tuner gain set to automatic.\n");
|
||||
} else {
|
||||
fprintf(stderr, "Tuner gain set to %0.2f dB.\n", gain/10.0);
|
||||
}
|
||||
|
||||
r = rtlsdr_set_freq_correction(dev, ppm_error);
|
||||
r = rtlsdr_set_agc_mode(dev, 1);
|
||||
|
||||
/* Set the tuner frequency */
|
||||
r = rtlsdr_set_center_freq(dev, ADSB_FREQ);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "WARNING: Failed to set center freq.\n");}
|
||||
else {
|
||||
fprintf(stderr, "Tuned to %u Hz.\n", ADSB_FREQ);}
|
||||
|
||||
/* Set the sample rate */
|
||||
fprintf(stderr, "Sampling at %u Hz.\n", ADSB_RATE);
|
||||
r = rtlsdr_set_sample_rate(dev, ADSB_RATE);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "WARNING: Failed to set sample rate.\n");}
|
||||
|
||||
/* 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");}
|
||||
|
||||
/* flush old junk */
|
||||
sleep(1);
|
||||
rtlsdr_read_sync(dev, NULL, 4096, NULL);
|
||||
|
||||
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);
|
||||
|
||||
if (file != stdout) {
|
||||
fclose(file);}
|
||||
|
||||
rtlsdr_close(dev);
|
||||
free(buffer);
|
||||
return r >= 0 ? r : -r;
|
||||
}
|
||||
|
423
src/rtl_eeprom.c
423
src/rtl_eeprom.c
|
@ -1,423 +0,0 @@
|
|||
/*
|
||||
* 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, "Configuration successfully written.\n");
|
||||
|
||||
exit:
|
||||
if (file)
|
||||
fclose(file);
|
||||
|
||||
rtlsdr_close(dev);
|
||||
|
||||
return r >= 0 ? r : -r;
|
||||
}
|
838
src/rtl_fm.c
838
src/rtl_fm.c
|
@ -1,838 +0,0 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* written because people could not do real time
|
||||
* FM demod on Atom hardware with GNU radio
|
||||
* based on rtl_sdr.c and rtl_tcp.c
|
||||
* todo: realtime ARMv5
|
||||
* remove float math (disqualifies complex.h)
|
||||
* in-place array operations
|
||||
* sanity checks
|
||||
* nicer FIR than square
|
||||
* scale squelch to other input parameters
|
||||
* test all the demodulations
|
||||
* pad output on hop
|
||||
* nearest gain approx
|
||||
* frequency ranges could be stored better
|
||||
*/
|
||||
|
||||
#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"
|
||||
#define usleep(x) Sleep(x/1000)
|
||||
#define round(x) (x > 0.0 ? floor(x + 0.5): ceil(x - 0.5))
|
||||
#endif
|
||||
|
||||
#include <semaphore.h>
|
||||
#include <pthread.h>
|
||||
#include <libusb.h>
|
||||
|
||||
#include "rtl-sdr.h"
|
||||
|
||||
#define DEFAULT_SAMPLE_RATE 24000
|
||||
#define DEFAULT_ASYNC_BUF_NUMBER 32
|
||||
#define DEFAULT_BUF_LENGTH (1 * 16384)
|
||||
#define MAXIMUM_OVERSAMPLE 16
|
||||
#define MAXIMUM_BUF_LENGTH (MAXIMUM_OVERSAMPLE * DEFAULT_BUF_LENGTH)
|
||||
#define AUTO_GAIN -100
|
||||
|
||||
static pthread_t demod_thread;
|
||||
static sem_t data_ready;
|
||||
static int do_exit = 0;
|
||||
static rtlsdr_dev_t *dev = NULL;
|
||||
static int lcm_post[17] = {1,1,1,3,1,5,3,7,1,9,5,11,3,13,7,15,1};
|
||||
|
||||
struct fm_state
|
||||
{
|
||||
int now_r;
|
||||
int now_j;
|
||||
int pre_r;
|
||||
int pre_j;
|
||||
int prev_index;
|
||||
int downsample; /* min 1, max 256 */
|
||||
int post_downsample;
|
||||
int output_scale;
|
||||
int squelch_level;
|
||||
int conseq_squelch;
|
||||
int squelch_hits;
|
||||
int terminate_on_squelch;
|
||||
int exit_flag;
|
||||
uint8_t buf[MAXIMUM_BUF_LENGTH];
|
||||
uint32_t buf_len;
|
||||
int signal[MAXIMUM_BUF_LENGTH]; /* 16 bit signed i/q pairs */
|
||||
int16_t signal2[MAXIMUM_BUF_LENGTH]; /* signal has lowpass, signal2 has demod */
|
||||
int signal_len;
|
||||
int signal2_len;
|
||||
FILE *file;
|
||||
int edge;
|
||||
uint32_t freqs[1000];
|
||||
int freq_len;
|
||||
int freq_now;
|
||||
uint32_t sample_rate;
|
||||
int output_rate;
|
||||
int fir_enable;
|
||||
int fir[256]; /* fir_len == downsample */
|
||||
int fir_sum;
|
||||
int custom_atan;
|
||||
int deemph;
|
||||
int deemph_a;
|
||||
int now_lpr;
|
||||
int prev_lpr_index;
|
||||
void (*mode_demod)(struct fm_state*);
|
||||
};
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"rtl_fm, a simple narrow band FM demodulator for RTL2832 based DVB-T receivers\n\n"
|
||||
"Use:\trtl_fm -f freq [-options] [filename]\n"
|
||||
"\t-f frequency_to_tune_to [Hz]\n"
|
||||
"\t (use multiple -f for scanning, requires squelch)\n"
|
||||
"\t (ranges supported, -f 118M:137M:25k)\n"
|
||||
"\t[-s sample_rate (default: 24k)]\n"
|
||||
"\t[-d device_index (default: 0)]\n"
|
||||
"\t[-g tuner_gain (default: automatic)]\n"
|
||||
"\t[-l squelch_level (default: 0/off)]\n"
|
||||
"\t[-o oversampling (default: 1, 4 recommended)]\n"
|
||||
"\t[-p ppm_error (default: 0)]\n"
|
||||
"\t[-E sets lower edge tuning (default: center)]\n"
|
||||
"\t[-N enables NBFM mode (default: on)]\n"
|
||||
"\t[-W enables WBFM mode (default: off)]\n"
|
||||
"\t (-N -s 170k -o 4 -A -r 32k -l 0 -D)\n"
|
||||
"\tfilename (a '-' dumps samples to stdout)\n"
|
||||
"\t (omitting the filename also uses stdout)\n\n"
|
||||
"Experimental options:\n"
|
||||
"\t[-r output_rate (default: same as -s)]\n"
|
||||
"\t[-t squelch_delay (default: 20)]\n"
|
||||
"\t (+values will mute/scan, -values will exit)\n"
|
||||
"\t[-M enables AM mode (default: off)]\n"
|
||||
"\t[-L enables LSB mode (default: off)]\n"
|
||||
"\t[-U enables USB mode (default: off)]\n"
|
||||
//"\t[-D enables DSB mode (default: off)]\n"
|
||||
"\t[-R enables raw mode (default: off, 2x16 bit output)]\n"
|
||||
"\t[-F enables high quality FIR (default: off/square)]\n"
|
||||
"\t[-D enables de-emphasis (default: off)]\n"
|
||||
"\t[-A enables high speed arctan (default: off)]\n\n"
|
||||
"Produces signed 16 bit ints, use Sox or aplay to hear them.\n"
|
||||
"\trtl_fm ... - | play -t raw -r 24k -e signed-integer -b 16 -c 1 -V1 -\n"
|
||||
"\t | aplay -r 24k -f S16_LE -t raw -c 1\n"
|
||||
"\t -s 22.5k - | multimon -t raw /dev/stdin\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 rotate_90(unsigned char *buf, uint32_t len)
|
||||
/* 90 rotation is 1+0j, 0+1j, -1+0j, 0-1j
|
||||
or [0, 1, -3, 2, -4, -5, 7, -6] */
|
||||
{
|
||||
uint32_t i;
|
||||
unsigned char tmp;
|
||||
for (i=0; i<len; i+=8) {
|
||||
/* uint8_t negation = 255 - x */
|
||||
tmp = 255 - buf[i+3];
|
||||
buf[i+3] = buf[i+2];
|
||||
buf[i+2] = tmp;
|
||||
|
||||
buf[i+4] = 255 - buf[i+4];
|
||||
buf[i+5] = 255 - buf[i+5];
|
||||
|
||||
tmp = 255 - buf[i+6];
|
||||
buf[i+6] = buf[i+7];
|
||||
buf[i+7] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
void low_pass(struct fm_state *fm, unsigned char *buf, uint32_t len)
|
||||
/* simple square window FIR */
|
||||
{
|
||||
int i=0, i2=0;
|
||||
while (i < (int)len) {
|
||||
fm->now_r += ((int)buf[i] - 128);
|
||||
fm->now_j += ((int)buf[i+1] - 128);
|
||||
i += 2;
|
||||
fm->prev_index++;
|
||||
if (fm->prev_index < fm->downsample) {
|
||||
continue;
|
||||
}
|
||||
fm->signal[i2] = fm->now_r * fm->output_scale;
|
||||
fm->signal[i2+1] = fm->now_j * fm->output_scale;
|
||||
fm->prev_index = 0;
|
||||
fm->now_r = 0;
|
||||
fm->now_j = 0;
|
||||
i2 += 2;
|
||||
}
|
||||
fm->signal_len = i2;
|
||||
}
|
||||
|
||||
void build_fir(struct fm_state *fm)
|
||||
/* for now, a simple triangle
|
||||
* fancy FIRs are equally expensive, so use one */
|
||||
/* point = sum(sample[i] * fir[i] * fir_len / fir_sum) */
|
||||
{
|
||||
int i, len;
|
||||
len = fm->downsample;
|
||||
for(i = 0; i < (len/2); i++) {
|
||||
fm->fir[i] = i;
|
||||
}
|
||||
for(i = len-1; i >= (len/2); i--) {
|
||||
fm->fir[i] = len - i;
|
||||
}
|
||||
fm->fir_sum = 0;
|
||||
for(i = 0; i < len; i++) {
|
||||
fm->fir_sum += fm->fir[i];
|
||||
}
|
||||
}
|
||||
|
||||
void low_pass_fir(struct fm_state *fm, unsigned char *buf, uint32_t len)
|
||||
/* perform an arbitrary FIR, doubles CPU use */
|
||||
// possibly bugged, or overflowing
|
||||
{
|
||||
int i=0, i2=0, i3=0;
|
||||
while (i < (int)len) {
|
||||
i3 = fm->prev_index;
|
||||
fm->now_r += ((int)buf[i] - 128) * fm->fir[i3] * fm->downsample / fm->fir_sum;
|
||||
fm->now_j += ((int)buf[i+1] - 128) * fm->fir[i3] * fm->downsample / fm->fir_sum;
|
||||
i += 2;
|
||||
fm->prev_index++;
|
||||
if (fm->prev_index < fm->downsample) {
|
||||
continue;
|
||||
}
|
||||
fm->signal[i2] = fm->now_r * fm->output_scale;
|
||||
fm->signal[i2+1] = fm->now_j * fm->output_scale;
|
||||
fm->prev_index = 0;
|
||||
fm->now_r = 0;
|
||||
fm->now_j = 0;
|
||||
i2 += 2;
|
||||
}
|
||||
fm->signal_len = i2;
|
||||
}
|
||||
|
||||
int low_pass_simple(int16_t *signal2, int len, int step)
|
||||
// no wrap around, length must be multiple of step
|
||||
{
|
||||
int i, i2, sum;
|
||||
for(i=0; i < len; i+=step) {
|
||||
sum = 0;
|
||||
for(i2=0; i2<step; i2++) {
|
||||
sum += (int)signal2[i + i2];
|
||||
}
|
||||
//signal2[i/step] = (int16_t)(sum / step);
|
||||
signal2[i/step] = (int16_t)(sum);
|
||||
}
|
||||
signal2[i/step + 1] = signal2[i/step];
|
||||
return len / step;
|
||||
}
|
||||
|
||||
void low_pass_real(struct fm_state *fm)
|
||||
/* simple square window FIR */
|
||||
// add support for upsampling?
|
||||
{
|
||||
int i=0, i2=0;
|
||||
int fast = (int)fm->sample_rate / fm->post_downsample;
|
||||
int slow = fm->output_rate;
|
||||
while (i < fm->signal2_len) {
|
||||
fm->now_lpr += fm->signal2[i];
|
||||
i++;
|
||||
fm->prev_lpr_index += slow;
|
||||
if (fm->prev_lpr_index < fast) {
|
||||
continue;
|
||||
}
|
||||
fm->signal2[i2] = (int16_t)(fm->now_lpr / (fast/slow));
|
||||
fm->prev_lpr_index -= fast;
|
||||
fm->now_lpr = 0;
|
||||
i2 += 1;
|
||||
}
|
||||
fm->signal2_len = i2;
|
||||
}
|
||||
|
||||
/* define our own complex math ops
|
||||
because ARMv5 has no hardware float */
|
||||
|
||||
void multiply(int ar, int aj, int br, int bj, int *cr, int *cj)
|
||||
{
|
||||
*cr = ar*br - aj*bj;
|
||||
*cj = aj*br + ar*bj;
|
||||
}
|
||||
|
||||
int polar_discriminant(int ar, int aj, int br, int bj)
|
||||
{
|
||||
int cr, cj;
|
||||
double angle;
|
||||
multiply(ar, aj, br, -bj, &cr, &cj);
|
||||
angle = atan2((double)cj, (double)cr);
|
||||
return (int)(angle / 3.14159 * (1<<14));
|
||||
}
|
||||
|
||||
int fast_atan2(int y, int x)
|
||||
/* pre scaled for int16 */
|
||||
{
|
||||
int yabs, angle;
|
||||
int pi4=(1<<12), pi34=3*(1<<12); // note pi = 1<<14
|
||||
if (x==0 && y==0) {
|
||||
return 0;
|
||||
}
|
||||
yabs = y;
|
||||
if (yabs < 0) {
|
||||
yabs = -yabs;
|
||||
}
|
||||
if (x >= 0) {
|
||||
angle = pi4 - pi4 * (x-yabs) / (x+yabs);
|
||||
} else {
|
||||
angle = pi34 - pi4 * (x+yabs) / (yabs-x);
|
||||
}
|
||||
if (y < 0) {
|
||||
return -angle;
|
||||
}
|
||||
return angle;
|
||||
}
|
||||
|
||||
int polar_disc_fast(int ar, int aj, int br, int bj)
|
||||
{
|
||||
int cr, cj;
|
||||
multiply(ar, aj, br, -bj, &cr, &cj);
|
||||
return fast_atan2(cj, cr);
|
||||
}
|
||||
|
||||
void fm_demod(struct fm_state *fm)
|
||||
{
|
||||
int i, pcm;
|
||||
pcm = polar_discriminant(fm->signal[0], fm->signal[1],
|
||||
fm->pre_r, fm->pre_j);
|
||||
fm->signal2[0] = (int16_t)pcm;
|
||||
for (i = 2; i < (fm->signal_len); i += 2) {
|
||||
if (fm->custom_atan) {
|
||||
pcm = polar_disc_fast(fm->signal[i], fm->signal[i+1],
|
||||
fm->signal[i-2], fm->signal[i-1]);
|
||||
} else {
|
||||
pcm = polar_discriminant(fm->signal[i], fm->signal[i+1],
|
||||
fm->signal[i-2], fm->signal[i-1]);
|
||||
}
|
||||
fm->signal2[i/2] = (int16_t)pcm;
|
||||
}
|
||||
fm->pre_r = fm->signal[fm->signal_len - 2];
|
||||
fm->pre_j = fm->signal[fm->signal_len - 1];
|
||||
fm->signal2_len = fm->signal_len/2;
|
||||
}
|
||||
|
||||
void am_demod(struct fm_state *fm)
|
||||
// todo, fix this extreme laziness
|
||||
{
|
||||
int i, pcm;
|
||||
for (i = 0; i < (fm->signal_len); i += 2) {
|
||||
// hypot uses floats but won't overflow
|
||||
//fm->signal2[i/2] = (int16_t)hypot(fm->signal[i], fm->signal[i+1]);
|
||||
pcm = fm->signal[i] * fm->signal[i];
|
||||
pcm += fm->signal[i+1] * fm->signal[i+1];
|
||||
fm->signal2[i/2] = (int16_t)sqrt(pcm); // * fm->output_scale;
|
||||
}
|
||||
fm->signal2_len = fm->signal_len/2;
|
||||
// lowpass? (3khz) highpass? (dc)
|
||||
}
|
||||
|
||||
void usb_demod(struct fm_state *fm)
|
||||
{
|
||||
int i, pcm;
|
||||
for (i = 0; i < (fm->signal_len); i += 2) {
|
||||
pcm = fm->signal[i] + fm->signal[i+1];
|
||||
fm->signal2[i/2] = (int16_t)pcm; // * fm->output_scale;
|
||||
}
|
||||
fm->signal2_len = fm->signal_len/2;
|
||||
}
|
||||
|
||||
void lsb_demod(struct fm_state *fm)
|
||||
{
|
||||
int i, pcm;
|
||||
for (i = 0; i < (fm->signal_len); i += 2) {
|
||||
pcm = fm->signal[i] - fm->signal[i+1];
|
||||
fm->signal2[i/2] = (int16_t)pcm; // * fm->output_scale;
|
||||
}
|
||||
fm->signal2_len = fm->signal_len/2;
|
||||
}
|
||||
|
||||
void raw_demod(struct fm_state *fm)
|
||||
{
|
||||
/* hacky and pointless code */
|
||||
int i;
|
||||
for (i = 0; i < (fm->signal_len); i++) {
|
||||
fm->signal2[i] = (int16_t)fm->signal[i];
|
||||
}
|
||||
fm->signal2_len = fm->signal_len;
|
||||
}
|
||||
|
||||
void deemph_filter(struct fm_state *fm)
|
||||
{
|
||||
static int avg; // cheating...
|
||||
int i, d;
|
||||
// de-emph IIR
|
||||
// avg = avg * (1 - alpha) + sample * alpha;
|
||||
for (i = 0; i < fm->signal2_len; i++) {
|
||||
d = fm->signal2[i] - avg;
|
||||
if (d > 0) {
|
||||
avg += (d + fm->deemph_a/2) / fm->deemph_a;
|
||||
} else {
|
||||
avg += (d - fm->deemph_a/2) / fm->deemph_a;
|
||||
}
|
||||
fm->signal2[i] = (int16_t)avg;
|
||||
}
|
||||
}
|
||||
|
||||
int mad(int *samples, int len, int step)
|
||||
/* mean average deviation */
|
||||
{
|
||||
int i=0, sum=0, ave=0;
|
||||
if (len == 0)
|
||||
{return 0;}
|
||||
for (i=0; i<len; i+=step) {
|
||||
sum += samples[i];
|
||||
}
|
||||
ave = sum / (len * step);
|
||||
sum = 0;
|
||||
for (i=0; i<len; i+=step) {
|
||||
sum += abs(samples[i] - ave);
|
||||
}
|
||||
return sum / (len / step);
|
||||
}
|
||||
|
||||
int post_squelch(struct fm_state *fm)
|
||||
/* returns 1 for active signal, 0 for no signal */
|
||||
{
|
||||
int dev_r, dev_j, len, sq_l;
|
||||
/* only for small samples, big samples need chunk processing */
|
||||
len = fm->signal_len;
|
||||
sq_l = fm->squelch_level;
|
||||
dev_r = mad(&(fm->signal[0]), len, 2);
|
||||
dev_j = mad(&(fm->signal[1]), len, 2);
|
||||
if ((dev_r > sq_l) || (dev_j > sq_l)) {
|
||||
fm->squelch_hits = 0;
|
||||
return 1;
|
||||
}
|
||||
fm->squelch_hits++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void optimal_settings(struct fm_state *fm, int freq, int hopping)
|
||||
{
|
||||
int r, capture_freq, capture_rate;
|
||||
fm->downsample = (1000000 / fm->sample_rate) + 1;
|
||||
fm->freq_now = freq;
|
||||
capture_rate = fm->downsample * fm->sample_rate;
|
||||
capture_freq = fm->freqs[freq] + capture_rate/4;
|
||||
capture_freq += fm->edge * fm->sample_rate / 2;
|
||||
fm->output_scale = (1<<15) / (128 * fm->downsample);
|
||||
if (fm->output_scale < 1) {
|
||||
fm->output_scale = 1;}
|
||||
fm->output_scale = 1;
|
||||
/* Set the frequency */
|
||||
r = rtlsdr_set_center_freq(dev, (uint32_t)capture_freq);
|
||||
if (hopping) {
|
||||
return;}
|
||||
fprintf(stderr, "Oversampling input by: %ix.\n", fm->downsample);
|
||||
fprintf(stderr, "Oversampling output by: %ix.\n", fm->post_downsample);
|
||||
fprintf(stderr, "Buffer size: %0.2fms\n",
|
||||
1000 * 0.5 * lcm_post[fm->post_downsample] * (float)DEFAULT_BUF_LENGTH / (float)capture_rate);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "WARNING: Failed to set center freq.\n");}
|
||||
else {
|
||||
fprintf(stderr, "Tuned to %u Hz.\n", capture_freq);}
|
||||
|
||||
/* Set the sample rate */
|
||||
fprintf(stderr, "Sampling at %u Hz.\n", capture_rate);
|
||||
if (fm->output_rate > 0) {
|
||||
fprintf(stderr, "Output at %u Hz.\n", fm->output_rate);
|
||||
} else {
|
||||
fprintf(stderr, "Output at %u Hz.\n", fm->sample_rate/fm->post_downsample);}
|
||||
r = rtlsdr_set_sample_rate(dev, (uint32_t)capture_rate);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "WARNING: Failed to set sample rate.\n");}
|
||||
|
||||
}
|
||||
|
||||
void full_demod(struct fm_state *fm)
|
||||
{
|
||||
int i, sr, freq_next, hop = 0;
|
||||
rotate_90(fm->buf, fm->buf_len);
|
||||
if (fm->fir_enable) {
|
||||
low_pass_fir(fm, fm->buf, fm->buf_len);
|
||||
} else {
|
||||
low_pass(fm, fm->buf, fm->buf_len);
|
||||
}
|
||||
fm->mode_demod(fm);
|
||||
if (fm->mode_demod == &raw_demod) {
|
||||
fwrite(fm->signal2, 2, fm->signal2_len, fm->file);
|
||||
return;
|
||||
}
|
||||
sr = post_squelch(fm);
|
||||
if (!sr && fm->squelch_hits > fm->conseq_squelch) {
|
||||
if (fm->terminate_on_squelch) {
|
||||
fm->exit_flag = 1;}
|
||||
if (fm->freq_len == 1) { /* mute */
|
||||
for (i=0; i<fm->signal_len; i++) {
|
||||
fm->signal2[i] = 0;}
|
||||
}
|
||||
else {
|
||||
hop = 1;}
|
||||
}
|
||||
if (fm->post_downsample > 1) {
|
||||
fm->signal2_len = low_pass_simple(fm->signal2, fm->signal2_len, fm->post_downsample);}
|
||||
if (fm->output_rate > 0) {
|
||||
low_pass_real(fm);
|
||||
}
|
||||
if (fm->deemph) {
|
||||
deemph_filter(fm);}
|
||||
/* ignore under runs for now */
|
||||
fwrite(fm->signal2, 2, fm->signal2_len, fm->file);
|
||||
if (hop) {
|
||||
freq_next = (fm->freq_now + 1) % fm->freq_len;
|
||||
optimal_settings(fm, freq_next, 1);
|
||||
fm->squelch_hits = fm->conseq_squelch + 1; /* hair trigger */
|
||||
/* wait for settling and flush buffer */
|
||||
usleep(5000);
|
||||
rtlsdr_read_sync(dev, NULL, 4096, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
|
||||
{
|
||||
struct fm_state *fm2 = ctx;
|
||||
int dr_val;
|
||||
if (do_exit) {
|
||||
return;}
|
||||
if (!ctx) {
|
||||
return;}
|
||||
memcpy(fm2->buf, buf, len);
|
||||
fm2->buf_len = len;
|
||||
/* single threaded uses 25% less CPU? */
|
||||
/* full_demod(fm2); */
|
||||
sem_getvalue(&data_ready, &dr_val);
|
||||
if (dr_val <= 0) {
|
||||
sem_post(&data_ready);}
|
||||
}
|
||||
|
||||
static void *demod_thread_fn(void *arg)
|
||||
{
|
||||
struct fm_state *fm2 = arg;
|
||||
while (!do_exit) {
|
||||
sem_wait(&data_ready);
|
||||
full_demod(fm2);
|
||||
if (fm2->exit_flag) {
|
||||
do_exit = 1;
|
||||
rtlsdr_cancel_async(dev);}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
double atofs(char* f)
|
||||
/* standard suffixes */
|
||||
{
|
||||
char* chop;
|
||||
double suff = 1.0;
|
||||
chop = malloc((strlen(f)+1)*sizeof(char));
|
||||
strncpy(chop, f, strlen(f)-1);
|
||||
switch (f[strlen(f)-1]) {
|
||||
case 'G':
|
||||
suff *= 1e3;
|
||||
case 'M':
|
||||
suff *= 1e3;
|
||||
case 'k':
|
||||
suff *= 1e3;
|
||||
suff *= atof(chop);}
|
||||
free(chop);
|
||||
if (suff != 1.0) {
|
||||
return suff;}
|
||||
return atof(f);
|
||||
}
|
||||
|
||||
void frequency_range(struct fm_state *fm, char *arg)
|
||||
{
|
||||
char *start, *stop, *step;
|
||||
int i;
|
||||
start = arg;
|
||||
stop = strchr(start, ':') + 1;
|
||||
stop[-1] = '\0';
|
||||
step = strchr(stop, ':') + 1;
|
||||
step[-1] = '\0';
|
||||
for(i=(int)atofs(start); i<=(int)atofs(stop); i+=(int)atofs(step))
|
||||
{
|
||||
fm->freqs[fm->freq_len] = (uint32_t)i;
|
||||
fm->freq_len++;
|
||||
}
|
||||
stop[-1] = ':';
|
||||
step[-1] = ':';
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
struct sigaction sigact;
|
||||
#endif
|
||||
struct fm_state fm;
|
||||
char *filename = NULL;
|
||||
int n_read, r, opt, wb_mode = 0;
|
||||
int i, gain = AUTO_GAIN; // tenths of a dB
|
||||
uint8_t *buffer;
|
||||
uint32_t dev_index = 0;
|
||||
int device_count;
|
||||
int ppm_error = 0;
|
||||
char vendor[256], product[256], serial[256];
|
||||
fm.freqs[0] = 100000000;
|
||||
fm.sample_rate = DEFAULT_SAMPLE_RATE;
|
||||
fm.squelch_level = 0;
|
||||
fm.conseq_squelch = 20;
|
||||
fm.terminate_on_squelch = 0;
|
||||
fm.freq_len = 0;
|
||||
fm.edge = 0;
|
||||
fm.fir_enable = 0;
|
||||
fm.prev_index = 0;
|
||||
fm.post_downsample = 1; // once this works, default = 4
|
||||
fm.custom_atan = 0;
|
||||
fm.deemph = 0;
|
||||
fm.output_rate = -1; // flag for disabled
|
||||
fm.mode_demod = &fm_demod;
|
||||
sem_init(&data_ready, 0, 0);
|
||||
|
||||
while ((opt = getopt(argc, argv, "d:f:g:s:b:l:o:t:r:p:EFANWMULRD")) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
dev_index = atoi(optarg);
|
||||
break;
|
||||
case 'f':
|
||||
if (strchr(optarg, ':'))
|
||||
{frequency_range(&fm, optarg);}
|
||||
else
|
||||
{
|
||||
fm.freqs[fm.freq_len] = (uint32_t)atofs(optarg);
|
||||
fm.freq_len++;
|
||||
}
|
||||
break;
|
||||
case 'g':
|
||||
gain = (int)(atof(optarg) * 10);
|
||||
break;
|
||||
case 'l':
|
||||
fm.squelch_level = (int)atof(optarg);
|
||||
break;
|
||||
case 's':
|
||||
fm.sample_rate = (uint32_t)atofs(optarg);
|
||||
break;
|
||||
case 'r':
|
||||
fm.output_rate = (int)atofs(optarg);
|
||||
break;
|
||||
case 'o':
|
||||
fm.post_downsample = (int)atof(optarg);
|
||||
if (fm.post_downsample < 1 || fm.post_downsample > MAXIMUM_OVERSAMPLE) {
|
||||
fprintf(stderr, "Oversample must be between 1 and %i\n", MAXIMUM_OVERSAMPLE);}
|
||||
break;
|
||||
case 't':
|
||||
fm.conseq_squelch = (int)atof(optarg);
|
||||
if (fm.conseq_squelch < 0) {
|
||||
fm.conseq_squelch = -fm.conseq_squelch;
|
||||
fm.terminate_on_squelch = 1;
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
ppm_error = atoi(optarg);
|
||||
break;
|
||||
case 'E':
|
||||
fm.edge = 1;
|
||||
break;
|
||||
case 'F':
|
||||
fm.fir_enable = 1;
|
||||
break;
|
||||
case 'A':
|
||||
fm.custom_atan = 1;
|
||||
break;
|
||||
case 'D':
|
||||
fm.deemph = 1;
|
||||
break;
|
||||
case 'N':
|
||||
fm.mode_demod = &fm_demod;
|
||||
break;
|
||||
case 'W':
|
||||
wb_mode = 1;
|
||||
fm.mode_demod = &fm_demod;
|
||||
fm.sample_rate = 170000;
|
||||
fm.output_rate = 32000;
|
||||
fm.custom_atan = 1;
|
||||
fm.post_downsample = 4;
|
||||
fm.deemph = 1;
|
||||
fm.squelch_level = 0;
|
||||
break;
|
||||
case 'M':
|
||||
fm.mode_demod = &am_demod;
|
||||
break;
|
||||
case 'U':
|
||||
fm.mode_demod = &usb_demod;
|
||||
break;
|
||||
case 'L':
|
||||
fm.mode_demod = &lsb_demod;
|
||||
break;
|
||||
case 'R':
|
||||
fm.mode_demod = &raw_demod;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* quadruple sample_rate to limit to Δθ to ±π/2 */
|
||||
fm.sample_rate *= fm.post_downsample;
|
||||
|
||||
if (fm.freq_len > 1) {
|
||||
fm.terminate_on_squelch = 0;
|
||||
}
|
||||
|
||||
if (argc <= optind) {
|
||||
//usage();
|
||||
filename = "-";
|
||||
} else {
|
||||
filename = argv[optind];
|
||||
}
|
||||
|
||||
buffer = malloc(lcm_post[fm.post_downsample] * DEFAULT_BUF_LENGTH * sizeof(uint8_t));
|
||||
|
||||
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++) {
|
||||
rtlsdr_get_device_usb_strings(i, vendor, product, serial);
|
||||
fprintf(stderr, " %d: %s, %s, SN: %s\n", i, vendor, product, serial);
|
||||
}
|
||||
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);
|
||||
}
|
||||
#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
|
||||
|
||||
/* WBFM is special */
|
||||
if (wb_mode) {
|
||||
fm.freqs[0] += 16000;
|
||||
}
|
||||
|
||||
if (fm.deemph) {
|
||||
fm.deemph_a = (int)round(1.0/((1.0-exp(-1.0/(fm.output_rate * 75e-6)))));
|
||||
}
|
||||
|
||||
optimal_settings(&fm, 0, 0);
|
||||
build_fir(&fm);
|
||||
|
||||
/* Set the tuner gain */
|
||||
if (gain == AUTO_GAIN) {
|
||||
r = rtlsdr_set_tuner_gain_mode(dev, 0);
|
||||
} else {
|
||||
r = rtlsdr_set_tuner_gain_mode(dev, 1);
|
||||
r = rtlsdr_set_tuner_gain(dev, gain);
|
||||
}
|
||||
if (r != 0) {
|
||||
fprintf(stderr, "WARNING: Failed to set tuner gain.\n");
|
||||
} else if (gain == AUTO_GAIN) {
|
||||
fprintf(stderr, "Tuner gain set to automatic.\n");
|
||||
} else {
|
||||
fprintf(stderr, "Tuner gain set to %0.2f dB.\n", gain/10.0);
|
||||
}
|
||||
r = rtlsdr_set_freq_correction(dev, ppm_error);
|
||||
|
||||
if (strcmp(filename, "-") == 0) { /* Write samples to stdout */
|
||||
fm.file = stdout;
|
||||
#ifdef _WIN32
|
||||
_setmode(_fileno(fm.file), _O_BINARY);
|
||||
#endif
|
||||
} else {
|
||||
fm.file = fopen(filename, "wb");
|
||||
if (!fm.file) {
|
||||
fprintf(stderr, "Failed to open %s\n", filename);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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_create(&demod_thread, NULL, demod_thread_fn, (void *)(&fm));
|
||||
rtlsdr_read_async(dev, rtlsdr_callback, (void *)(&fm),
|
||||
DEFAULT_ASYNC_BUF_NUMBER,
|
||||
lcm_post[fm.post_downsample] * 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);
|
||||
|
||||
if (fm.file != stdout) {
|
||||
fclose(fm.file);}
|
||||
|
||||
rtlsdr_close(dev);
|
||||
free (buffer);
|
||||
return r >= 0 ? r : -r;
|
||||
}
|
297
src/rtl_sdr.c
297
src/rtl_sdr.c
|
@ -1,297 +0,0 @@
|
|||
/*
|
||||
* 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"
|
||||
|
||||
#define DEFAULT_SAMPLE_RATE 2048000
|
||||
#define DEFAULT_ASYNC_BUF_NUMBER 32
|
||||
#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[-s samplerate (default: 2048000 Hz)]\n"
|
||||
"\t[-d device_index (default: 0)]\n"
|
||||
"\t[-g gain (default: 0 for auto)]\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 i, gain = 0;
|
||||
int sync_mode = 0;
|
||||
FILE *file;
|
||||
uint8_t *buffer;
|
||||
uint32_t dev_index = 0;
|
||||
uint32_t frequency = 100000000;
|
||||
uint32_t samp_rate = DEFAULT_SAMPLE_RATE;
|
||||
uint32_t out_block_size = DEFAULT_BUF_LENGTH;
|
||||
int device_count;
|
||||
char vendor[256], product[256], serial[256];
|
||||
|
||||
while ((opt = getopt(argc, argv, "d:f:g:s:b:n:S::")) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
dev_index = atoi(optarg);
|
||||
break;
|
||||
case 'f':
|
||||
frequency = (uint32_t)atof(optarg);
|
||||
break;
|
||||
case 'g':
|
||||
gain = (int)(atof(optarg) * 10); /* tenths of a dB */
|
||||
break;
|
||||
case 's':
|
||||
samp_rate = (uint32_t)atof(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;
|
||||
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));
|
||||
|
||||
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++) {
|
||||
rtlsdr_get_device_usb_strings(i, vendor, product, serial);
|
||||
fprintf(stderr, " %d: %s, %s, SN: %s\n", i, vendor, product, serial);
|
||||
}
|
||||
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);
|
||||
}
|
||||
#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 */
|
||||
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 %u Hz.\n", frequency);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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) */
|
||||
r = rtlsdr_reset_buffer(dev);
|
||||
if (r < 0)
|
||||
fprintf(stderr, "WARNING: Failed to reset buffers.\n");
|
||||
|
||||
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,
|
||||
DEFAULT_ASYNC_BUF_NUMBER, 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;
|
||||
}
|
604
src/rtl_tcp.c
604
src/rtl_tcp.c
|
@ -1,604 +0,0 @@
|
|||
/*
|
||||
* 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>
|
||||
*
|
||||
* 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"
|
||||
|
||||
#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 volatile int dead[2] = {0, 0};
|
||||
|
||||
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;
|
||||
|
||||
int global_numq = 0;
|
||||
static struct llist *ll_buffers = 0;
|
||||
|
||||
static int do_exit = 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[-g gain (default: 0 for auto)]\n"
|
||||
"\t[-s samplerate in Hz (default: 2048000 Hz)]\n"
|
||||
"\t[-b number of buffers (default: 32, set by library)]\n"
|
||||
"\t[-d device index (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;
|
||||
tmp -= 11644473600000000Ui64;
|
||||
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");
|
||||
if (!do_exit) {
|
||||
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++;
|
||||
}
|
||||
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);
|
||||
dead[0]=1;
|
||||
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);
|
||||
if (bytessent == SOCKET_ERROR) {
|
||||
perror("worker socket error");
|
||||
sighandler(0);
|
||||
dead[0]=1;
|
||||
pthread_exit(NULL);
|
||||
} else if (do_exit) {
|
||||
printf("do_exit\n");
|
||||
dead[0]=1;
|
||||
pthread_exit(NULL);
|
||||
} else {
|
||||
bytesleft -= bytessent;
|
||||
index += bytessent;
|
||||
}
|
||||
} else if(do_exit) {
|
||||
printf("worker socket bye\n");
|
||||
sighandler(0);
|
||||
dead[0]=1;
|
||||
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;
|
||||
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);
|
||||
if(received == SOCKET_ERROR){
|
||||
perror("comm recv socket error");
|
||||
sighandler(0);
|
||||
dead[1]=1;
|
||||
pthread_exit(NULL);
|
||||
} else if(do_exit){
|
||||
printf("do exit\n");
|
||||
dead[1]=1;
|
||||
pthread_exit(NULL);
|
||||
} else {
|
||||
left -= received;
|
||||
}
|
||||
} else if(do_exit) {
|
||||
printf("comm recv bye\n");
|
||||
sighandler(0);
|
||||
dead[1] = 1;
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
}
|
||||
switch(cmd.cmd) {
|
||||
case 0x01:
|
||||
printf("set freq %d\n", ntohl(cmd.param));
|
||||
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, tmp & 0xffff);
|
||||
rtlsdr_set_tuner_if_gain(dev, tmp >> 16, 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));
|
||||
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;
|
||||
int device_count;
|
||||
uint32_t dev_index = 0, buf_num = 0;
|
||||
int gain = 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:d:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
dev_index = atoi(optarg);
|
||||
break;
|
||||
case 'f':
|
||||
frequency = (uint32_t)atof(optarg);
|
||||
break;
|
||||
case 'g':
|
||||
gain = (int)(atof(optarg) * 10); /* tenths of a dB */
|
||||
break;
|
||||
case 's':
|
||||
samp_rate = (uint32_t)atof(optarg);
|
||||
break;
|
||||
case 'a':
|
||||
addr = optarg;
|
||||
break;
|
||||
case 'p':
|
||||
port = atoi(optarg);
|
||||
break;
|
||||
case 'b':
|
||||
buf_num = atoi(optarg);
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc < optind)
|
||||
usage();
|
||||
|
||||
device_count = rtlsdr_get_device_count();
|
||||
if (!device_count) {
|
||||
fprintf(stderr, "No supported devices found.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("Found %d device(s).\n", device_count);
|
||||
|
||||
rtlsdr_open(&dev, dev_index);
|
||||
if (NULL == dev) {
|
||||
fprintf(stderr, "Failed to open rtlsdr device #%d.\n", dev_index);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("Using %s\n", rtlsdr_get_device_name(dev_index));
|
||||
#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 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 == 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);
|
||||
|
||||
if(!dead[0])
|
||||
pthread_join(tcp_worker_thread, &status);
|
||||
dead[0]=0;
|
||||
|
||||
if(!dead[1])
|
||||
pthread_join(command_thread, &status);
|
||||
dead[1]=0;
|
||||
|
||||
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;
|
||||
}
|
379
src/rtl_test.c
379
src/rtl_test.c
|
@ -1,379 +0,0 @@
|
|||
/*
|
||||
* 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>
|
||||
#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"
|
||||
|
||||
#define DEFAULT_SAMPLE_RATE 2048000
|
||||
#define DEFAULT_ASYNC_BUF_NUMBER 32
|
||||
#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
|
||||
|
||||
static int do_exit = 0;
|
||||
static rtlsdr_dev_t *dev = NULL;
|
||||
|
||||
static int ppm_benchmark = 0;
|
||||
static int64_t ppm_count = 0L;
|
||||
static int64_t ppm_total = 0L;
|
||||
|
||||
#ifndef _WIN32
|
||||
static struct timespec ppm_start;
|
||||
static struct timespec ppm_recent;
|
||||
static struct timespec ppm_now;
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
static struct timeval tv;
|
||||
#endif
|
||||
|
||||
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 enable PPM error measurement]\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
|
||||
|
||||
uint8_t bcnt, uninit = 1;
|
||||
|
||||
static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
|
||||
{
|
||||
uint32_t i, lost = 0;
|
||||
int64_t ns;
|
||||
|
||||
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++;
|
||||
}
|
||||
|
||||
if (lost)
|
||||
printf("lost at least %d bytes\n", lost);
|
||||
|
||||
if (!ppm_benchmark) {
|
||||
return;
|
||||
}
|
||||
ppm_count += (int64_t)len;
|
||||
#ifndef _WIN32
|
||||
#ifndef __APPLE__
|
||||
clock_gettime(CLOCK_REALTIME, &ppm_now);
|
||||
#else
|
||||
gettimeofday(&tv, NULL);
|
||||
ppm_now.tv_sec = tv.tv_sec;
|
||||
ppm_now.tv_nsec = tv.tv_usec*1000;
|
||||
#endif
|
||||
if (ppm_now.tv_sec - ppm_recent.tv_sec > PPM_DURATION) {
|
||||
ns = 1000000000L * (int64_t)(ppm_now.tv_sec - ppm_recent.tv_sec);
|
||||
ns += (int64_t)(ppm_now.tv_nsec - ppm_recent.tv_nsec);
|
||||
printf("real sample rate: %i\n",
|
||||
(int)((1000000000L * ppm_count / 2L) / ns));
|
||||
#ifndef __APPLE__
|
||||
clock_gettime(CLOCK_REALTIME, &ppm_recent);
|
||||
#else
|
||||
gettimeofday(&tv, NULL);
|
||||
ppm_recent.tv_sec = tv.tv_sec;
|
||||
ppm_recent.tv_nsec = tv.tv_usec*1000;
|
||||
#endif
|
||||
ppm_total += ppm_count / 2L;
|
||||
ppm_count = 0L;
|
||||
}
|
||||
#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;
|
||||
int r, opt;
|
||||
int i, tuner_benchmark = 0;
|
||||
int sync_mode = 0;
|
||||
uint8_t *buffer;
|
||||
uint32_t dev_index = 0;
|
||||
uint32_t samp_rate = DEFAULT_SAMPLE_RATE;
|
||||
uint32_t out_block_size = DEFAULT_BUF_LENGTH;
|
||||
int device_count;
|
||||
int count;
|
||||
int gains[100];
|
||||
int real_rate;
|
||||
int64_t ns;
|
||||
|
||||
while ((opt = getopt(argc, argv, "d:s:b:tpS::")) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
dev_index = atoi(optarg);
|
||||
break;
|
||||
case 's':
|
||||
samp_rate = (uint32_t)atof(optarg);
|
||||
break;
|
||||
case 'b':
|
||||
out_block_size = (uint32_t)atof(optarg);
|
||||
break;
|
||||
case 't':
|
||||
tuner_benchmark = 1;
|
||||
break;
|
||||
case 'p':
|
||||
ppm_benchmark = PPM_DURATION;
|
||||
break;
|
||||
case 'S':
|
||||
sync_mode = 1;
|
||||
break;
|
||||
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));
|
||||
|
||||
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);
|
||||
}
|
||||
#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 */
|
||||
r = rtlsdr_set_sample_rate(dev, samp_rate);
|
||||
if (r < 0)
|
||||
fprintf(stderr, "WARNING: Failed to set sample rate.\n");
|
||||
|
||||
if (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) */
|
||||
r = rtlsdr_reset_buffer(dev);
|
||||
if (r < 0)
|
||||
fprintf(stderr, "WARNING: Failed to reset buffers.\n");
|
||||
|
||||
if (ppm_benchmark && !sync_mode) {
|
||||
fprintf(stderr, "Reporting PPM error measurement every %i seconds...\n", ppm_benchmark);
|
||||
fprintf(stderr, "Press ^C after a few minutes.\n");
|
||||
#ifdef __APPLE__
|
||||
gettimeofday(&tv, NULL);
|
||||
ppm_recent.tv_sec = tv.tv_sec;
|
||||
ppm_recent.tv_nsec = tv.tv_usec*1000;
|
||||
ppm_start.tv_sec = tv.tv_sec;
|
||||
ppm_start.tv_nsec = tv.tv_usec*1000;
|
||||
#elif __unix__
|
||||
clock_gettime(CLOCK_REALTIME, &ppm_recent);
|
||||
clock_gettime(CLOCK_REALTIME, &ppm_start);
|
||||
#endif
|
||||
}
|
||||
|
||||
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 ((uint32_t)n_read < out_block_size) {
|
||||
fprintf(stderr, "Short read, samples lost, exiting!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Reading samples in async mode...\n");
|
||||
r = rtlsdr_read_async(dev, rtlsdr_callback, NULL,
|
||||
DEFAULT_ASYNC_BUF_NUMBER, out_block_size);
|
||||
}
|
||||
|
||||
if (do_exit) {
|
||||
fprintf(stderr, "\nUser cancel, exiting...\n");
|
||||
if (ppm_benchmark) {
|
||||
#ifndef _WIN32
|
||||
ns = 1000000000L * (int64_t)(ppm_recent.tv_sec - ppm_start.tv_sec);
|
||||
ns += (int64_t)(ppm_recent.tv_nsec - ppm_start.tv_nsec);
|
||||
real_rate = (int)(ppm_total * 1000000000L / ns);
|
||||
printf("Cumulative PPM error: %i\n",
|
||||
(int)round((double)(1000000 * (real_rate - (int)samp_rate)) / (double)samp_rate));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
fprintf(stderr, "\nLibrary error %d, exiting...\n", r);
|
||||
|
||||
exit:
|
||||
rtlsdr_close(dev);
|
||||
free (buffer);
|
||||
|
||||
return r >= 0 ? r : -r;
|
||||
}
|
978
src/tuner_e4k.c
978
src/tuner_e4k.c
|
@ -1,978 +0,0 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <reg_field.h>
|
||||
#include <tuner_e4k.h>
|
||||
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
|
||||
/* If this is defined, the limits are somewhat relaxed compared to what the
|
||||
* vendor claims is possible */
|
||||
#define OUT_OF_SPEC
|
||||
|
||||
#define MHZ(x) ((x)*1000*1000)
|
||||
#define KHZ(x) ((x)*1000)
|
||||
|
||||
uint32_t unsigned_delta(uint32_t a, uint32_t b)
|
||||
{
|
||||
if (a > b)
|
||||
return a - b;
|
||||
else
|
||||
return b - a;
|
||||
}
|
||||
|
||||
/* look-up table bit-width -> mask */
|
||||
static const uint8_t width2mask[] = {
|
||||
0, 1, 3, 7, 0xf, 0x1f, 0x3f, 0x7f, 0xff
|
||||
};
|
||||
|
||||
/***********************************************************************
|
||||
* Register Access */
|
||||
|
||||
#if 0
|
||||
/*! \brief Write a register of the tuner chip
|
||||
* \param[in] e4k reference to the tuner
|
||||
* \param[in] reg number of the register
|
||||
* \param[in] val value to be written
|
||||
* \returns 0 on success, negative in case of error
|
||||
*/
|
||||
int e4k_reg_write(struct e4k_state *e4k, uint8_t reg, uint8_t val)
|
||||
{
|
||||
/* FIXME */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! \brief Read a register of the tuner chip
|
||||
* \param[in] e4k reference to the tuner
|
||||
* \param[in] reg number of the register
|
||||
* \returns positive 8bit register contents on success, negative in case of error
|
||||
*/
|
||||
int e4k_reg_read(struct e4k_state *e4k, uint8_t reg)
|
||||
{
|
||||
/* FIXME */
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*! \brief Set or clear some (masked) bits inside a register
|
||||
* \param[in] e4k reference to the tuner
|
||||
* \param[in] reg number of the register
|
||||
* \param[in] mask bit-mask of the value
|
||||
* \param[in] val data value to be written to register
|
||||
* \returns 0 on success, negative in case of error
|
||||
*/
|
||||
static int e4k_reg_set_mask(struct e4k_state *e4k, uint8_t reg,
|
||||
uint8_t mask, uint8_t val)
|
||||
{
|
||||
uint8_t tmp = e4k_reg_read(e4k, reg);
|
||||
|
||||
if ((tmp & mask) == val)
|
||||
return 0;
|
||||
|
||||
return e4k_reg_write(e4k, reg, (tmp & ~mask) | (val & mask));
|
||||
}
|
||||
|
||||
/*! \brief Write a given field inside a register
|
||||
* \param[in] e4k reference to the tuner
|
||||
* \param[in] field structure describing the field
|
||||
* \param[in] val value to be written
|
||||
* \returns 0 on success, negative in case of error
|
||||
*/
|
||||
static int e4k_field_write(struct e4k_state *e4k, const struct reg_field *field, uint8_t val)
|
||||
{
|
||||
int rc;
|
||||
uint8_t mask;
|
||||
|
||||
rc = e4k_reg_read(e4k, field->reg);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
mask = width2mask[field->width] << field->shift;
|
||||
|
||||
return e4k_reg_set_mask(e4k, field->reg, mask, val << field->shift);
|
||||
}
|
||||
|
||||
/*! \brief Read a given field inside a register
|
||||
* \param[in] e4k reference to the tuner
|
||||
* \param[in] field structure describing the field
|
||||
* \returns positive value of the field, negative in case of error
|
||||
*/
|
||||
static int e4k_field_read(struct e4k_state *e4k, const struct reg_field *field)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = e4k_reg_read(e4k, field->reg);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = (rc >> field->shift) & width2mask[field->width];
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Filter Control */
|
||||
|
||||
static const uint32_t rf_filt_center_uhf[] = {
|
||||
MHZ(360), MHZ(380), MHZ(405), MHZ(425),
|
||||
MHZ(450), MHZ(475), MHZ(505), MHZ(540),
|
||||
MHZ(575), MHZ(615), MHZ(670), MHZ(720),
|
||||
MHZ(760), MHZ(840), MHZ(890), MHZ(970)
|
||||
};
|
||||
|
||||
static const uint32_t rf_filt_center_l[] = {
|
||||
MHZ(1300), MHZ(1320), MHZ(1360), MHZ(1410),
|
||||
MHZ(1445), MHZ(1460), MHZ(1490), MHZ(1530),
|
||||
MHZ(1560), MHZ(1590), MHZ(1640), MHZ(1660),
|
||||
MHZ(1680), MHZ(1700), MHZ(1720), MHZ(1750)
|
||||
};
|
||||
|
||||
static int closest_arr_idx(const uint32_t *arr, unsigned int arr_size, uint32_t freq)
|
||||
{
|
||||
unsigned int i, bi = 0;
|
||||
uint32_t best_delta = 0xffffffff;
|
||||
|
||||
/* iterate over the array containing a list of the center
|
||||
* frequencies, selecting the closest one */
|
||||
for (i = 0; i < arr_size; i++) {
|
||||
uint32_t delta = unsigned_delta(freq, arr[i]);
|
||||
if (delta < best_delta) {
|
||||
best_delta = delta;
|
||||
bi = i;
|
||||
}
|
||||
}
|
||||
|
||||
return bi;
|
||||
}
|
||||
|
||||
/* return 4-bit index as to which RF filter to select */
|
||||
static int choose_rf_filter(enum e4k_band band, uint32_t freq)
|
||||
{
|
||||
int rc;
|
||||
|
||||
switch (band) {
|
||||
case E4K_BAND_VHF2:
|
||||
case E4K_BAND_VHF3:
|
||||
rc = 0;
|
||||
break;
|
||||
case E4K_BAND_UHF:
|
||||
rc = closest_arr_idx(rf_filt_center_uhf,
|
||||
ARRAY_SIZE(rf_filt_center_uhf),
|
||||
freq);
|
||||
break;
|
||||
case E4K_BAND_L:
|
||||
rc = closest_arr_idx(rf_filt_center_l,
|
||||
ARRAY_SIZE(rf_filt_center_l),
|
||||
freq);
|
||||
break;
|
||||
default:
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* \brief Automatically select apropriate RF filter based on e4k state */
|
||||
int e4k_rf_filter_set(struct e4k_state *e4k)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = choose_rf_filter(e4k->band, e4k->vco.flo);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
return e4k_reg_set_mask(e4k, E4K_REG_FILT1, 0xF, rc);
|
||||
}
|
||||
|
||||
/* Mixer Filter */
|
||||
static const uint32_t mix_filter_bw[] = {
|
||||
KHZ(27000), KHZ(27000), KHZ(27000), KHZ(27000),
|
||||
KHZ(27000), KHZ(27000), KHZ(27000), KHZ(27000),
|
||||
KHZ(4600), KHZ(4200), KHZ(3800), KHZ(3400),
|
||||
KHZ(3300), KHZ(2700), KHZ(2300), KHZ(1900)
|
||||
};
|
||||
|
||||
/* IF RC Filter */
|
||||
static const uint32_t ifrc_filter_bw[] = {
|
||||
KHZ(21400), KHZ(21000), KHZ(17600), KHZ(14700),
|
||||
KHZ(12400), KHZ(10600), KHZ(9000), KHZ(7700),
|
||||
KHZ(6400), KHZ(5300), KHZ(4400), KHZ(3400),
|
||||
KHZ(2600), KHZ(1800), KHZ(1200), KHZ(1000)
|
||||
};
|
||||
|
||||
/* IF Channel Filter */
|
||||
static const uint32_t ifch_filter_bw[] = {
|
||||
KHZ(5500), KHZ(5300), KHZ(5000), KHZ(4800),
|
||||
KHZ(4600), KHZ(4400), KHZ(4300), KHZ(4100),
|
||||
KHZ(3900), KHZ(3800), KHZ(3700), KHZ(3600),
|
||||
KHZ(3400), KHZ(3300), KHZ(3200), KHZ(3100),
|
||||
KHZ(3000), KHZ(2950), KHZ(2900), KHZ(2800),
|
||||
KHZ(2750), KHZ(2700), KHZ(2600), KHZ(2550),
|
||||
KHZ(2500), KHZ(2450), KHZ(2400), KHZ(2300),
|
||||
KHZ(2280), KHZ(2240), KHZ(2200), KHZ(2150)
|
||||
};
|
||||
|
||||
static const uint32_t *if_filter_bw[] = {
|
||||
mix_filter_bw,
|
||||
ifch_filter_bw,
|
||||
ifrc_filter_bw,
|
||||
};
|
||||
|
||||
static const uint32_t if_filter_bw_len[] = {
|
||||
ARRAY_SIZE(mix_filter_bw),
|
||||
ARRAY_SIZE(ifch_filter_bw),
|
||||
ARRAY_SIZE(ifrc_filter_bw),
|
||||
};
|
||||
|
||||
static const struct reg_field if_filter_fields[] = {
|
||||
{
|
||||
E4K_REG_FILT2, 4, 4,
|
||||
},
|
||||
{
|
||||
E4K_REG_FILT3, 0, 5,
|
||||
},
|
||||
{
|
||||
E4K_REG_FILT2, 0, 4,
|
||||
}
|
||||
};
|
||||
|
||||
static int find_if_bw(enum e4k_if_filter filter, uint32_t bw)
|
||||
{
|
||||
if (filter >= ARRAY_SIZE(if_filter_bw))
|
||||
return -EINVAL;
|
||||
|
||||
return closest_arr_idx(if_filter_bw[filter],
|
||||
if_filter_bw_len[filter], bw);
|
||||
}
|
||||
|
||||
/*! \brief Set the filter band-width of any of the IF filters
|
||||
* \param[in] e4k reference to the tuner chip
|
||||
* \param[in] filter filter to be configured
|
||||
* \param[in] bandwidth bandwidth to be configured
|
||||
* \returns positive actual filter band-width, negative in case of error
|
||||
*/
|
||||
int e4k_if_filter_bw_set(struct e4k_state *e4k, enum e4k_if_filter filter,
|
||||
uint32_t bandwidth)
|
||||
{
|
||||
int bw_idx;
|
||||
const struct reg_field *field;
|
||||
|
||||
if (filter >= ARRAY_SIZE(if_filter_bw))
|
||||
return -EINVAL;
|
||||
|
||||
bw_idx = find_if_bw(filter, bandwidth);
|
||||
|
||||
field = &if_filter_fields[filter];
|
||||
|
||||
return e4k_field_write(e4k, field, bw_idx);
|
||||
}
|
||||
|
||||
/*! \brief Enables / Disables the channel filter
|
||||
* \param[in] e4k reference to the tuner chip
|
||||
* \param[in] on 1=filter enabled, 0=filter disabled
|
||||
* \returns 0 success, negative errors
|
||||
*/
|
||||
int e4k_if_filter_chan_enable(struct e4k_state *e4k, int on)
|
||||
{
|
||||
return e4k_reg_set_mask(e4k, E4K_REG_FILT3, E4K_FILT3_DISABLE,
|
||||
on ? 0 : E4K_FILT3_DISABLE);
|
||||
}
|
||||
|
||||
int e4k_if_filter_bw_get(struct e4k_state *e4k, enum e4k_if_filter filter)
|
||||
{
|
||||
const uint32_t *arr;
|
||||
int rc;
|
||||
const struct reg_field *field;
|
||||
|
||||
if (filter >= ARRAY_SIZE(if_filter_bw))
|
||||
return -EINVAL;
|
||||
|
||||
field = &if_filter_fields[filter];
|
||||
|
||||
rc = e4k_field_read(e4k, field);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
arr = if_filter_bw[filter];
|
||||
|
||||
return arr[rc];
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* Frequency Control */
|
||||
|
||||
#define E4K_FVCO_MIN_KHZ 2600000 /* 2.6 GHz */
|
||||
#define E4K_FVCO_MAX_KHZ 3900000 /* 3.9 GHz */
|
||||
#define E4K_PLL_Y 65536
|
||||
|
||||
#ifdef OUT_OF_SPEC
|
||||
#define E4K_FLO_MIN_MHZ 50
|
||||
#define E4K_FLO_MAX_MHZ 2200UL
|
||||
#else
|
||||
#define E4K_FLO_MIN_MHZ 64
|
||||
#define E4K_FLO_MAX_MHZ 1700
|
||||
#endif
|
||||
|
||||
struct pll_settings {
|
||||
uint32_t freq;
|
||||
uint8_t reg_synth7;
|
||||
uint8_t mult;
|
||||
};
|
||||
|
||||
static const struct pll_settings pll_vars[] = {
|
||||
{KHZ(72400), (1 << 3) | 7, 48},
|
||||
{KHZ(81200), (1 << 3) | 6, 40},
|
||||
{KHZ(108300), (1 << 3) | 5, 32},
|
||||
{KHZ(162500), (1 << 3) | 4, 24},
|
||||
{KHZ(216600), (1 << 3) | 3, 16},
|
||||
{KHZ(325000), (1 << 3) | 2, 12},
|
||||
{KHZ(350000), (1 << 3) | 1, 8},
|
||||
{KHZ(432000), (0 << 3) | 3, 8},
|
||||
{KHZ(667000), (0 << 3) | 2, 6},
|
||||
{KHZ(1200000), (0 << 3) | 1, 4}
|
||||
};
|
||||
|
||||
static int is_fvco_valid(uint32_t fvco_z)
|
||||
{
|
||||
/* check if the resulting fosc is valid */
|
||||
if (fvco_z/1000 < E4K_FVCO_MIN_KHZ ||
|
||||
fvco_z/1000 > E4K_FVCO_MAX_KHZ) {
|
||||
fprintf(stderr, "[E4K] Fvco %u invalid\n", fvco_z);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int is_fosc_valid(uint32_t fosc)
|
||||
{
|
||||
if (fosc < MHZ(16) || fosc > MHZ(30)) {
|
||||
fprintf(stderr, "[E4K] Fosc %u invalid\n", fosc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int is_z_valid(uint32_t z)
|
||||
{
|
||||
if (z > 255) {
|
||||
fprintf(stderr, "[E4K] Z %u invalid\n", z);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*! \brief Determine if 3-phase mixing shall be used or not */
|
||||
static int use_3ph_mixing(uint32_t flo)
|
||||
{
|
||||
/* this is a magic number somewhre between VHF and UHF */
|
||||
if (flo < MHZ(350))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* \brief compute Fvco based on Fosc, Z and X
|
||||
* \returns positive value (Fvco in Hz), 0 in case of error */
|
||||
static uint64_t compute_fvco(uint32_t f_osc, uint8_t z, uint16_t x)
|
||||
{
|
||||
uint64_t fvco_z, fvco_x, fvco;
|
||||
|
||||
/* We use the following transformation in order to
|
||||
* handle the fractional part with integer arithmetic:
|
||||
* Fvco = Fosc * (Z + X/Y) <=> Fvco = Fosc * Z + (Fosc * X)/Y
|
||||
* This avoids X/Y = 0. However, then we would overflow a 32bit
|
||||
* integer, as we cannot hold e.g. 26 MHz * 65536 either.
|
||||
*/
|
||||
fvco_z = (uint64_t)f_osc * z;
|
||||
|
||||
#if 0
|
||||
if (!is_fvco_valid(fvco_z))
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
fvco_x = ((uint64_t)f_osc * x) / E4K_PLL_Y;
|
||||
|
||||
fvco = fvco_z + fvco_x;
|
||||
|
||||
return fvco;
|
||||
}
|
||||
|
||||
static uint32_t compute_flo(uint32_t f_osc, uint8_t z, uint16_t x, uint8_t r)
|
||||
{
|
||||
uint64_t fvco = compute_fvco(f_osc, z, x);
|
||||
if (fvco == 0)
|
||||
return -EINVAL;
|
||||
|
||||
return fvco / r;
|
||||
}
|
||||
|
||||
static int e4k_band_set(struct e4k_state *e4k, enum e4k_band band)
|
||||
{
|
||||
int rc;
|
||||
|
||||
switch (band) {
|
||||
case E4K_BAND_VHF2:
|
||||
case E4K_BAND_VHF3:
|
||||
case E4K_BAND_UHF:
|
||||
e4k_reg_write(e4k, E4K_REG_BIAS, 3);
|
||||
break;
|
||||
case E4K_BAND_L:
|
||||
e4k_reg_write(e4k, E4K_REG_BIAS, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
/* workaround: if we don't reset this register before writing to it,
|
||||
* we get a gap between 325-350 MHz */
|
||||
rc = e4k_reg_set_mask(e4k, E4K_REG_SYNTH1, 0x06, 0);
|
||||
rc = e4k_reg_set_mask(e4k, E4K_REG_SYNTH1, 0x06, band << 1);
|
||||
if (rc >= 0)
|
||||
e4k->band = band;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*! \brief Compute PLL parameters for givent target frequency
|
||||
* \param[out] oscp Oscillator parameters, if computation successful
|
||||
* \param[in] fosc Clock input frequency applied to the chip (Hz)
|
||||
* \param[in] intended_flo target tuning frequency (Hz)
|
||||
* \returns actual PLL frequency, as close as possible to intended_flo,
|
||||
* 0 in case of error
|
||||
*/
|
||||
uint32_t e4k_compute_pll_params(struct e4k_pll_params *oscp, uint32_t fosc, uint32_t intended_flo)
|
||||
{
|
||||
uint32_t i;
|
||||
uint8_t r = 2;
|
||||
uint64_t intended_fvco, remainder;
|
||||
uint64_t z = 0;
|
||||
uint32_t x;
|
||||
int flo;
|
||||
int three_phase_mixing = 0;
|
||||
oscp->r_idx = 0;
|
||||
|
||||
if (!is_fosc_valid(fosc))
|
||||
return 0;
|
||||
|
||||
for(i = 0; i < ARRAY_SIZE(pll_vars); ++i) {
|
||||
if(intended_flo < pll_vars[i].freq) {
|
||||
three_phase_mixing = (pll_vars[i].reg_synth7 & 0x08) ? 1 : 0;
|
||||
oscp->r_idx = pll_vars[i].reg_synth7;
|
||||
r = pll_vars[i].mult;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//fprintf(stderr, "[E4K] Fint=%u, R=%u\n", intended_flo, r);
|
||||
|
||||
/* flo(max) = 1700MHz, R(max) = 48, we need 64bit! */
|
||||
intended_fvco = (uint64_t)intended_flo * r;
|
||||
|
||||
/* compute integral component of multiplier */
|
||||
z = intended_fvco / fosc;
|
||||
|
||||
/* compute fractional part. this will not overflow,
|
||||
* as fosc(max) = 30MHz and z(max) = 255 */
|
||||
remainder = intended_fvco - (fosc * z);
|
||||
/* remainder(max) = 30MHz, E4K_PLL_Y = 65536 -> 64bit! */
|
||||
x = (remainder * E4K_PLL_Y) / fosc;
|
||||
/* x(max) as result of this computation is 65536 */
|
||||
|
||||
flo = compute_flo(fosc, z, x, r);
|
||||
|
||||
oscp->fosc = fosc;
|
||||
oscp->flo = flo;
|
||||
oscp->intended_flo = intended_flo;
|
||||
oscp->r = r;
|
||||
// oscp->r_idx = pll_vars[i].reg_synth7 & 0x0;
|
||||
oscp->threephase = three_phase_mixing;
|
||||
oscp->x = x;
|
||||
oscp->z = z;
|
||||
|
||||
return flo;
|
||||
}
|
||||
|
||||
int e4k_tune_params(struct e4k_state *e4k, struct e4k_pll_params *p)
|
||||
{
|
||||
uint8_t val;
|
||||
|
||||
/* program R + 3phase/2phase */
|
||||
e4k_reg_write(e4k, E4K_REG_SYNTH7, p->r_idx);
|
||||
/* program Z */
|
||||
e4k_reg_write(e4k, E4K_REG_SYNTH3, p->z);
|
||||
/* program X */
|
||||
e4k_reg_write(e4k, E4K_REG_SYNTH4, p->x & 0xff);
|
||||
e4k_reg_write(e4k, E4K_REG_SYNTH5, p->x >> 8);
|
||||
|
||||
/* we're in auto calibration mode, so there's no need to trigger it */
|
||||
|
||||
memcpy(&e4k->vco, p, sizeof(e4k->vco));
|
||||
|
||||
/* set the band */
|
||||
if (e4k->vco.flo < MHZ(140))
|
||||
e4k_band_set(e4k, E4K_BAND_VHF2);
|
||||
else if (e4k->vco.flo < MHZ(350))
|
||||
e4k_band_set(e4k, E4K_BAND_VHF3);
|
||||
else if (e4k->vco.flo < MHZ(1135))
|
||||
e4k_band_set(e4k, E4K_BAND_UHF);
|
||||
else
|
||||
e4k_band_set(e4k, E4K_BAND_L);
|
||||
|
||||
/* select and set proper RF filter */
|
||||
e4k_rf_filter_set(e4k);
|
||||
|
||||
return e4k->vco.flo;
|
||||
}
|
||||
|
||||
/*! \brief High-level tuning API, just specify frquency
|
||||
*
|
||||
* This function will compute matching PLL parameters, program them into the
|
||||
* hardware and set the band as well as RF filter.
|
||||
*
|
||||
* \param[in] e4k reference to tuner
|
||||
* \param[in] freq frequency in Hz
|
||||
* \returns actual tuned frequency, negative in case of error
|
||||
*/
|
||||
int e4k_tune_freq(struct e4k_state *e4k, uint32_t freq)
|
||||
{
|
||||
uint32_t rc;
|
||||
struct e4k_pll_params p;
|
||||
|
||||
/* determine PLL parameters */
|
||||
rc = e4k_compute_pll_params(&p, e4k->vco.fosc, freq);
|
||||
if (!rc)
|
||||
return -EINVAL;
|
||||
|
||||
/* actually tune to those parameters */
|
||||
rc = e4k_tune_params(e4k, &p);
|
||||
|
||||
/* check PLL lock */
|
||||
rc = e4k_reg_read(e4k, E4K_REG_SYNTH1);
|
||||
if (!(rc & 0x01)) {
|
||||
fprintf(stderr, "[E4K] PLL not locked for %u Hz!\n", freq);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Gain Control */
|
||||
|
||||
static const int8_t if_stage1_gain[] = {
|
||||
-3, 6
|
||||
};
|
||||
|
||||
static const int8_t if_stage23_gain[] = {
|
||||
0, 3, 6, 9
|
||||
};
|
||||
|
||||
static const int8_t if_stage4_gain[] = {
|
||||
0, 1, 2, 2
|
||||
};
|
||||
|
||||
static const int8_t if_stage56_gain[] = {
|
||||
3, 6, 9, 12, 15, 15, 15, 15
|
||||
};
|
||||
|
||||
static const int8_t *if_stage_gain[] = {
|
||||
0,
|
||||
if_stage1_gain,
|
||||
if_stage23_gain,
|
||||
if_stage23_gain,
|
||||
if_stage4_gain,
|
||||
if_stage56_gain,
|
||||
if_stage56_gain
|
||||
};
|
||||
|
||||
static const uint8_t if_stage_gain_len[] = {
|
||||
0,
|
||||
ARRAY_SIZE(if_stage1_gain),
|
||||
ARRAY_SIZE(if_stage23_gain),
|
||||
ARRAY_SIZE(if_stage23_gain),
|
||||
ARRAY_SIZE(if_stage4_gain),
|
||||
ARRAY_SIZE(if_stage56_gain),
|
||||
ARRAY_SIZE(if_stage56_gain)
|
||||
};
|
||||
|
||||
static const struct reg_field if_stage_gain_regs[] = {
|
||||
{ 0, 0, 0 },
|
||||
{ E4K_REG_GAIN3, 0, 1 },
|
||||
{ E4K_REG_GAIN3, 1, 2 },
|
||||
{ E4K_REG_GAIN3, 3, 2 },
|
||||
{ E4K_REG_GAIN3, 5, 2 },
|
||||
{ E4K_REG_GAIN4, 0, 3 },
|
||||
{ E4K_REG_GAIN4, 3, 3 }
|
||||
};
|
||||
|
||||
static const int32_t lnagain[] = {
|
||||
-50, 0,
|
||||
-25, 1,
|
||||
0, 4,
|
||||
25, 5,
|
||||
50, 6,
|
||||
75, 7,
|
||||
100, 8,
|
||||
125, 9,
|
||||
150, 10,
|
||||
175, 11,
|
||||
200, 12,
|
||||
250, 13,
|
||||
300, 14,
|
||||
};
|
||||
|
||||
static const int32_t enhgain[] = {
|
||||
10, 30, 50, 70
|
||||
};
|
||||
|
||||
int e4k_set_lna_gain(struct e4k_state *e4k, int32_t gain)
|
||||
{
|
||||
uint32_t i;
|
||||
for(i = 0; i < ARRAY_SIZE(lnagain)/2; ++i) {
|
||||
if(lnagain[i*2] == gain) {
|
||||
e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, lnagain[i*2+1]);
|
||||
return gain;
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int e4k_set_enh_gain(struct e4k_state *e4k, int32_t gain)
|
||||
{
|
||||
uint32_t i;
|
||||
for(i = 0; i < ARRAY_SIZE(enhgain); ++i) {
|
||||
if(enhgain[i] == gain) {
|
||||
e4k_reg_set_mask(e4k, E4K_REG_AGC11, 0x7, E4K_AGC11_LNA_GAIN_ENH | (i << 1));
|
||||
return gain;
|
||||
}
|
||||
}
|
||||
e4k_reg_set_mask(e4k, E4K_REG_AGC11, 0x7, 0);
|
||||
|
||||
/* special case: 0 = off*/
|
||||
if(0 == gain)
|
||||
return 0;
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int e4k_enable_manual_gain(struct e4k_state *e4k, uint8_t manual)
|
||||
{
|
||||
if (manual) {
|
||||
/* Set LNA mode to manual */
|
||||
e4k_reg_set_mask(e4k, E4K_REG_AGC1, E4K_AGC1_MOD_MASK, E4K_AGC_MOD_SERIAL);
|
||||
|
||||
/* Set Mixer Gain Control to manual */
|
||||
e4k_reg_set_mask(e4k, E4K_REG_AGC7, E4K_AGC7_MIX_GAIN_AUTO, 0);
|
||||
} else {
|
||||
/* Set LNA mode to auto */
|
||||
e4k_reg_set_mask(e4k, E4K_REG_AGC1, E4K_AGC1_MOD_MASK, E4K_AGC_MOD_IF_SERIAL_LNA_AUTON);
|
||||
/* Set Mixer Gain Control to auto */
|
||||
e4k_reg_set_mask(e4k, E4K_REG_AGC7, E4K_AGC7_MIX_GAIN_AUTO, 1);
|
||||
|
||||
e4k_reg_set_mask(e4k, E4K_REG_AGC11, 0x7, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int find_stage_gain(uint8_t stage, int8_t val)
|
||||
{
|
||||
const int8_t *arr;
|
||||
int i;
|
||||
|
||||
if (stage >= ARRAY_SIZE(if_stage_gain))
|
||||
return -EINVAL;
|
||||
|
||||
arr = if_stage_gain[stage];
|
||||
|
||||
for (i = 0; i < if_stage_gain_len[stage]; i++) {
|
||||
if (arr[i] == val)
|
||||
return i;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*! \brief Set the gain of one of the IF gain stages
|
||||
* \param [e4k] handle to the tuner chip
|
||||
* \param [stage] number of the stage (1..6)
|
||||
* \param [value] gain value in dB
|
||||
* \returns 0 on success, negative in case of error
|
||||
*/
|
||||
int e4k_if_gain_set(struct e4k_state *e4k, uint8_t stage, int8_t value)
|
||||
{
|
||||
int rc;
|
||||
uint8_t mask;
|
||||
const struct reg_field *field;
|
||||
|
||||
rc = find_stage_gain(stage, value);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* compute the bit-mask for the given gain field */
|
||||
field = &if_stage_gain_regs[stage];
|
||||
mask = width2mask[field->width] << field->shift;
|
||||
|
||||
return e4k_reg_set_mask(e4k, field->reg, mask, rc << field->shift);
|
||||
}
|
||||
|
||||
int e4k_mixer_gain_set(struct e4k_state *e4k, int8_t value)
|
||||
{
|
||||
uint8_t bit;
|
||||
|
||||
switch (value) {
|
||||
case 4:
|
||||
bit = 0;
|
||||
break;
|
||||
case 12:
|
||||
bit = 1;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return e4k_reg_set_mask(e4k, E4K_REG_GAIN2, 1, bit);
|
||||
}
|
||||
|
||||
int e4k_commonmode_set(struct e4k_state *e4k, int8_t value)
|
||||
{
|
||||
if(value < 0)
|
||||
return -EINVAL;
|
||||
else if(value > 7)
|
||||
return -EINVAL;
|
||||
|
||||
return e4k_reg_set_mask(e4k, E4K_REG_DC7, 7, value);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DC Offset */
|
||||
|
||||
int e4k_manual_dc_offset(struct e4k_state *e4k, int8_t iofs, int8_t irange, int8_t qofs, int8_t qrange)
|
||||
{
|
||||
int res;
|
||||
|
||||
if((iofs < 0x00) || (iofs > 0x3f))
|
||||
return -EINVAL;
|
||||
if((irange < 0x00) || (irange > 0x03))
|
||||
return -EINVAL;
|
||||
if((qofs < 0x00) || (qofs > 0x3f))
|
||||
return -EINVAL;
|
||||
if((qrange < 0x00) || (qrange > 0x03))
|
||||
return -EINVAL;
|
||||
|
||||
res = e4k_reg_set_mask(e4k, E4K_REG_DC2, 0x3f, iofs);
|
||||
if(res < 0)
|
||||
return res;
|
||||
|
||||
res = e4k_reg_set_mask(e4k, E4K_REG_DC3, 0x3f, qofs);
|
||||
if(res < 0)
|
||||
return res;
|
||||
|
||||
res = e4k_reg_set_mask(e4k, E4K_REG_DC4, 0x33, (qrange << 4) | irange);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*! \brief Perform a DC offset calibration right now
|
||||
* \param [e4k] handle to the tuner chip
|
||||
*/
|
||||
int e4k_dc_offset_calibrate(struct e4k_state *e4k)
|
||||
{
|
||||
/* make sure the DC range detector is enabled */
|
||||
e4k_reg_set_mask(e4k, E4K_REG_DC5, E4K_DC5_RANGE_DET_EN, E4K_DC5_RANGE_DET_EN);
|
||||
|
||||
return e4k_reg_write(e4k, E4K_REG_DC1, 0x01);
|
||||
}
|
||||
|
||||
|
||||
static const int8_t if_gains_max[] = {
|
||||
0, 6, 9, 9, 2, 15, 15
|
||||
};
|
||||
|
||||
struct gain_comb {
|
||||
int8_t mixer_gain;
|
||||
int8_t if1_gain;
|
||||
uint8_t reg;
|
||||
};
|
||||
|
||||
static const struct gain_comb dc_gain_comb[] = {
|
||||
{ 4, -3, 0x50 },
|
||||
{ 4, 6, 0x51 },
|
||||
{ 12, -3, 0x52 },
|
||||
{ 12, 6, 0x53 },
|
||||
};
|
||||
|
||||
#define TO_LUT(offset, range) (offset | (range << 6))
|
||||
|
||||
int e4k_dc_offset_gen_table(struct e4k_state *e4k)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
/* FIXME: read ont current gain values and write them back
|
||||
* before returning to the caller */
|
||||
|
||||
/* disable auto mixer gain */
|
||||
e4k_reg_set_mask(e4k, E4K_REG_AGC7, E4K_AGC7_MIX_GAIN_AUTO, 0);
|
||||
|
||||
/* set LNA/IF gain to full manual */
|
||||
e4k_reg_set_mask(e4k, E4K_REG_AGC1, E4K_AGC1_MOD_MASK,
|
||||
E4K_AGC_MOD_SERIAL);
|
||||
|
||||
/* set all 'other' gains to maximum */
|
||||
for (i = 2; i <= 6; i++)
|
||||
e4k_if_gain_set(e4k, i, if_gains_max[i]);
|
||||
|
||||
/* iterate over all mixer + if_stage_1 gain combinations */
|
||||
for (i = 0; i < ARRAY_SIZE(dc_gain_comb); i++) {
|
||||
uint8_t offs_i, offs_q, range, range_i, range_q;
|
||||
|
||||
/* set the combination of mixer / if1 gain */
|
||||
e4k_mixer_gain_set(e4k, dc_gain_comb[i].mixer_gain);
|
||||
e4k_if_gain_set(e4k, 1, dc_gain_comb[i].if1_gain);
|
||||
|
||||
/* perform actual calibration */
|
||||
e4k_dc_offset_calibrate(e4k);
|
||||
|
||||
/* extract I/Q offset and range values */
|
||||
offs_i = e4k_reg_read(e4k, E4K_REG_DC2) & 0x3f;
|
||||
offs_q = e4k_reg_read(e4k, E4K_REG_DC3) & 0x3f;
|
||||
range = e4k_reg_read(e4k, E4K_REG_DC4);
|
||||
range_i = range & 0x3;
|
||||
range_q = (range >> 4) & 0x3;
|
||||
|
||||
fprintf(stderr, "[E4K] Table %u I=%u/%u, Q=%u/%u\n",
|
||||
i, range_i, offs_i, range_q, offs_q);
|
||||
|
||||
/* write into the table */
|
||||
e4k_reg_write(e4k, dc_gain_comb[i].reg,
|
||||
TO_LUT(offs_q, range_q));
|
||||
e4k_reg_write(e4k, dc_gain_comb[i].reg + 0x10,
|
||||
TO_LUT(offs_i, range_i));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Initialization */
|
||||
|
||||
static int magic_init(struct e4k_state *e4k)
|
||||
{
|
||||
e4k_reg_write(e4k, 0x7e, 0x01);
|
||||
e4k_reg_write(e4k, 0x7f, 0xfe);
|
||||
e4k_reg_write(e4k, 0x82, 0x00);
|
||||
e4k_reg_write(e4k, 0x86, 0x50); /* polarity A */
|
||||
e4k_reg_write(e4k, 0x87, 0x20);
|
||||
e4k_reg_write(e4k, 0x88, 0x01);
|
||||
e4k_reg_write(e4k, 0x9f, 0x7f);
|
||||
e4k_reg_write(e4k, 0xa0, 0x07);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! \brief Initialize the E4K tuner
|
||||
*/
|
||||
int e4k_init(struct e4k_state *e4k)
|
||||
{
|
||||
/* make a dummy i2c read or write command, will not be ACKed! */
|
||||
e4k_reg_read(e4k, 0);
|
||||
|
||||
/* Make sure we reset everything and clear POR indicator */
|
||||
e4k_reg_write(e4k, E4K_REG_MASTER1,
|
||||
E4K_MASTER1_RESET |
|
||||
E4K_MASTER1_NORM_STBY |
|
||||
E4K_MASTER1_POR_DET
|
||||
);
|
||||
|
||||
/* Configure clock input */
|
||||
e4k_reg_write(e4k, E4K_REG_CLK_INP, 0x00);
|
||||
|
||||
/* Disable clock output */
|
||||
e4k_reg_write(e4k, E4K_REG_REF_CLK, 0x00);
|
||||
e4k_reg_write(e4k, E4K_REG_CLKOUT_PWDN, 0x96);
|
||||
|
||||
/* Write some magic values into registers */
|
||||
magic_init(e4k);
|
||||
#if 0
|
||||
/* Set common mode voltage a bit higher for more margin 850 mv */
|
||||
e4k_commonmode_set(e4k, 4);
|
||||
|
||||
/* Initialize DC offset lookup tables */
|
||||
e4k_dc_offset_gen_table(e4k);
|
||||
|
||||
/* Enable time variant DC correction */
|
||||
e4k_reg_write(e4k, E4K_REG_DCTIME1, 0x01);
|
||||
e4k_reg_write(e4k, E4K_REG_DCTIME2, 0x01);
|
||||
#endif
|
||||
|
||||
/* Set LNA mode to manual */
|
||||
e4k_reg_write(e4k, E4K_REG_AGC4, 0x10); /* High threshold */
|
||||
e4k_reg_write(e4k, E4K_REG_AGC5, 0x04); /* Low threshold */
|
||||
e4k_reg_write(e4k, E4K_REG_AGC6, 0x1a); /* LNA calib + loop rate */
|
||||
|
||||
e4k_reg_set_mask(e4k, E4K_REG_AGC1, E4K_AGC1_MOD_MASK,
|
||||
E4K_AGC_MOD_SERIAL);
|
||||
|
||||
/* Set Mixer Gain Control to manual */
|
||||
e4k_reg_set_mask(e4k, E4K_REG_AGC7, E4K_AGC7_MIX_GAIN_AUTO, 0);
|
||||
|
||||
#if 0
|
||||
/* Enable LNA Gain enhancement */
|
||||
e4k_reg_set_mask(e4k, E4K_REG_AGC11, 0x7,
|
||||
E4K_AGC11_LNA_GAIN_ENH | (2 << 1));
|
||||
|
||||
/* Enable automatic IF gain mode switching */
|
||||
e4k_reg_set_mask(e4k, E4K_REG_AGC8, 0x1, E4K_AGC8_SENS_LIN_AUTO);
|
||||
#endif
|
||||
|
||||
/* Use auto-gain as default */
|
||||
e4k_enable_manual_gain(e4k, 0);
|
||||
|
||||
/* Select moderate gain levels */
|
||||
e4k_if_gain_set(e4k, 1, 6);
|
||||
e4k_if_gain_set(e4k, 2, 0);
|
||||
e4k_if_gain_set(e4k, 3, 0);
|
||||
e4k_if_gain_set(e4k, 4, 0);
|
||||
e4k_if_gain_set(e4k, 5, 9);
|
||||
e4k_if_gain_set(e4k, 6, 9);
|
||||
|
||||
/* Set the most narrow filter we can possibly use */
|
||||
e4k_if_filter_bw_set(e4k, E4K_IF_FILTER_MIX, KHZ(1900));
|
||||
e4k_if_filter_bw_set(e4k, E4K_IF_FILTER_RC, KHZ(1000));
|
||||
e4k_if_filter_bw_set(e4k, E4K_IF_FILTER_CHAN, KHZ(2150));
|
||||
e4k_if_filter_chan_enable(e4k, 1);
|
||||
|
||||
/* Disable time variant DC correction and LUT */
|
||||
e4k_reg_set_mask(e4k, E4K_REG_DC5, 0x03, 0);
|
||||
e4k_reg_set_mask(e4k, E4K_REG_DCTIME1, 0x03, 0);
|
||||
e4k_reg_set_mask(e4k, E4K_REG_DCTIME2, 0x03, 0);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,345 +0,0 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
|
@ -1,500 +0,0 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
|
@ -1,494 +0,0 @@
|
|||
/*
|
||||
* 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;
|
||||
//
|
||||
//}
|
||||
|
3050
src/tuner_r820t.c
3050
src/tuner_r820t.c
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue