mirror of https://github.com/drowe67/librtlsdr.git
Compare commits
44 Commits
dev_2020-0
...
developmen
Author | SHA1 | Date |
---|---|---|
|
c557fd69b3 | |
|
9eb6b4e1b2 | |
|
4d95c38abb | |
|
7398187ba9 | |
|
92ff2a9e8c | |
|
d0de9c53a2 | |
|
344ff4a66e | |
|
e03a0bfa41 | |
|
c3e944f7a4 | |
|
10ef497eb1 | |
|
f030c97642 | |
|
ad1adfa379 | |
|
c3854221a7 | |
|
14688f5e43 | |
|
a51cee492c | |
|
ebef4a2818 | |
|
5c1ad40ca1 | |
|
db50e9ed9d | |
|
60e63c9dbb | |
|
8ba0319b4b | |
|
4e85c4d1d0 | |
|
b3549df70d | |
|
89f758437e | |
|
78f0cfd90e | |
|
1c5a141d61 | |
|
0299f5fc2d | |
|
8ef067e642 | |
|
f8c64755cf | |
|
6fc09b8915 | |
|
7c6b9e05f8 | |
|
776c31abcb | |
|
1819a8db99 | |
|
c7d071e17e | |
|
907da08bfc | |
|
3551e61903 | |
|
5868a660a4 | |
|
e5cdaf1ac9 | |
|
2b88e8934b | |
|
35b8c01015 | |
|
3864bf7889 | |
|
39d225267e | |
|
1af2be095e | |
|
a3349bd52b | |
|
bff8cf771d |
|
@ -0,0 +1,47 @@
|
|||
name: C/C++ CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master, development ]
|
||||
pull_request:
|
||||
branches: [ master, development ]
|
||||
|
||||
jobs:
|
||||
build_ubuntu-amd64_latest:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: prerequisites
|
||||
# pre-installed on ubuntu-1804: build-essential, git 2.28.0, cmake 3.10/3.17, make
|
||||
# pre-installed: clang 6.0 / 8 / 9, gcc/++ 7.5.0/8.4.0/9.3.0
|
||||
run: sudo apt -qq update && sudo apt -yqq install libusb-1.0-0-dev
|
||||
- name: cmake_make
|
||||
run: mkdir build && cmake -S . -B build && cd build && make
|
||||
- name: compress
|
||||
run: tar zcvf librtlsdr_build_ubuntu-amd64_latest.tar.gz --directory=build/src --exclude=CMakeFiles --exclude=*.cmake --exclude=Makefile --exclude=rtl_app_ver.h .
|
||||
- name: 'Upload Artifact'
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: ubuntu_latest_build
|
||||
path: librtlsdr_build_ubuntu-amd64_latest.tar.gz
|
||||
|
||||
build_macos_latest:
|
||||
runs-on: macos-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
#- name: prerequisites
|
||||
# pre-installed on macos-10.15: git 2.28.0, cmake 3.18.2, libusb 1.0.23
|
||||
# pre-installed: clang/LLVM 10.0.1, gcc/++ 8.4.0/9.3.0
|
||||
# run: brew install libusb
|
||||
- name: cmake_make
|
||||
run: mkdir build && cmake -S . -B build && cd build && make
|
||||
- name: compress
|
||||
run: tar zcvf librtlsdr_build_macos-latest.tar.gz --directory=build/src --exclude=CMakeFiles --exclude=*.cmake --exclude=Makefile --exclude=rtl_app_ver.h .
|
||||
- name: 'Upload Artifact'
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: macos_latest_build
|
||||
path: librtlsdr_build_macos-latest.tar.gz
|
||||
|
|
@ -38,7 +38,6 @@ src/rtl_tcp
|
|||
CMakeCache.txt
|
||||
*/CMakeFiles
|
||||
CMakeFiles
|
||||
*.cmake
|
||||
build
|
||||
|
||||
**/*.o
|
||||
|
|
|
@ -124,6 +124,30 @@ endif()
|
|||
if(NOT THREADS_FOUND)
|
||||
message(FATAL_ERROR "pthreads(-win32) required to compile rtl-sdr")
|
||||
endif()
|
||||
|
||||
# Find codec2
|
||||
if(CODEC2_BUILD_DIR)
|
||||
find_package(codec2 REQUIRED
|
||||
PATHS ${CODEC2_BUILD_DIR}
|
||||
NO_DEFAULT_PATH
|
||||
CONFIGS codec2.cmake
|
||||
)
|
||||
if(codec2_FOUND)
|
||||
message(STATUS "Codec2 library found in build tree.")
|
||||
endif()
|
||||
else()
|
||||
find_package(codec2 REQUIRED)
|
||||
endif()
|
||||
|
||||
# Find csdr
|
||||
if(CSDR_BUILD_DIR)
|
||||
message(STATUS "setting up CSDR... ${CSDR_BUILD_DIR}")
|
||||
else()
|
||||
message(FATAL_ERROR "CSDR_BUILD_DIR not set")
|
||||
endif()
|
||||
set(CSDR_LIBRARY ${CSDR_BUILD_DIR}/libcsdr.so)
|
||||
ADD_DEFINITIONS(-DUSE_FFTW)
|
||||
|
||||
########################################################################
|
||||
# Setup the include and linker paths
|
||||
########################################################################
|
||||
|
@ -132,6 +156,7 @@ include_directories(
|
|||
${LIBUSB_INCLUDE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}/src
|
||||
${THREADS_PTHREADS_INCLUDE_DIR}
|
||||
${CSDR_BUILD_DIR}
|
||||
)
|
||||
|
||||
#link_directories(
|
||||
|
|
|
@ -4,8 +4,9 @@
|
|||
|
||||
# Description
|
||||
|
||||
rtl-sdr turns your Realtek RTL2832 based DVB dongle into a SDR receiver
|
||||
Fork of [librtlsdr](https://github.com/librtlsdr/librtlsdr) for Open VHF/UHF IP link using Pi and RTL-SDR.
|
||||
|
||||
Turns your Realtek RTL2832 based DVB dongle into a **FSK** receiver.
|
||||
|
||||
# For more information see:
|
||||
|
||||
|
|
|
@ -172,6 +172,20 @@ RTLSDR_API int rtlsdr_read_eeprom(rtlsdr_dev_t *dev, uint8_t *data,
|
|||
*/
|
||||
RTLSDR_API int rtlsdr_set_center_freq(rtlsdr_dev_t *dev, uint32_t freq);
|
||||
|
||||
/*!
|
||||
* Check, if tuner PLL (frequency) is still locked.
|
||||
* Tuner/PLL might loose lock (at high frequencies),
|
||||
* e.g. for temperature reasons
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \return 1: PLL is NOT locked
|
||||
* \return 0: PLL HAS lock
|
||||
* \return < 0: if device handle is invalid or some other error
|
||||
* \return -2: not supported for devices' tuner
|
||||
*/
|
||||
RTLSDR_API int rtlsdr_is_tuner_PLL_locked(rtlsdr_dev_t *dev);
|
||||
|
||||
|
||||
/*!
|
||||
* Get actual frequency the device is tuned to.
|
||||
*
|
||||
|
@ -180,6 +194,7 @@ RTLSDR_API int rtlsdr_set_center_freq(rtlsdr_dev_t *dev, uint32_t freq);
|
|||
*/
|
||||
RTLSDR_API uint32_t rtlsdr_get_center_freq(rtlsdr_dev_t *dev);
|
||||
|
||||
|
||||
/*!
|
||||
* Set the frequency correction value for the device.
|
||||
*
|
||||
|
@ -535,8 +550,10 @@ RTLSDR_API int rtlsdr_ir_query(rtlsdr_dev_t *dev, uint8_t *buf, size_t buf_len);
|
|||
|
||||
|
||||
/*!
|
||||
* Enable or disable (the bias tee on) GPIO PIN 0. (Works for rtl-sdr.com v3 dongles)
|
||||
* See: http://www.rtl-sdr.com/rtl-sdr-blog-v-3-dongles-user-guide/
|
||||
* Enable or disable (the bias tee on) GPIO PIN 0 - if not reconfigured.
|
||||
* See rtlsdr_set_opt_string() option 'T'.
|
||||
* This works for rtl-sdr.com v3 dongles, see
|
||||
* http://www.rtl-sdr.com/rtl-sdr-blog-v-3-dongles-user-guide/
|
||||
* Note: rtlsdr_close() does not clear GPIO lines,
|
||||
* so it leaves the (bias tee) line enabled if a client program
|
||||
* doesn't explictly disable it.
|
||||
|
@ -554,12 +571,48 @@ RTLSDR_API int rtlsdr_set_bias_tee(rtlsdr_dev_t *dev, int on);
|
|||
* doesn't explictly disable it.
|
||||
*
|
||||
* \param dev the device handle given by rtlsdr_open()
|
||||
* \param gpio the gpio pin to configure as a Bias T control.
|
||||
* \param gpio the gpio pin -- assuming this line is connected to Bias T.
|
||||
* gpio needs to be in 0 .. 7. BUT pin 4 is connected to Tuner RESET.
|
||||
* and for FC0012 is already connected/reserved pin 6 for switching V/U-HF.
|
||||
* \param on 1 for Bias T on. 0 for Bias T off.
|
||||
* \return -1 if device is not initialized. 0 otherwise.
|
||||
*/
|
||||
RTLSDR_API int rtlsdr_set_bias_tee_gpio(rtlsdr_dev_t *dev, int gpio, int on);
|
||||
|
||||
|
||||
/*
|
||||
* GPIO 0 .. 7 correspond to RTL2832U's pins as follows:
|
||||
* Pin information from http://lea.hamradio.si/~s57uuu/mischam/rtlsdr/ports.html
|
||||
*
|
||||
* GPIO0 (=pin 37): BiasT for RTL-SDR.com V3
|
||||
* GPIO1 (=pin 32): usually free - on RTL-SDR.com V3's Expansion Ports
|
||||
* GPIO2 (=pin 31): usually free - on RTL-SDR.com V3's Expansion Ports
|
||||
* GPIO3 (=pin 36): usually free
|
||||
* GPIO4 (=pin 30): RESET for Tuners FC2580 and FC0012 / on RTL-SDR.com V3's Expansion Ports
|
||||
* GPIO5 (=pin 29): usually free - on RTL-SDR.com V3's Expansion Ports
|
||||
* GPIO6 (=pin 22): select V-band/U-band filter for FC0012-Tuner
|
||||
* GPIO7 (=pin 21): usually free
|
||||
*
|
||||
* CAUTION: The port pins use 3.3V logic levels and are static sensitive!
|
||||
*
|
||||
* most of following functions are also copied from Marko Cebokli's site
|
||||
* http://lea.hamradio.si/~s57uuu/mischam/rtlsdr/ports.html
|
||||
* but added return of error/status.
|
||||
* GPIO numbers 'gpio' in range 0 .. 7 for the following gpio functions
|
||||
* all \return negative values, on error
|
||||
*/
|
||||
RTLSDR_API int rtlsdr_set_gpio_output(rtlsdr_dev_t *dev, uint8_t gpio);
|
||||
RTLSDR_API int rtlsdr_set_gpio_input(rtlsdr_dev_t *dev, uint8_t gpio);
|
||||
|
||||
RTLSDR_API int rtlsdr_set_gpio_bit(rtlsdr_dev_t *dev, uint8_t gpio, int val);
|
||||
RTLSDR_API int rtlsdr_get_gpio_bit(rtlsdr_dev_t *dev, uint8_t gpio, int *val);
|
||||
|
||||
RTLSDR_API int rtlsdr_set_gpio_byte(rtlsdr_dev_t *dev, int val);
|
||||
RTLSDR_API int rtlsdr_get_gpio_byte(rtlsdr_dev_t *dev, int *val);
|
||||
|
||||
RTLSDR_API int rtlsdr_set_gpio_status(rtlsdr_dev_t *dev, int *status );
|
||||
|
||||
|
||||
/*!
|
||||
* Sets multiple options from a string encoded like "bw=300:agc=0:gain=27.3:dagc=0:T=1".
|
||||
* this is a helper function, that programs don't need to implement every single option
|
||||
|
|
|
@ -68,6 +68,15 @@ enum RTL_TCP_COMMANDS {
|
|||
SET_SIDEBAND = 0x47, /* Mixer Sideband for R820T */
|
||||
REPORT_I2C_REGS = 0x48, /* perodically report I2C registers
|
||||
* - if reverse channel is enabled */
|
||||
|
||||
GPIO_SET_OUTPUT_MODE = 0x49, /* rtlsdr_set_gpio_output() */
|
||||
GPIO_SET_INPUT_MODE = 0x50, /* rtlsdr_set_gpio_input() */
|
||||
GPIO_GET_IO_STATUS = 0x51, /* rtlsdr_set_gpio_status() */
|
||||
GPIO_WRITE_PIN = 0x52, /* rtlsdr_set_gpio_output() and rtlsdr_set_gpio_bit() */
|
||||
GPIO_READ_PIN = 0x53, /* rtlsdr_get_gpio_bit() */
|
||||
GPIO_GET_BYTE = 0x54, /* rtlsdr_get_gpio_byte() */
|
||||
|
||||
IS_TUNER_PLL_LOCKED = 0x55, /* rtlsdr_is_tuner_PLL_locked() */
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
#define FC2580_CHECK_ADDR 0x01
|
||||
#define FC2580_CHECK_VAL 0x56
|
||||
|
||||
/* 16.384 MHz (at least on the Logilink VG0002A) */
|
||||
#define FC2580_XTAL_FREQ 16384000
|
||||
|
||||
typedef enum {
|
||||
FC2580_UHF_BAND,
|
||||
FC2580_L_BAND,
|
||||
|
|
|
@ -68,10 +68,14 @@ enum r82xx_xtal_cap_value {
|
|||
|
||||
struct r82xx_config {
|
||||
uint8_t i2c_addr;
|
||||
uint8_t vco_curr_min; /* VCO min/max current for R18/0x12 bits [7:5] in 0 .. 7. use 0xff for default */
|
||||
uint8_t vco_curr_max; /* value is inverted: programmed is 7-value, that 0 is lowest current */
|
||||
uint8_t vco_algo;
|
||||
uint32_t xtal;
|
||||
enum r82xx_chip rafael_chip;
|
||||
unsigned int max_i2c_msg_len;
|
||||
int use_predetect;
|
||||
int verbose;
|
||||
};
|
||||
|
||||
struct r82xx_priv {
|
||||
|
@ -89,7 +93,9 @@ struct r82xx_priv {
|
|||
* on which the band center shall be positioned */
|
||||
uint8_t fil_cal_code;
|
||||
uint8_t input;
|
||||
uint8_t last_vco_curr;
|
||||
int has_lock;
|
||||
int tuner_pll_set;
|
||||
int init_done;
|
||||
int sideband;
|
||||
int disable_dither;
|
||||
|
@ -145,6 +151,7 @@ enum r82xx_delivery_system {
|
|||
int r82xx_standby(struct r82xx_priv *priv);
|
||||
int r82xx_init(struct r82xx_priv *priv);
|
||||
int r82xx_set_freq(struct r82xx_priv *priv, uint32_t freq);
|
||||
int r82xx_is_tuner_locked(struct r82xx_priv *priv);
|
||||
int r82xx_set_gain(struct r82xx_priv *priv, int set_manual_gain, int gain, int extended_mode, int lna_gain, int mixer_gain, int vga_gain, int *rtl_vga_control);
|
||||
int r82xx_get_rf_gain(struct r82xx_priv *priv);
|
||||
int r82xx_get_if_gain(struct r82xx_priv *priv);
|
||||
|
|
|
@ -118,6 +118,7 @@ endif()
|
|||
########################################################################
|
||||
# Build utility
|
||||
########################################################################
|
||||
add_executable(rtl_fsk rtl_fsk.c)
|
||||
add_executable(rtl_sdr rtl_sdr.c)
|
||||
add_executable(rtl_tcp rtl_tcp.c controlThread.c)
|
||||
add_executable(rtl_udp rtl_udp.c)
|
||||
|
@ -139,6 +140,13 @@ else()
|
|||
set(INSTALL_TARGETS rtlsdr_shared rtlsdr_static rtl_sdr rtl_tcp rtl_udp rtl_test rtl_fm rtl_ir rtl_eeprom rtl_adsb rtl_power rtl_biast rtl_raw2wav rtl_wavestat rtl_wavestream)
|
||||
endif()
|
||||
|
||||
target_link_libraries(rtl_fsk codec2 rtlsdr_shared convenience_static
|
||||
${LIBUSB_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${CSDR_LIBRARY}
|
||||
fftw3
|
||||
)
|
||||
|
||||
target_link_libraries(rtl_sdr ${RTLSDR_TOOL_LIB} convenience_static
|
||||
${LIBUSB_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
|
|
273
src/librtlsdr.c
273
src/librtlsdr.c
|
@ -99,6 +99,13 @@
|
|||
#define LOG_API_SET_FREQ 0
|
||||
|
||||
#define INIT_R820T_TUNER_GAIN 0
|
||||
#define ENABLE_VCO_OPTIONS 1
|
||||
|
||||
|
||||
/* activate/use RTL's IF AGC control .. from https://github.com/old-dab/rtlsdr
|
||||
* purpose: make AGC more smooth .. and NOT freeze
|
||||
* most of it is in switch case on tuner_type in rtlsdr_open() */
|
||||
#define USE_OLD_DAB_IF_GAIN 1
|
||||
|
||||
|
||||
typedef struct rtlsdr_tuner_iface {
|
||||
|
@ -249,6 +256,9 @@ struct rtlsdr_dev {
|
|||
#endif
|
||||
|
||||
int biast_gpio_pin_no;
|
||||
uint32_t gpio_state_known; /* bitmask over pins 0 .. 7 */
|
||||
uint32_t gpio_state; /* bitmask over pins 0 .. 7: = 0 == write, 1 == read */
|
||||
|
||||
int called_set_opt;
|
||||
|
||||
/* status */
|
||||
|
@ -261,7 +271,6 @@ struct rtlsdr_dev {
|
|||
int dev_num;
|
||||
};
|
||||
|
||||
static void rtlsdr_set_gpio_bit(rtlsdr_dev_t *dev, uint8_t gpio, int val);
|
||||
static int rtlsdr_demod_write_reg(rtlsdr_dev_t *dev, uint8_t page, uint16_t addr, uint16_t val, uint8_t len);
|
||||
static int rtlsdr_set_if_freq(rtlsdr_dev_t *dev, uint32_t freq);
|
||||
static int rtlsdr_update_ds(rtlsdr_dev_t *dev, uint32_t freq);
|
||||
|
@ -460,10 +469,12 @@ int rtlsdr_vga_control( rtlsdr_dev_t* devt, int rc, int rtl_vga_control ) {
|
|||
if ( rtl_vga_control != devt->rtl_vga_control ) {
|
||||
/* enable/disable RF AGC loop */
|
||||
|
||||
#if USE_OLD_DAB_IF_GAIN == 0
|
||||
rc = rtlsdr_demod_write_reg(devt, 1, 0x04, rtl_vga_control ? 0x80 : 0x00, 1);
|
||||
if ( devt->verbose )
|
||||
fprintf(stderr, "rtlsdr_vga_control(%s) returned %d\n"
|
||||
, rtl_vga_control ? "activate" : "deactivate", rc );
|
||||
#endif
|
||||
devt->rtl_vga_control = rtl_vga_control;
|
||||
}
|
||||
return rc;
|
||||
|
@ -922,27 +933,97 @@ int rtlsdr_demod_write_reg(rtlsdr_dev_t *dev, uint8_t page, uint16_t addr, uint1
|
|||
return (r == len) ? 0 : -1;
|
||||
}
|
||||
|
||||
void rtlsdr_set_gpio_bit(rtlsdr_dev_t *dev, uint8_t gpio, int val)
|
||||
int rtlsdr_set_gpio_bit(rtlsdr_dev_t *dev, uint8_t gpio, int val)
|
||||
{
|
||||
uint16_t r;
|
||||
uint16_t r, retval;
|
||||
|
||||
gpio = 1 << gpio;
|
||||
r = rtlsdr_read_reg(dev, SYSB, GPO, 1);
|
||||
r = val ? (r | gpio) : (r & ~gpio);
|
||||
rtlsdr_write_reg(dev, SYSB, GPO, r, 1);
|
||||
retval = rtlsdr_write_reg(dev, SYSB, GPO, r, 1);
|
||||
return retval;
|
||||
}
|
||||
|
||||
void rtlsdr_set_gpio_output(rtlsdr_dev_t *dev, uint8_t gpio)
|
||||
int rtlsdr_set_gpio_output(rtlsdr_dev_t *dev, uint8_t gpio)
|
||||
{
|
||||
int r;
|
||||
int r, retval = 0;
|
||||
gpio = 1 << gpio;
|
||||
|
||||
r = rtlsdr_read_reg(dev, SYSB, GPD, 1);
|
||||
rtlsdr_write_reg(dev, SYSB, GPD, r & ~gpio, 1);
|
||||
r = rtlsdr_read_reg(dev, SYSB, GPOE, 1);
|
||||
rtlsdr_write_reg(dev, SYSB, GPOE, r | gpio, 1);
|
||||
/* state: bitmask over pins 0 .. 7: = 0 == write, 1 == read */
|
||||
if ( !(dev->gpio_state_known & gpio) || (dev->gpio_state & gpio) )
|
||||
{
|
||||
r = rtlsdr_read_reg(dev, SYSB, GPD, 1);
|
||||
retval = rtlsdr_write_reg(dev, SYSB, GPD, r & ~gpio, 1);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
r = rtlsdr_read_reg(dev, SYSB, GPOE, 1);
|
||||
retval = rtlsdr_write_reg(dev, SYSB, GPOE, r | gpio, 1);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
dev->gpio_state_known |= gpio;
|
||||
dev->gpio_state &= ~( (uint32_t)gpio );
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int rtlsdr_get_gpio_bit(rtlsdr_dev_t *dev, uint8_t gpio, int *val)
|
||||
{
|
||||
uint16_t r;
|
||||
|
||||
gpio = 1 << gpio;
|
||||
r = rtlsdr_read_reg(dev, SYSB, GPI, 1);
|
||||
*val = (r & gpio) ? 1 : 0;
|
||||
return 0; /* no way to determine error with rtlsdr_read_reg() for now! */
|
||||
}
|
||||
|
||||
int rtlsdr_set_gpio_input(rtlsdr_dev_t *dev, uint8_t gpio)
|
||||
{
|
||||
int r, retval = 0;
|
||||
gpio = 1 << gpio;
|
||||
|
||||
/* state: bitmask over pins 0 .. 7: = 0 == write, 1 == read */
|
||||
if ( !(dev->gpio_state_known & gpio) || !(dev->gpio_state & gpio) )
|
||||
{
|
||||
r = rtlsdr_read_reg(dev, SYSB, GPD, 1);
|
||||
retval = rtlsdr_write_reg(dev, SYSB, GPD, r | gpio, 1);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
r = rtlsdr_read_reg(dev, SYSB, GPOE, 1);
|
||||
retval = rtlsdr_write_reg(dev, SYSB, GPOE, r & ~gpio, 1);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
dev->gpio_state_known |= gpio;
|
||||
dev->gpio_state |= ( (uint32_t)gpio );
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int rtlsdr_set_gpio_status(rtlsdr_dev_t *dev, int *status )
|
||||
{
|
||||
int r;
|
||||
r = rtlsdr_read_reg(dev, SYSB, GPD, 1);
|
||||
*status = r;
|
||||
return 0; /* no way to determine error with rtlsdr_read_reg() for now! */
|
||||
}
|
||||
|
||||
|
||||
int rtlsdr_get_gpio_byte(rtlsdr_dev_t *dev, int *val)
|
||||
{
|
||||
*val = rtlsdr_read_reg(dev, SYSB, GPI, 1);
|
||||
return 0; /* no way to determine error with rtlsdr_read_reg() for now! */
|
||||
}
|
||||
|
||||
int rtlsdr_set_gpio_byte(rtlsdr_dev_t *dev, int val)
|
||||
{
|
||||
int retval = rtlsdr_write_reg(dev, SYSB, GPO, val, 1);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
void rtlsdr_set_i2c_repeater(rtlsdr_dev_t *dev, int on)
|
||||
{
|
||||
if (on)
|
||||
|
@ -1034,7 +1115,9 @@ void rtlsdr_init_baseband(rtlsdr_dev_t *dev)
|
|||
rtlsdr_demod_write_reg(dev, 1, 0x11, 0x00, 1);
|
||||
|
||||
/* disable RF and IF AGC loop */
|
||||
#if USE_OLD_DAB_IF_GAIN == 0
|
||||
rtlsdr_demod_write_reg(dev, 1, 0x04, 0x00, 1);
|
||||
#endif
|
||||
dev->rtl_vga_control = 0;
|
||||
|
||||
/* disable PID filter (enable_PID = 0) */
|
||||
|
@ -1370,6 +1453,29 @@ int rtlsdr_set_center_freq(rtlsdr_dev_t *dev, uint32_t freq)
|
|||
return r;
|
||||
}
|
||||
|
||||
|
||||
int rtlsdr_is_tuner_PLL_locked(rtlsdr_dev_t *dev)
|
||||
{
|
||||
int r = -1;
|
||||
|
||||
#if LOG_API_CALLS && LOG_API_SET_FREQ
|
||||
fprintf(stderr, "LOG: rtlsdr_is_tuner_PLL_locked()\n");
|
||||
#endif
|
||||
|
||||
if (!dev || !dev->tuner)
|
||||
return -1;
|
||||
|
||||
if (dev->tuner_type != RTLSDR_TUNER_R820T && dev->tuner_type != RTLSDR_TUNER_R828D )
|
||||
return -2;
|
||||
|
||||
rtlsdr_set_i2c_repeater(dev, 1);
|
||||
r = r82xx_is_tuner_locked(&dev->r82xx_p);
|
||||
rtlsdr_set_i2c_repeater(dev, 0);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
uint32_t rtlsdr_get_center_freq(rtlsdr_dev_t *dev)
|
||||
{
|
||||
#ifdef _ENABLE_RPC
|
||||
|
@ -2914,8 +3020,16 @@ int rtlsdr_open(rtlsdr_dev_t **out_dev, uint32_t index)
|
|||
|
||||
dev->rtl_vga_control = 0;
|
||||
dev->biast_gpio_pin_no = 0;
|
||||
dev->gpio_state_known = 0;
|
||||
dev->gpio_state = 0;
|
||||
dev->called_set_opt = 0;
|
||||
|
||||
/* fprintf(stderr, "\n*********************************\ninit/overwrite tuner VCO settings\n"); */
|
||||
dev->r82xx_c.vco_curr_min = 0xff; /* VCO min/max current for R18/0x12 bits [7:5] in 0 .. 7. use 0xff for default */
|
||||
dev->r82xx_c.vco_curr_max = 0xff; /* value is inverted: programmed is 7-value, that 0 is lowest current */
|
||||
dev->r82xx_c.vco_algo = 0x00;
|
||||
dev->r82xx_c.verbose = 0;
|
||||
|
||||
/* dev->softagc.command_thread; */
|
||||
dev->softagc.agcState = SOFTSTATE_OFF;
|
||||
dev->softagc.softAgcMode = SOFTAGC_OFF; /* SOFTAGC_FREQ_CHANGE SOFTAGC_ATTEN SOFTAGC_ALL */
|
||||
|
@ -3069,20 +3183,97 @@ found:
|
|||
dev->tuner = &tuners[dev->tuner_type];
|
||||
|
||||
switch (dev->tuner_type) {
|
||||
case RTLSDR_TUNER_FC2580:
|
||||
#if USE_OLD_DAB_IF_GAIN
|
||||
dev->tun_xtal = FC2580_XTAL_FREQ;
|
||||
#endif
|
||||
break;
|
||||
case RTLSDR_TUNER_E4000:
|
||||
#if USE_OLD_DAB_IF_GAIN
|
||||
rtlsdr_demod_write_reg(dev, 1, 0x12, 0x5a, 1);//DVBT_DAGC_TRG_VAL
|
||||
rtlsdr_demod_write_reg(dev, 1, 0x02, 0x40, 1);//DVBT_AGC_TARG_VAL_0
|
||||
rtlsdr_demod_write_reg(dev, 1, 0x03, 0x5a, 1);//DVBT_AGC_TARG_VAL_8_1
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xc7, 0x30, 1);//DVBT_AAGC_LOOP_GAIN
|
||||
rtlsdr_demod_write_reg(dev, 1, 0x04, 0xd0, 1);//DVBT_LOOP_GAIN2_3_0
|
||||
rtlsdr_demod_write_reg(dev, 1, 0x05, 0xbe, 1);//DVBT_LOOP_GAIN2_4
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xc8, 0x18, 1);//DVBT_LOOP_GAIN3
|
||||
rtlsdr_demod_write_reg(dev, 1, 0x06, 0x35, 1);//DVBT_VTOP1
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xc9, 0x21, 1);//DVBT_VTOP2
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xca, 0x21, 1);//DVBT_VTOP3
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xcb, 0x00, 1);//DVBT_KRF1
|
||||
rtlsdr_demod_write_reg(dev, 1, 0x07, 0x40, 1);//DVBT_KRF2
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xcd, 0x10, 1);//DVBT_KRF3
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xce, 0x10, 1);//DVBT_KRF4
|
||||
rtlsdr_demod_write_reg(dev, 0, 0x11, 0xe9d4, 2);//DVBT_AD7_SETTING
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xe5, 0xf0, 1);//DVBT_EN_GI_PGA
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xd9, 0x00, 1);//DVBT_THD_LOCK_UP
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xdb, 0x00, 1);//DVBT_THD_LOCK_DW
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xdd, 0x14, 1);//DVBT_THD_UP1
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xde, 0xec, 1);//DVBT_THD_DW1
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xd8, 0x0c, 1);//DVBT_INTER_CNT_LEN
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xe6, 0x02, 1);//DVBT_GI_PGA_STATE
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xd7, 0x09, 1);//DVBT_EN_AGC_PGA
|
||||
rtlsdr_demod_write_reg(dev, 0, 0x10, 0x49, 1);//DVBT_REG_GPO
|
||||
rtlsdr_demod_write_reg(dev, 0, 0x0d, 0x85, 1);//DVBT_REG_MON,DVBT_REG_MONSEL
|
||||
rtlsdr_demod_write_reg(dev, 0, 0x13, 0x02, 1);
|
||||
#endif
|
||||
break;
|
||||
case RTLSDR_TUNER_FC0012:
|
||||
case RTLSDR_TUNER_FC0013:
|
||||
#if USE_OLD_DAB_IF_GAIN
|
||||
rtlsdr_demod_write_reg(dev, 1, 0x12, 0x5a, 1);//DVBT_DAGC_TRG_VAL
|
||||
rtlsdr_demod_write_reg(dev, 1, 0x02, 0x40, 1);//DVBT_AGC_TARG_VAL_0
|
||||
rtlsdr_demod_write_reg(dev, 1, 0x03, 0x5a, 1);//DVBT_AGC_TARG_VAL_8_1
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xc7, 0x2c, 1);//DVBT_AAGC_LOOP_GAIN
|
||||
rtlsdr_demod_write_reg(dev, 1, 0x04, 0xcc, 1);//DVBT_LOOP_GAIN2_3_0
|
||||
rtlsdr_demod_write_reg(dev, 1, 0x05, 0xbe, 1);//DVBT_LOOP_GAIN2_4
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xc8, 0x16, 1);//DVBT_LOOP_GAIN3
|
||||
rtlsdr_demod_write_reg(dev, 1, 0x06, 0x35, 1);//DVBT_VTOP1
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xc9, 0x21, 1);//DVBT_VTOP2
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xca, 0x21, 1);//DVBT_VTOP3
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xcb, 0x00, 1);//DVBT_KRF1
|
||||
rtlsdr_demod_write_reg(dev, 1, 0x07, 0x40, 1);//DVBT_KRF2
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xcd, 0x10, 1);//DVBT_KRF3
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xce, 0x10, 1);//DVBT_KRF4
|
||||
rtlsdr_demod_write_reg(dev, 0, 0x11, 0xe9bf, 2);//DVBT_AD7_SETTING
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xe5, 0xf0, 1);//DVBT_EN_GI_PGA
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xd9, 0x00, 1);//DVBT_THD_LOCK_UP
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xdb, 0x00, 1);//DVBT_THD_LOCK_DW
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xdd, 0x11, 1);//DVBT_THD_UP1
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xde, 0xef, 1);//DVBT_THD_DW1
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xd8, 0x0c, 1);//DVBT_INTER_CNT_LEN
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xe6, 0x02, 1);//DVBT_GI_PGA_STATE
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xd7, 0x09, 1);//DVBT_EN_AGC_PGA
|
||||
#endif
|
||||
break;
|
||||
case RTLSDR_TUNER_R828D:
|
||||
dev->tun_xtal = R828D_XTAL_FREQ;
|
||||
/* fall-through */
|
||||
case RTLSDR_TUNER_R820T:
|
||||
#if USE_OLD_DAB_IF_GAIN
|
||||
rtlsdr_demod_write_reg(dev, 1, 0x12, 0x5a, 1);//DVBT_DAGC_TRG_VAL
|
||||
rtlsdr_demod_write_reg(dev, 1, 0x02, 0x40, 1);//DVBT_AGC_TARG_VAL_0
|
||||
rtlsdr_demod_write_reg(dev, 1, 0x03, 0x80, 1);//DVBT_AGC_TARG_VAL_8_1
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xc7, 0x24, 1);//DVBT_AAGC_LOOP_GAIN
|
||||
rtlsdr_demod_write_reg(dev, 1, 0x04, 0xcc, 1);//DVBT_LOOP_GAIN2_3_0
|
||||
rtlsdr_demod_write_reg(dev, 1, 0x05, 0xbe, 1);//DVBT_LOOP_GAIN2_4
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xc8, 0x14, 1);//DVBT_LOOP_GAIN3
|
||||
rtlsdr_demod_write_reg(dev, 1, 0x06, 0x35, 1);//DVBT_VTOP1
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xc9, 0x21, 1);//DVBT_VTOP2
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xca, 0x21, 1);//DVBT_VTOP3
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xcb, 0x00, 1);//DVBT_KRF1
|
||||
rtlsdr_demod_write_reg(dev, 1, 0x07, 0x40, 1);//DVBT_KRF2
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xcd, 0x10, 1);//DVBT_KRF3
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xce, 0x10, 1);//DVBT_KRF4
|
||||
rtlsdr_demod_write_reg(dev, 0, 0x11, 0xe9f4, 2);//DVBT_AD7_SETTING
|
||||
#endif
|
||||
/* disable Zero-IF mode */
|
||||
rtlsdr_demod_write_reg(dev, 1, 0xb1, 0x1a, 1);
|
||||
|
||||
/* only enable In-phase ADC input */
|
||||
rtlsdr_demod_write_reg(dev, 0, 0x08, 0x4d, 1);
|
||||
|
||||
/* the R82XX use 3.57 MHz IF for the DVB-T 6 MHz mode, and
|
||||
* 4.57 MHz for the 8 MHz mode */
|
||||
rtlsdr_set_if_freq(dev, R82XX_IF_FREQ);
|
||||
|
||||
/* enable spectrum inversion */
|
||||
rtlsdr_demod_write_reg(dev, 1, 0x15, 0x01, 1);
|
||||
break;
|
||||
|
@ -4024,6 +4215,11 @@ const char * rtlsdr_get_opt_help(int longInfo)
|
|||
"\t\t 0: use I & Q; 1: use I; 2: use Q; 3: use I below threshold frequency;\n"
|
||||
"\t\t 4: use Q below threshold frequency (=RTL-SDR v3)\n"
|
||||
"\t\t other values set the threshold frequency\n"
|
||||
#if ENABLE_VCO_OPTIONS
|
||||
"\t\tvcocmin=<current> set R820T/2 VCO current min: 0..7: higher value is more current\n"
|
||||
"\t\tvcocmax=<current> set R820T/2 VCO current max: 0..7\n"
|
||||
"\t\tvcoalgo=<algo> set R820T/2 VCO algorithm. 0: default. 1: with vcomax=3.9G. 2: Youssef/Carl\n"
|
||||
#endif
|
||||
"\t\tTp=<gpio_pin> set GPIO pin for Bias T, default =0 for rtl-sdr.com compatible V3\n"
|
||||
"\t\tT=<bias_tee> 1 activates power at antenna one some dongles, e.g. rtl-sdr.com's V3\n"
|
||||
#ifdef WITH_UDP_SERVER
|
||||
|
@ -4036,7 +4232,12 @@ const char * rtlsdr_get_opt_help(int longInfo)
|
|||
"\t[-O\tset RTL options string seperated with ':', e.g. -O 'bc=30000:agc=0' ]\n"
|
||||
"\t\tverbose:f=<freqHz>:bw=<bw_in_kHz>:bc=<if_in_Hz>:sb=<sideband>\n"
|
||||
"\t\tagc=<tuner_gain_mode>:gain=<tenth_dB>:ifm=<tuner_if_mode>:dagc=<rtl_agc>\n"
|
||||
#if ENABLE_VCO_OPTIONS
|
||||
"\t\tds=<direct_sampling>:dm=<ds_mode_thresh>:vcocmin=<c>:vcocmax=<c>:vcoalgo=<a>\n"
|
||||
"\t\tT=<bias_tee>\n"
|
||||
#else
|
||||
"\t\tds=<direct_sampling>:dm=<ds_mode_thresh>:T=<bias_tee>\n"
|
||||
#endif
|
||||
#ifdef WITH_UDP_SERVER
|
||||
"\t\tport=<udp_port default with 1>\n"
|
||||
#endif
|
||||
|
@ -4067,9 +4268,10 @@ int rtlsdr_set_opt_string(rtlsdr_dev_t *dev, const char *opts, int verbose)
|
|||
int ret = 0;
|
||||
//if (verbose || dev->verbose)
|
||||
// fprintf(stderr, "\nrtlsdr_set_opt_string(): parsing option '%s'\n", optPart);
|
||||
if (!strcmp(optPart, "verbose")) {
|
||||
if (!strcmp(optPart, "verbose") || !strcmp(optPart, "v")) {
|
||||
fprintf(stderr, "\nrtlsdr_set_opt_string(): parsed option verbose\n");
|
||||
dev->verbose = verbose = 1;
|
||||
verbose = ++dev->verbose;
|
||||
dev->r82xx_c.verbose = verbose;
|
||||
ret = 0;
|
||||
}
|
||||
else if (!strncmp(optPart, "f=", 2)) {
|
||||
|
@ -4154,6 +4356,47 @@ int rtlsdr_set_opt_string(rtlsdr_dev_t *dev, const char *opts, int verbose)
|
|||
dev->direct_sampling_threshold = dm;
|
||||
ret = rtlsdr_set_ds_mode(dev, dev->direct_sampling_mode, dev->direct_sampling_threshold);
|
||||
}
|
||||
#if ENABLE_VCO_OPTIONS
|
||||
else if (!strncmp(optPart, "vcocmin=", 8)) {
|
||||
int current = atoi(optPart +8);
|
||||
if ( 0 <= current && current <= 7 )
|
||||
{
|
||||
dev->r82xx_c.vco_curr_min = 7 - current;
|
||||
ret = 0;
|
||||
if (verbose)
|
||||
fprintf(stderr, "\nrtlsdr_set_opt_string(): parsed vcocmin config %d\n", current);
|
||||
} else if (verbose) {
|
||||
fprintf(stderr, "\nrtlsdr_set_opt_string(): error parsing vcocmin config: valid range 0 .. 7\n");
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
else if (!strncmp(optPart, "vcocmax=", 8)) {
|
||||
int current = atoi(optPart +8);
|
||||
if ( 0 <= current && current <= 7 )
|
||||
{
|
||||
dev->r82xx_c.vco_curr_max = 7 - current;
|
||||
ret = 0;
|
||||
if (verbose)
|
||||
fprintf(stderr, "\nrtlsdr_set_opt_string(): parsed vcocmax config %d\n", current);
|
||||
} else if (verbose) {
|
||||
fprintf(stderr, "\nrtlsdr_set_opt_string(): error parsing vcocmax config: valid range 0 .. 7\n");
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
else if (!strncmp(optPart, "vcoalgo=", 8)) {
|
||||
int algo = atoi(optPart +8);
|
||||
if ( 0 <= algo && algo <= 2 )
|
||||
{
|
||||
dev->r82xx_c.vco_curr_max = algo;
|
||||
ret = 0;
|
||||
if (verbose)
|
||||
fprintf(stderr, "\nrtlsdr_set_opt_string(): parsed vcoalgo config %d\n", algo);
|
||||
} else if (verbose) {
|
||||
fprintf(stderr, "\nrtlsdr_set_opt_string(): error parsing vcoalgo config: valid range 0 .. 2\n");
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else if (!strncmp(optPart, "tp=", 3) || !strncmp(optPart, "Tp=", 3) || !strncmp(optPart, "TP=", 3) ) {
|
||||
int gpio_pin_no = atoi(optPart +3);
|
||||
if (verbose)
|
||||
|
|
|
@ -50,32 +50,51 @@ void usage(void)
|
|||
fprintf(stderr,
|
||||
"Usage:\trtl_biast [-options]\n"
|
||||
"\t[-d device_index (default: 0)]\n"
|
||||
"\t[-b bias_on (default: 0)]\n"
|
||||
"\t[-g GPIO select (default: 0)]\n");
|
||||
"\t[-g GPIO select (default: 0)]\n"
|
||||
"\t[-b set write bias_on (default: 0, in output mode)]\n"
|
||||
"\t[-r read pin (in input mode)]\n"
|
||||
"\t[-w write pin (in output mode)]\n"
|
||||
"\t[-s read all GPIO pins status (0 = write, 1 = read ?? )]\n"
|
||||
"\t[-R read all GPIO pins ?? ]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, r, opt;
|
||||
int i, r, opt, val;
|
||||
int dev_index = 0;
|
||||
int dev_given = 0;
|
||||
int write_pin_given = 0;
|
||||
int read_pin_given = 0;
|
||||
int read_all_given = 0;
|
||||
int req_status = 0;
|
||||
uint32_t bias_on = 0;
|
||||
uint32_t gpio_pin = 0;
|
||||
int gpio_pin = 0;
|
||||
int device_count;
|
||||
|
||||
while ((opt = getopt(argc, argv, "d:b:g:h?")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "d:b:w:g:srRh?")) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
dev_index = verbose_device_search(optarg);
|
||||
dev_given = 1;
|
||||
break;
|
||||
case 'b':
|
||||
case 'w':
|
||||
bias_on = atoi(optarg);
|
||||
write_pin_given = 1;
|
||||
break;
|
||||
case 'g':
|
||||
gpio_pin = atoi(optarg);
|
||||
break;
|
||||
case 'r':
|
||||
read_pin_given = 1;
|
||||
break;
|
||||
case 'R':
|
||||
read_all_given = 1;
|
||||
break;
|
||||
case 's':
|
||||
req_status = 1;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
|
@ -91,7 +110,71 @@ int main(int argc, char **argv)
|
|||
}
|
||||
|
||||
r = rtlsdr_open(&dev, dev_index);
|
||||
rtlsdr_set_bias_tee_gpio(dev, gpio_pin, bias_on);
|
||||
if (r < 0)
|
||||
{
|
||||
fprintf(stderr, "error opening device with index %d\n", dev_index);
|
||||
return -r;
|
||||
}
|
||||
|
||||
if (write_pin_given)
|
||||
{
|
||||
r = rtlsdr_set_bias_tee_gpio(dev, gpio_pin, bias_on);
|
||||
if (r < 0)
|
||||
fprintf(stderr, "error setting value %d on pin %d\n", bias_on, gpio_pin);
|
||||
}
|
||||
|
||||
else if (read_pin_given)
|
||||
{
|
||||
r = rtlsdr_set_gpio_input(dev, gpio_pin);
|
||||
if (r < 0)
|
||||
fprintf(stderr, "error configuring pin %d to input\n", gpio_pin);
|
||||
|
||||
r = rtlsdr_get_gpio_bit(dev, gpio_pin, &val);
|
||||
if (r < 0)
|
||||
fprintf(stderr, "error reading value for pin %d\n", gpio_pin);
|
||||
else
|
||||
printf("value %d at pin %d\n", val, gpio_pin);
|
||||
}
|
||||
|
||||
else if (read_all_given)
|
||||
{
|
||||
r = rtlsdr_get_gpio_byte(dev, &val);
|
||||
if (r < 0)
|
||||
fprintf(stderr, "error reading value for all pins\n");
|
||||
else
|
||||
{
|
||||
printf("GPIO 0x%02x = bin ", val);
|
||||
for (gpio_pin = 7; gpio_pin >= 4; --gpio_pin)
|
||||
printf("%d", ((val >> gpio_pin) & 1));
|
||||
printf(" ");
|
||||
for (gpio_pin = 3; gpio_pin >= 0; --gpio_pin)
|
||||
printf("%d", ((val >> gpio_pin) & 1));
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
else if (req_status)
|
||||
{
|
||||
r = rtlsdr_set_gpio_status(dev, &val);
|
||||
if (r < 0)
|
||||
fprintf(stderr, "error reading status for all pins\n");
|
||||
else
|
||||
{
|
||||
printf("STATUS 0x%02x = bin ", val);
|
||||
for (gpio_pin = 7; gpio_pin >= 4; --gpio_pin)
|
||||
printf("%d", ((val >> gpio_pin) & 1));
|
||||
printf(" ");
|
||||
for (gpio_pin = 3; gpio_pin >= 0; --gpio_pin)
|
||||
printf("%d", ((val >> gpio_pin) & 1));
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
usage();
|
||||
r = -1;
|
||||
}
|
||||
|
||||
exit:
|
||||
/*
|
||||
|
|
|
@ -0,0 +1,864 @@
|
|||
/*
|
||||
* rtl_fsk, turns your Realtek RTL2832 based DVB dongle into a FSK receiver
|
||||
*
|
||||
* Based on rtl_sdr
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
//added M flag and R flag (for Rs) as command line options
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <getopt.h>
|
||||
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
#include "getopt/getopt.h"
|
||||
#endif
|
||||
|
||||
#include "rtl-sdr.h"
|
||||
#include "convenience/convenience.h"
|
||||
#include "convenience/rtl_convenience.h"
|
||||
#include "fsk.h"
|
||||
#include "libcsdr.h"
|
||||
#include "ldpc_codes.h"
|
||||
#include "freedv_api.h"
|
||||
|
||||
/* rtlsdr ------------------------------------*/
|
||||
|
||||
#define DEFAULT_SAMPLE_RATE 1800000
|
||||
#define DEFAULT_BANDWIDTH 0 /* automatic bandwidth */
|
||||
#define DEFAULT_BUF_LENGTH (16 * 16384)
|
||||
#define MINIMAL_BUF_LENGTH 512
|
||||
#define MAXIMAL_BUF_LENGTH (256 * 16384)
|
||||
#define BUF_SZ 8192
|
||||
|
||||
/* fsk modem ----------------------------------*/
|
||||
|
||||
#define CSDR_BUFSIZE 1024
|
||||
#define DEFAULT_MODEM_SAMPLE_RATE 40000 /* sample rate we run demod at */
|
||||
#define DEFAULT_SYMBOL_RATE 10000 /* symbols/s */
|
||||
#define DEFAULT_M 2 /* 2FSK */
|
||||
#define NDFT 256 /* number of DFT points on dashboard */
|
||||
#define DEFAULT_CHANNEL_WIDTH 25000 /* 25 kHz channel for freq est */
|
||||
#define NORM_RX_TIMING_LOG_SZ 1024
|
||||
|
||||
static int do_exit = 0;
|
||||
static uint32_t bytes_to_read = 0;
|
||||
static rtlsdr_dev_t *dev = NULL;
|
||||
static struct FSK *fsk;
|
||||
static uint32_t out_block_size = DEFAULT_BUF_LENGTH;
|
||||
static unsigned char *rawbuf;
|
||||
static size_t nrawbuf = 0;
|
||||
static size_t nrawbuf_max = 0;
|
||||
static int dashboard = 0;
|
||||
static int sockfd;
|
||||
static struct sockaddr_in serveraddr;
|
||||
static int portno = 8001;
|
||||
|
||||
static uint32_t samp_rate = DEFAULT_SAMPLE_RATE;
|
||||
static uint32_t modem_samp_rate = DEFAULT_MODEM_SAMPLE_RATE;
|
||||
static uint32_t sample_counter;
|
||||
static float norm_rx_timing_log[NORM_RX_TIMING_LOG_SZ];
|
||||
static uint32_t norm_rx_timing_log_index = 0;
|
||||
static int fsk_lower = 0;
|
||||
static int fsk_upper = 0;
|
||||
static int output_bits;
|
||||
|
||||
static int csdr_factor;
|
||||
static float csdr_in[CSDR_BUFSIZE*2];
|
||||
static float csdr_out[CSDR_BUFSIZE*2];
|
||||
static int csdr_nout, csdr_nin;
|
||||
static int csdr_padded_taps_length;
|
||||
static float *csdr_taps;
|
||||
|
||||
static COMP* modembuf;
|
||||
static size_t nmodembuf = 0;
|
||||
static size_t nmodembuf_max = 0;
|
||||
|
||||
static struct freedv *freedv = NULL;
|
||||
static int fsk_ldpc = 0;
|
||||
static uint8_t *bytes_out;
|
||||
static uint8_t *zeros_out;
|
||||
static int verbose = 0;
|
||||
static int data_bytes_per_frame;
|
||||
static int periodic_output = 0;
|
||||
static uint8_t filter = 0;
|
||||
static int inject_snr = 0;
|
||||
static int log_snr = 0;
|
||||
static float RxGain = 0.0;
|
||||
static int Rs = DEFAULT_SYMBOL_RATE;
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"rtl_fsk, a FSK demodulator for RTL2832 based DVB-T receivers\n\n"
|
||||
"Usage:\t -f frequency_to_tune_to [Hz]\n"
|
||||
"\t[-a FSK modem sample rate (default: %d Hz)]\n"
|
||||
"\t[-s samplerate (default: %d Hz)]\n"
|
||||
"\t[-d device_index (default: 0)]\n"
|
||||
"\t[-e extended gain -e 0xlmi (l,m,i single hex digits 0-f)\n"
|
||||
"\t[-g gain (default: 0 for auto)]\n"
|
||||
"\t[-p ppm_error (default: 0)]\n"
|
||||
"\t[-M modn order (default: 2)]\n"
|
||||
"\t[-n number of samples to read (default: 0, infinite)]\n"
|
||||
"\t[-q periodic | status byte | data bytes | output (default: off)]\n"
|
||||
"\t[-r FSK modem symbol rate (default: %d Hz)]\n"
|
||||
"\t[-m number of FSK modem tones (default: %d)]\n"
|
||||
"\t[-u hostname (optional hostname:8001 where we send UDP dashboard diagnostics)\n"
|
||||
"\t[-x output complex float samples (default output demodulated bits)]\n"
|
||||
"\t[-t toneSpacingHz use 'mask' freq est]\n"
|
||||
"\t[--code CodeName Use LDPC code CodeName] (note packed bytes out)\n"
|
||||
"\t[--listcodes List available LDPC codes]\n"
|
||||
"\t[--testframes] Built in testframe mode\n"
|
||||
"\t[--filter Byte Filter (don't output) FSK_LDPC frames starting with (non-zero) Byte\n"
|
||||
"\t[--injectsnr inject S and N floats into packet output\n"
|
||||
"\t[--logsnr SNR info on stderr when packet received\n"
|
||||
"\tfilename ( '-' dumps bits to stdout)\n\n", DEFAULT_MODEM_SAMPLE_RATE, DEFAULT_SAMPLE_RATE, DEFAULT_SYMBOL_RATE, DEFAULT_M);
|
||||
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
|
||||
|
||||
|
||||
/* CSDR decimation helper functions -------------------------------------------------*/
|
||||
|
||||
static void csdr_decimate_cc(float *out, float *in, int the_bufsize, float *taps, int taps_length, int factor, int *nout, int *next_nin) {
|
||||
int output_size, input_skip;
|
||||
|
||||
output_size=fir_decimate_cc((complexf*)in, (complexf*)out, the_bufsize, factor, taps, taps_length);
|
||||
input_skip=factor*output_size;
|
||||
memmove((complexf*)in,((complexf*)in)+input_skip,(the_bufsize-input_skip)*sizeof(complexf));
|
||||
*nout = output_size;
|
||||
*next_nin = input_skip;
|
||||
}
|
||||
|
||||
static float *csdr_init_decimate_cc(int factor, float transition_bw, window_t window, int *padded_taps_length) {
|
||||
int taps_length;
|
||||
float *taps;
|
||||
int i;
|
||||
|
||||
fprintf(stderr,"fir_decimate_cc: factor = %d window = %s\n", factor, firdes_get_string_from_window(window));
|
||||
taps_length = firdes_filter_len(transition_bw);
|
||||
fprintf(stderr,"fir_decimate_cc: taps_length = %d\n",taps_length);
|
||||
|
||||
// allocate taps array
|
||||
*padded_taps_length = taps_length;
|
||||
#define NEON_ALIGNMENT (4*4*2)
|
||||
#ifdef NEON_OPTS
|
||||
errhead(); fprintf(stderr,"taps_length = %d\n", taps_length);
|
||||
*padded_taps_length = taps_length+(NEON_ALIGNMENT/4)-1 - ((taps_length+(NEON_ALIGNMENT/4)-1)%(NEON_ALIGNMENT/4));
|
||||
fprintf(stderr,"padded_taps_length = %d\n", *padded_taps_length);
|
||||
|
||||
taps = (float*) (float*)malloc((*padded_taps_length+NEON_ALIGNMENT)*sizeof(float));
|
||||
fprintf(stderr,"taps = %x\n", taps);
|
||||
taps = (float*)((((unsigned)taps)+NEON_ALIGNMENT-1) & ~(NEON_ALIGNMENT-1));
|
||||
errhead(); fprintf(stderr,"NEON aligned taps = %x\n", taps);
|
||||
for(i=0;i<*padded_taps_length-taps_length;i++) taps[taps_length+i]=0;
|
||||
#else
|
||||
taps = (float*)malloc(taps_length*sizeof(float));
|
||||
#endif
|
||||
|
||||
firdes_lowpass_f(taps,taps_length, 0.5/(float)factor,window);
|
||||
return taps;
|
||||
}
|
||||
|
||||
|
||||
/* dashboard functions ------------------------------------------*/
|
||||
|
||||
static void udp_sendbuf(char buf[]) {
|
||||
int n;
|
||||
|
||||
/* send the message to the server */
|
||||
n = sendto(sockfd, buf, strlen(buf), 0, (const struct sockaddr *)&serveraddr, sizeof(serveraddr));
|
||||
if (n < 0) {
|
||||
fprintf(stderr, "ERROR in sendto\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void update_dashboard(struct FSK *fsk) {
|
||||
unsigned int i;
|
||||
|
||||
/* update buffer of timing samples */
|
||||
if (norm_rx_timing_log_index < NORM_RX_TIMING_LOG_SZ)
|
||||
norm_rx_timing_log[norm_rx_timing_log_index++] = fsk->norm_rx_timing;
|
||||
else
|
||||
fprintf(stderr, "norm_rx_timing_log full!");
|
||||
sample_counter += fsk_nin(fsk);
|
||||
|
||||
if (sample_counter > modem_samp_rate) {
|
||||
/* one second has passed, lets send some dashboard information */
|
||||
char buf[BUF_SZ];
|
||||
char buf1[BUF_SZ];
|
||||
size_t Ndft;
|
||||
float *f_est, sum;
|
||||
int m, step, start, k;
|
||||
float SfdB[NDFT];
|
||||
|
||||
sample_counter -= modem_samp_rate;
|
||||
buf[0]=0;
|
||||
|
||||
/* Current magnitude spectrum Sf[] from freq estimator */
|
||||
|
||||
/* Limit spectrum to NDFT points */
|
||||
if (fsk->Ndft > NDFT) {
|
||||
step = fsk->Ndft/NDFT;
|
||||
Ndft = NDFT;
|
||||
} else {
|
||||
step = 1;
|
||||
Ndft = fsk->Ndft;
|
||||
}
|
||||
|
||||
for(i=0, start=0; i<Ndft; i++, start+=step) {
|
||||
/* Sf[] array is linear magnitudes */
|
||||
sum = 0.0;
|
||||
for(k=0; k<step; k++)
|
||||
sum += fsk->Sf[start+k];
|
||||
SfdB[i] = 20.0*log10(sum+1E-6);
|
||||
}
|
||||
|
||||
snprintf(buf1, BUF_SZ, "{"); strncat(buf, buf1, BUF_SZ-1);
|
||||
snprintf(buf1, BUF_SZ, "\"SfdB\":["); strncat(buf, buf1, BUF_SZ);
|
||||
for(i=0; i<Ndft; i++) {
|
||||
snprintf(buf1, BUF_SZ, "%f",SfdB[i]); strncat(buf, buf1, BUF_SZ);
|
||||
if(i<Ndft-1) { snprintf(buf1, BUF_SZ, ", "); strncat(buf, buf1, BUF_SZ); }
|
||||
}
|
||||
snprintf(buf1, BUF_SZ, "]"); strncat(buf, buf1, BUF_SZ);
|
||||
|
||||
/* FSK tone freq estimates */
|
||||
|
||||
snprintf(buf1, BUF_SZ, ", \"fsk_lower_Hz\":%d, \"fsk_upper_Hz\":%d",
|
||||
fsk_lower, fsk_upper); strncat(buf, buf1, BUF_SZ);
|
||||
if (fsk->freq_est_type)
|
||||
f_est = fsk->f2_est;
|
||||
else
|
||||
f_est = fsk->f_est;
|
||||
snprintf(buf1, BUF_SZ, ", \"f_est_Hz\":["); strncat(buf, buf1, BUF_SZ);
|
||||
for(m=0; m<fsk->mode; m++) {
|
||||
snprintf(buf1, BUF_SZ, "%f", f_est[m]); strncat(buf, buf1, BUF_SZ);
|
||||
if (m < (fsk->mode-1)) { snprintf(buf1, BUF_SZ, ", "); strncat(buf, buf1, BUF_SZ); }
|
||||
}
|
||||
snprintf(buf1, BUF_SZ, "]"); strncat(buf, buf1, BUF_SZ);
|
||||
|
||||
snprintf(buf1, BUF_SZ, ", \"norm_rx_timing\":["); strncat(buf, buf1, BUF_SZ);
|
||||
for(i=0; i<norm_rx_timing_log_index; i++) {
|
||||
snprintf(buf1, BUF_SZ, "%f", norm_rx_timing_log[i]); strncat(buf, buf1, BUF_SZ);
|
||||
if (i < (norm_rx_timing_log_index-1)) { snprintf(buf1, BUF_SZ, ", "); strncat(buf, buf1, BUF_SZ); }
|
||||
}
|
||||
snprintf(buf1, BUF_SZ, "]"); strncat(buf, buf1, BUF_SZ);
|
||||
norm_rx_timing_log_index = 0;
|
||||
|
||||
snprintf(buf1, BUF_SZ, ", \"SNRest_lin\":%f, \"Fs_Hz\":%d",
|
||||
fsk->SNRest, fsk->Fs); strncat(buf, buf1, BUF_SZ);
|
||||
|
||||
/* finish up JSON and send to dashboard GUI over UDP */
|
||||
snprintf(buf1, BUF_SZ, "}\n"); strncat(buf, buf1, BUF_SZ);
|
||||
udp_sendbuf(buf);
|
||||
if (verbose == 0) fprintf(stderr, ".");
|
||||
}
|
||||
}
|
||||
|
||||
/* rtl_sdr functions ------------------------------------------*/
|
||||
|
||||
static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
|
||||
{
|
||||
unsigned char *pout;
|
||||
unsigned int i;
|
||||
unsigned char bitbuf[fsk->Nbits];
|
||||
COMP *pmodembuf;
|
||||
int prev_fsk_nin;
|
||||
int nbytes = 0;
|
||||
uint8_t rx_status = 0;
|
||||
|
||||
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);
|
||||
}
|
||||
*/
|
||||
|
||||
/* resample rawbuf to demod sample rate ------------------------------- */
|
||||
|
||||
memcpy(&rawbuf[nrawbuf],buf,len);
|
||||
nrawbuf += len;
|
||||
assert(nrawbuf < 2*out_block_size);
|
||||
assert(nrawbuf < nrawbuf_max);
|
||||
pout = rawbuf;
|
||||
pmodembuf = modembuf + nmodembuf;
|
||||
while(nrawbuf >= 2*(size_t)csdr_nin) {
|
||||
complexf *pcsdr_in = ((complexf*)csdr_in)+(CSDR_BUFSIZE-csdr_nin);
|
||||
for(i=0;i<(uint32_t)csdr_nin;i++) {
|
||||
pcsdr_in[i].i = ((float)pout[2*i]-127.0)/128.0;
|
||||
pcsdr_in[i].q = ((float)pout[2*i+1]-127.0)/128.0;
|
||||
}
|
||||
csdr_decimate_cc((float*)pmodembuf, csdr_in, CSDR_BUFSIZE, csdr_taps, csdr_padded_taps_length, csdr_factor,
|
||||
&csdr_nout, &csdr_nin);
|
||||
/* place resampled signal in modem input buf */
|
||||
pmodembuf += csdr_nout;
|
||||
nmodembuf += csdr_nout;
|
||||
assert(pmodem_buf < (modembuf + nmodembuf_max));
|
||||
|
||||
pout += 2*csdr_nin;
|
||||
nrawbuf -= 2*csdr_nin;
|
||||
assert(nrawbuf >= 0);
|
||||
}
|
||||
/* copy left over rawbuf samples to start for next time */
|
||||
memmove(rawbuf,pout,nrawbuf);
|
||||
|
||||
/* when we have fsk_nin() samples run demod ----------------------------- */
|
||||
|
||||
pmodembuf = modembuf;
|
||||
while(nmodembuf >= fsk_nin(fsk)) {
|
||||
prev_fsk_nin = fsk_nin(fsk); /* fsk_nin gets updated in fsk_demod() */
|
||||
/* note: in coded mode fsk_nin() == freedv_nin() */
|
||||
if (output_bits == 0)
|
||||
fwrite((float*)pmodembuf, sizeof(complexf), prev_fsk_nin, (FILE*)ctx);
|
||||
else {
|
||||
if (fsk_ldpc == 0)
|
||||
fsk_demod(fsk, bitbuf, pmodembuf);
|
||||
else {
|
||||
nbytes = freedv_rawdatacomprx(freedv, bytes_out, pmodembuf);
|
||||
rx_status = freedv_get_rx_status(freedv);
|
||||
/* optional filtering of packets */
|
||||
if ((rx_status & FREEDV_RX_BITS) && filter) {
|
||||
//fprintf(stderr,"bytes_out[0]: 0x%02x filter: 0x%02x\n", bytes_out[0], filter);
|
||||
if (bytes_out[0] == filter)
|
||||
rx_status &= ~FREEDV_RX_BITS;
|
||||
}
|
||||
/* optional received SNR info in packet bytes for retransmission */
|
||||
if (inject_snr && (rx_status & FREEDV_RX_BITS)) {
|
||||
float S,N;
|
||||
freedv_get_fsk_S_and_N(freedv, &S, &N);
|
||||
//fprintf(stderr, "S: %f N: %f snr: %f\n", S, N, 10*log10(S/N));
|
||||
memcpy(&bytes_out[2], (uint8_t*)&S, sizeof(float));
|
||||
memcpy(&bytes_out[6], (uint8_t*)&N, sizeof(float));
|
||||
}
|
||||
/* optional SNR info to stderr for logging */
|
||||
if (log_snr && (rx_status & FREEDV_RX_BITS)) {
|
||||
float S,N,RxpowerdBm,NodBmHz;
|
||||
float FsonRsdB = 20*log10((float)modem_samp_rate/Rs);
|
||||
freedv_get_fsk_S_and_N(freedv, &S, &N);
|
||||
RxpowerdBm = 10*log10(S) + RxGain - FsonRsdB;
|
||||
NodBmHz = 10*log10(N) + RxGain - FsonRsdB - 10*log10((float)Rs);
|
||||
fprintf(stderr, "%lu ", (unsigned long)time(NULL));
|
||||
fprintf(stderr, "Rx Frame Rxloc: %6.2f Noloc: %6.2f snrloc: %5.2f ", RxpowerdBm, NodBmHz, 10*log10(S/N));
|
||||
memcpy(&S, &bytes_out[2], sizeof(float));
|
||||
memcpy(&N, &bytes_out[6], sizeof(float));
|
||||
if ((S>0) && (N>0)) {
|
||||
RxpowerdBm = 10*log10(S) + RxGain - FsonRsdB;
|
||||
NodBmHz = 10*log10(N) + RxGain - FsonRsdB - 10*log10((float)Rs);;
|
||||
fprintf(stderr, "Rxrem: %6.2f Norem: %6.2f snrrem: %5.2f\n", RxpowerdBm, NodBmHz, 10*log10(S/N));
|
||||
}
|
||||
else
|
||||
fprintf(stderr, "Srem: %6.2f Nrem: %6.2f snrrem: %5.2f\n", 0., 0., 0.);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
pmodembuf += prev_fsk_nin;
|
||||
nmodembuf -= prev_fsk_nin;
|
||||
assert(nmodembuf >= 0);
|
||||
|
||||
/* output demodulated bits - bunch of different modes */
|
||||
if (output_bits) {
|
||||
if (fsk_ldpc == 0)
|
||||
/* vanilla uncoded */
|
||||
fwrite(bitbuf, 1, fsk->Nbits, (FILE*)ctx); /* one bit per byte */
|
||||
else {
|
||||
/* LDPC_FEC */
|
||||
if (periodic_output) {
|
||||
/* in this mode we output status (and data if available) regularly, which is useful
|
||||
for driving state machines */
|
||||
fwrite(&rx_status, 1, 1, (FILE*)ctx);
|
||||
/* write a dummy frame if no bytes available */
|
||||
if (rx_status & FREEDV_RX_BITS) {
|
||||
fwrite(bytes_out, 1, nbytes, (FILE*)ctx);
|
||||
}
|
||||
else
|
||||
fwrite(zeros_out, 1, data_bytes_per_frame, (FILE*)ctx);
|
||||
|
||||
}
|
||||
else /* in this mode we only output bytes when available */
|
||||
if (rx_status & FREEDV_RX_BITS)
|
||||
fwrite(bytes_out, 1, nbytes, (FILE*)ctx); /* packed bytes */
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if((FILE*)ctx == stdout) fflush((FILE*)ctx);
|
||||
|
||||
if (dashboard) {
|
||||
update_dashboard(fsk);
|
||||
}
|
||||
}
|
||||
/* copy left over modem samples to start of buffer */
|
||||
memmove(modembuf, pmodembuf, nmodembuf*sizeof(COMP));
|
||||
|
||||
if (bytes_to_read > 0)
|
||||
bytes_to_read -= len;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
struct sigaction sigact;
|
||||
#endif
|
||||
char *filename = NULL;
|
||||
int n_read;
|
||||
int r, opt;
|
||||
int gain = 0;
|
||||
int ppm_error = 0;
|
||||
int sync_mode = 0;
|
||||
FILE *file;
|
||||
uint8_t *buffer;
|
||||
int dev_index = 0;
|
||||
int dev_given = 0;
|
||||
char hostname[256];
|
||||
uint32_t frequency = 100000000;
|
||||
int M = DEFAULT_M;
|
||||
int channel_width = DEFAULT_CHANNEL_WIDTH;
|
||||
uint32_t bandwidth = DEFAULT_BANDWIDTH;
|
||||
int tone_spacing = 100;
|
||||
int freq_est_mask = 0;
|
||||
int ext_gain = 0;
|
||||
int gains_hex, lna_gain=15, mixer_gain=15, vga_gain=8;
|
||||
int opt_idx = 0;
|
||||
struct freedv_advanced adv;
|
||||
int use_testframes = 0;
|
||||
|
||||
output_bits = 1;
|
||||
opt = 0;
|
||||
|
||||
while( opt != -1 ){
|
||||
static struct option long_opts[] = {
|
||||
{"listcodes", no_argument, 0, 'j'},
|
||||
{"code", required_argument, 0, 'k'},
|
||||
{"testframes",no_argument, 0, 'i'},
|
||||
{"vv", no_argument, 0, 'l'},
|
||||
{"mask", required_argument, 0, 't'},
|
||||
{"filter", required_argument, 0, 'o'},
|
||||
{"injectsnr", no_argument, 0, 'n'},
|
||||
{"logsnr", no_argument, 0, 'L'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
opt = getopt_long(argc,argv,"a:d:e:f:g:S:bn:p:s:u:r:Lm:c:M:R:xt:w:jk:vq",long_opts,&opt_idx);
|
||||
if (opt != -1) {
|
||||
switch (opt) {
|
||||
case 'a':
|
||||
modem_samp_rate = (uint32_t)atofs(optarg);
|
||||
break;
|
||||
case 'j':
|
||||
ldpc_codes_list();
|
||||
exit(0);
|
||||
break;
|
||||
case 'k':
|
||||
fsk_ldpc = 1;
|
||||
adv.codename = optarg;
|
||||
break;
|
||||
case 'i':
|
||||
if (fsk_ldpc == 0) {
|
||||
fprintf(stderr, "internal testframe mode only supported in --code coded mode!\n");
|
||||
exit(1);
|
||||
}
|
||||
use_testframes = 1;
|
||||
break;
|
||||
case 'd':
|
||||
dev_index = verbose_device_search(optarg);
|
||||
dev_given = 1;
|
||||
break;
|
||||
case 'e':
|
||||
ext_gain = 1;
|
||||
gains_hex = (int)strtol(optarg, NULL, 16);
|
||||
lna_gain = gains_hex >> 8; mixer_gain = (gains_hex >> 4) & 0xf; vga_gain = gains_hex & 0xf;
|
||||
fprintf(stderr, "lna_gain: %d mixer_gain: %d vga_gain: %d\n", lna_gain, mixer_gain, vga_gain);
|
||||
break;
|
||||
case 'f':
|
||||
frequency = (uint32_t)atofs(optarg);
|
||||
break;
|
||||
case 'g':
|
||||
gain = (int)(atof(optarg) * 10); /* tenths of a dB */
|
||||
/* note YMMV - these will vary across RTLSDR brands and samples */
|
||||
|
||||
/* Initial calibration with Fs=200E3 and Rs=10E3, so lets normalise such
|
||||
that other ratios can be used */
|
||||
float cal_Fs_on_Rs = 20.0*log10(200/10);
|
||||
if (gain/10 == 49)
|
||||
RxGain = -90.7 + cal_Fs_on_Rs;
|
||||
else if (gain/10 == 45)
|
||||
RxGain = -85.6 + cal_Fs_on_Rs;
|
||||
else if (gain/10 == 40)
|
||||
RxGain = -81.1 + cal_Fs_on_Rs;
|
||||
else if (gain/10 == 35)
|
||||
RxGain = -76.9 + cal_Fs_on_Rs;
|
||||
else if (gain/10 == 30)
|
||||
RxGain = -71.0 + cal_Fs_on_Rs;
|
||||
else
|
||||
fprintf(stderr,"rtl_fsk: WARNING RxGain not calibrated at this -g gain\n");
|
||||
fprintf(stderr,"rtl_fsk: RxGain: %f\n", RxGain);
|
||||
break;
|
||||
case 's':
|
||||
samp_rate = (uint32_t)atofs(optarg);
|
||||
break;
|
||||
case 'w':
|
||||
bandwidth = (uint32_t)atofs(optarg);
|
||||
break;
|
||||
case 'p':
|
||||
ppm_error = atoi(optarg);
|
||||
break;
|
||||
case 'q':
|
||||
periodic_output = 1;
|
||||
break;
|
||||
case 'b':
|
||||
inject_snr = 1;
|
||||
break;
|
||||
case 'n':
|
||||
bytes_to_read = (uint32_t)atof(optarg) * 2;
|
||||
break;
|
||||
case 'o':
|
||||
filter = strtol(optarg, NULL, 0);
|
||||
break;
|
||||
case 'R':
|
||||
case 'r':
|
||||
Rs = atoi(optarg);
|
||||
break;
|
||||
case 'M':
|
||||
case 'm':
|
||||
M = atoi(optarg);
|
||||
break;
|
||||
case 'S':
|
||||
sync_mode = 1;
|
||||
break;
|
||||
case 'u':
|
||||
dashboard = 1;
|
||||
strcpy(hostname, optarg);
|
||||
break;
|
||||
M = atoi(optarg);
|
||||
break;
|
||||
case 'c':
|
||||
channel_width = atoi(optarg);
|
||||
break;
|
||||
case 'x':
|
||||
output_bits = 0;
|
||||
break;
|
||||
case 't':
|
||||
freq_est_mask = 1;
|
||||
tone_spacing = atoi(optarg);
|
||||
break;
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
break;
|
||||
case 'l':
|
||||
verbose = 2;
|
||||
break;
|
||||
case 'L':
|
||||
log_snr = 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)); assert(buffer != NULL);
|
||||
nrawbuf_max = 2 * out_block_size;
|
||||
rawbuf = malloc(nrawbuf_max * sizeof(uint8_t)); assert(rawbuf != NULL);
|
||||
nrawbuf = 0;
|
||||
|
||||
assert((samp_rate % modem_samp_rate) == 0);
|
||||
nmodembuf_max = nrawbuf_max*samp_rate/modem_samp_rate;
|
||||
modembuf = (COMP*)malloc(nmodembuf_max * sizeof(COMP)); assert(modembuf != NULL);
|
||||
|
||||
/* create UDP socket for dashboard debug/status information ----------------------------- */
|
||||
|
||||
if (dashboard) {
|
||||
struct hostent *server;
|
||||
|
||||
/* socket: create the socket */
|
||||
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sockfd < 0) {
|
||||
fprintf(stderr,"ERROR opening socket");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* gethostbyname: get the server's DNS entry */
|
||||
server = gethostbyname(hostname);
|
||||
if (server == NULL) {
|
||||
fprintf(stderr,"ERROR, no such host as %s\n", hostname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* build the server's Internet address */
|
||||
bzero((char *) &serveraddr, sizeof(serveraddr));
|
||||
serveraddr.sin_family = AF_INET;
|
||||
bcopy((char *)server->h_addr,
|
||||
(char *)&serveraddr.sin_addr.s_addr, server->h_length);
|
||||
serveraddr.sin_port = htons(portno);
|
||||
}
|
||||
|
||||
/* continue RTL SDR setup ...... */
|
||||
|
||||
if (!dev_given) {
|
||||
dev_index = verbose_device_search("0");
|
||||
}
|
||||
|
||||
if (dev_index < 0) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
r = rtlsdr_open(&dev, (uint32_t)dev_index);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "Failed to open rtlsdr device #%d.\n", dev_index);
|
||||
exit(1);
|
||||
}
|
||||
#ifndef _WIN32
|
||||
sigact.sa_handler = sighandler;
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = 0;
|
||||
sigaction(SIGINT, &sigact, NULL);
|
||||
sigaction(SIGTERM, &sigact, NULL);
|
||||
sigaction(SIGQUIT, &sigact, NULL);
|
||||
sigaction(SIGPIPE, &sigact, NULL);
|
||||
#else
|
||||
SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE );
|
||||
#endif
|
||||
/* Set the sample rate */
|
||||
verbose_set_sample_rate(dev, samp_rate);
|
||||
|
||||
/* Set the tuner bandwidth */
|
||||
verbose_set_bandwidth(dev, bandwidth);
|
||||
|
||||
/* Set the frequency */
|
||||
verbose_set_frequency(dev, frequency);
|
||||
|
||||
if (ext_gain == 0) {
|
||||
if (0 == gain) {
|
||||
/* Enable automatic gain */
|
||||
verbose_auto_gain(dev);
|
||||
} else {
|
||||
/* Enable manual gain */
|
||||
gain = nearest_gain(dev, gain);
|
||||
verbose_gain_set(dev, gain);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "setting extended gain....\n");
|
||||
rtlsdr_set_tuner_gain_ext(dev, lna_gain, mixer_gain, vga_gain);
|
||||
}
|
||||
|
||||
verbose_ppm_set(dev, ppm_error);
|
||||
|
||||
if(strcmp(filename, "-") == 0) { /* Write samples to stdout */
|
||||
file = stdout;
|
||||
#ifdef _WIN32
|
||||
_setmode(_fileno(stdin), _O_BINARY);
|
||||
#endif
|
||||
} else {
|
||||
file = fopen(filename, "wb");
|
||||
if (!file) {
|
||||
fprintf(stderr, "Failed to open %s\n", filename);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup the CSDR Decimator -------------------------------------------------*/
|
||||
{
|
||||
// design decimating filter
|
||||
float transition_bw = 0.05;
|
||||
window_t window = WINDOW_DEFAULT;
|
||||
|
||||
if (samp_rate % modem_samp_rate) {
|
||||
fprintf(stderr, "ERROR: samplerate/modem_samplerate = %d/%d must be an integer\n",
|
||||
samp_rate, modem_samp_rate);
|
||||
exit(1);
|
||||
}
|
||||
csdr_factor = samp_rate/modem_samp_rate;
|
||||
csdr_taps = csdr_init_decimate_cc(csdr_factor, transition_bw, window, &csdr_padded_taps_length);
|
||||
assert(CSDR_BUFSIZE > padded_taps_length);
|
||||
|
||||
// first call to work out how many input samples needed (csdr_nin)
|
||||
csdr_decimate_cc(csdr_out, csdr_in, CSDR_BUFSIZE, csdr_taps, csdr_padded_taps_length, csdr_factor, &csdr_nout, &csdr_nin);
|
||||
}
|
||||
|
||||
/* Setup the FSK demod -------------------------------------------------*/
|
||||
|
||||
if (modem_samp_rate % Rs) {
|
||||
fprintf(stderr, "Error: (modem sample rate) / (modem symbol rate) must be an integer\n");
|
||||
exit(1);
|
||||
}
|
||||
if ((modem_samp_rate / Rs) < 8) {
|
||||
fprintf(stderr, "Error: (modem sample rate) / (modem symbol rate) must be >= 8\n");
|
||||
exit(1);
|
||||
}
|
||||
if (fsk_ldpc == 0) {
|
||||
/* uncoded mode: just set up FSK demod by itself */
|
||||
int P = modem_samp_rate/Rs;
|
||||
fsk = fsk_create_hbr(modem_samp_rate,Rs,M,P,FSK_DEFAULT_NSYM,FSK_NONE,tone_spacing);
|
||||
} else {
|
||||
/* coded mode: use FreeDV API to set up and run FSK modem, LDPC, framer */
|
||||
|
||||
int data_bits_per_frame;
|
||||
adv.Rs = Rs; adv.Fs = modem_samp_rate; adv.M = M; adv.tone_spacing = tone_spacing;
|
||||
freedv = freedv_open_advanced(FREEDV_MODE_FSK_LDPC, &adv);
|
||||
assert(freedv != NULL);
|
||||
data_bits_per_frame = freedv_get_bits_per_modem_frame(freedv);
|
||||
assert(data_bits_ber_frame % 8); /* only want codes that send complete bytes */
|
||||
fprintf(stderr, "FSK LDPC mode code: %s data_bits_per_frame: %d\n", adv.codename, data_bits_per_frame);
|
||||
fsk = freedv_get_fsk(freedv);
|
||||
data_bytes_per_frame = data_bits_per_frame / 8;
|
||||
bytes_out = malloc(data_bytes_per_frame); assert(bytes_out != NULL);
|
||||
zeros_out = malloc(data_bytes_per_frame); assert(zeros_out != NULL);
|
||||
memset(zeros_out, 0, data_bytes_per_frame);
|
||||
freedv_set_verbose(freedv, verbose);
|
||||
freedv_set_test_frames(freedv, use_testframes);
|
||||
}
|
||||
fprintf(stderr,"FSK Demod Fs: %5.1f kHz Rs: %3.1f kHz M: %d P: %d Ndft: %d fest_mask: %d\n",
|
||||
(float)modem_samp_rate/1000,
|
||||
(float)Rs/1000, M, fsk->P, fsk->Ndft, freq_est_mask);
|
||||
|
||||
fsk_set_freq_est_alg(fsk, freq_est_mask);
|
||||
{
|
||||
/* set minimum "channel" for freq est */
|
||||
fsk_lower = Rs/2;
|
||||
fsk_upper = 2*M*Rs;
|
||||
if (fsk_lower < 2000) fsk_lower = 2000;
|
||||
if (fsk_upper < channel_width) fsk_upper = channel_width;
|
||||
if (fsk_upper > (int)modem_samp_rate/2) fsk_upper = modem_samp_rate/2;
|
||||
fprintf(stderr,"Setting estimator limits to %d to %d Hz.\n", fsk_lower, fsk_upper);
|
||||
fsk_set_freq_est_limits(fsk,fsk_lower,fsk_upper);
|
||||
}
|
||||
|
||||
/* Reset endpoint before we start reading from it (mandatory) */
|
||||
verbose_reset_buffer(dev);
|
||||
|
||||
if (sync_mode) {
|
||||
fprintf(stderr, "Reading samples in sync mode...\n");
|
||||
while (!do_exit) {
|
||||
r = rtlsdr_read_sync(dev, buffer, out_block_size, &n_read);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "WARNING: sync read failed.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if ((bytes_to_read > 0) && (bytes_to_read < (uint32_t)n_read)) {
|
||||
n_read = bytes_to_read;
|
||||
do_exit = 1;
|
||||
}
|
||||
|
||||
if (fwrite(buffer, 1, n_read, file) != (size_t)n_read) {
|
||||
fprintf(stderr, "Short write, samples lost, exiting!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if ((uint32_t)n_read < out_block_size) {
|
||||
fprintf(stderr, "Short read, samples lost, exiting!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (bytes_to_read > 0)
|
||||
bytes_to_read -= n_read;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Reading samples in async mode...\n");
|
||||
r = rtlsdr_read_async(dev, rtlsdr_callback, (void *)file,
|
||||
0, out_block_size);
|
||||
}
|
||||
|
||||
if (do_exit)
|
||||
fprintf(stderr, "\nUser cancel, exiting...\n");
|
||||
else
|
||||
fprintf(stderr, "\nLibrary error %d, exiting...\n", r);
|
||||
|
||||
if (file != stdout)
|
||||
fclose(file);
|
||||
|
||||
rtlsdr_close(dev);
|
||||
if (fsk_ldpc == 0)
|
||||
fsk_destroy(fsk);
|
||||
else {
|
||||
free(bytes_out);
|
||||
freedv_close(freedv);
|
||||
}
|
||||
|
||||
free (buffer);
|
||||
free (rawbuf);
|
||||
free(modembuf);
|
||||
out:
|
||||
return r >= 0 ? r : -r;
|
||||
}
|
|
@ -210,13 +210,20 @@ int main(int argc, char **argv)
|
|||
fprintf(stderr, "Opened '%s' for input\n", rawfilename);
|
||||
if (!haveTime) {
|
||||
int gotmodtim = 0;
|
||||
#ifdef _WIN32
|
||||
#if defined(_WIN32)
|
||||
struct _stat attr;
|
||||
if (!_stat(rawfilename, &attr)) {
|
||||
tim = attr.st_mtime;
|
||||
fraction = 0.0;
|
||||
gotmodtim = 1;
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
struct stat attr;
|
||||
if (!stat(rawfilename, &attr)) {
|
||||
tim = attr.st_mtime;
|
||||
fraction = attr.st_mtimespec.tv_nsec / 1E9;
|
||||
gotmodtim = 1;
|
||||
}
|
||||
#else
|
||||
struct stat attr;
|
||||
if (!stat(rawfilename, &attr)) {
|
||||
|
|
|
@ -62,6 +62,7 @@ void usage(void)
|
|||
"\t[-s samplerate (default: 2048000 Hz)]\n"
|
||||
"\t[-w tuner_bandwidth (default: automatic)]\n"
|
||||
"\t[-d device_index or serial (default: 0)]\n"
|
||||
"\t[-e extended gain -e 0xlmi (l,m,i single hex digits 0-f)\n"
|
||||
"\t[-g gain (default: 0 for auto)]\n"
|
||||
"\t[-p ppm_error (default: 0)]\n"
|
||||
"%s"
|
||||
|
@ -158,13 +159,21 @@ int main(int argc, char **argv)
|
|||
uint32_t samp_rate = DEFAULT_SAMPLE_RATE;
|
||||
uint32_t out_block_size = DEFAULT_BUF_LENGTH;
|
||||
int verbosity = 0;
|
||||
|
||||
while ((opt = getopt(argc, argv, "d:f:g:s:w:b:n:p:O:SNHv")) != -1) {
|
||||
int ext_gain = 0;
|
||||
int gains_hex, lna_gain, mixer_gain, vga_gain;
|
||||
|
||||
while ((opt = getopt(argc, argv, "d:e:f:g:s:w:b:n:p:O:SNHv")) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
dev_index = verbose_device_search(optarg);
|
||||
dev_given = 1;
|
||||
break;
|
||||
case 'e':
|
||||
ext_gain = 1;
|
||||
gains_hex = (int)strtol(optarg, NULL, 16);
|
||||
lna_gain = gains_hex >> 8; mixer_gain = (gains_hex >> 4) & 0xf; vga_gain = gains_hex & 0xf;
|
||||
fprintf(stderr, "lna_gain: %d mixer_gain: %d vga_gain: %d\n", lna_gain, mixer_gain, vga_gain);
|
||||
break;
|
||||
case 'f':
|
||||
frequency = (uint32_t)atofs(optarg);
|
||||
break;
|
||||
|
@ -270,15 +279,20 @@ int main(int argc, char **argv)
|
|||
/* Set the frequency */
|
||||
verbose_set_frequency(dev, frequency);
|
||||
|
||||
if (0 == gain) {
|
||||
/* Enable automatic gain */
|
||||
if (ext_gain == 0) {
|
||||
if (0 == gain) {
|
||||
/* Enable automatic gain */
|
||||
verbose_auto_gain(dev);
|
||||
} else {
|
||||
} else {
|
||||
/* Enable manual gain */
|
||||
gain = nearest_gain(dev, gain);
|
||||
verbose_gain_set(dev, gain);
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "setting extended gain....\n");
|
||||
rtlsdr_set_tuner_gain_ext(dev, lna_gain, mixer_gain, vga_gain);
|
||||
}
|
||||
|
||||
if (rtlOpts) {
|
||||
rtlsdr_set_opt_string(dev, rtlOpts, verbosity);
|
||||
}
|
||||
|
|
247
src/rtl_tcp.c
247
src/rtl_tcp.c
|
@ -289,20 +289,55 @@ static int set_gain_by_index(rtlsdr_dev_t *_dev, unsigned int index)
|
|||
int* gains;
|
||||
int count = rtlsdr_get_tuner_gains(_dev, NULL);
|
||||
|
||||
if (count > 0 && (unsigned int)count > index) {
|
||||
if (count > 0 && index < (unsigned int)count) {
|
||||
gains = malloc(sizeof(int) * count);
|
||||
count = rtlsdr_get_tuner_gains(_dev, gains);
|
||||
|
||||
res = rtlsdr_set_tuner_gain(_dev, gains[index]);
|
||||
if (verbosity)
|
||||
fprintf(stderr, "set tuner gain to %.1f dB\n", gains[index] / 10.0);
|
||||
printf("set tuner gain to %.1f dB\n", gains[index] / 10.0);
|
||||
res = rtlsdr_set_tuner_gain(_dev, gains[index]);
|
||||
if (res < 0)
|
||||
printf(" error setting tuner gain index failed\n");
|
||||
|
||||
free(gains);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("set tuner gain index to %u\n", index);
|
||||
printf(" error setting tuner gain index failed: valid range: 0 .. %d\n", count-1);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void check_tuner_pll(rtlsdr_dev_t *dev, int *tuner_unsupported, int *last_lock_report)
|
||||
{
|
||||
int r = rtlsdr_is_tuner_PLL_locked(dev);
|
||||
/* printf("performed lock check:\n"); */
|
||||
if (r == 1) {
|
||||
if (*last_lock_report != r)
|
||||
printf("tuner PLL is unlocked!\n");
|
||||
*last_lock_report = r;
|
||||
}
|
||||
else if (r == 0) {
|
||||
if (*last_lock_report != r)
|
||||
printf("tuner PLL is locked.\n");
|
||||
*last_lock_report = r;
|
||||
}
|
||||
else if (r == -2) {
|
||||
printf("error at PLL-locked check: tuner not supported! No further tests.\n");
|
||||
*tuner_unsupported = 1;
|
||||
}
|
||||
else if (r < 0)
|
||||
printf("error checking tuner PLL!\n");
|
||||
else
|
||||
printf("unknown error at tuner PLL check!\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#define __attribute__(x)
|
||||
#pragma pack(push, 1)
|
||||
|
@ -320,10 +355,14 @@ static void *command_worker(void *arg)
|
|||
fd_set readfds;
|
||||
struct command cmd={0, 0};
|
||||
struct timeval tv= {1, 0};
|
||||
unsigned tuner_check_timeout = 0;
|
||||
int last_lock_report = -1;
|
||||
int tuner_unsupported = 0;
|
||||
int r = 0;
|
||||
uint32_t tmp;
|
||||
int32_t itmp;
|
||||
int32_t if_band_center_freq;
|
||||
int iitmp;
|
||||
|
||||
while(1) {
|
||||
left=sizeof(cmd);
|
||||
|
@ -336,6 +375,19 @@ static void *command_worker(void *arg)
|
|||
if(r) {
|
||||
received = recv(s, (char*)&cmd+(sizeof(cmd)-left), left, 0);
|
||||
left -= received;
|
||||
/* printf("received %d bytes\n", received); */
|
||||
}
|
||||
else if (!tuner_unsupported)
|
||||
{
|
||||
/* timeout: nothing happend */
|
||||
++tuner_check_timeout;
|
||||
if (tuner_check_timeout >= 3)
|
||||
{
|
||||
/* automatic check every 3 seconds */
|
||||
check_tuner_pll(dev, &tuner_unsupported, &last_lock_report);
|
||||
tuner_check_timeout = 0;
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
if(received == SOCKET_ERROR || do_exit) {
|
||||
printf("comm recv bye\n");
|
||||
|
@ -347,61 +399,90 @@ static void *command_worker(void *arg)
|
|||
case SET_FREQUENCY:
|
||||
tmp = ntohl(cmd.param);
|
||||
printf("set freq %u\n", tmp);
|
||||
rtlsdr_set_center_freq(dev, tmp);
|
||||
r = rtlsdr_set_center_freq(dev, tmp);
|
||||
if (r < 0) {
|
||||
printf(" error setting frequency!\n");
|
||||
last_lock_report = -1;
|
||||
}
|
||||
break;
|
||||
case SET_SAMPLE_RATE:
|
||||
tmp = ntohl(cmd.param);
|
||||
printf("set sample rate %u\n", tmp);
|
||||
rtlsdr_set_sample_rate(dev, tmp);
|
||||
/*verbose_set_bandwidth(dev, bandwidth);*/
|
||||
r = rtlsdr_set_sample_rate(dev, tmp);
|
||||
if (r < 0)
|
||||
printf(" error setting sample rate! sample rate is %u\n", rtlsdr_get_sample_rate(dev));
|
||||
break;
|
||||
case SET_GAIN_MODE:
|
||||
tmp = ntohl(cmd.param);
|
||||
printf("set gain mode %u\n", tmp);
|
||||
rtlsdr_set_tuner_gain_mode(dev, tmp);
|
||||
printf("set gain mode %u (=%s)\n", tmp, tmp?"manual":"automatic");
|
||||
r = rtlsdr_set_tuner_gain_mode(dev, tmp);
|
||||
if (r < 0)
|
||||
printf(" error setting gain mode!\n");
|
||||
break;
|
||||
case SET_GAIN:
|
||||
tmp = ntohl(cmd.param);
|
||||
printf("set gain %u\n", tmp);
|
||||
rtlsdr_set_tuner_gain(dev, tmp);
|
||||
printf("set manual tuner gain %.1f dB\n", tmp/10.0);
|
||||
r = rtlsdr_set_tuner_gain(dev, tmp);
|
||||
if (r < 0)
|
||||
printf(" error setting tuner gain!\n");
|
||||
break;
|
||||
case SET_FREQUENCY_CORRECTION:
|
||||
itmp = ntohl(cmd.param);
|
||||
printf("set freq correction %d\n", itmp);
|
||||
rtlsdr_set_freq_correction(dev, itmp);
|
||||
printf("set freq correction %d ppm\n", itmp);
|
||||
r = rtlsdr_set_freq_correction(dev, itmp);
|
||||
if (r < 0) {
|
||||
printf(" error setting frequency correction!\n");
|
||||
last_lock_report = -1;
|
||||
}
|
||||
break;
|
||||
case SET_IF_STAGE:
|
||||
tmp = ntohl(cmd.param);
|
||||
printf("set if stage %d gain %d\n", tmp >> 16, (short)(tmp & 0xffff));
|
||||
rtlsdr_set_tuner_if_gain(dev, tmp >> 16, (short)(tmp & 0xffff));
|
||||
printf("set if stage %d gain %.1f dB\n", tmp >> 16, ((short)(tmp & 0xffff))/10.0);
|
||||
r = rtlsdr_set_tuner_if_gain(dev, tmp >> 16, (short)(tmp & 0xffff));
|
||||
if (r < 0)
|
||||
printf(" error setting gain for stage!\n");
|
||||
break;
|
||||
case SET_TEST_MODE:
|
||||
tmp = ntohl(cmd.param);
|
||||
printf("set test mode %d\n", tmp);
|
||||
rtlsdr_set_testmode(dev, tmp);
|
||||
printf("set test mode %d (=%s)\n", tmp, tmp?"active":"inactive");
|
||||
r = rtlsdr_set_testmode(dev, tmp);
|
||||
if (r < 0)
|
||||
printf(" error setting test mode!\n");
|
||||
break;
|
||||
case SET_AGC_MODE:
|
||||
tmp = ntohl(cmd.param);
|
||||
printf("set agc mode %d\n", tmp);
|
||||
rtlsdr_set_agc_mode(dev, tmp);
|
||||
printf("set rtl2832's digital agc mode %d (=%s)\n", tmp, tmp?"enabled":"disabled");
|
||||
r = rtlsdr_set_agc_mode(dev, tmp);
|
||||
if (r < 0)
|
||||
printf(" error setting digital agc mode!\n");
|
||||
break;
|
||||
case SET_DIRECT_SAMPLING:
|
||||
tmp = ntohl(cmd.param);
|
||||
printf("set direct sampling %u\n", tmp);
|
||||
rtlsdr_set_direct_sampling(dev, tmp);
|
||||
printf("set direct sampling %u (=%s)\n", tmp, (!tmp) ? "disabled": (tmp==1)?"pin I-ADC": (tmp==2)? "pin Q-ADC":"unknown!");
|
||||
r = rtlsdr_set_direct_sampling(dev, tmp);
|
||||
if (r < 0)
|
||||
printf(" error setting direct sampling!\n");
|
||||
break;
|
||||
case SET_OFFSET_TUNING:
|
||||
itmp = ntohl(cmd.param);
|
||||
printf("set offset tuning %d\n", itmp);
|
||||
rtlsdr_set_offset_tuning(dev, itmp);
|
||||
r = rtlsdr_set_offset_tuning(dev, itmp);
|
||||
if (r < 0) {
|
||||
printf(" error setting offset tuning!\n");
|
||||
last_lock_report = -1;
|
||||
}
|
||||
break;
|
||||
case SET_RTL_CRYSTAL:
|
||||
printf("set rtl xtal %d\n", ntohl(cmd.param));
|
||||
rtlsdr_set_xtal_freq(dev, ntohl(cmd.param), 0);
|
||||
printf("set rtl xtal frequency %d\n", ntohl(cmd.param));
|
||||
r = rtlsdr_set_xtal_freq(dev, ntohl(cmd.param), 0);
|
||||
if (r < 0)
|
||||
printf(" error setting rtl xtal frequency!\n");
|
||||
break;
|
||||
case SET_TUNER_CRYSTAL:
|
||||
printf("set tuner xtal %d\n", ntohl(cmd.param));
|
||||
rtlsdr_set_xtal_freq(dev, 0, ntohl(cmd.param));
|
||||
r = rtlsdr_set_xtal_freq(dev, 0, ntohl(cmd.param));
|
||||
if (r < 0)
|
||||
printf(" error setting tuner xtal frequency!\n");
|
||||
break;
|
||||
case SET_TUNER_GAIN_BY_INDEX:
|
||||
tmp = ntohl(cmd.param);
|
||||
|
@ -410,8 +491,10 @@ static void *command_worker(void *arg)
|
|||
break;
|
||||
case SET_BIAS_TEE:
|
||||
tmp = ntohl(cmd.param);
|
||||
printf("set bias tee %u\n", tmp);
|
||||
rtlsdr_set_bias_tee(dev, tmp);
|
||||
printf("set bias T %u (%s)\n", tmp, tmp?"on":"off");
|
||||
r = rtlsdr_set_bias_tee(dev, tmp);
|
||||
if (r < 0)
|
||||
printf(" error setting bias tee!\n");
|
||||
break;
|
||||
case SET_TUNER_BANDWIDTH:
|
||||
bandwidth = ntohl(cmd.param);
|
||||
|
@ -421,29 +504,51 @@ static void *command_worker(void *arg)
|
|||
case SET_I2C_TUNER_REGISTER:
|
||||
tmp = ntohl(cmd.param);
|
||||
printf("set i2c register x%03X to x%03X with mask x%02X\n", (tmp >> 20) & 0xfff, tmp & 0xfff, (tmp >> 12) & 0xff );
|
||||
rtlsdr_set_tuner_i2c_register(dev, (tmp >> 20) & 0xfff, (tmp >> 12) & 0xff, tmp & 0xfff);
|
||||
r = rtlsdr_set_tuner_i2c_register(dev, (tmp >> 20) & 0xfff, (tmp >> 12) & 0xff, tmp & 0xfff);
|
||||
if (r < 0)
|
||||
printf(" error setting i2c register!\n");
|
||||
break;
|
||||
case SET_I2C_TUNER_OVERRIDE:
|
||||
tmp = ntohl(cmd.param);
|
||||
printf("set i2c override register x%03X to x%03X with mask x%02X\n", (tmp >> 20) & 0xfff, tmp & 0xfff, (tmp >> 12) & 0xff );
|
||||
rtlsdr_set_tuner_i2c_override(dev, (tmp >> 20) & 0xfff, (tmp >> 12) & 0xff, tmp & 0xfff);
|
||||
r = rtlsdr_set_tuner_i2c_override(dev, (tmp >> 20) & 0xfff, (tmp >> 12) & 0xff, tmp & 0xfff);
|
||||
if (r < 0)
|
||||
printf(" error setting i2c register!\n");
|
||||
break;
|
||||
case SET_TUNER_BW_IF_CENTER:
|
||||
if_band_center_freq = ntohl(cmd.param);
|
||||
printf("set tuner band to IF frequency %i Hz from center\n", if_band_center_freq);
|
||||
rtlsdr_set_tuner_band_center(dev, if_band_center_freq );
|
||||
r = rtlsdr_set_tuner_band_center(dev, if_band_center_freq );
|
||||
if (r < 0)
|
||||
printf(" error setting tuner band's IF center frequency!\n");
|
||||
break;
|
||||
case SET_TUNER_IF_MODE:
|
||||
itmp = ntohl(cmd.param);
|
||||
printf("set tuner IF mode to %i\n", itmp);
|
||||
rtlsdr_set_tuner_if_mode(dev, itmp);
|
||||
printf("set tuner IF mode to %i: ", itmp);
|
||||
if (!itmp)
|
||||
printf("automatic gain of VGA controlled from RTL2832\n");
|
||||
else if (-2500 <= itmp && itmp <= 2500)
|
||||
printf("VGA nearest to %.1f dB)\n", itmp/10.0);
|
||||
else if (10000 <=itmp && itmp <= 10015)
|
||||
printf("VGA gain idx %d\n", itmp - 10000);
|
||||
else if (10016 <= itmp && itmp <= 10031)
|
||||
printf("VGA gain idx %d - but with automatic gain of VGA controlled from RTL2832\n", itmp-10016);
|
||||
else
|
||||
printf("unknown!\n");
|
||||
r = rtlsdr_set_tuner_if_mode(dev, itmp);
|
||||
if (r < 0)
|
||||
printf(" error setting tuner IF mode!\n");
|
||||
break;
|
||||
case SET_SIDEBAND:
|
||||
tmp = ntohl(cmd.param);
|
||||
if(tmp)
|
||||
tmp = 1;
|
||||
printf("set to %s sideband\n", (tmp ? "upper" : "lower") );
|
||||
rtlsdr_set_tuner_sideband(dev, tmp);
|
||||
printf("set tuner sideband %d: %s sideband\n", tmp, (tmp ? "upper" : "lower") );
|
||||
r = rtlsdr_set_tuner_sideband(dev, tmp);
|
||||
if (r < 0) {
|
||||
printf(" error setting tuner sideband!\n");
|
||||
last_lock_report = -1;
|
||||
}
|
||||
break;
|
||||
case REPORT_I2C_REGS:
|
||||
tmp = ntohl(cmd.param);
|
||||
|
@ -451,7 +556,83 @@ static void *command_worker(void *arg)
|
|||
tmp = 1;
|
||||
ctrldata.report_i2c = tmp; /* (de)activate reporting */
|
||||
break;
|
||||
case GPIO_SET_OUTPUT_MODE: /* rtlsdr_set_gpio_output() */
|
||||
itmp = ntohl(cmd.param);
|
||||
if ( 0 <= itmp && itmp < 8 )
|
||||
{
|
||||
printf("set gpio pin %d to output\n", itmp);
|
||||
r = rtlsdr_set_gpio_output(dev, (uint8_t)itmp);
|
||||
if (r < 0)
|
||||
printf(" error setting gpio pin to output mode!\n");
|
||||
}
|
||||
else
|
||||
printf("set gpio pin %d to output: error: pin has to be in 0 .. 7\n", itmp);
|
||||
break;
|
||||
case GPIO_SET_INPUT_MODE: /* rtlsdr_set_gpio_input() */
|
||||
itmp = ntohl(cmd.param);
|
||||
if ( 0 <= itmp && itmp < 8 )
|
||||
{
|
||||
printf("set gpio pin %d to input\n", itmp);
|
||||
r = rtlsdr_set_gpio_input(dev, (uint8_t)itmp);
|
||||
if (r < 0)
|
||||
printf(" error setting gpio pin to input mode!\n");
|
||||
}
|
||||
else
|
||||
printf("set gpio pin %d to input: error: pin has to be in 0 .. 7\n", itmp);
|
||||
break;
|
||||
case GPIO_GET_IO_STATUS: /* rtlsdr_set_gpio_status() */
|
||||
r = rtlsdr_set_gpio_status(dev, &iitmp );
|
||||
if (r < 0)
|
||||
printf("error at requesting gpio io status!\n");
|
||||
else
|
||||
printf("request for gpio io status: 0x%02x = %d%d%d%d %d%d%d%d for bits 7 .. 0\n",
|
||||
iitmp & 0xff,
|
||||
(iitmp >>7) & 1, (iitmp >>6) & 1, (iitmp >>5) & 1, (iitmp >>4) & 1,
|
||||
(iitmp >>3) & 1, (iitmp >>2) & 1, (iitmp >>1) & 1, iitmp & 1 );
|
||||
break;
|
||||
case GPIO_WRITE_PIN: /* rtlsdr_set_gpio_bit() */
|
||||
itmp = ntohl(cmd.param);
|
||||
if ( 0 <= ((itmp >> 16) & 0xffff) && ((itmp >> 16) & 0xffff) < 8 )
|
||||
{
|
||||
printf("write %d to gpio %d\n", itmp & 0xffff, (itmp >> 16) & 0xffff);
|
||||
rtlsdr_set_gpio_output(dev, (uint8_t)((itmp >> 16) & 0xffff));
|
||||
rtlsdr_set_gpio_bit(dev, (uint8_t)((itmp >> 16) & 0xffff), itmp & 0xffff);
|
||||
}
|
||||
else
|
||||
printf("write %d to gpio %d: error: pin has to be in 0 .. 7\n", itmp & 0xffff, (itmp >> 16) & 0xffff);
|
||||
break;
|
||||
case GPIO_READ_PIN:
|
||||
itmp = ntohl(cmd.param);
|
||||
if ( 0 <= itmp && itmp < 8 )
|
||||
{
|
||||
r = rtlsdr_get_gpio_bit(dev, itmp, &iitmp);
|
||||
if (r < 0)
|
||||
printf(" error reading gpio pin!\n");
|
||||
else
|
||||
printf("read gpio pin %d: %d\n", itmp, iitmp);
|
||||
}
|
||||
else
|
||||
printf("read gpio pin %d out of range: pin has to be in 0 .. 7\n", itmp);
|
||||
break;
|
||||
case GPIO_GET_BYTE:
|
||||
r = rtlsdr_get_gpio_byte(dev, &iitmp);
|
||||
if (r < 0)
|
||||
printf("error reading gpio byte!\n");
|
||||
else
|
||||
printf("read gpio byte: 0x%02x = %d%d%d%d %d%d%d%d for bits 7 .. 0\n",
|
||||
iitmp & 0xff,
|
||||
(iitmp >>7) & 1, (iitmp >>6) & 1, (iitmp >>5) & 1, (iitmp >>4) & 1,
|
||||
(iitmp >>3) & 1, (iitmp >>2) & 1, (iitmp >>1) & 1, iitmp & 1 );
|
||||
break;
|
||||
case IS_TUNER_PLL_LOCKED:
|
||||
itmp = -1; /* always print lock status */
|
||||
check_tuner_pll(dev, &tuner_unsupported, &itmp);
|
||||
if (itmp != -1)
|
||||
last_lock_report = itmp;
|
||||
tuner_check_timeout = 0;
|
||||
break;
|
||||
default:
|
||||
printf("unknown command 0x%02x\n", cmd.cmd);
|
||||
break;
|
||||
}
|
||||
cmd.cmd = 0xff;
|
||||
|
|
|
@ -107,6 +107,8 @@ void usage(void)
|
|||
"\t[-d device_index or serial (default: 0)]\n"
|
||||
"%s"
|
||||
"\t[-t enable tuner range benchmark]\n"
|
||||
"\t[-f first/begin frequency for tuner range benchmark, default: 0]\n"
|
||||
"\t[-e end frequency for tuner range benchmark, default: 3e9 = 3G ]\n"
|
||||
#ifndef _WIN32
|
||||
"\t[-p[seconds] enable PPM error measurement (default: 10 seconds)]\n"
|
||||
#endif
|
||||
|
@ -338,9 +340,9 @@ static int set_center_freq_wait(rtlsdr_dev_t *dev, uint32_t freq, const char * s
|
|||
}
|
||||
|
||||
|
||||
void tuner_benchmark(void)
|
||||
void tuner_benchmark(uint32_t beg_freq, uint32_t end_freq)
|
||||
{
|
||||
uint32_t current = max_step(0);
|
||||
uint32_t current = beg_freq; /* max_step(0); */
|
||||
uint32_t band_start = 0;
|
||||
uint32_t low_bound = 0, high_bound = 0;
|
||||
int rc;
|
||||
|
@ -357,16 +359,16 @@ void tuner_benchmark(void)
|
|||
*/
|
||||
|
||||
/* handle bands starting at 0Hz */
|
||||
rc = set_center_freq_wait(dev, 0, "FIND_START");
|
||||
rc = set_center_freq_wait(dev, current, "FIND_START");
|
||||
if (rc < 0)
|
||||
state = FIND_START;
|
||||
else {
|
||||
band_start = 0;
|
||||
band_start = current;
|
||||
report_band_start(band_start);
|
||||
state = FIND_END;
|
||||
}
|
||||
|
||||
while (current < 3e9 && !do_exit) {
|
||||
while (current < end_freq && !do_exit) {
|
||||
switch (state) {
|
||||
case FIND_START:
|
||||
/* scanning for the start of a new band */
|
||||
|
@ -508,10 +510,12 @@ int main(int argc, char **argv)
|
|||
int dev_index = 0;
|
||||
int dev_given = 0;
|
||||
uint32_t out_block_size = DEFAULT_BUF_LENGTH;
|
||||
uint32_t tuner_bench_beg_freq = 0;
|
||||
uint32_t tuner_bench_end_freq = 0;
|
||||
int count;
|
||||
int gains[100];
|
||||
|
||||
while ((opt = getopt(argc, argv, "d:s:b:O:tp::Sh")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "d:s:b:O:tf:e:p::Sh")) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
dev_index = verbose_device_search(optarg);
|
||||
|
@ -529,6 +533,12 @@ int main(int argc, char **argv)
|
|||
case 't':
|
||||
test_mode = TUNER_BENCHMARK;
|
||||
break;
|
||||
case 'f':
|
||||
tuner_bench_beg_freq = (uint32_t)atofs(optarg);
|
||||
break;
|
||||
case 'e':
|
||||
tuner_bench_end_freq = (uint32_t)atofs(optarg);
|
||||
break;
|
||||
case 'p':
|
||||
test_mode = PPM_BENCHMARK;
|
||||
if (optarg)
|
||||
|
@ -598,7 +608,7 @@ int main(int argc, char **argv)
|
|||
}
|
||||
|
||||
if (test_mode == TUNER_BENCHMARK) {
|
||||
tuner_benchmark();
|
||||
tuner_benchmark(tuner_bench_beg_freq, tuner_bench_end_freq);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
|
|
@ -108,9 +108,6 @@ int main(int argc, char **argv)
|
|||
int inputFmt = 0; /* PCM16 = 0, FLOAT32 = 1 */
|
||||
int16_t formatTag;
|
||||
uint32_t numFrames;
|
||||
time_t tim = 0;
|
||||
double fraction = 0.0;
|
||||
struct tm *ptm = NULL;
|
||||
|
||||
while ((opt = getopt(argc, argv, "f:w:vh")) != -1) {
|
||||
switch (opt) {
|
||||
|
@ -271,8 +268,8 @@ int main(int argc, char **argv)
|
|||
else if ( inputFmt == 0 && targetFmt == 1 ) {
|
||||
const int16_t *ai = (const int16_t*)pvInp;
|
||||
float * ao = (float*)pvOut;
|
||||
size_t w;
|
||||
for ( size_t k = 0; k < numRead; ++k )
|
||||
size_t w, k;
|
||||
for ( k = 0; k < numRead; ++k )
|
||||
ao[k] = ai[k] * (1.0F / 32768.0F);
|
||||
w = fwrite(pvOut, outSmpSize, numRead, stdout);
|
||||
if ( w != numRead ) {
|
||||
|
@ -284,8 +281,8 @@ int main(int argc, char **argv)
|
|||
else if ( inputFmt == 1 && targetFmt == 0 ) {
|
||||
const float *ai = (const float*)pvInp;
|
||||
int16_t * ao = (int16_t*)pvOut;
|
||||
size_t w;
|
||||
for ( size_t k = 0; k < numRead; ++k )
|
||||
size_t w, k;
|
||||
for ( k = 0; k < numRead; ++k )
|
||||
ao[k] = (int16_t)( ai[k] * 32768.0F );
|
||||
w = fwrite(pvOut, outSmpSize, numRead, stdout);
|
||||
if ( w != numRead ) {
|
||||
|
|
|
@ -33,6 +33,9 @@
|
|||
#define WITH_ASYM_FILTER 0
|
||||
#define PRINT_PLL_ERRORS 0
|
||||
#define PRINT_VGA_REG 0
|
||||
#define PRINT_INITIAL_REGISTERS 0
|
||||
#define PRINT_ACTUAL_VCO_AND_ERR 0
|
||||
|
||||
|
||||
/* #define VGA_FOR_AGC_MODE 16 */
|
||||
#define DEFAULT_IF_VGA_VAL 11
|
||||
|
@ -280,35 +283,35 @@ static const uint8_t r82xx_init_array[] = {
|
|||
|
||||
0xc0, /* Reg 0x08 */
|
||||
0x40, /* Reg 0x09 */
|
||||
0xdb, /* Reg 0x0a */
|
||||
0xdb, /* Reg 0x0a */
|
||||
0x6b, /* Reg 0x0b */
|
||||
|
||||
/* Reg 0x0c:
|
||||
* for manual gain was: set fixed VGA gain for now (16.3 dB): 0x08
|
||||
* with active agc was: set fixed VGA gain for now (26.5 dB): 0x0b */
|
||||
0xe0 | DEFAULT_IF_VGA_VAL, /* Reg 0x0c */
|
||||
0x53, /* Reg 0x0d */
|
||||
0x75, /* Reg 0x0e */
|
||||
0x53, /* Reg 0x0d */
|
||||
0x75, /* Reg 0x0e */
|
||||
0x68, /* Reg 0x0f */
|
||||
|
||||
0x6c, /* Reg 0x10 */
|
||||
0xbb, /* Reg 0x11 */
|
||||
0x80, /* Reg 0x12 */
|
||||
0x6c, /* Reg 0x10 */
|
||||
0xbb, /* Reg 0x11 */
|
||||
0x80, /* Reg 0x12 */
|
||||
VER_NUM & 0x3f, /* Reg 0x13 */
|
||||
|
||||
0x0f, /* Reg 0x14 */
|
||||
0x00, /* Reg 0x15 */
|
||||
0xc0, /* Reg 0x16 */
|
||||
0x0f, /* Reg 0x14 */
|
||||
0x00, /* Reg 0x15 */
|
||||
0xc0, /* Reg 0x16 */
|
||||
0x30, /* Reg 0x17 */
|
||||
|
||||
0x48, /* Reg 0x18 */
|
||||
0xec, /* Reg 0x19 */
|
||||
0x60, /* Reg 0x1a */
|
||||
0x48, /* Reg 0x18 */
|
||||
0xec, /* Reg 0x19 */
|
||||
0x60, /* Reg 0x1a */
|
||||
0x00, /* Reg 0x1b */
|
||||
|
||||
0x24, /* Reg 0x1c */
|
||||
0xdd, /* Reg 0x1d */
|
||||
0x0e, /* Reg 0x1e */
|
||||
0xdd, /* Reg 0x1d */
|
||||
0x0e, /* Reg 0x1e */
|
||||
0x40 /* Reg 0x1f */
|
||||
};
|
||||
|
||||
|
@ -711,6 +714,154 @@ static int r82xx_set_mux(struct r82xx_priv *priv, uint32_t freq)
|
|||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* function of Youssef (AirSpy) and Carl (RTL-SDR) */
|
||||
static int r82xx_set_pll_yc(struct r82xx_priv *priv, uint32_t freq)
|
||||
{
|
||||
const uint32_t vco_min = 1770000000;
|
||||
const uint32_t vco_max = 3900000000U;
|
||||
uint32_t pll_ref = (priv->cfg->xtal);
|
||||
uint32_t pll_ref_2x = (pll_ref * 2);
|
||||
|
||||
int rc;
|
||||
uint32_t vco_exact;
|
||||
uint32_t vco_frac;
|
||||
uint32_t con_frac;
|
||||
uint32_t div_num;
|
||||
uint32_t n_sdm;
|
||||
uint16_t sdm;
|
||||
uint8_t ni;
|
||||
uint8_t si;
|
||||
uint8_t nint;
|
||||
uint8_t val_dith;
|
||||
uint8_t data[5];
|
||||
|
||||
/* Calculate divider */
|
||||
for (div_num = 0; div_num < 5; div_num++)
|
||||
{
|
||||
vco_exact = freq << (div_num + 1);
|
||||
if (vco_exact >= vco_min && vco_exact <= vco_max)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
vco_exact = freq << (div_num + 1);
|
||||
nint = (uint8_t) ((vco_exact + (pll_ref >> 16)) / pll_ref_2x);
|
||||
vco_frac = vco_exact - pll_ref_2x * nint;
|
||||
|
||||
nint -= 13;
|
||||
ni = (nint >> 2);
|
||||
si = nint - (ni << 2);
|
||||
|
||||
/* Set the phase splitter */
|
||||
rc = r82xx_write_reg_mask(priv, 0x10, (uint8_t) (div_num << 5), 0xe0);
|
||||
if(rc < 0) {
|
||||
if (priv->cfg->verbose)
|
||||
fprintf(stderr, "r82xx_set_pll_yc(): error writing 'phase splitter' into i2c reg 0x10\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Disable Dither */
|
||||
val_dith = (priv->disable_dither) ? 0x10 : 0x00;
|
||||
rc = r82xx_write_reg_mask(priv, 0x12, val_dith, 0x18);
|
||||
if (rc < 0) {
|
||||
if (priv->cfg->verbose)
|
||||
fprintf(stderr, "r82xx_set_pll_yc(): error writing 'dither' into i2c reg 0x12\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Set the rough VCO frequency */
|
||||
rc = r82xx_write_reg(priv, 0x14, (uint8_t) (ni + (si << 6)));
|
||||
if(rc < 0) {
|
||||
if (priv->cfg->verbose)
|
||||
fprintf(stderr, "r82xx_set_pll_yc(): error writing 'rough VCO frequency' into i2c reg 0x14\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (vco_frac == 0) {
|
||||
/* Disable frac pll */
|
||||
rc = r82xx_write_reg_mask(priv, 0x12, 0x08, 0x08);
|
||||
if(rc < 0) {
|
||||
if (priv->cfg->verbose)
|
||||
fprintf(stderr, "r82xx_set_pll_yc(): error writing 'disable frac pll' into i2c reg 0x12\n");
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vco_frac += pll_ref >> 16;
|
||||
sdm = 0;
|
||||
for(n_sdm = 0; n_sdm < 16; n_sdm++)
|
||||
{
|
||||
con_frac = pll_ref >> n_sdm;
|
||||
if (vco_frac >= con_frac)
|
||||
{
|
||||
sdm |= (uint16_t) (0x8000 >> n_sdm);
|
||||
vco_frac -= con_frac;
|
||||
if (vco_frac == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
actual_freq = (((nint << 16) + sdm) * (uint64_t) pll_ref_2x) >> (div_num + 1 + 16);
|
||||
delta = freq - actual_freq
|
||||
if (actual_freq != freq)
|
||||
{
|
||||
fprintf(stderr,"Tunning delta: %d Hz", delta);
|
||||
}
|
||||
*/
|
||||
rc = r82xx_write_reg(priv, 0x15, (uint8_t)(sdm & 0xff));
|
||||
if (rc < 0) {
|
||||
if (priv->cfg->verbose)
|
||||
fprintf(stderr, "r82xx_set_pll_yc(): error writing 'sdm lo' into i2c reg 0x15\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = r82xx_write_reg(priv, 0x16, (uint8_t)(sdm >> 8));
|
||||
if (rc < 0) {
|
||||
if (priv->cfg->verbose)
|
||||
fprintf(stderr, "r82xx_set_pll_yc(): error writing 'sdm hi' into i2c reg 0x16\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Enable frac pll */
|
||||
rc = r82xx_write_reg_mask(priv, 0x12, 0x00, 0x08);
|
||||
if (rc < 0) {
|
||||
if (priv->cfg->verbose)
|
||||
fprintf(stderr, "r82xx_set_pll_yc(): error writing 'enable frac pll' into i2c reg 0x12\n");
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
/* all PLL stuff / registers set for this frequency */
|
||||
priv->tuner_pll_set = 1;
|
||||
|
||||
/***/
|
||||
|
||||
/* Check if PLL has locked */
|
||||
rc = r82xx_read(priv, 0x00, data, 3);
|
||||
if (rc < 0) {
|
||||
if (priv->cfg->verbose)
|
||||
fprintf(stderr, "r82xx_set_pll_yc(): error reading 'pll lock status' from i2c reg 0x00..0x02\n");
|
||||
return rc;
|
||||
}
|
||||
if (!(data[2] & 0x40)) {
|
||||
if (priv->cfg->verbose || PRINT_PLL_ERRORS)
|
||||
//fprintf(stderr, "r82xx_set_pll_yc(): error writing 'sdm lo' into i2c reg 0x15\n");
|
||||
fprintf(stderr, "[R82XX] PLL not locked at Tuner LO %u Hz for RF %u Hz!\n",
|
||||
freq, priv->rf_freq);
|
||||
priv->has_lock = 0;
|
||||
return -1;
|
||||
}
|
||||
priv->has_lock = 1;
|
||||
|
||||
return rc;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static int r82xx_set_pll(struct r82xx_priv *priv, uint32_t freq)
|
||||
{
|
||||
/* freq == tuner's LO frequency */
|
||||
|
@ -718,7 +869,7 @@ static int r82xx_set_pll(struct r82xx_priv *priv, uint32_t freq)
|
|||
uint64_t vco_freq;
|
||||
uint64_t vco_div;
|
||||
uint32_t vco_min = 1770000; /* kHz */
|
||||
uint32_t vco_max = vco_min * 2; /* kHz */
|
||||
uint32_t vco_max = (priv->cfg->vco_algo == 0) ? (vco_min * 2) : 3900000; /* kHz */
|
||||
uint32_t freq_khz, pll_ref;
|
||||
uint32_t sdm = 0;
|
||||
uint8_t mix_div = 2;
|
||||
|
@ -727,25 +878,63 @@ static int r82xx_set_pll(struct r82xx_priv *priv, uint32_t freq)
|
|||
uint8_t vco_power_ref = 2;
|
||||
uint8_t refdiv2 = 0;
|
||||
uint8_t ni, si, nint, vco_fine_tune, val;
|
||||
uint8_t vco_curr_min = (priv->cfg->vco_curr_min == 0xff) ? 0x80 : ( priv->cfg->vco_curr_min << 5 );
|
||||
uint8_t vco_curr_max = (priv->cfg->vco_curr_max == 0xff) ? 0x60 : ( priv->cfg->vco_curr_max << 5 );
|
||||
/* devt->r82xx_c.vco_min = 0xff; * VCO min/max current for R18/0x12 bits [7:5] in 0 .. 7. use 0xff for default */
|
||||
/* devt->r82xx_c.vco_max = 0xff; * value is inverted: programmed is 7-value, that 0 is lowest current */
|
||||
uint8_t data[5];
|
||||
|
||||
priv->tuner_pll_set = 0;
|
||||
|
||||
if (priv->cfg->vco_algo == 2)
|
||||
{
|
||||
/* r82xx_set_pll_yc() assumes fixed maximum current */
|
||||
if (priv->last_vco_curr != vco_curr_max) {
|
||||
rc = r82xx_write_reg_mask(priv, 0x12, vco_curr_max, 0xe0);
|
||||
if (rc < 0) {
|
||||
if (priv->cfg->verbose)
|
||||
fprintf(stderr, "r82xx_set_pll(): error writing 'vco current' into i2c reg 0x12\n");
|
||||
return rc;
|
||||
}
|
||||
priv->last_vco_curr = vco_curr_max;
|
||||
}
|
||||
return r82xx_set_pll_yc(priv, freq);
|
||||
}
|
||||
|
||||
/* Frequency in kHz */
|
||||
freq_khz = (freq + 500) / 1000;
|
||||
pll_ref = priv->cfg->xtal;
|
||||
|
||||
rc = r82xx_write_reg_mask(priv, 0x10, refdiv2, 0x10);
|
||||
if (rc < 0)
|
||||
if (rc < 0) {
|
||||
if (priv->cfg->verbose)
|
||||
fprintf(stderr, "r82xx_set_pll(): error writing 'refdiv2' into i2c reg 0x10\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* set pll autotune = 128kHz */
|
||||
rc = r82xx_write_reg_mask(priv, 0x1a, 0x00, 0x0c);
|
||||
if (rc < 0)
|
||||
if (rc < 0) {
|
||||
if (priv->cfg->verbose)
|
||||
fprintf(stderr, "r82xx_set_pll(): error writing 'pll autotune 128kHz' into i2c reg 0x1a\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* set VCO current = 100 */
|
||||
rc = r82xx_write_reg_mask(priv, 0x12, 0x80, 0xe0);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
if (priv->last_vco_curr != vco_curr_min) {
|
||||
rc = r82xx_write_reg_mask(priv, 0x12, vco_curr_min, 0xe0);
|
||||
if (rc < 0) {
|
||||
if (priv->cfg->verbose)
|
||||
fprintf(stderr, "r82xx_set_pll(): error writing 'vco current min' into i2c reg 0x12\n");
|
||||
return rc;
|
||||
}
|
||||
priv->last_vco_curr = vco_curr_min;
|
||||
}
|
||||
|
||||
#if 0
|
||||
fprintf(stderr, "vco_last = 0x%02x; vcocmin << 5 = 0x%02x; vcocmax << 5 = 0x%02x\n",
|
||||
(unsigned)priv->last_vco_curr, (unsigned)vco_curr_min, (unsigned)vco_curr_max);
|
||||
#endif
|
||||
|
||||
/* Calculate divider */
|
||||
while (mix_div <= 64) {
|
||||
|
@ -762,8 +951,11 @@ static int r82xx_set_pll(struct r82xx_priv *priv, uint32_t freq)
|
|||
}
|
||||
|
||||
rc = r82xx_read(priv, 0x00, data, sizeof(data));
|
||||
if (rc < 0)
|
||||
if (rc < 0) {
|
||||
if (priv->cfg->verbose)
|
||||
fprintf(stderr, "r82xx_set_pll(): error reading 'status' from i2c reg 0x00 .. 0x04\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (priv->cfg->rafael_chip == CHIP_R828D)
|
||||
vco_power_ref = 1;
|
||||
|
@ -776,8 +968,11 @@ static int r82xx_set_pll(struct r82xx_priv *priv, uint32_t freq)
|
|||
div_num = div_num + 1;
|
||||
|
||||
rc = r82xx_write_reg_mask(priv, 0x10, div_num << 5, 0xe0);
|
||||
if (rc < 0)
|
||||
if (rc < 0) {
|
||||
if (priv->cfg->verbose)
|
||||
fprintf(stderr, "r82xx_set_pll(): error writing 'div_num' into i2c reg 0x10\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
vco_freq = (uint64_t)freq * (uint64_t)mix_div;
|
||||
|
||||
|
@ -802,18 +997,17 @@ static int r82xx_set_pll(struct r82xx_priv *priv, uint32_t freq)
|
|||
nint = (uint32_t) (vco_div / 65536);
|
||||
sdm = (uint32_t) (vco_div % 65536);
|
||||
|
||||
#if 0
|
||||
#if PRINT_ACTUAL_VCO_AND_ERR
|
||||
{
|
||||
uint64_t actual_vco = (uint64_t)2 * pll_ref * nint + (uint64_t)2 * pll_ref * sdm / 65536;
|
||||
fprintf(stderr, "[R82XX] requested %uHz; selected mix_div=%u vco_freq=%lu nint=%u sdm=%u; actual_vco=%lu; tuning error=%+dHz\n",
|
||||
fprintf(stderr, "[R82XX] requested %u Hz; selected mix_div=%u vco_freq=%lu nint=%u sdm=%u; actual_vco=%lu; tuning error=%+dHz\n",
|
||||
freq, mix_div, vco_freq, nint, sdm, actual_vco, (int32_t) (actual_vco - vco_freq) / mix_div);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (nint > ((128 / vco_power_ref) - 1)) {
|
||||
#if PRINT_PLL_ERRORS
|
||||
fprintf(stderr, "[R82XX] No valid PLL values for %u Hz!\n", freq);
|
||||
#endif
|
||||
if (priv->cfg->verbose || PRINT_PLL_ERRORS)
|
||||
fprintf(stderr, "[R82XX] No valid PLL values for %u Hz!\n", freq);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -821,8 +1015,11 @@ static int r82xx_set_pll(struct r82xx_priv *priv, uint32_t freq)
|
|||
si = nint - 4 * ni - 13;
|
||||
|
||||
rc = r82xx_write_reg(priv, 0x14, ni + (si << 6));
|
||||
if (rc < 0)
|
||||
if (rc < 0) {
|
||||
if (priv->cfg->verbose)
|
||||
fprintf(stderr, "r82xx_set_pll(): error writing 'ni+(si<<6)' into i2c reg 0x14\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* pw_sdm */
|
||||
if (sdm == 0)
|
||||
|
@ -834,38 +1031,58 @@ static int r82xx_set_pll(struct r82xx_priv *priv, uint32_t freq)
|
|||
val |= 0x10;
|
||||
|
||||
rc = r82xx_write_reg_mask(priv, 0x12, val, 0x18);
|
||||
if (rc < 0)
|
||||
if (rc < 0) {
|
||||
if (priv->cfg->verbose)
|
||||
fprintf(stderr, "r82xx_set_pll(): error writing 'dither' into i2c reg 0x12\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = r82xx_write_reg(priv, 0x16, sdm >> 8);
|
||||
if (rc < 0)
|
||||
if (rc < 0) {
|
||||
if (priv->cfg->verbose)
|
||||
fprintf(stderr, "r82xx_set_pll(): error writing 'sdm hi' into i2c reg 0x16\n");
|
||||
return rc;
|
||||
}
|
||||
rc = r82xx_write_reg(priv, 0x15, sdm & 0xff);
|
||||
if (rc < 0)
|
||||
if (rc < 0) {
|
||||
if (priv->cfg->verbose)
|
||||
fprintf(stderr, "r82xx_set_pll(): error writing 'sdm lo' into i2c reg 0x12\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* all PLL stuff / registers set for this frequency - except 8 kHz pll autotune */
|
||||
priv->tuner_pll_set = 1;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
|
||||
/* Check if PLL has locked */
|
||||
rc = r82xx_read(priv, 0x00, data, 3);
|
||||
if (rc < 0)
|
||||
if (rc < 0) {
|
||||
if (priv->cfg->verbose)
|
||||
fprintf(stderr, "r82xx_set_pll(): error reading 'pll lock status' from i2c reg 0x00 .. 0x02\n");
|
||||
return rc;
|
||||
if (data[2] & 0x40)
|
||||
}
|
||||
if ( (data[2] & 0x40) || vco_curr_max == vco_curr_min )
|
||||
break;
|
||||
|
||||
if (!i) {
|
||||
/* Didn't lock. Increase VCO current */
|
||||
rc = r82xx_write_reg_mask(priv, 0x12, 0x60, 0xe0);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
if (priv->last_vco_curr != vco_curr_max) {
|
||||
rc = r82xx_write_reg_mask(priv, 0x12, vco_curr_max, 0xe0);
|
||||
if (rc < 0) {
|
||||
if (priv->cfg->verbose)
|
||||
fprintf(stderr, "r82xx_set_pll(): error writing 'vco current max' into i2c reg 0x12\n");
|
||||
return rc;
|
||||
}
|
||||
priv->last_vco_curr = vco_curr_max;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(data[2] & 0x40)) {
|
||||
#if PRINT_PLL_ERRORS
|
||||
fprintf(stderr, "[R82XX] PLL not locked at Tuner LO %u Hz for RF %u Hz!\n",
|
||||
freq, priv->rf_freq);
|
||||
#endif
|
||||
if (priv->cfg->verbose || PRINT_PLL_ERRORS)
|
||||
fprintf(stderr, "[R82XX] PLL not locked at Tuner LO %u Hz for RF %u Hz!\n",
|
||||
freq, priv->rf_freq);
|
||||
priv->has_lock = 0;
|
||||
return -1;
|
||||
}
|
||||
|
@ -878,10 +1095,35 @@ static int r82xx_set_pll(struct r82xx_priv *priv, uint32_t freq)
|
|||
|
||||
/* set pll autotune = 8kHz */
|
||||
rc = r82xx_write_reg_mask(priv, 0x1a, 0x08, 0x08);
|
||||
if (rc < 0 && priv->cfg->verbose)
|
||||
fprintf(stderr, "r82xx_set_pll(): error writing 'pll autotune 8kHz' into i2c reg 0x1a\n");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int r82xx_is_tuner_locked(struct r82xx_priv *priv)
|
||||
{
|
||||
int rc;
|
||||
uint8_t data[5];
|
||||
|
||||
/* was all PLL stuff set for last frequency? */
|
||||
if (! priv->tuner_pll_set)
|
||||
return 1;
|
||||
|
||||
/* Check if PLL has locked */
|
||||
rc = r82xx_read(priv, 0x00, data, sizeof(data));
|
||||
if (rc < 0)
|
||||
return -3;
|
||||
if (!(data[2] & 0x40)) {
|
||||
if (priv->cfg->verbose || PRINT_PLL_ERRORS)
|
||||
fprintf(stderr, "[R82XX] PLL not locked at check!\n");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int r82xx_sysfreq_sel(struct r82xx_priv *priv,
|
||||
enum r82xx_tuner_type type)
|
||||
{
|
||||
|
@ -995,6 +1237,7 @@ static int r82xx_set_tv_standard(struct r82xx_priv *priv,
|
|||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
priv->tuner_pll_set = 0;
|
||||
rc = r82xx_set_pll(priv, priv->rf_freq);
|
||||
if (rc < 0 || !priv->has_lock)
|
||||
return rc;
|
||||
|
@ -1134,6 +1377,7 @@ int r82xx_set_gain(struct r82xx_priv *priv, int set_manual_gain, int gain,
|
|||
|
||||
if (set_manual_gain) {
|
||||
r82xx_get_rf_gain_index(gain, &lna_gain_idx, &mixer_gain_idx);
|
||||
new_if_mode = 10000 + 8;
|
||||
}
|
||||
|
||||
/* LNA auto off == manual */
|
||||
|
@ -1193,7 +1437,7 @@ int r82xx_set_gain(struct r82xx_priv *priv, int set_manual_gain, int gain,
|
|||
|
||||
/* Set VGA */
|
||||
rc = r82xx_set_if_mode(priv, new_if_mode, rtl_vga_control);
|
||||
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -1217,7 +1461,7 @@ int r82xx_get_if_gain(struct r82xx_priv *priv)
|
|||
int r82xx_set_if_mode(struct r82xx_priv *priv, int if_mode, int *rtl_vga_control)
|
||||
{
|
||||
int rc = 0, vga_gain_idx = 0;
|
||||
|
||||
|
||||
if (rtl_vga_control)
|
||||
*rtl_vga_control = 0;
|
||||
|
||||
|
@ -1250,6 +1494,7 @@ int r82xx_set_if_mode(struct r82xx_priv *priv, int if_mode, int *rtl_vga_control
|
|||
(vga_gain_idx & 0x0f), (-12.0 + 3.5 * (vga_gain_idx & 0x0f)),
|
||||
( (vga_gain_idx & 0x10) && rtl_vga_control ) ? "" : "de" );
|
||||
#endif
|
||||
|
||||
rc = r82xx_write_reg_mask(priv, 0x0c, vga_gain_idx, 0x1f);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
@ -1409,6 +1654,8 @@ static const struct IFinfo IFi[] = {
|
|||
{ 2, 1100+2, IFB(1100), 0, 0x0F, 0xEF, 0x60 }, /* steep high freq edge */
|
||||
#endif
|
||||
|
||||
{ 3, 1200+0, 1350, 0, 0x0F, 0xEE, 0x00 }, /* centered with hpf */
|
||||
|
||||
{ 3, 1300+0, 2050, -7, 0x0F, 0x8A, 0x00 }, /* centered with hpf */
|
||||
#if (WITH_ASYM_FILTER)
|
||||
{ 1, 1300+1, IFA(1300), 26, 0x0F, 0xEF, 0x60 }, /* steep low freq edge */
|
||||
|
@ -1418,7 +1665,15 @@ static const struct IFinfo IFi[] = {
|
|||
{ 3, 1500+3, 1300, -24, 0x0F, 0xEF, 0x60 },
|
||||
{ 3, 1600+0, 1900, 0, 0x0F, 0x8B, 0x00 }, /* centered with hpf */
|
||||
{ 3, 1750+3, 1400, 12, 0x0F, 0xCF, 0x60 }, /* 20 */
|
||||
{ 3, 1950+3, 1500, 30, 0x0F, 0x8F, 0x60 }
|
||||
|
||||
{ 3, 1800+0, 1400, 0, 0x0F, 0xAF, 0x00 },
|
||||
|
||||
{ 3, 1950+3, 1500, 30, 0x0F, 0x8F, 0x60 },
|
||||
|
||||
{ 3, 2200+0, 1600, 0, 0x0F, 0x8F, 0x00 },
|
||||
{ 3, 3000+0, 2000, 0, 0x04, 0x8F, 0x00 },
|
||||
{ 3, 5000+0, 3570, 0, 0x0B, 0x6B, 0x00 }
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -1642,6 +1897,8 @@ int r82xx_set_freq(struct r82xx_priv *priv, uint32_t freq)
|
|||
uint32_t lo_freq;
|
||||
uint8_t air_cable1_in;
|
||||
|
||||
priv->tuner_pll_set = 0;
|
||||
|
||||
if (!freq)
|
||||
freq = priv->rf_freq; /* ignore zero frequency; keep last one */
|
||||
else
|
||||
|
@ -1660,8 +1917,11 @@ int r82xx_set_freq(struct r82xx_priv *priv, uint32_t freq)
|
|||
#endif
|
||||
|
||||
rc = r82xx_set_mux(priv, lo_freq);
|
||||
if (rc < 0)
|
||||
if (rc < 0) {
|
||||
if (priv->cfg->verbose)
|
||||
fprintf(stderr, "r82xx_set_freq(): error at r82xx_set_mux()\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
rc = r82xx_set_pll(priv, lo_freq);
|
||||
if (rc < 0 || !priv->has_lock)
|
||||
|
@ -1677,6 +1937,8 @@ int r82xx_set_freq(struct r82xx_priv *priv, uint32_t freq)
|
|||
(air_cable1_in != priv->input)) {
|
||||
priv->input = air_cable1_in;
|
||||
rc = r82xx_write_reg_mask(priv, 0x05, air_cable1_in, 0x60);
|
||||
if (rc < 0 && priv->cfg->verbose)
|
||||
fprintf(stderr, "r82xx_set_freq(): error writing R828D's 'input selection' into i2c reg 0x05\n");
|
||||
}
|
||||
|
||||
err:
|
||||
|
@ -1752,6 +2014,19 @@ int r82xx_init(struct r82xx_priv *priv)
|
|||
{
|
||||
int rc;
|
||||
|
||||
#if PRINT_INITIAL_REGISTERS
|
||||
#define INIT_NUM_READ_REGS 16
|
||||
uint8_t initial_register_values[INIT_NUM_READ_REGS]; /* see what is 'default' */
|
||||
int k;
|
||||
/* get initial register values - just to see .. */
|
||||
memset( &(initial_register_values[0]), 0, sizeof(initial_register_values) );
|
||||
printf("R820T/2 initial register settings:\n");
|
||||
r82xx_read(priv, 0x00, initial_register_values, sizeof(initial_register_values));
|
||||
for (k=0; k < INIT_NUM_READ_REGS; ++k)
|
||||
printf("register 0x%02x: 0x%02x\n", k, initial_register_values[k]);
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
/* TODO: R828D might need r82xx_xtal_check() */
|
||||
priv->xtal_cap_sel = XTAL_HIGH_CAP_0P;
|
||||
|
||||
|
@ -1764,6 +2039,7 @@ int r82xx_init(struct r82xx_priv *priv)
|
|||
priv->last_LNA_value = 0;
|
||||
priv->last_Mixer_value = 0;
|
||||
priv->last_VGA_value = DEFAULT_IF_VGA_VAL;
|
||||
priv->last_vco_curr = 0xff;
|
||||
|
||||
/* Initialize override registers */
|
||||
memset( &(priv->override_data[0]), 0, NUM_REGS * sizeof(uint8_t) );
|
||||
|
@ -1773,6 +2049,8 @@ int r82xx_init(struct r82xx_priv *priv)
|
|||
rc = r82xx_write_arr(priv, 0x05,
|
||||
r82xx_init_array, sizeof(r82xx_init_array));
|
||||
|
||||
priv->last_vco_curr = r82xx_init_array[0x12 - 0x05] & 0xe0;
|
||||
|
||||
rc = r82xx_set_tv_standard(priv, TUNER_DIGITAL_TV, 0);
|
||||
if (rc < 0)
|
||||
goto err;
|
||||
|
|
Loading…
Reference in New Issue