removed rtl-sdr files and modified CMake and autotools configurations

This commit is contained in:
Helge Weissig 2015-01-19 12:05:01 -08:00
parent 7748f464cf
commit 50cfd95da1
37 changed files with 109 additions and 11853 deletions

6
.gitignore vendored
View file

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

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

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff