Compare commits

...

44 Commits

Author SHA1 Message Date
David Rowe c557fd69b3 resolved conflicts 2021-10-22 15:20:27 +10:30
David Rowe 9eb6b4e1b2 rebuilt Rx level and No estimation for be indep of Rs and Fs 2021-10-22 15:07:56 +10:30
David Rowe 4d95c38abb announce RxGain 2021-10-09 16:05:50 +10:30
David Rowe 7398187ba9 attempt at calibration of Rx level and No 2020-11-23 09:13:03 +10:30
David Rowe 92ff2a9e8c Rx Frame label 2020-11-22 09:30:40 +00:00
David d0de9c53a2 adjusting format of -L log output 2020-11-19 17:22:13 +10:30
David 344ff4a66e logging S,N,SNR of local and remote stations to stderr 2020-11-15 13:39:32 +10:30
David Rowe e03a0bfa41 injection of received SNR into packet 2020-11-13 23:15:23 +00:00
David c3e944f7a4 building up S+N reporting 2020-11-14 08:55:04 +10:30
David 10ef497eb1 support for filtering of packets based on source byte 2020-11-13 08:57:25 +10:30
David Rowe f030c97642 Revert "adding fifo to control muting of rx"
This reverts commit ad1adfa379.
2020-11-11 20:00:31 +00:00
David Rowe ad1adfa379 adding fifo to control muting of rx 2020-11-11 08:14:48 +00:00
David Rowe c3854221a7 cleaned up some debug code 2020-11-11 07:53:51 +00:00
David 14688f5e43 periodic status byte output mode 2020-11-08 18:34:04 +10:30
David a51cee492c trapping sample rate/Rs conflicts 2020-10-25 10:30:14 +10:30
David ebef4a2818 larger freq est upper limit for 4FSK 2020-10-10 10:02:17 +10:30
David 5c1ad40ca1 mask freq est method working 2020-10-07 20:41:25 +10:30
David db50e9ed9d testframe rx mode 2020-10-02 12:15:19 +09:30
David 60e63c9dbb neater debug info 2020-09-30 11:17:10 +09:30
David 8ba0319b4b FSK LDPC mode, builds OK but not tested 2020-09-29 17:38:53 +09:30
David 4e85c4d1d0 check for integer samplrate/modem_samplerate 2020-09-19 12:51:44 +09:30
David b3549df70d command line extended gain and bandwidth options 2020-09-19 11:07:11 +09:30
David 89f758437e README mods and added extended gain cmd line option to rtl_fsk.c 2020-09-19 09:11:08 +09:30
David 78f0cfd90e integrating rtl_fsk into librtlsdr 2020-09-19 08:58:34 +09:30
David 1c5a141d61 Merge branch 'development' of github.com:drowe67/librtlsdr into development 2020-09-19 08:29:45 +09:30
David 0299f5fc2d soem debug fprintfs's plus manual gain option for rtl_sdr.c 2020-09-19 08:24:12 +09:30
hayati ayguen 8ef067e642 fix compiler warnings/errors
Signed-off-by: hayati ayguen <h_ayguen@web.de>
2020-09-16 19:23:17 +00:00
hayati ayguen f8c64755cf added bandwidths 1200, 1800, 2200, 3000 and 5000 kHz for R820T/2
needs some testing/measurement
see "distorted ends" at https://github.com/librtlsdr/librtlsdr/issues/96

Signed-off-by: hayati ayguen <h_ayguen@web.de>
2020-09-16 21:17:13 +02:00
hayati ayguen 6fc09b8915 detailed error messages when r82xx_set_pll() fails with verbose flag
* see https://github.com/librtlsdr/librtlsdr/issues/91
* fixed r82xx_is_tuner_locked(): do not report lock,
 when not all necessary PLL registers were set successfully
* shortcut for 'verbose' flag: 'v'

Signed-off-by: hayati ayguen <h_ayguen@web.de>
2020-09-10 20:32:10 +02:00
hayati ayguen 7c6b9e05f8 rtl_tcp: fixed erroneous message and added last_lock_report
Signed-off-by: hayati ayguen <h_ayguen@web.de>
2020-09-10 08:24:03 +02:00
hayati ayguen 776c31abcb fixed compiler warning on vco_max value 3.9 GHz
Signed-off-by: hayati ayguen <h_ayguen@web.de>
2020-09-10 08:00:07 +02:00
hayati ayguen 1819a8db99 bugfix for vco options, added rtlsdr_is_tuner_PLL_locked() to API
* bugfix for vco options: moved init of vco variables:
 parsed options got overwritten at r820t_init().
 see https://github.com/librtlsdr/librtlsdr/issues/91
