merge of great additions, e.g. rtlsdr_set_tuner_sideband()

* rtlsdr_set_tuner_sideband():
- "HF-Hase" Bernhard Kistinger (DB9PP) found out,
that one of the undocumented I2C register bits of R820T tuner
controls the used tuner/mixer lower or supper sideband.
That was by testing/playing with a special QIRX version,
showing and allowing change of all I2C registers.
- previous additions in rtl_tcp allowed control of I2C registers;
in addition register contents can be transmitted periodically (to QIRX)
- "Oldenburger" developed a first version controlling the sideband bit,
and additional spectral flipping (spectrum inversion) in the RTL2832
- i've merged Oldenburger's changes with my rtlsdr_set_tuner_band_center()
=> altogether, there's no spectrum inversion, the band center stays,
just the IF filters (steep lowpass and not-so-steep highpass) switch positions

* Oldenburger's changes for FC0012 tuner
* Oldenburger added description of R820T's I2C registers
* rtl_tcp's new response channel now occupies an additional port,
usally 1235, which is +1 of default control port.
this can be deactivated by command line

Signed-off-by: hayati ayguen <h_ayguen@web.de>
development
hayati ayguen 2019-07-28 01:21:21 +02:00
parent 75f97e566d
commit 22a920d0a6
12 changed files with 995 additions and 388 deletions

View File

@ -0,0 +1,43 @@
/*
* rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver
* Copyright (C) 2019 <>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __RTL_CONTROL_THREAD_H
#define __RTL_CONTROL_THREAD_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct
{
rtlsdr_dev_t *dev;
SOCKET port;
int wait;
int report_i2c;
char *addr;
int* pDoExit;
}
ctrl_thread_data_t;
void *ctrl_thread_fn(void *arg);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -253,6 +253,15 @@ RTLSDR_API int rtlsdr_set_tuner_bandwidth(rtlsdr_dev_t *dev, uint32_t bw );
*/
RTLSDR_API int rtlsdr_set_tuner_band_center(rtlsdr_dev_t *dev, int32_t if_band_center_freq );
/*!
* Set the mixer sideband for the device.
*
* \param dev the device handle given by rtlsdr_open()
* \param sideband mixer sideband 0 means lower sideband, 1 means upper sideband.
* \return 0 on success
*/
RTLSDR_API int rtlsdr_set_tuner_sideband(rtlsdr_dev_t *dev, int sideband);
/*!
* Get actual gain the device is configured to.
*

View File

@ -65,6 +65,9 @@ enum RTL_TCP_COMMANDS {
* the bandwidth (from SET_TUNER_BANDWIDTH)
* is set to be centered at given IF frequency */
SET_TUNER_AGC_VARIANT = 0x46, /* set tuner agc algorithm/variant */
SET_SIDEBAND = 0x47, /* Mixer Sideband for R820T */
REPORT_I2C_REGS = 0x48, /* perodically report I2C registers
* - if reverse channel is enabled */
};
#ifdef __cplusplus

View File

@ -32,5 +32,7 @@
int fc0012_init(void *dev);
int fc0012_set_params(void *dev, uint32_t freq, uint32_t bandwidth);
int fc0012_set_gain(void *dev, int gain);
int fc0012_set_i2c_register(void *dev, unsigned i2c_register, unsigned data);
int fc0012_get_i2c_register(void *dev, unsigned char* data, int len);
#endif

View File

@ -35,7 +35,7 @@
#define R82XX_IF_FREQ 3570000
#define REG_SHADOW_START 5
#define NUM_REGS 30
#define NUM_REGS 32
#define NUM_IMR 5
#define IMR_TRIAL 9
@ -89,6 +89,7 @@ struct r82xx_priv {
uint8_t input;
int has_lock;
int init_done;
int sideband;
/* Store current mode */
uint32_t delsys;
@ -140,14 +141,17 @@ 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_set_gain(struct r82xx_priv *priv, int set_manual_gain, int gain);
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_set_agc_mode(struct r82xx_priv *priv, int agc_mode, int *rtl_vga_control);
int r82xx_set_i2c_register(struct r82xx_priv *priv, unsigned i2c_register, unsigned data, unsigned mask);
int r82xx_get_i2c_register(struct r82xx_priv *priv, unsigned char* data, int len);
int r82xx_set_i2c_override(struct r82xx_priv *priv, unsigned i2c_register, unsigned data, unsigned mask);
int r82xx_set_bandwidth(struct r82xx_priv *priv, int bandwidth, uint32_t rate, uint32_t * applied_bw, int apply);
int r82xx_set_bw_center(struct r82xx_priv *priv, int32_t if_band_center_freq);
/* Mixer Sideband: 0: lower, 1: upper */
int r82xx_set_sideband(struct r82xx_priv *priv, int sideband);
int r82xx_read_cache_reg(struct r82xx_priv *priv, int reg);
int r82xx_write_reg_mask(struct r82xx_priv *priv, uint8_t reg, uint8_t val,uint8_t bit_mask);

View File

@ -119,7 +119,7 @@ endif()
# Build utility
########################################################################
add_executable(rtl_sdr rtl_sdr.c)
add_executable(rtl_tcp rtl_tcp.c)
add_executable(rtl_tcp rtl_tcp.c controlThread.c)
add_executable(rtl_udp rtl_udp.c)
add_executable(rtl_test rtl_test.c)
add_executable(rtl_fm rtl_fm.c)

230
src/controlThread.c 100644
View File

@ -0,0 +1,230 @@
/*
* rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver
* Copyright (C) 2012 by Steve Markgraf <steve@steve-m.de>
* Copyright (C) 2012-2013 by Hoernchen <la@tfc-server.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <fcntl.h>
#else
#include <winsock2.h>
#include "getopt/getopt.h"
#define usleep(x) Sleep(x/1000)
#endif
#ifdef NEED_PTHREADS_WORKARROUND
#define HAVE_STRUCT_TIMESPEC
#endif
#include <pthread.h>
#include "rtl-sdr.h"
#include "rtl_tcp.h"
#include "controlThread.h"
#include "convenience/convenience.h"
#include "tuner_r82xx.h"
#ifdef _WIN32
#pragma comment(lib, "ws2_32.lib")
typedef int socklen_t;
#else
#define closesocket close
#define SOCKADDR struct sockaddr
#define SOCKET int
#define SOCKET_ERROR -1
#endif
/* we need a message id in the protocol: 1st 2 byte (little endian) == message id */
#define USE_MSGID_IN_PROTOCOL 1
#define NUM_I2C_REGISTERS 32
#define TX_BUF_LEN (NUM_I2C_REGISTERS +4) //2 len, 1 head, 1 tail
ctrl_thread_data_t ctrl_thread_data;
void *ctrl_thread_fn(void *arg)
{
unsigned char reg_values [NUM_I2C_REGISTERS];
#if USE_MSGID_IN_PROTOCOL
unsigned char txbuf [2+2 +1+NUM_I2C_REGISTERS+1]; //2 type, 2 length, 1 head, 1 tail
#else
unsigned char txbuf [NUM_I2C_REGISTERS+4]; //2 length, 1 head, 1 tail
#endif
int r = 1;
struct timeval tv = { 1,0 };
struct linger ling = { 1,0 };
SOCKET listensocket;
SOCKET controlSocket;
struct sockaddr_in local, remote;
socklen_t rlen;
int error = 0;
int ret = 0, len, result;
fd_set connfds;
fd_set writefds;
int bytesleft, bytessent, index;
ctrl_thread_data_t *data = (ctrl_thread_data_t *)arg;
rtlsdr_dev_t *dev = data->dev;
int port = data->port;
int wait = data->wait;
int report_i2c = data->report_i2c;
char *addr = data->addr;
int* do_exit = data->pDoExit;
u_long blockmode = 1;
memset(reg_values, 0, NUM_I2C_REGISTERS);
memset(&local, 0, sizeof(local));
local.sin_family = AF_INET;
local.sin_port = htons(port);
local.sin_addr.s_addr = inet_addr(addr);
listensocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
setsockopt(listensocket, SOL_SOCKET, SO_REUSEADDR, (char *)&r, sizeof(int));
setsockopt(listensocket, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling));
int retval = bind(listensocket, (struct sockaddr *)&local, sizeof(local));
if (retval == SOCKET_ERROR)
error = WSAGetLastError();
#ifdef _WIN32
ioctlsocket(listensocket, FIONBIO, &blockmode);
#else
r = fcntl(listensocket, F_GETFL, 0);
r = fcntl(listensocket, F_SETFL, r | O_NONBLOCK);
#endif
while (1) {
printf("listening on Control port %d...\n", port);
retval = listen(listensocket, 1);
if (retval == SOCKET_ERROR)
#ifdef _WIN32
error = WSAGetLastError();
#else
;
#endif
while (1) {
FD_ZERO(&connfds);
FD_SET(listensocket, &connfds);
tv.tv_sec = 1;
tv.tv_usec = 0;
r = select(listensocket + 1, &connfds, NULL, NULL, &tv);
if (*do_exit) {
goto close;
}
else if (r) {
rlen = sizeof(remote);
controlSocket = accept(listensocket, (struct sockaddr *)&remote, &rlen);
break;
}
}
setsockopt(controlSocket, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling));
printf("Control client accepted!\n");
usleep(5000000);
while (1) {
/* check if i2c reporting is to be (de)activated */
if ( report_i2c && !data->report_i2c )
report_i2c = 0;
else if ( !report_i2c && data->report_i2c )
report_i2c = 1;
/* @TODO: check if something else has to be transmitted */
if ( !report_i2c )
goto sleep;
result = rtlsdr_get_tuner_i2c_register(dev, reg_values, NUM_I2C_REGISTERS);
/* printf("rtlsdr_get_tuner_i2c_register\n"); */
memset(txbuf, 0, TX_BUF_LEN);
if (result)
goto sleep;
/* Little Endian */
len = 0;
/* we need some message id: use enum RTL_TCP_COMMANDS */
#if USE_MSGID_IN_PROTOCOL
txbuf[len++] = REPORT_I2C_REGS & 0x0FF;
txbuf[len++] = (REPORT_I2C_REGS >> 8) & 0x0FF;
/* following message length in Little Endian */
txbuf[len++] = TX_BUF_LEN - 2 - 2; /* sub message id and length field */
#else
txbuf[len++] = TX_BUF_LEN - 2; /* sub message id and length field */
#endif
txbuf[len++] = 0;
/* now the message contents */
txbuf[len++] = 0x55; /* @CS: do we need this? */
memcpy(&txbuf[len], reg_values, NUM_I2C_REGISTERS);
txbuf[TX_BUF_LEN - 1] = 0xaa; /* @CS: do we need this? */
len = sizeof(txbuf);
/* now start (possibly blocking) transmission */
bytessent = 0;
bytesleft = len;
index = 0;
while (bytesleft > 0) {
FD_ZERO(&writefds);
FD_SET(controlSocket, &writefds);
tv.tv_sec = 1;
tv.tv_usec = 0;
r = select(controlSocket + 1, NULL, &writefds, NULL, &tv);
if (r) {
bytessent = send(controlSocket, &txbuf[index], bytesleft, 0);
bytesleft -= bytessent;
index += bytessent;
}
if (bytessent == SOCKET_ERROR || *do_exit) {
goto close;
}
}
sleep:
usleep(wait);
}
close:
closesocket(controlSocket);
if (*do_exit)
{
closesocket(listensocket);
printf("Control Thread terminates\n");
break;
}
}
return 0;
}

View File

@ -107,7 +107,9 @@ typedef struct rtlsdr_tuner_iface {
int (*set_gain_mode)(void *, int manual);
int (*set_i2c_register)(void *, unsigned i2c_register, unsigned data /* byte */, unsigned mask /* byte */ );
int (*set_i2c_override)(void *, unsigned i2c_register, unsigned data /* byte */, unsigned mask /* byte */ );
unsigned (*get_i2c_register)(void *, int i2c_register);
unsigned (*get_i2c_register)(void *, int i2c_register); /* read single register */
int (*get_i2c_reg_array)(void *, unsigned char* data, int len); /* -cs- */
int (*set_sideband)(void *, int sideband);
} rtlsdr_tuner_iface_t;
enum rtlsdr_async_status {
@ -206,6 +208,8 @@ struct rtlsdr_dev {
uint32_t bw;
uint32_t offs_freq; /* Hz */
int32_t if_band_center_freq; /* Hz - rtlsdr_set_tuner_band_center() */
int tuner_if_freq;
int tuner_sideband;
int corr; /* ppm */
int gain; /* tenth dB */
enum rtlsdr_ds_mode direct_sampling_mode;
@ -216,6 +220,9 @@ struct rtlsdr_dev {
/* soft tuner agc */
struct softagc_state softagc;
/* -cs- Concurrent lock for the periodic reading of I2C registers */
pthread_mutex_t cs_mutex;
/* UDP controller server */
#ifdef WITH_UDP_SERVER
#define UDP_TX_BUFLEN 1024
@ -241,14 +248,13 @@ struct rtlsdr_dev {
int rc_active;
int verbose;
int dev_num;
uint8_t saved_27;
int handled;
};
void rtlsdr_set_gpio_bit(rtlsdr_dev_t *dev, uint8_t gpio, int val);
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);
static int rtlsdr_set_spectrum_inversion(rtlsdr_dev_t *dev, int sideband);
static void softagc_init(rtlsdr_dev_t *dev);
static void softagc_uninit(rtlsdr_dev_t *dev);
@ -310,7 +316,6 @@ int e4000_set_gain_mode(void *dev, int manual) {
return e4k_enable_manual_gain(&devt->e4k_s, manual);
}
int _fc0012_init(void *dev) { return fc0012_init(dev); }
int fc0012_exit(void *dev) { return 0; }
int fc0012_set_freq(void *dev, uint32_t freq) {
/* select V-band/U-band filter */
@ -318,8 +323,10 @@ int fc0012_set_freq(void *dev, uint32_t freq) {
return fc0012_set_params(dev, freq, 6000000);
}
int fc0012_set_bw(void *dev, int bw, uint32_t *applied_bw, int apply) { return 0; }
int _fc0012_set_gain(void *dev, int gain) { return fc0012_set_gain(dev, gain); }
int fc0012_set_gain_mode(void *dev, int manual) { return 0; }
int _fc0012_set_i2c_register(void *dev, unsigned i2c_register, unsigned data, unsigned mask ) {
return fc0012_set_i2c_register(dev, i2c_register, data);
}
int _fc0013_init(void *dev) { return fc0013_init(dev); }
int fc0013_exit(void *dev) { return 0; }
@ -372,7 +379,6 @@ int r820t_set_freq(void *dev, uint32_t freq) {
return r82xx_set_freq(&devt->r82xx_p, freq);
}
#define BWC_MUL_SIGN +
int r820t_set_bw(void *dev, int bw, uint32_t *applied_bw, int apply) {
int r, iffreq;
@ -383,15 +389,27 @@ int r820t_set_bw(void *dev, int bw, uint32_t *applied_bw, int apply) {
return 0;
if(iffreq < 0) {
r = iffreq;
if ( devt->verbose )
fprintf(stderr, "r820t_set_bw(%d): r82xx_set_bandwidth() returned error %d\n", bw, r);
return r;
}
devt->tuner_if_freq = iffreq;
iffreq = (devt->tuner_sideband) /* -1 for USB; +1 for LSB */
? ( devt->tuner_if_freq - devt->if_band_center_freq )
: ( devt->tuner_if_freq + devt->if_band_center_freq );
r = rtlsdr_set_if_freq(devt, iffreq );
if (r)
{
if ( devt->verbose )
fprintf(stderr, "r820t_set_bw(%d): rtlsdr_set_if_freq(%d) returned error %d\n", bw, iffreq, r);
return r;
}
iffreq = iffreq BWC_MUL_SIGN devt->if_band_center_freq;
r = rtlsdr_set_if_freq(devt, iffreq );
if (r)
return r;
return rtlsdr_set_center_freq(devt, devt->freq);
r = rtlsdr_set_center_freq(devt, devt->freq);
if ( r && devt->verbose )
fprintf(stderr, "r820t_set_bw(%d): rtlsdr_set_center_freq(%d) returned error %d\n", bw, devt->freq, r);
return r;
}
int r820t_set_bw_center(void *dev, int32_t if_band_center_freq) {
@ -401,16 +419,28 @@ int r820t_set_bw_center(void *dev, int32_t if_band_center_freq) {
iffreq = r82xx_set_bw_center(&devt->r82xx_p, if_band_center_freq);
if(iffreq < 0) {
r = iffreq;
if ( devt->verbose )
fprintf(stderr, "r820t_set_bw_center(%d): r82xx_set_bw_center() returned error %d\n", if_band_center_freq, r);
return r;
}
devt->tuner_if_freq = iffreq;
devt->if_band_center_freq = if_band_center_freq;
iffreq = (devt->tuner_sideband) /* -1 for USB; +1 for LSB */
? ( devt->tuner_if_freq - devt->if_band_center_freq )
: ( devt->tuner_if_freq + devt->if_band_center_freq );
r = rtlsdr_set_if_freq(devt, iffreq );
if (r)
{
if ( devt->verbose )
fprintf(stderr, "r820t_set_bw_center(%d): rtlsdr_set_if_freq(%d) returned error %d\n", if_band_center_freq, iffreq, r);
return r;
}
devt->if_band_center_freq = if_band_center_freq;
iffreq = iffreq BWC_MUL_SIGN devt->if_band_center_freq;
r = rtlsdr_set_if_freq(devt, iffreq );
if (r)
return r;
return rtlsdr_set_center_freq(devt, devt->freq);
r = rtlsdr_set_center_freq(devt, devt->freq);
if ( r && devt->verbose )
fprintf(stderr, "r820t_set_bw_center(%d): rtlsdr_set_center_freq(%d) returned error %d\n", if_band_center_freq, devt->freq, r);
return r;
}
int rtlsdr_vga_control( rtlsdr_dev_t* devt, int rc, int rtl_vga_control ) {
@ -469,6 +499,49 @@ int r820t_set_i2c_register(void *dev, unsigned i2c_register, unsigned data, unsi
rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;
return r82xx_set_i2c_register(&devt->r82xx_p, i2c_register, data, mask);
}
/* -cs- */
int r820t_get_i2c_reg_array(void *dev, unsigned char* data, int len) {
rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;
return r82xx_get_i2c_register(&devt->r82xx_p, data, len);
}
int r820t_set_sideband(void *dev, int sideband) {
int r;
rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;
if ( devt->verbose )
fprintf(stderr, "r820t_set_sideband(%d): r82xx_set_sideband() ..\n", sideband);
r = r82xx_set_sideband(&devt->r82xx_p, sideband);
if(r < 0) {
if ( devt->verbose )
fprintf(stderr, "r820t_set_sideband(%d): r82xx_set_sideband() returned %d\n", sideband, r);
return r;
}
if ( devt->verbose )
fprintf(stderr, "r820t_set_sideband(%d): rtlsdr_set_spectrum_inversion() ..\n", sideband);
r = rtlsdr_set_spectrum_inversion(devt, sideband);
if (r) {
if ( devt->verbose )
fprintf(stderr, "r820t_set_sideband(%d): rtlsdr_set_spectrum_inversion() returned %d\n", sideband, r);
return r;
}
if (!devt->freq)
return r;
if ( devt->verbose )
fprintf(stderr, "r820t_set_sideband(%d): rtlsdr_set_center_freq(%d) ..\n", sideband, devt->freq);
r = rtlsdr_set_center_freq(devt, devt->freq);
if (r) {
if ( devt->verbose )
fprintf(stderr, "r820t_set_sideband(%d): rtlsdr_set_center_freq(%d) returned %d\n", sideband, devt->freq, r);
}
return r;
}
int r820t_set_i2c_override(void *dev, unsigned i2c_register, unsigned data, unsigned mask ) {
rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;
return r82xx_set_i2c_override(&devt->r82xx_p, i2c_register, data, mask);
@ -478,37 +551,40 @@ int r820t_set_i2c_override(void *dev, unsigned i2c_register, unsigned data, unsi
/* definition order must match enum rtlsdr_tuner */
static rtlsdr_tuner_iface_t tuners[] = {
{
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL /* dummy for unknown tuners */
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL /* dummy for unknown tuners */
},
{
e4000_init, e4000_exit,
e4000_set_freq, e4000_set_bw, NULL, e4000_set_gain, e4000_set_if_gain,
e4000_set_gain_mode, NULL, NULL, NULL
e4000_set_gain_mode, NULL, NULL, NULL, NULL, NULL
},
{
_fc0012_init, fc0012_exit,
fc0012_set_freq, fc0012_set_bw, NULL, _fc0012_set_gain, NULL,
fc0012_set_gain_mode, NULL, NULL, NULL
fc0012_init, fc0012_exit,
fc0012_set_freq, fc0012_set_bw, NULL, fc0012_set_gain, NULL,
fc0012_set_gain_mode, _fc0012_set_i2c_register, NULL, NULL, fc0012_get_i2c_register, NULL
},
{
_fc0013_init, fc0013_exit,
fc0013_set_freq, fc0013_set_bw, NULL, _fc0013_set_gain, NULL,
fc0013_set_gain_mode, NULL, NULL, NULL
fc0013_set_gain_mode, NULL, NULL, NULL, NULL, NULL
},
{
fc2580_init, fc2580_exit,
_fc2580_set_freq, fc2580_set_bw, NULL, fc2580_set_gain, NULL,
fc2580_set_gain_mode, NULL, NULL, NULL
fc2580_set_gain_mode, NULL, NULL, NULL, NULL, NULL
},
{
r820t_init, r820t_exit,
r820t_set_freq, r820t_set_bw, r820t_set_bw_center, r820t_set_gain, NULL,
r820t_set_gain_mode, r820t_set_i2c_register, r820t_set_i2c_override, r820t_get_i2c_register
r820t_set_gain_mode, r820t_set_i2c_register, r820t_set_i2c_override, r820t_get_i2c_register, r820t_get_i2c_reg_array,
r820t_set_sideband
},
{
r820t_init, r820t_exit,
r820t_set_freq, r820t_set_bw, r820t_set_bw_center, r820t_set_gain, NULL,
r820t_set_gain_mode, r820t_set_i2c_register, r820t_set_i2c_override, r820t_get_i2c_register
r820t_set_gain_mode, r820t_set_i2c_register, r820t_set_i2c_override, r820t_get_i2c_register, r820t_get_i2c_reg_array,
r820t_set_sideband
},
};
@ -848,7 +924,13 @@ void rtlsdr_set_gpio_output(rtlsdr_dev_t *dev, uint8_t gpio)
void rtlsdr_set_i2c_repeater(rtlsdr_dev_t *dev, int on)
{
if (on)
pthread_mutex_lock(&dev->cs_mutex);
rtlsdr_demod_write_reg(dev, 1, 0x01, on ? 0x18 : 0x10, 1);
if (!on)
pthread_mutex_unlock(&dev->cs_mutex);
}
int rtlsdr_set_fir(rtlsdr_dev_t *dev)
@ -996,6 +1078,18 @@ static int rtlsdr_set_if_freq(rtlsdr_dev_t *dev, uint32_t freq)
return r;
}
static int rtlsdr_set_spectrum_inversion(rtlsdr_dev_t *dev, int sideband)
{
int r;
if(sideband)
/* disable spectrum inversion */
r = rtlsdr_demod_write_reg(dev, 1, 0x15, 0x00, 1);
else
/* enable spectrum inversion */
r = rtlsdr_demod_write_reg(dev, 1, 0x15, 0x01, 1);
return r;
}
int rtlsdr_set_sample_freq_correction(rtlsdr_dev_t *dev, int ppm)
{
int r = 0;
@ -1223,7 +1317,6 @@ int rtlsdr_set_center_freq(rtlsdr_dev_t *dev, uint32_t freq)
rtlsdr_set_i2c_repeater(dev, 1);
r = dev->tuner->set_freq(dev, freq - dev->offs_freq);
rtlsdr_set_i2c_repeater(dev, 0);
reactivate_softagc(dev, SOFTSTATE_RESET);
}
if (!r)
@ -1231,13 +1324,6 @@ int rtlsdr_set_center_freq(rtlsdr_dev_t *dev, uint32_t freq)
else
dev->freq = 0;
/* restore filters */
if (dev->handled) {
rtlsdr_set_i2c_repeater(dev, 1);
dev->tuner->set_i2c_register(dev, 27, dev->saved_27, 255);
rtlsdr_set_i2c_repeater(dev, 0);
}
return r;
}
@ -1585,6 +1671,56 @@ int rtlsdr_set_tuner_gain_mode(rtlsdr_dev_t *dev, int mode)
return r;
}
int rtlsdr_set_tuner_sideband(rtlsdr_dev_t *dev, int sideband)
{
int r = 0, iffreq;
rtlsdr_dev_t *devt = dev;
if (!dev || !dev->tuner)
return -1;
if (dev->tuner->set_sideband) {
if ( devt->verbose )
fprintf(stderr, "rtlsdr_set_tuner_sideband(%d): tuner.set_sideband() ..\n", sideband);
rtlsdr_set_i2c_repeater(dev, 1);
r = dev->tuner->set_sideband((void *)dev, sideband);
rtlsdr_set_i2c_repeater(dev, 0);
if (r)
{
if ( devt->verbose )
fprintf(stderr, "rtlsdr_set_tuner_sideband(%d): tuner.set_sideband() returned error %d\n", sideband, r);
return r;
}
devt->tuner_sideband = sideband;
iffreq = (devt->tuner_sideband) /* -1 for USB; +1 for LSB */
? ( devt->tuner_if_freq - devt->if_band_center_freq )
: ( devt->tuner_if_freq + devt->if_band_center_freq );
fprintf(stderr, "rtlsdr_set_tuner_sideband(%d): rtlsdr_set_if_freq(%d) ..\n", sideband, iffreq);
r = rtlsdr_set_if_freq(devt, iffreq );
if (r)
{
if ( devt->verbose )
fprintf(stderr, "rtlsdr_set_tuner_sideband(%d): rtlsdr_set_if_freq(%d) returned error %d\n", sideband, iffreq);
return r;
}
if (!devt->freq)
return r;
if (devt->verbose )
fprintf(stderr, "rtlsdr_set_tuner_sideband(%d): rtlsdr_set_center_freq(%d) ..\n", sideband, devt->freq);
r = rtlsdr_set_center_freq(devt, devt->freq);
if (r && devt->verbose )
fprintf(stderr, "rtlsdr_set_tuner_sideband(%d): rtlsdr_set_center_freq(%d) returned error %d\n", sideband, devt->freq, r);
return r;
}
return r;
}
int rtlsdr_set_tuner_i2c_register(rtlsdr_dev_t *dev, unsigned i2c_register, unsigned mask /* byte */, unsigned data /* byte */ )
{
int r = 0;
@ -1608,6 +1744,23 @@ int rtlsdr_set_tuner_i2c_register(rtlsdr_dev_t *dev, unsigned i2c_register, unsi
return r;
}
/* -cs- */
int rtlsdr_get_tuner_i2c_register(rtlsdr_dev_t *dev, unsigned char* data, int len)
{
int r = 0;
if (!dev || !dev->tuner)
return -1;
if (dev->tuner->get_i2c_register) {
rtlsdr_set_i2c_repeater(dev, 1);
r = dev->tuner->get_i2c_reg_array((void *)dev, data, len);
rtlsdr_set_i2c_repeater(dev, 0);
}
return r;
}
int rtlsdr_set_tuner_i2c_override(rtlsdr_dev_t *dev, unsigned i2c_register, unsigned mask /* byte */, unsigned data /* byte */ )
{
int r = 0;
@ -2242,6 +2395,7 @@ static int parse(char *message, rtlsdr_dev_t *dev)
uint8_t mask = 0xff, reg=0;
uint32_t freq;
int32_t bandcenter;
int sideband;
int retCode;
str1 = message;
@ -2270,7 +2424,8 @@ static int parse(char *message, rtlsdr_dev_t *dev)
* f <RFfrequency> # set rtl center frequency
* b <bandwidth> # set tuner bandwidth
* c <frequency> # set tuner bandwidth center in output. value in [ -1 600 000 .. 1 600 000 ]
*
* v <sideband> # set tuner sideband inversion
*
* a <tunerAgcVariant> # 0: LNA/Mixer = auto; VGA = fixed 26.5 dB
* # -1: LNA/Mixer = last value from prev rtlsdr_set_tuner_gain; VGA = auto
* # >0: LNA/Mixer = from rtlsdr_set_tuner_gain(tunerAgcMode); VGA = auto
@ -2304,6 +2459,7 @@ static int parse(char *message, rtlsdr_dev_t *dev)
if (!strcmp(token, "f")) comm = 256 + 1;
if (!strcmp(token, "b")) comm = 256 + 2;
if (!strcmp(token, "c")) comm = 256 + 3;
if (!strcmp(token, "v")) comm = 256 + 4;
if (!strcmp(token, "a")) comm = 512 + 1;
if (!strcmp(token, "m")) comm = 512 + 2;
if (!strcmp(token, "M")) comm = 512 + 3;
@ -2367,7 +2523,6 @@ static int parse(char *message, rtlsdr_dev_t *dev)
return -1;
}
} else if (comm == 64 +2 || comm == 64 +3 ) {
dev->saved_27 = dev->tuner->get_i2c_register(dev,27);
if ( dev->verbose )
{
fprintf(stderr, "parsed 'set i2c register %s %d = x%02X value %d = %s = %s with mask %s = %s'\n"
@ -2451,6 +2606,15 @@ static int parse(char *message, rtlsdr_dev_t *dev)
if ( dev->verbose )
fprintf(stderr, " rtlsdr_set_tuner_band_center() returned %d\n", retCode);
break;
case 4: /* sideband */
sideband = (int32_t)freqVal;
if ( dev->verbose )
fprintf(stderr, "parsed sideband = %d = %s from token '%s'\n",
sideband, (sideband ? "USB" : "LSB"), token);
retCode = rtlsdr_set_tuner_sideband(dev, sideband);
if ( dev->verbose )
fprintf(stderr, " rtlsdr_set_tuner_sideband() returned %d\n", retCode);
break;
default:
break;
}
@ -2505,6 +2669,7 @@ static int parse(char *message, rtlsdr_dev_t *dev)
"f <RFfrequency>\n"
"b <bandwidth>\n"
"c <frequency>\n"
"v <sideband>\n"
"a <tunerAgcVariant>\n"
"m <tuner gain>\n"
"M <gainMode>\n" );
@ -2614,6 +2779,13 @@ int rtlsdr_open(rtlsdr_dev_t **out_dev, uint32_t index)
dev->softagc.rpcNumGains = 0;
dev->softagc.rpcGainValues = NULL;
/* -cs- */
#ifdef __MINGW32__
dev->cs_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
#else
dev->cs_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
#endif
/* UDP controller server */
#ifdef WITH_UDP_SERVER
dev->udpPortNo = 0; /* default port 32323 .. but deactivated - by default */
@ -2745,6 +2917,8 @@ int rtlsdr_open(rtlsdr_dev_t **out_dev, uint32_t index)
fprintf(stderr, "Found Fitipower FC0012 tuner\n");
rtlsdr_set_gpio_output(dev, 6);
dev->tuner_type = RTLSDR_TUNER_FC0012;
/* rtlsdr_set_gpio_output(dev, 5); */
/* rtlsdr_set_gpio_bit(dev, 5, 1); */
goto found;
}
@ -2785,7 +2959,6 @@ found:
rtlsdr_set_i2c_repeater(dev, 0);
*out_dev = dev;
return 0;
err:
if (dev) {
@ -2843,10 +3016,6 @@ int rtlsdr_close(rtlsdr_dev_t *dev)
libusb_exit(dev->ctx);
if (dev->handled) {
dev->handled = 0;
}
free(dev);
return 0;
@ -3508,7 +3677,6 @@ static int rtlsdr_read_regs(rtlsdr_dev_t *dev, uint8_t block, uint16_t addr, uin
static int rtlsdr_write_reg_mask(rtlsdr_dev_t *d, int block, uint16_t reg, uint8_t val,
uint8_t mask)
{
int ret;
uint8_t tmp;
/* no need for read if whole reg is written */
@ -3561,7 +3729,7 @@ int rtlsdr_ir_query(rtlsdr_dev_t *d, uint8_t *buf, size_t buf_len)
ret = rtlsdr_write_reg_mask(d, init_tab[i].block, init_tab[i].reg,
init_tab[i].val, init_tab[i].mask);
if (ret < 0) {
fprintf(stderr, "write %zd reg %d %.4x %.2x %.2x failed\n", i, init_tab[i].block,
fprintf(stderr, "write %ld reg %d %.4x %.2x %.2x failed\n", (unsigned long)i, init_tab[i].block,
init_tab[i].reg, init_tab[i].val, init_tab[i].mask);
goto err;
}
@ -3639,7 +3807,7 @@ const char * rtlsdr_get_opt_help(int longInfo)
if ( longInfo )
return
"\t[-O\tset RTL options string seperated with ':' ]\n"
"\t\tverbose:f=<freqHz>:bw=<bw_in_kHz>:bc=<if_in_Hz>\n"
"\t\tverbose:f=<freqHz>:bw=<bw_in_kHz>:bc=<if_in_Hz>:sb=<sideband>\n"
"\t\tagc=<tuner_gain_mode>:agcv=<>:gain=<tenth_dB>:dagc=<rtl_agc>\n"
"\t\tds=<direct_sampling_mode>:T=<bias_tee>\n"
#ifdef WITH_UDP_SERVER
@ -3694,6 +3862,12 @@ int rtlsdr_set_opt_string(rtlsdr_dev_t *dev, const char *opts, int verbose)
fprintf(stderr, "\nrtlsdr_set_opt_string(): parsed band center %d\n", (int)if_band_center_freq);
ret = rtlsdr_set_tuner_band_center(dev, if_band_center_freq );
}
else if (!strncmp(optPart, "sb=", 3)) {
int32_t sideband = (int32_t)(atoi(optPart +3));
if (verbose)
fprintf(stderr, "\nrtlsdr_set_opt_string(): parsed sideband %d == %s\n", (int)sideband, (sideband ? "Upper" : "Lower") );
ret = rtlsdr_set_tuner_sideband(dev, sideband );
}
else if (!strncmp(optPart, "agc=", 4)) {
int manual = 1 - atoi(optPart +4); /* invert logic */
if (verbose)
@ -3781,8 +3955,6 @@ int rtlsdr_set_opt_string(rtlsdr_dev_t *dev, const char *opts, int verbose)
#ifdef WITH_UDP_SERVER
if (dev->udpPortNo && dev->srv_started == 0 && dev->tuner_type==RTLSDR_TUNER_R820T) {
dev->handled = 1;
dev->saved_27 = dev->tuner->get_i2c_register(dev,27); /* highest/lowest corner for LPNF and LPF */
/* signal(SIGPIPE, SIG_IGN); */
if(pthread_create(&dev->srv_thread, NULL, srv_server, dev)) {
fprintf(stderr, "Error creating thread\n");

View File

@ -61,6 +61,10 @@ typedef int socklen_t;
#define SOCKET_ERROR -1
#endif
#include "controlThread.h"
static ctrl_thread_data_t ctrldata;
static SOCKET s;
static pthread_t tcp_worker_thread;
@ -108,7 +112,8 @@ void usage(void)
);
fprintf(stderr, "Usage:\t[-a listen address]\n"
"\t[-p listen port (default: 1234)]\n"
"\t[-p control listen port (default: 1234)]\n"
"\t[-r response listen port: 0 = off; 1 (=default) for On at control listen port +1; or port]\n"
"\t[-I infrared sensor listen port (default: 0=none)]\n"
"\t[-W infrared sensor query wait interval usec (default: 10000)]\n"
"\t[-f frequency to tune to [Hz]]\n"
@ -434,6 +439,19 @@ static void *command_worker(void *arg)
printf("set tuner agc variant to %i\n", itmp);
rtlsdr_set_tuner_agc_mode(dev, itmp);
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);
break;
case REPORT_I2C_REGS:
tmp = ntohl(cmd.param);
if(tmp)
tmp = 1;
ctrldata.report_i2c = tmp; /* (de)activate reporting */
break;
default:
break;
}
@ -521,6 +539,10 @@ int main(int argc, char **argv)
int port_ir = 0;
int wait_ir = 10000;
pthread_t thread_ir;
pthread_t thread_ctrl; /* -cs- for periodically reading the register values */
int port_resp = 1;
int report_i2c = 0;
int do_exit_thrd_ctrl = 0;
uint32_t frequency = 100000000, samp_rate = 2048000;
enum rtlsdr_ds_mode ds_mode = RTLSDR_DS_IQ;
@ -563,7 +585,7 @@ int main(int argc, char **argv)
struct sigaction sigact, sigign;
#endif
opt_str = "a:p:f:g:s:b:n:d:P:O:TI:W:l:w:D:v";
opt_str = "a:p:f:g:s:b:n:d:P:O:TI:W:l:w:D:vr:";
while ((opt = getopt(argc, argv, opt_str)) != -1) {
switch (opt) {
case 'd':
@ -585,6 +607,10 @@ int main(int argc, char **argv)
case 'p':
port = atoi(optarg);
break;
case 'r':
port_resp = atoi(optarg);
report_i2c = 0;
break;
case 'I':
port_ir = atoi(optarg);
break;
@ -724,6 +750,25 @@ int main(int argc, char **argv)
pthread_create(&thread_ir, NULL, &ir_thread_fn, (void *)(&data));
}
#if 0
fprintf(stderr, "enabling Response channel with I2C reporting\n");
port_resp = 1;
report_i2c = 1;
#endif
if ( port_resp == 1 )
port_resp = port + 1;
ctrldata.port = port_resp;
ctrldata.dev = dev;
ctrldata.addr = addr;
ctrldata.wait = 500000; /* = 0.5 sec */
ctrldata.report_i2c = report_i2c;
ctrldata.pDoExit = &do_exit_thrd_ctrl;
if ( port_resp ) {
fprintf(stderr, "activating Response channel on port %d with %s I2C reporting\n"
, port_resp, (report_i2c ? "active" : "inactive") );
pthread_create(&thread_ctrl, NULL, &ctrl_thread_fn, &ctrldata);
}
memset(&local,0,sizeof(local));
local.sin_family = AF_INET;
local.sin_port = htons(port);
@ -825,6 +870,11 @@ out:
closesocket(listensocket);
/* if (port_ir) pthread_join(thread_ir, &status); */
if ( port_resp ) {
do_exit_thrd_ctrl = 1;
pthread_join(thread_ctrl, &status);
}
closesocket(s);
#ifdef _WIN32
WSACleanup();

View File

@ -440,6 +440,15 @@ static void *command_worker(void *arg)
printf("set tuner agc variant to %i\n", itmp);
rtlsdr_set_tuner_agc_mode(dev, itmp);
break;
case SET_SIDEBAND:
tmp = ntohl(cmd.param);
if(tmp) {
tmp = 1;
printf("set to upper sideband\n");
} else
printf("set to lower sideband\n");
rtlsdr_set_tuner_sideband(dev, tmp);
break;
default:
break;
}

View File

@ -54,38 +54,92 @@ static int fc0012_readreg(void *dev, uint8_t reg, uint8_t *val)
return 0;
}
/* expose/permit tuner specific i2c register hacking! */
int fc0012_set_i2c_register(void *dev, unsigned i2c_register, unsigned data)
{
uint8_t reg = i2c_register & 0xFF;
uint8_t reg_val = data & 0xFF;
return fc0012_writereg(dev, reg, reg_val);
}
int fc0012_get_i2c_register(void *dev, unsigned char* data, int len)
{
int len1;
data[0] = 0;
/* The lower 16 I2C registers can be read with the normal read fct,
* the upper ones are read from the cache */
if(len < 16)
len1 = len;
else
len1 = 16;
if (rtlsdr_i2c_write_fn(dev, FC0012_I2C_ADDR, data, 1) < 0)
return -1;
if (rtlsdr_i2c_read_fn(dev, FC0012_I2C_ADDR, data, len1) < 0)
return -1;
if(len > 16)
{
len1 = len - 16;
data[16] = 16;
if (rtlsdr_i2c_write_fn(dev, FC0012_I2C_ADDR, data+16, 1) < 0)
return -1;
if (rtlsdr_i2c_read_fn(dev, FC0012_I2C_ADDR, data+16, len1) < 0)
return -1;
}
return 0;
}
static int print_registers(void *dev)
{
uint8_t data[32];
unsigned int i;
if (fc0012_get_i2c_register(dev, data, 32) < 0)
return -1;
for(i=0; i<16; i++)
printf("%02x ", data[i]);
printf("\n");
for(i=16; i<32; i++)
printf("%02x ", data[i]);
printf("\n");
return 0;
}
/* Incomplete list of register settings:
*
* Name Reg Bits Desc
* CHIP_ID 0x00 0-7 Chip ID (constant 0xA1)
* RF_A 0x01 0-3 Number of count-to-9 cycles in RF
* divider (suggested: 2..9)
* RF_M 0x02 0-7 Total number of cycles (to-8 and to-9)
* in RF divider
* Name Reg BitsDesc
* CHIP_ID 0x00 0-7 Chip ID (constant 0xA1)
* RF_A 0x01 0-3 Number of count-to-9 cycles in RF
* divider (suggested: 2..9)
* RF_M 0x02 0-7 Total number of cycles (to-8 and to-9)
* in RF divider
* RF_K_HIGH 0x03 0-6 Bits 8..14 of fractional divider
* RF_K_LOW 0x04 0-7 Bits 0..7 of fractional RF divider
* RF_K_LOW 0x04 0-7 Bits 0..7 of fractional RF divider
* RF_OUTDIV_A 0x05 3-7 Power of two required?
* LNA_POWER_DOWN 0x06 0 Set to 1 to switch off low noise amp
* RF_OUTDIV_B 0x06 1 Set to select 3 instead of 2 for the
* RF output divider
* RF output divider
* VCO_SPEED 0x06 3 Select tuning range of VCO:
* 0 = Low range, (ca. 1.1 - 1.5GHz)
* 1 = High range (ca. 1.4 - 1.8GHz)
* 0 = Low range, (ca. 1.1 - 1.5GHz)
* 1 = High range (ca. 1.4 - 1.8GHz)
* BANDWIDTH 0x06 6-7 Set bandwidth. 6MHz = 0x80, 7MHz=0x40
* 8MHz=0x00
* 8MHz=0x00
* XTAL_SPEED 0x07 5 Set to 1 for 28.8MHz Crystal input
* or 0 for 36MHz
* or 0 for 36MHz
* <agc params> 0x08 0-7
* EN_CAL_RSSI 0x09 4 Enable calibrate RSSI
* (Receive Signal Strength Indicator)
* (Receive Signal Strength Indicator)
* LNA_FORCE 0x0d 0
* AGC_FORCE 0x0d ?
* LNA_GAIN 0x13 3-4 Low noise amp gain
* LNA_COMPS 0x15 3 ?
* VCO_CALIB 0x0e 7 Set high then low to calibrate VCO
* (fast lock?)
* (fast lock?)
* VCO_VOLTAGE 0x0e 0-6 Read Control voltage of VCO
* (big value -> low freq)
* (big value -> low freq)
* LNA_GAIN 0x13 3-4 Low noise amp gain
* LNA_COMPS 0x15 3 ?
*/
int fc0012_init(void *dev)
@ -112,8 +166,8 @@ int fc0012_init(void *dev)
0x00, /* reg. 0x0e */
0x00, /* reg. 0x0f */
0x00, /* reg. 0x10: may also be 0x0d */
0x00, /* reg. 0x11 */
0x1f, /* reg. 0x12: Set to maximum gain */
0x0a, /* reg. 0x11 */
0x51, /* reg. 0x12: Set to maximum gain */
0x08, /* reg. 0x13: Set to Middle Gain: 0x08,
Low Gain: 0x00, High Gain: 0x10, enable IX2: 0x80 */
0x00, /* reg. 0x14 */
@ -133,7 +187,7 @@ int fc0012_init(void *dev)
#endif
reg[0x07] |= 0x20;
// if (priv->dual_master)
/* if (priv->dual_master) */
reg[0x0c] |= 0x02;
for (i = 1; i < sizeof(reg); i++) {
@ -278,7 +332,7 @@ int fc0012_set_params(void *dev, uint32_t freq, uint32_t bandwidth)
ret = fc0012_writereg(dev, 0x0e, 0x00);
if (!ret) {
// msleep(10);
/* msleep(10); */
ret = fc0012_readreg(dev, 0x0e, &tmp);
}
if (ret)
@ -340,6 +394,6 @@ int fc0012_set_gain(void *dev, int gain)
}
ret = fc0012_writereg(dev, 0x13, tmp);
/* print_registers(dev); */
return ret;
}

View File

@ -30,26 +30,277 @@
#include "rtlsdr_i2c.h"
#include "tuner_r82xx.h"
#define WITH_ASYM_FILTER 1
#define WITH_ASYM_FILTER 0
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#define MHZ(x) ((x)*1000*1000)
#define KHZ(x) ((x)*1000)
/*
Reg Bitmap Symbol Description
------------------------------------------------------------------------------------
R0 [7:0] CHIP_ID reference check point for read mode
0x00 0x96
------------------------------------------------------------------------------------
R1 ?
0x01
------------------------------------------------------------------------------------
R2 [7] 0
0x02 [6:0] VCO_INDICATOR
------------------------------------------------------------------------------------
R3 [7:4] RF_INDICATOR LNA gain
0x03 0: Lowest, 15: Highest
[3:0] Mixer gain
0: Lowest, 15: Highest
------------------------------------------------------------------------------------
R4 ?
0x04
------------------------------------------------------------------------------------
R5 [7] PWD_LT Loop through ON/OFF
0x05 0: on, 1: off
[6] 0
[5] PWD_LNA1 LNA 1 power control
0:on, 1:off
[4] LNA_GAIN_MODE LNA gain mode switch
0: auto, 1: manual
[3:0] LNA_GAIN LNA manual gain control
15: max gain, 0: min gain
------------------------------------------------------------------------------------
R6 [7] PWD_PDET1 Power detector 1 on/off
0x06 0: on, 1: off
[6] PWD_PDET3 Power detector 3 on/off
0: off, 1: on
[5] FILT_3DB Filter gain 3db
0:0db, 1:+3db
[4:3] 10
[2:0] PW_LNA LNA power control
000: max, 111: min
------------------------------------------------------------------------------------
R7 [7] Mixer Sideband
0x07 0: lower, 1: upper
[6] PWD_MIX Mixer power
0:off, 1:on
[5] PW0_MIX Mixer current control
0:max current, 1:normal current
[4] MIXGAIN_MODE Mixer gain mode
0:manual mode, 1:auto mode
[3:0] MIX_GAIN Mixer manual gain control
0000->min, 1111->max
------------------------------------------------------------------------------------
R8 [7] PWD_AMP Mixer buffer power on/off
0x08 0: off, 1:on
[6] PW0_AMP Mixer buffer current setting
0: high current, 1: low current
[5:0] IMR_G Image Gain Adjustment
0: min, 63: max
------------------------------------------------------------------------------------
R9 [7] PWD_IFFILT IF Filter power on/off
0x09 0: filter on, 1: off
[6] PW1_IFFILT IF Filter current
0: high current, 1: low current
[5:0] IMR_P Image Phase Adjustment
0: min, 63: max
------------------------------------------------------------------------------------
R10 [7] PWD_FILT Filter power on/off
0x0A 0: channel filter off, 1: on
[6:5] PW_FILT Filter power control
00: highest power, 11: lowest power
[4] 1
[3:0] FILT_CODE Filter bandwidth manual fine tune
0000 Widest, 1111 narrowest
------------------------------------------------------------------------------------
R11 [7:5] FILT_BW Filter bandwidth manual course tunnel
0x0B 000: widest
010 or 001: middle
111: narrowest
[4] 0
[3:0] HPF High pass filter corner control
0000: highest
1111: lowest
------------------------------------------------------------------------------------
R12 [7] 1
0x0C [6] PWD_VGA VGA power control
0: vga power off, 1: vga power on
[5] 1
[4] VGA_MODE VGA GAIN manual / pin selector
1: IF vga gain controlled by vagc pin
0: IF vga gain controlled by vga_code[3:0]
[3:0] VGA_CODE IF vga manual gain control
0000: -12.0 dB
1111: +40.5 dB; -3.5dB/step
------------------------------------------------------------------------------------
R13 [7:4] LNA_VTHH LNA agc power detector voltage threshold high setting
0x0D 1111: 1.94 V
0000: 0.34 V, ~0.1 V/step
[3:0] LNA_VTHL LNA agc power detector voltage threshold low setting
1111: 1.94 V
0000: 0.34 V, ~0.1 V/step
------------------------------------------------------------------------------------
R14 [7:4] MIX_VTH_H MIXER agc power detector voltage threshold high setting
0x0E 1111: 1.94 V
0000: 0.34 V, ~0.1 V/step
[3:0] MIX_VTH_L MIXER agc power detector voltage threshold low setting
1111: 1.94 V
0000: 0.34 V, ~0.1 V/step
------------------------------------------------------------------------------------
R15 [7] filter extension widest
0: off, 1: on
0x0F [4] CLK_OUT_ENB Clock out pin control
0: clk output on, 1: off
[3] 1
[2] set cali clk
0: off, 1: on
[1] CLK_AGC_ENB AGC clk control
0: internal agc clock on, 1: off
[0] GPIO 0
------------------------------------------------------------------------------------
R16 [7:5] SEL_DIV PLL to Mixer divider number control
0x10 000: mixer in = vco out /2
001: mixer in = vco out / 4
010: mixer in = vco out / 8
011: mixer in = vco out
[4] REFDIV PLL Reference frequency Divider
0 -> fref=xtal_freq
1 -> fref=xta_freql / 2 (for Xtal >24MHz)
[3:2] 01
[1:0] CAPX Internal xtal cap setting
00->no cap
01->10pF
10->20pF
11->30pF
------------------------------------------------------------------------------------
R17 [7:6] PW_LDO_A PLL analog low drop out regulator switch
0x11 00: off
01: 2.1V
10: 2.0V
11: 1.9V
[5:3] cp_cur
101: 0.2, 111: auto
[2:0] 011
------------------------------------------------------------------------------------
R18 [7:5] set VCO current
0x12 [4] PW_SDM 0
[3:0] 000
------------------------------------------------------------------------------------
R19 [7:6] 00
[5:0] VER_NUM 0x31
------------------------------------------------------------------------------------
R20 [7:6] SI2C PLL integer divider number input Si2c
0x14 Nint=4*Ni2c+Si2c+13
PLL divider number Ndiv = (Nint + Nfra)*2
[5:0] NI2C PLL integer divider number input Ni2c
------------------------------------------------------------------------------------
R21 [7:0] SDM_IN[8:1] PLL fractional divider number input SDM[16:1]
0x15 Nfra=SDM_IN[16]*2^-1+SDM_IN[15]*2^-2+...
R22 [7:0] SDM_IN[16:9] +SDM_IN[2]*2^-15+SDM_IN[1]*2^-16
0x16
------------------------------------------------------------------------------------
R23 [7:6] PW_LDO_D PLL digital low drop out regulator supply current switch
0x17 00: 1.8V,8mA
01: 1.8V,4mA
10: 2.0V,8mA
11: OFF
[5:4] div_buf_cur
10: 200u, 11: 150u
[3] OPEN_D Open drain
0: High-Z, 1: Low-Z
[2:0] 100
------------------------------------------------------------------------------------
R25 [7] PWD_RFFILT RF Filter power
0x19 0: off, 1:on
[6:5] RF poly filter current
00: min
[4] SW_AGC Switch agc_pin
0:agc=agc_in
1:agc=agc_in2
[3:2] 11
------------------------------------------------------------------------------------
R26 [7:6] RFMUX Tracking Filter switch
0x1A 00: TF on
01: Bypass
[5:4] AGC clk
00: 300ms, 01: 300ms, 10: 80ms, 11: 20ms
[3:2] PLL_AUTO_CLK PLL auto tune clock rate
00: 128 kHz
01: 32 kHz
10: 8 kHz
[1:0] RFFILT RF FILTER band selection
00: highest band
01: med band
10: low band
------------------------------------------------------------------------------------
R27 [7:4] TF_NCH 0000 highest corner for LPNF
0x1B 1111 lowerst corner for LPNF
[3:0] TF_LP 0000 highest corner for LPF
1111 lowerst corner for LPF
------------------------------------------------------------------------------------
R28 [7:4] PDET3_GAIN Power detector 3 (Mixer) TOP(take off point) control
0x1C 0: Highest, 15: Lowest
[3] discharge mode
0: on
[2] 1
[0] 0
------------------------------------------------------------------------------------
R29 [7:6] 11
0x1D [5:3] PDET1_GAIN Power detector 1 (LNA) TOP(take off point) control
0: Highest, 7: Lowest
[2:0] PDET2_GAIN Power detector 2 TOP(take off point) control
0: Highest, 7: Lowest
------------------------------------------------------------------------------------
R30 [7] 0
0x1E [6] FILTER_EXT Filter extension under weak signal
0: Disable, 1: Enable
[5:0] PDET_CLK Power detector timing control (LNA discharge current)
111111: max, 000000: min
------------------------------------------------------------------------------------
R31 [7] Loop through attenuation
0x1F 0: Enable, 1: Disable
[6:2] 10000
------------------------------------------------------------------------------------
R0...R4 read, R5...R15 read/write, R16..R31 write
*/
/*
* Static constants
*/
/* Those initial values start from REG_SHADOW_START */
static const uint8_t r82xx_init_array[NUM_REGS] = {
0x83, 0x32, 0x75, /* 05 to 07 */
0xc0, 0x40, 0xd6, 0x6c, /* 08 to 0b */
0xf5, 0x63, 0x75, 0x68, /* 0c to 0f */
0x6c, 0x83, 0x80, 0x00, /* 10 to 13 */
0x0f, 0x00, 0xc0, 0x30, /* 14 to 17 */
0x48, 0xcc, 0x60, 0x00, /* 18 to 1b */
0x54, 0xae, 0x4a, 0xc0 /* 1c to 1f */
static const uint8_t r82xx_init_array[] = {
0x80, /* Reg 0x05 */
0x12, /* Reg 0x06 */
0x70, /* Reg 0x07 */
0xc0, /* Reg 0x08 */
0x40, /* Reg 0x09 */
0xdb, /* Reg 0x0a */
0x6b, /* Reg 0x0b */
0xf0, /* Reg 0x0c */
0x53, /* Reg 0x0d */
0x75, /* Reg 0x0e */
0x68, /* Reg 0x0f */
0x6c, /* Reg 0x10 */
0xbb, /* Reg 0x11 */
0x80, /* Reg 0x12 */
VER_NUM & 0x3f, /* Reg 0x13 */
0x0f, /* Reg 0x14 */
0x00, /* Reg 0x15 */
0xc0, /* Reg 0x16 */
0x30, /* Reg 0x17 */
0x48, /* Reg 0x18 */
0xec, /* Reg 0x19 */
0x60, /* Reg 0x1a */
0x00, /* Reg 0x1b */
0x24, /* Reg 0x1c */
0xdd, /* Reg 0x1d */
0x0e, /* Reg 0x1e */
0x40 /* Reg 0x1f */
};
/* Tuner frequency ranges */
@ -225,14 +476,6 @@ static const struct r82xx_freq_range freq_ranges[] = {
}
};
static int r82xx_xtal_capacitor[][2] = {
{ 0x0b, XTAL_LOW_CAP_30P },
{ 0x02, XTAL_LOW_CAP_20P },
{ 0x01, XTAL_LOW_CAP_10P },
{ 0x00, XTAL_LOW_CAP_0P },
{ 0x10, XTAL_HIGH_CAP_0P },
};
/*
* I2C read/write code and shadow registers logic
*/
@ -369,11 +612,6 @@ static int r82xx_read(struct r82xx_priv *priv, uint8_t reg, uint8_t *val, int le
uint8_t *p = &priv->buf[1];
priv->buf[0] = reg;
rc = rtlsdr_i2c_write_fn(priv->rtl_dev, priv->cfg->i2c_addr, priv->buf, 1);
if (rc < 1)
return rc;
rc = rtlsdr_i2c_read_fn(priv->rtl_dev, priv->cfg->i2c_addr, p, len);
if (rc != len) {
@ -391,6 +629,23 @@ static int r82xx_read(struct r82xx_priv *priv, uint8_t reg, uint8_t *val, int le
return 0;
}
static void print_registers(struct r82xx_priv *priv)
{
uint8_t data[5];
int rc;
unsigned int i;
rc = r82xx_read(priv, 0x00, data, sizeof(data));
if (rc < 0)
return;
for(i=0; i<sizeof(data); i++)
printf("%02x ", data[i]);
printf("\n");
for(i=sizeof(data); i<32; i++)
printf("%02x ", r82xx_read_cache_reg(priv, i));
printf("\n");
}
/*
* r82xx tuning logic
*/
@ -443,14 +698,6 @@ static int r82xx_set_mux(struct r82xx_priv *priv, uint32_t freq)
break;
}
rc = r82xx_write_reg_mask(priv, 0x10, val, 0x0b);
if (rc < 0)
return rc;
rc = r82xx_write_reg_mask(priv, 0x08, 0x00, 0x3f);
if (rc < 0)
return rc;
rc = r82xx_write_reg_mask(priv, 0x09, 0x00, 0x3f);
return rc;
}
@ -534,13 +781,13 @@ static int r82xx_set_pll(struct r82xx_priv *priv, uint32_t freq)
* nint + sdm/65536
*
* where nint,sdm are integers and 0 < nint, 0 <= sdm < 65536
*
*
* Scaling to fixed point and rounding:
*
* vco_div = 65536*(nint + sdm/65536) = int( 0.5 + 65536 * vco_freq / (2 * pll_ref) )
* vco_div = 65536*nint + sdm = int( (pll_ref + 65536 * vco_freq) / (2 * pll_ref) )
*/
vco_div = (pll_ref + 65536 * vco_freq) / (2 * pll_ref);
nint = (uint32_t) (vco_div / 65536);
sdm = (uint32_t) (vco_div % 65536);
@ -583,7 +830,6 @@ static int r82xx_set_pll(struct r82xx_priv *priv, uint32_t freq)
return rc;
for (i = 0; i < 2; i++) {
// usleep_range(sleep_time, sleep_time + 1000);
/* Check if PLL has locked */
rc = r82xx_read(priv, 0x00, data, 3);
@ -614,76 +860,15 @@ static int r82xx_set_pll(struct r82xx_priv *priv, uint32_t freq)
return rc;
}
static int r82xx_sysfreq_sel(struct r82xx_priv *priv, uint32_t freq,
enum r82xx_tuner_type type,
uint32_t delsys)
static int r82xx_sysfreq_sel(struct r82xx_priv *priv,
enum r82xx_tuner_type type)
{
int rc;
uint8_t mixer_top, lna_top, cp_cur, div_buf_cur, lna_vth_l, mixer_vth_l;
uint8_t air_cable1_in, cable2_in, pre_dect, lna_discharge, filter_cur;
switch (delsys) {
case SYS_DVBT:
if ((freq == 506000000) || (freq == 666000000) ||
(freq == 818000000)) {
mixer_top = 0x14; /* mixer top:14 , top-1, low-discharge */
lna_top = 0xe5; /* detect bw 3, lna top:4, predet top:2 */
cp_cur = 0x28; /* 101, 0.2 */
div_buf_cur = 0x20; /* 10, 200u */
} else {
mixer_top = 0x24; /* mixer top:13 , top-1, low-discharge */
lna_top = 0xe5; /* detect bw 3, lna top:4, predet top:2 */
cp_cur = 0x38; /* 111, auto */
div_buf_cur = 0x30; /* 11, 150u */
}
lna_vth_l = 0x53; /* lna vth 0.84 , vtl 0.64 */
mixer_vth_l = 0x75; /* mixer vth 1.04, vtl 0.84 */
air_cable1_in = 0x00;
cable2_in = 0x00;
pre_dect = 0x40;
lna_discharge = 14;
filter_cur = 0x40; /* 10, low */
break;
case SYS_DVBT2:
mixer_top = 0x24; /* mixer top:13 , top-1, low-discharge */
lna_top = 0xe5; /* detect bw 3, lna top:4, predet top:2 */
lna_vth_l = 0x53; /* lna vth 0.84 , vtl 0.64 */
mixer_vth_l = 0x75; /* mixer vth 1.04, vtl 0.84 */
air_cable1_in = 0x00;
cable2_in = 0x00;
pre_dect = 0x40;
lna_discharge = 14;
cp_cur = 0x38; /* 111, auto */
div_buf_cur = 0x30; /* 11, 150u */
filter_cur = 0x40; /* 10, low */
break;
case SYS_ISDBT:
mixer_top = 0x24; /* mixer top:13 , top-1, low-discharge */
lna_top = 0xe5; /* detect bw 3, lna top:4, predet top:2 */
lna_vth_l = 0x75; /* lna vth 1.04 , vtl 0.84 */
mixer_vth_l = 0x75; /* mixer vth 1.04, vtl 0.84 */
air_cable1_in = 0x00;
cable2_in = 0x00;
pre_dect = 0x40;
lna_discharge = 14;
cp_cur = 0x38; /* 111, auto */
div_buf_cur = 0x30; /* 11, 150u */
filter_cur = 0x40; /* 10, low */
break;
default: /* DVB-T 8M */
mixer_top = 0x24; /* mixer top:13 , top-1, low-discharge */
lna_top = 0xe5; /* detect bw 3, lna top:4, predet top:2 */
lna_vth_l = 0x53; /* lna vth 0.84 , vtl 0.64 */
mixer_vth_l = 0x75; /* mixer vth 1.04, vtl 0.84 */
air_cable1_in = 0x00;
cable2_in = 0x00;
pre_dect = 0x40;
lna_discharge = 14;
cp_cur = 0x38; /* 111, auto */
div_buf_cur = 0x30; /* 11, 150u */
filter_cur = 0x40; /* 10, low */
break;
}
uint8_t lna_top = 0xe5; /* detect bw 3, lna top:4, predet top:2 */
uint8_t pre_dect = 0x40;
uint8_t air_cable1_in = 0x00;
uint8_t cable2_in = 0x00;
if (priv->cfg->use_predetect) {
rc = r82xx_write_reg_mask(priv, 0x06, pre_dect, 0x40);
@ -691,19 +876,6 @@ static int r82xx_sysfreq_sel(struct r82xx_priv *priv, uint32_t freq,
return rc;
}
rc = r82xx_write_reg_mask(priv, 0x1d, lna_top, 0xc7);
if (rc < 0)
return rc;
rc = r82xx_write_reg_mask(priv, 0x1c, mixer_top, 0xf8);
if (rc < 0)
return rc;
rc = r82xx_write_reg(priv, 0x0d, lna_vth_l);
if (rc < 0)
return rc;
rc = r82xx_write_reg(priv, 0x0e, mixer_vth_l);
if (rc < 0)
return rc;
priv->input = air_cable1_in;
/* Air-IN only for Astrometa */
@ -714,16 +886,6 @@ static int r82xx_sysfreq_sel(struct r82xx_priv *priv, uint32_t freq,
if (rc < 0)
return rc;
rc = r82xx_write_reg_mask(priv, 0x11, cp_cur, 0x38);
if (rc < 0)
return rc;
rc = r82xx_write_reg_mask(priv, 0x17, div_buf_cur, 0x30);
if (rc < 0)
return rc;
rc = r82xx_write_reg_mask_ext(priv, 0x0a, filter_cur, 0x60, __FUNCTION__);
if (rc < 0)
return rc;
/*
* Set LNA
*/
@ -734,11 +896,6 @@ static int r82xx_sysfreq_sel(struct r82xx_priv *priv, uint32_t freq,
if (rc < 0)
return rc;
/* 0: normal mode */
rc = r82xx_write_reg_mask(priv, 0x1c, 0, 0x04);
if (rc < 0)
return rc;
/* 0: PRE_DECT off */
rc = r82xx_write_reg_mask(priv, 0x06, 0, 0x40);
if (rc < 0)
@ -749,27 +906,11 @@ static int r82xx_sysfreq_sel(struct r82xx_priv *priv, uint32_t freq,
if (rc < 0)
return rc;
// msleep(250);
/* write LNA TOP = 3 */
rc = r82xx_write_reg_mask(priv, 0x1d, 0x18, 0x38);
if (rc < 0)
return rc;
/*
* write discharge mode
* FIXME: IMHO, the mask here is wrong, but it matches
* what's there at the original driver
*/
rc = r82xx_write_reg_mask(priv, 0x1c, mixer_top, 0x04);
if (rc < 0)
return rc;
/* LNA discharge current */
rc = r82xx_write_reg_mask(priv, 0x1e, lna_discharge, 0x1f);
if (rc < 0)
return rc;
/* agc clk 60hz */
rc = r82xx_write_reg_mask(priv, 0x1a, 0x20, 0x30);
if (rc < 0)
@ -785,20 +926,6 @@ static int r82xx_sysfreq_sel(struct r82xx_priv *priv, uint32_t freq,
if (rc < 0)
return rc;
/*
* write discharge mode
* FIXME: IMHO, the mask here is wrong, but it matches
* what's there at the original driver
*/
rc = r82xx_write_reg_mask(priv, 0x1c, mixer_top, 0x04);
if (rc < 0)
return rc;
/* LNA discharge current */
rc = r82xx_write_reg_mask(priv, 0x1e, lna_discharge, 0x1f);
if (rc < 0)
return rc;
/* agc clk 1Khz, external det1 cap 1u */
rc = r82xx_write_reg_mask(priv, 0x1a, 0x00, 0x30);
if (rc < 0)
@ -812,75 +939,40 @@ static int r82xx_sysfreq_sel(struct r82xx_priv *priv, uint32_t freq,
}
static int r82xx_set_tv_standard(struct r82xx_priv *priv,
unsigned bw,
enum r82xx_tuner_type type,
uint32_t delsys)
{
int rc, i;
uint32_t if_khz, filt_cal_lo;
uint8_t data[5];
uint8_t filt_gain, img_r, filt_q, hp_cor, ext_enable, loop_through;
uint8_t lt_att, flt_ext_widest, polyfil_cur;
int need_calibration;
int need_calibration = 1;
/* BW < 6 MHz */
if_khz = 3570;
filt_cal_lo = 56000; /* 52000->56000 */
filt_gain = 0x10; /* +3db, 6mhz on */
img_r = 0x00; /* image negative */
filt_q = 0x10; /* r10[4]:low q(1'b1) */
hp_cor = 0x6b; /* 1.7m disable, +2cap, 1.0mhz */
ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */
loop_through = 0x01; /* r5[7], lt off */
lt_att = 0x00; /* r31[7], lt att enable */
flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
polyfil_cur = 0x60; /* r25[6:5]:min */
/* Initialize the shadow registers */
memcpy(priv->regs, r82xx_init_array, sizeof(r82xx_init_array));
/* Init Flag & Xtal_check Result (inits VGA gain, needed?)*/
rc = r82xx_write_reg_mask(priv, 0x0c, 0x00, 0x0f);
if (rc < 0)
return rc;
/* version */
rc = r82xx_write_reg_mask(priv, 0x13, VER_NUM, 0x3f);
if (rc < 0)
return rc;
uint32_t filt_cal_lo = 56000; /* 52000->56000 */
uint8_t filt_q = 0x10; /* r10[4]:low q(1'b1) */
/* for LT Gain test */
if (type != TUNER_ANALOG_TV) {
rc = r82xx_write_reg_mask(priv, 0x1d, 0x00, 0x38);
if (rc < 0)
return rc;
// usleep_range(1000, 2000);
}
priv->if_band_center_freq = 0;
priv->int_freq = if_khz * 1000;
priv->int_freq = 3570 * 1000;
priv->sideband = 0;
/* Check if standard changed. If so, filter calibration is needed */
/* as we call this function only once in rtlsdr, force calibration */
need_calibration = 1;
if (need_calibration) {
for (i = 0; i < 2; i++) {
/* Set filt_cap */
rc = r82xx_write_reg_mask_ext(priv, 0x0b, hp_cor, 0x60, __FUNCTION__);
if (rc < 0)
return rc;
/* set cali clk =on */
rc = r82xx_write_reg_mask(priv, 0x0f, 0x04, 0x04);
if (rc < 0)
return rc;
/* X'tal cap 0pF for PLL */
rc = r82xx_write_reg_mask(priv, 0x10, 0x00, 0x03);
if (rc < 0)
return rc;
rc = r82xx_set_pll(priv, filt_cal_lo * 1000);
if (rc < 0 || !priv->has_lock)
return rc;
@ -890,8 +982,6 @@ static int r82xx_set_tv_standard(struct r82xx_priv *priv,
if (rc < 0)
return rc;
// usleep_range(1000, 2000);
/* Stop Trigger */
rc = r82xx_write_reg_mask_ext(priv, 0x0b, 0x00, 0x10, __FUNCTION__);
if (rc < 0)
@ -921,50 +1011,10 @@ static int r82xx_set_tv_standard(struct r82xx_priv *priv,
if (rc < 0)
return rc;
/* Set BW, Filter_gain, & HP corner */
rc = r82xx_write_reg_mask_ext(priv, 0x0b, hp_cor, 0xef, __FUNCTION__);
if (rc < 0)
return rc;
/* Set Img_R */
rc = r82xx_write_reg_mask(priv, 0x07, img_r, 0x80);
if (rc < 0)
return rc;
/* Set filt_3dB, V6MHz */
rc = r82xx_write_reg_mask(priv, 0x06, filt_gain, 0x30);
if (rc < 0)
return rc;
/* channel filter extension */
rc = r82xx_write_reg_mask_ext(priv, 0x1e, ext_enable, 0x60, __FUNCTION__);
if (rc < 0)
return rc;
/* Loop through */
rc = r82xx_write_reg_mask(priv, 0x05, loop_through, 0x80);
if (rc < 0)
return rc;
/* Loop through attenuation */
rc = r82xx_write_reg_mask(priv, 0x1f, lt_att, 0x80);
if (rc < 0)
return rc;
/* filter extension widest */
rc = r82xx_write_reg_mask(priv, 0x0f, flt_ext_widest, 0x80);
if (rc < 0)
return rc;
/* RF poly filter current */
rc = r82xx_write_reg_mask(priv, 0x19, polyfil_cur, 0x60);
if (rc < 0)
return rc;
/* Store current standard. If it changes, re-calibrate the tuner */
priv->delsys = delsys;
priv->type = type;
priv->bw = bw;
priv->bw = 3;
return 0;
}
@ -1125,6 +1175,26 @@ int r82xx_set_i2c_register(struct r82xx_priv *priv, unsigned i2c_register, unsig
return r82xx_write_reg_mask(priv, reg, reg_val, reg_mask);
}
//-cs-
int r82xx_get_i2c_register(struct r82xx_priv *priv, unsigned char* data, int len)
{
int rc, i, len1;
// The lower 5 I2C registers can be read with the normal read fct, the upper ones are read from the cache
if(len < 5)
len1 = len;
else
len1 = 5;
rc = r82xx_read(priv, 0x00, data, len1);
if (rc < 0)
return rc;
if(len > 5)
for (i = 5; i < len; i++)
data[i] = r82xx_read_cache_reg(priv, i);
return 0;
}
//-cs- end
int r82xx_set_i2c_override(struct r82xx_priv *priv, unsigned i2c_register, unsigned data, unsigned mask)
{
uint8_t reg = i2c_register & 0xFF;
@ -1170,11 +1240,6 @@ int r82xx_set_i2c_override(struct r82xx_priv *priv, unsigned i2c_register, unsig
}
/* Bandwidth contribution by low-pass filter. */
static const int r82xx_if_low_pass_bw_table[] = {
1700000, 1600000, 1550000, 1450000, 1200000, 900000, 700000, 550000, 450000, 350000
};
struct IFinfo
{
@ -1261,6 +1326,15 @@ static const struct IFinfo IFi[] = {
{ 3, 1950+3, 1500, 30, 0x0F, 0x8F, 0x60 }
};
/* settings from Oldenburger:
static const int r82xx_bws[]= { 300, 450, 600, 900, 1100, 1200, 1300, 1500, 1800, 2200, 3000, 5000 };
static const uint8_t r82xx_0xa[]= { 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0f, 0x0f, 0x04, 0x0b };
static const uint8_t r82xx_0xb[]= { 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xaf, 0x8f, 0x8f, 0x6b };
static const int r82xx_if[] = { 1700, 1650, 1600, 1500, 1400, 1350, 1320, 1270, 1400, 1600, 2000, 3570 };
*/
static const int r82xx_bw_tablen = sizeof(IFi) / sizeof(IFi[0]);
@ -1456,17 +1530,33 @@ int r82xx_set_bw_center(struct r82xx_priv *priv, int32_t if_band_center_freq)
return priv->int_freq;
}
int r82xx_set_sideband(struct r82xx_priv *priv, int sideband)
{
int rc;
priv->sideband = sideband;
rc = r82xx_write_reg_mask(priv, 0x07, (sideband << 7) & 0x80, 0x80);
if (rc < 0)
return rc;
return 0;
}
int r82xx_set_freq(struct r82xx_priv *priv, uint32_t freq)
{
int rc = -1;
uint32_t lo_freq = freq + priv->int_freq + priv->if_band_center_freq;
uint32_t lo_freq;
uint8_t air_cable1_in;
if(priv->sideband)
lo_freq = freq - priv->int_freq + priv->if_band_center_freq;
else
lo_freq = freq + priv->int_freq + priv->if_band_center_freq;
#if 0
fprintf(stderr, "%s(freq = %u) --> intfreq %u, ifcenter %d --> f %u\n"
, __FUNCTION__, (unsigned)freq
fprintf(stderr, "%s(freq = %u) @ %s--> intfreq %u, ifcenter %d --> f %u\n"
, __FUNCTION__, (unsigned)freq, (priv->sideband ? "USB" : "LSB")
, (unsigned)priv->int_freq, (int)priv->if_band_center_freq
, (unsigned)lo_freq );
#endif
uint8_t air_cable1_in;
rc = r82xx_set_mux(priv, lo_freq);
if (rc < 0)
@ -1548,65 +1638,6 @@ int r82xx_standby(struct r82xx_priv *priv)
* r82xx device init logic
*/
static int r82xx_xtal_check(struct r82xx_priv *priv)
{
int rc;
unsigned int i;
uint8_t data[3], val;
/* Initialize the shadow registers */
memcpy(priv->regs, r82xx_init_array, sizeof(r82xx_init_array));
/* cap 30pF & Drive Low */
rc = r82xx_write_reg_mask(priv, 0x10, 0x0b, 0x0b);
if (rc < 0)
return rc;
/* set pll autotune = 128kHz */
rc = r82xx_write_reg_mask(priv, 0x1a, 0x00, 0x0c);
if (rc < 0)
return rc;
/* set manual initial reg = 111111; */
rc = r82xx_write_reg_mask(priv, 0x13, 0x7f, 0x7f);
if (rc < 0)
return rc;
/* set auto */
rc = r82xx_write_reg_mask(priv, 0x13, 0x00, 0x40);
if (rc < 0)
return rc;
/* Try several xtal capacitor alternatives */
for (i = 0; i < ARRAY_SIZE(r82xx_xtal_capacitor); i++) {
rc = r82xx_write_reg_mask(priv, 0x10,
r82xx_xtal_capacitor[i][0], 0x1b);
if (rc < 0)
return rc;
// usleep_range(5000, 6000);
rc = r82xx_read(priv, 0x00, data, sizeof(data));
if (rc < 0)
return rc;
if (!(data[2] & 0x40))
continue;
val = data[2] & 0x3f;
if (priv->cfg->xtal == 16000000 && (val > 29 || val < 23))
break;
if (val != 0x3f)
break;
}
if (i == ARRAY_SIZE(r82xx_xtal_capacitor))
return -1;
return r82xx_xtal_capacitor[i][1];
}
int r82xx_init(struct r82xx_priv *priv)
{
int rc;
@ -1629,11 +1660,11 @@ int r82xx_init(struct r82xx_priv *priv)
rc = r82xx_write_arr(priv, 0x05,
r82xx_init_array, sizeof(r82xx_init_array));
rc = r82xx_set_tv_standard(priv, 3, TUNER_DIGITAL_TV, 0);
rc = r82xx_set_tv_standard(priv, TUNER_DIGITAL_TV, 0);
if (rc < 0)
goto err;
rc = r82xx_sysfreq_sel(priv, 0, TUNER_DIGITAL_TV, SYS_DVBT);
rc = r82xx_sysfreq_sel(priv, TUNER_DIGITAL_TV);
#if USE_R82XX_ENV_VARS
priv->printI2C = 0;