* added IS_TUNER_PLL_LOCKED (=0x55) command to rtl_tcp protocol
* rtl_tcp is checking rtlsdr_is_tuner_PLL_locked() automatically
 every 3 seconds - when idle:
 https://github.com/librtlsdr/librtlsdr/issues/91#issuecomment-689830755

Signed-off-by: hayati ayguen <h_ayguen@web.de>
2020-09-10 07:35:51 +02:00
hayati ayguen c7d071e17e added librtsdr options vcocmin/vcocmax/vcoalgo for testing
* see https://github.com/librtlsdr/librtlsdr/issues/91
* vcocmin/vcocmax: sets VCO current for R820T/2
* added tuner internal caching for VCO current,
 that register isn't written when unnecessary
* added vcoalgo option:
- vcoalgo=2 allows to select/use r82xx_set_pll() from
 https://github.com/rtlsdrblog/rtl-sdr.git
- vcoalgo=1 is previous algorithm, just with higher vco_max=3.9GHz
- vcoalgo=0 is previous algorithm - the default:
 kept this until https://github.com/steve-m/librtlsdr/pull/10
 is measured
* rtl_test: added options -f and -e to define where to start and end
 the tuner range test .. for quicker testing if the new options
 change/extend the tuner's frequency range

Signed-off-by: hayati ayguen <h_ayguen@web.de>
2020-09-09 08:02:49 +02:00
hayati ayguen 907da08bfc printing error messages when rtl_tcp commands fail
* see https://github.com/librtlsdr/librtlsdr/issues/93
* implemented some get commands - just printing the output

Signed-off-by: hayati ayguen <h_ayguen@web.de>
2020-09-09 07:53:03 +02:00
hayati ayguen 3551e61903 .cmake files are relevant in cmake/Modules subdirectory
Signed-off-by: hayati ayguen <h_ayguen@web.de>
2020-09-06 21:41:53 +02:00
hayati ayguen 5868a660a4 added github actions, building linux and macos
Signed-off-by: hayati ayguen <h_ayguen@web.de>
2020-09-06 21:27:38 +02:00
hayati ayguen e5cdaf1ac9 added docs on GPIO pins and the API
Signed-off-by: hayati ayguen <h_ayguen@web.de>
2020-09-03 22:53:51 +02:00
hayati ayguen 2b88e8934b caching of GPIO mode (in/out) and rtl_tcp commands for GPIO
Signed-off-by: hayati ayguen <h_ayguen@web.de>
2020-09-01 20:28:47 +02:00
hayati ayguen 35b8c01015 added gpio functions to API and extended rtl_biast
* functions were provided from Marko Cebokli
at http://lea.hamradio.si/~s57uuu/mischam/rtlsdr/ports.html
* changed functions to return error/status
* added rtlsdr_set_gpio_status() - for testing

Signed-off-by: hayati ayguen <h_ayguen@web.de>
2020-08-31 07:41:10 +02:00
hayati ayguen 3864bf7889
Merge pull request #90 from theresiasnow/bugfix/mac_os_time_struct_fix
Bugfix/mac os time struct fix
2020-08-30 22:32:35 +02:00
Theresia Sofia Snow 39d225267e fixed bug with mac os using another time struct 2020-08-30 22:17:57 +02:00
hayati ayguen 1af2be095e (try to) fix compilation error on mac os catalina
see https://github.com/librtlsdr/librtlsdr/issues/89
simply deactivated sub-second precision

Signed-off-by: hayati ayguen <h_ayguen@web.de>
2020-08-30 22:00:15 +02:00
hayati ayguen a3349bd52b activate/use RTL's IF AGC control .. from https://github.com/old-dab/rtlsdr
purpose: make AGC more smooth .. and NOT freeze

Signed-off-by: hayati ayguen <h_ayguen@web.de>
2020-08-26 22:42:56 +02:00
hayati ayguen bff8cf771d remove compiler warnings, unused variables
Signed-off-by: hayati ayguen <h_ayguen@web.de>
2020-08-26 21:31:25 +02:00
18 changed files with 1954 additions and 125 deletions

47
.github/workflows/c-cpp.yml vendored 100644
View File

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

1
.gitignore vendored
View File

@ -38,7 +38,6 @@ src/rtl_tcp
CMakeCache.txt
*/CMakeFiles
CMakeFiles
*.cmake
build
**/*.o

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

864
src/rtl_fsk.c 100644
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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