@ -46,53 +46,84 @@
# include "tuner_fc2580.h"
# include "tuner_fc2580.h"
typedef struct rtlsdr_tuner {
typedef struct rtlsdr_tuner {
int ( * init ) ( void * ) ;
/* tuner interface */
int ( * exit ) ( void * ) ;
int ( * init ) ( void * ) ;
int ( * tune ) ( void * , uint32_t freq /* Hz */ ) ;
int ( * exit ) ( void * ) ;
int ( * set_bw ) ( void * , int bw /* Hz */ ) ;
int ( * set_freq ) ( void * , uint32_t freq /* Hz */ ) ;
int ( * set_gain ) ( void * , int gain /* dB */ ) ;
int ( * set_bw ) ( void * , int bw /* Hz */ ) ;
int ( * set_gain ) ( void * , int gain /* dB */ ) ;
} rtlsdr_tuner_t ;
enum rtlsdr_async_status {
RTLSDR_INACTIVE = 0 ,
RTLSDR_CANCELING ,
RTLSDR_RUNNING
} ;
struct rtlsdr_dev {
libusb_context * ctx ;
struct libusb_device_handle * devh ;
uint32_t xfer_buf_num ;
uint32_t xfer_buf_len ;
struct libusb_transfer * * xfer ;
unsigned char * * xfer_buf ;
rtlsdr_read_async_cb_t cb ;
void * cb_ctx ;
enum rtlsdr_async_status async_status ;
/* rtl demod context */
uint32_t rate ; /* Hz */
uint32_t rtl_xtal ; /* Hz */
/* tuner context */
rtlsdr_tuner_t * tuner ;
uint32_t tun_xtal ; /* Hz */
uint32_t freq ; /* Hz */
uint32_t freq ; /* Hz */
int corr ; /* ppm */
int corr ; /* ppm */
int gain ; /* dB */
int gain ; /* dB */
} rtlsdr_tuner_t ;
} ;
void rtlsdr_set_gpio_bit ( rtlsdr_dev_t * dev , uint8_t gpio , int val ) ;
void rtlsdr_set_gpio_bit ( rtlsdr_dev_t * dev , uint8_t gpio , int val ) ;
/* generic tuner interface functions, shall be moved to the tuner implementations */
/* generic tuner interface functions, shall be moved to the tuner implementations */
int e4k_init ( void * dev ) { return e4000_Initialize ( dev ) ; }
int e4k_init ( void * dev ) { return e4000_Initialize ( dev ) ; }
int e4k_exit ( void * dev ) { return 0 ; }
int e4k_exit ( void * dev ) { return 0 ; }
int e4k_tune ( void * dev , uint32_t freq ) { return e4000_SetRfFreqHz ( dev , freq ) ; }
int e4k_set_freq ( void * dev , uint32_t freq ) {
int e4k_set_bw ( void * dev , int bw ) { return e4000_SetBandwidthHz ( dev , 4000000 ) ; }
return e4000_SetRfFreqHz ( dev , freq ) ;
}
int e4k_set_bw ( void * dev , int bw ) {
return e4000_SetBandwidthHz ( dev , 4000000 ) ;
}
int e4k_set_gain ( void * dev , int gain ) { return 0 ; }
int e4k_set_gain ( void * dev , int gain ) { return 0 ; }
int fc0012_init ( void * dev ) { return FC0012_Open ( dev ) ; }
int fc0012_init ( void * dev ) { return FC0012_Open ( dev ) ; }
int fc0012_exit ( void * dev ) { return 0 ; }
int fc0012_exit ( void * dev ) { return 0 ; }
int fc0012_tune ( void * dev , uint32_t freq ) {
int fc0012_set_freq ( void * dev , uint32_t freq ) {
/* select V-band/U-band filter */
/* select V-band/U-band filter */
rtlsdr_set_gpio_bit ( dev , 6 , ( freq > 300000000 ) ? 1 : 0 ) ;
rtlsdr_set_gpio_bit ( dev , 6 , ( freq > 300000000 ) ? 1 : 0 ) ;
return FC0012_SetFrequency ( dev , freq / 1000 , 6 ) ;
return FC0012_SetFrequency ( dev , freq / 1000 , 6 ) ;
}
}
int fc0012_set_bw ( void * dev , int bw ) {
int fc0012_set_bw ( void * dev , int bw ) {
unsigned long freq = ( ( rtlsdr_tuner_t * ) dev ) - > freq ;
return FC0012_SetFrequency ( dev , ( ( rtlsdr_dev_t * ) dev ) - > freq / 1000 , 6 ) ;
return FC0012_SetFrequency ( dev , freq / 1000 , 6 ) ;
}
}
int fc0012_set_gain ( void * dev , int gain ) { return 0 ; }
int fc0012_set_gain ( void * dev , int gain ) { return 0 ; }
int fc0013_init ( void * dev ) { return FC0013_Open ( dev ) ; }
int fc0013_init ( void * dev ) { return FC0013_Open ( dev ) ; }
int fc0013_exit ( void * dev ) { return 0 ; }
int fc0013_exit ( void * dev ) { return 0 ; }
int fc0013_tune ( void * dev , uint32_t freq ) {
int fc0013_set_freq ( void * dev , uint32_t freq ) {
return FC0013_SetFrequency ( dev , freq / 1000 , 6 ) ;
return FC0013_SetFrequency ( dev , freq / 1000 , 6 ) ;
}
}
int fc0013_set_bw ( void * dev , int bw ) {
int fc0013_set_bw ( void * dev , int bw ) {
unsigned long freq = ( ( rtlsdr_tuner_t * ) dev ) - > freq ;
return FC0013_SetFrequency ( dev , ( ( rtlsdr_dev_t * ) dev ) - > freq / 1000 , 6 ) ;
return FC0013_SetFrequency ( dev , freq / 1000 , 6 ) ;
}
}
int fc0013_set_gain ( void * dev , int gain ) { return 0 ; }
int fc0013_set_gain ( void * dev , int gain ) { return 0 ; }
int fc2580_init ( void * dev ) { return fc2580_Initialize ( dev ) ; }
int fc2580_init ( void * dev ) { return fc2580_Initialize ( dev ) ; }
int fc2580_exit ( void * dev ) { return 0 ; }
int fc2580_exit ( void * dev ) { return 0 ; }
int fc2580_tune ( void * dev , uint32_t freq ) { return fc2580_SetRfFreqHz ( dev , freq ) ; }
int _fc2580_set_freq ( void * dev , uint32_t freq ) {
int fc2580_set_bw ( void * dev , int bw ) { return fc2580_SetBandwidthMode ( dev , 1 ) ; }
return fc2580_SetRfFreqHz ( dev , freq ) ;
}
int fc2580_set_bw ( void * dev , int bw ) {
return fc2580_SetBandwidthMode ( dev , 1 ) ;
}
int fc2580_set_gain ( void * dev , int gain ) { return 0 ; }
int fc2580_set_gain ( void * dev , int gain ) { return 0 ; }
enum rtlsdr_tuners {
enum rtlsdr_tuners {
@ -103,22 +134,34 @@ enum rtlsdr_tuners {
} ;
} ;
static rtlsdr_tuner_t tuners [ ] = {
static rtlsdr_tuner_t tuners [ ] = {
{ e4k_init , e4k_exit , e4k_tune , e4k_set_bw , e4k_set_gain , 0 , 0 , 0 } ,
{
{ fc0012_init , fc0012_exit , fc0012_tune , fc0012_set_bw , fc0012_set_gain , 0 , 0 , 0 } ,
e4k_init , e4k_exit ,
{ fc0013_init , fc0013_exit , fc0013_tune , fc0013_set_bw , fc0013_set_gain , 0 , 0 , 0 } ,
e4k_set_freq , e4k_set_bw , e4k_set_gain
{ fc2580_init , fc2580_exit , fc2580_tune , fc2580_set_bw , fc2580_set_gain , 0 , 0 , 0 } ,
} ,
{
fc0012_init , fc0012_exit ,
fc0012_set_freq , fc0012_set_bw , fc0012_set_gain
} ,
{
fc0013_init , fc0013_exit ,
fc0013_set_freq , fc0013_set_bw , fc0013_set_gain
} ,
{
fc2580_init , fc2580_exit ,
_fc2580_set_freq , fc2580_set_bw , fc2580_set_gain
} ,
} ;
} ;
typedef struct rtlsdr_device {
typedef struct rtlsdr_dongl e {
uint16_t vid ;
uint16_t vid ;
uint16_t pid ;
uint16_t pid ;
const char * name ;
const char * name ;
} rtlsdr_device_t ;
} rtlsdr_dongl e_t ;
/*
/*
* Please add your device here and send a patch to osmocom - sdr @ lists . osmocom . org
* Please add your device here and send a patch to osmocom - sdr @ lists . osmocom . org
*/
*/
static rtlsdr_device_t devices [ ] = {
static rtlsdr_dongle_t known_ devices [ ] = {
{ 0x0bda , 0x2832 , " Generic RTL2832U (e.g. hama nano) " } ,
{ 0x0bda , 0x2832 , " Generic RTL2832U (e.g. hama nano) " } ,
{ 0x0bda , 0x2838 , " ezcap USB 2.0 DVB-T/DAB/FM dongle " } ,
{ 0x0bda , 0x2838 , " ezcap USB 2.0 DVB-T/DAB/FM dongle " } ,
{ 0x0ccd , 0x00a9 , " Terratec Cinergy T Stick Black (rev 1) " } ,
{ 0x0ccd , 0x00a9 , " Terratec Cinergy T Stick Black (rev 1) " } ,
@ -144,27 +187,10 @@ static rtlsdr_device_t devices[] = {
# define DEFAULT_BUF_NUMBER 32
# define DEFAULT_BUF_NUMBER 32
# define DEFAULT_BUF_LENGTH (16 * 32 * 512)
# define DEFAULT_BUF_LENGTH (16 * 32 * 512)
enum rtlsdr_async_status {
# define DEF_RTL_XTAL_FREQ 28800000
RTLSDR_INACTIVE = 0 ,
# define MIN_RTL_XTAL_FREQ (DEF_RTL_XTAL_FREQ - 1000)
RTLSDR_CANCELING ,
# define MAX_RTL_XTAL_FREQ (DEF_RTL_XTAL_FREQ + 1000)
RTLSDR_RUNNING
} ;
struct rtlsdr_dev {
libusb_context * ctx ;
struct libusb_device_handle * devh ;
uint32_t xfer_buf_num ;
uint32_t xfer_buf_len ;
struct libusb_transfer * * xfer ;
unsigned char * * xfer_buf ;
rtlsdr_read_async_cb_t cb ;
void * cb_ctx ;
enum rtlsdr_async_status async_status ;
rtlsdr_tuner_t * tuner ;
int rate ; /* Hz */
} ;
# define CRYSTAL_FREQ 28800000
# define MAX_SAMP_RATE 3200000
# define MAX_SAMP_RATE 3200000
# define CTRL_IN (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN)
# define CTRL_IN (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN)
@ -428,34 +454,100 @@ void rtlsdr_init_baseband(rtlsdr_dev_t *dev)
rtlsdr_demod_write_reg ( dev , 1 , 0xb1 , 0x1b , 1 ) ;
rtlsdr_demod_write_reg ( dev , 1 , 0xb1 , 0x1b , 1 ) ;
}
}
void rtlsdr_deinit_baseband ( rtlsdr_dev_t * dev )
int rtlsdr_deinit_baseband ( rtlsdr_dev_t * dev )
{
{
int r = 0 ;
if ( ! dev )
return - 1 ;
if ( dev - > tuner ) {
/* deinitialize tuner */
/* deinitialize tuner */
rtlsdr_set_i2c_repeater ( dev , 1 ) ;
rtlsdr_set_i2c_repeater ( dev , 1 ) ;
dev - > tuner - > exit ( dev ) ;
if ( dev - > tuner - > exit )
r = dev - > tuner - > exit ( dev ) ;
rtlsdr_set_i2c_repeater ( dev , 0 ) ;
rtlsdr_set_i2c_repeater ( dev , 0 ) ;
}
/* poweroff demodulator and ADCs */
/* poweroff demodulator and ADCs */
rtlsdr_write_reg ( dev , SYSB , DEMOD_CTL , 0x20 , 1 ) ;
rtlsdr_write_reg ( dev , SYSB , DEMOD_CTL , 0x20 , 1 ) ;
return r ;
}
int rtlsdr_set_xtal_freq ( rtlsdr_dev_t * dev , uint32_t rtl_freq , uint32_t tuner_freq )
{
int r = 0 ;
if ( ! dev )
return - 1 ;
if ( rtl_freq < MIN_RTL_XTAL_FREQ | | rtl_freq > MAX_RTL_XTAL_FREQ )
return - 2 ;
if ( dev - > rtl_xtal ! = rtl_freq ) {
dev - > rtl_xtal = rtl_freq ;
if ( 0 = = dev - > rtl_xtal )
dev - > rtl_xtal = DEF_RTL_XTAL_FREQ ;
/* update xtal-dependent settings */
if ( dev - > rate )
r = rtlsdr_set_sample_rate ( dev , dev - > rate ) ;
}
if ( dev - > tun_xtal ! = tuner_freq ) {
dev - > tun_xtal = tuner_freq ;
if ( 0 = = dev - > tun_xtal )
dev - > tun_xtal = dev - > rtl_xtal ;
/* update xtal-dependent settings */
if ( dev - > freq )
r = rtlsdr_set_center_freq ( dev , dev - > freq ) ;
}
return r ;
}
int rtlsdr_get_xtal_freq ( rtlsdr_dev_t * dev , uint32_t * rtl_freq , uint32_t * tuner_freq )
{
if ( ! dev )
return - 1 ;
* rtl_freq = dev - > rtl_xtal ;
if ( ! dev - > tuner )
return - 2 ;
* tuner_freq = dev - > tun_xtal ;
return 0 ;
}
}
int rtlsdr_set_center_freq ( rtlsdr_dev_t * dev , uint32_t freq )
int rtlsdr_set_center_freq ( rtlsdr_dev_t * dev , uint32_t freq )
{
{
int r ;
int r = - 1 ;
double f = ( double ) freq ;
double f = ( double ) freq ;
if ( ! dev | | ! dev - > tuner )
if ( ! dev | | ! dev - > tuner )
return - 1 ;
return - 1 ;
if ( dev - > tuner - > set_freq ) {
rtlsdr_set_i2c_repeater ( dev , 1 ) ;
rtlsdr_set_i2c_repeater ( dev , 1 ) ;
f * = 1.0 + dev - > tuner - > corr / 1e6 ;
f * = 1.0 + dev - > corr / 1e6 ;
r = dev - > tuner - > tune ( ( void * ) dev , ( uint32_t ) f ) ;
rtlsdr_set_i2c_repeater ( dev , 0 ) ;
r = dev - > tuner - > set_freq ( dev , ( uint32_t ) f ) ;
if ( ! r )
if ( ! r )
dev - > tuner - > freq = freq ;
dev - > freq = freq ;
rtlsdr_set_i2c_repeater ( dev , 0 ) ;
}
return r ;
return r ;
}
}
@ -465,7 +557,7 @@ uint32_t rtlsdr_get_center_freq(rtlsdr_dev_t *dev)
if ( ! dev | | ! dev - > tuner )
if ( ! dev | | ! dev - > tuner )
return 0 ;
return 0 ;
return dev - > tuner - > freq ;
return dev - > freq ;
}
}
int rtlsdr_set_freq_correction ( rtlsdr_dev_t * dev , int ppm )
int rtlsdr_set_freq_correction ( rtlsdr_dev_t * dev , int ppm )
@ -475,13 +567,13 @@ int rtlsdr_set_freq_correction(rtlsdr_dev_t *dev, int ppm)
if ( ! dev | | ! dev - > tuner )
if ( ! dev | | ! dev - > tuner )
return - 1 ;
return - 1 ;
if ( dev - > tuner - > corr = = ppm )
if ( dev - > corr = = ppm )
return - 1 ;
return - 1 ;
dev - > tuner - > corr = ppm ;
dev - > corr = ppm ;
/* retune to apply new correction value */
/* retune to apply new correction value */
r = rtlsdr_set_center_freq ( dev , dev - > tuner - > freq ) ;
r = rtlsdr_set_center_freq ( dev , dev - > freq ) ;
return r ;
return r ;
}
}
@ -491,20 +583,21 @@ int rtlsdr_get_freq_correction(rtlsdr_dev_t *dev)
if ( ! dev | | ! dev - > tuner )
if ( ! dev | | ! dev - > tuner )
return - 1 ;
return - 1 ;
return dev - > tuner - > corr ;
return dev - > corr ;
}
}
int rtlsdr_set_tuner_gain ( rtlsdr_dev_t * dev , int gain )
int rtlsdr_set_tuner_gain ( rtlsdr_dev_t * dev , int gain )
{
{
int r ;
int r = 0 ;
if ( ! dev | | ! dev - > tuner )
if ( ! dev | | ! dev - > tuner )
return - 1 ;
return - 1 ;
if ( dev - > tuner - > set_gain )
r = dev - > tuner - > set_gain ( ( void * ) dev , gain ) ;
r = dev - > tuner - > set_gain ( ( void * ) dev , gain ) ;
if ( ! r )
if ( ! r )
dev - > tuner - > gain = gain ;
dev - > gain = gain ;
return r ;
return r ;
}
}
@ -514,7 +607,7 @@ int rtlsdr_get_tuner_gain(rtlsdr_dev_t *dev)
if ( ! dev | | ! dev - > tuner )
if ( ! dev | | ! dev - > tuner )
return - 1 ;
return - 1 ;
return dev - > tuner - > gain ;
return dev - > gain ;
}
}
int rtlsdr_set_sample_rate ( rtlsdr_dev_t * dev , uint32_t samp_rate )
int rtlsdr_set_sample_rate ( rtlsdr_dev_t * dev , uint32_t samp_rate )
@ -530,16 +623,16 @@ int rtlsdr_set_sample_rate(rtlsdr_dev_t *dev, uint32_t samp_rate)
if ( samp_rate > MAX_SAMP_RATE )
if ( samp_rate > MAX_SAMP_RATE )
samp_rate = MAX_SAMP_RATE ;
samp_rate = MAX_SAMP_RATE ;
rsamp_ratio = ( CRYSTAL_FREQ * pow ( 2 , 22 ) ) / samp_rate ;
rsamp_ratio = ( dev - > rtl_xtal * pow ( 2 , 22 ) ) / samp_rate ;
rsamp_ratio & = ~ 3 ;
rsamp_ratio & = ~ 3 ;
real_rate = ( CRYSTAL_FREQ * pow ( 2 , 22 ) ) / rsamp_ratio ;
real_rate = ( dev - > rtl_xtal * pow ( 2 , 22 ) ) / rsamp_ratio ;
if ( ( ( double ) samp_rate ) ! = real_rate )
if ( ( ( double ) samp_rate ) ! = real_rate )
fprintf ( stderr , " Exact sample rate: %f Hz \n " , real_rate ) ;
fprintf ( stderr , " Exact sample rate is : %f Hz \n " , real_rate ) ;
if ( dev - > tuner )
if ( dev - > tuner & & dev - > tuner - > set_bw )
dev - > tuner - > set_bw ( ( void * ) dev , real_rate ) ;
dev - > tuner - > set_bw ( dev , real_rate ) ;
dev - > rate = samp_rate ;
dev - > rate = samp_rate ;
@ -563,14 +656,14 @@ uint32_t rtlsdr_get_sample_rate(rtlsdr_dev_t *dev)
return dev - > rate ;
return dev - > rate ;
}
}
rtlsdr_devic e_t * find_known_device ( uint16_t vid , uint16_t pid )
rtlsdr_dongl e_t * find_known_device ( uint16_t vid , uint16_t pid )
{
{
int i ;
unsigned int i ;
rtlsdr_devic e_t * device = NULL ;
rtlsdr_dongl e_t * device = NULL ;
for ( i = 0 ; i < sizeof ( devices ) / sizeof ( rtlsdr_devic e_t ) ; i + + ) {
for ( i = 0 ; i < sizeof ( known_ devices) / sizeof ( rtlsdr_dongl e_t ) ; i + + ) {
if ( devices [ i ] . vid = = vid & & devices [ i ] . pid = = pid ) {
if ( known_ devices[ i ] . vid = = vid & & known_ devices[ i ] . pid = = pid ) {
device = & devices [ i ] ;
device = & known_ devices[ i ] ;
break ;
break ;
}
}
}
}
@ -611,7 +704,7 @@ const char *rtlsdr_get_device_name(uint32_t index)
libusb_context * ctx ;
libusb_context * ctx ;
libusb_device * * list ;
libusb_device * * list ;
struct libusb_device_descriptor dd ;
struct libusb_device_descriptor dd ;
rtlsdr_devic e_t * device = NULL ;
rtlsdr_dongl e_t * device = NULL ;
uint32_t device_count = 0 ;
uint32_t device_count = 0 ;
ssize_t cnt ;
ssize_t cnt ;
@ -699,6 +792,8 @@ int rtlsdr_open(rtlsdr_dev_t **out_dev, uint32_t index)
goto err ;
goto err ;
}
}
dev - > rtl_xtal = DEF_RTL_XTAL_FREQ ;
rtlsdr_init_baseband ( dev ) ;
rtlsdr_init_baseband ( dev ) ;
/* Probe tuners */
/* Probe tuners */
@ -741,8 +836,12 @@ int rtlsdr_open(rtlsdr_dev_t **out_dev, uint32_t index)
}
}
found :
found :
if ( dev - > tuner )
if ( dev - > tuner ) {
r = dev - > tuner - > init ( dev ) ;
dev - > tun_xtal = dev - > rtl_xtal ;
if ( dev - > tuner - > init )
r = dev - > tuner - > init ( dev ) ;
}
rtlsdr_set_i2c_repeater ( dev , 0 ) ;
rtlsdr_set_i2c_repeater ( dev , 0 ) ;
@ -820,7 +919,7 @@ int rtlsdr_wait_async(rtlsdr_dev_t *dev, rtlsdr_read_async_cb_t cb, void *ctx)
static int _rtlsdr_alloc_async_buffers ( rtlsdr_dev_t * dev )
static int _rtlsdr_alloc_async_buffers ( rtlsdr_dev_t * dev )
{
{
int i ;
unsigned int i ;
if ( ! dev )
if ( ! dev )
return - 1 ;
return - 1 ;
@ -846,7 +945,7 @@ static int _rtlsdr_alloc_async_buffers(rtlsdr_dev_t *dev)
static int _rtlsdr_free_async_buffers ( rtlsdr_dev_t * dev )
static int _rtlsdr_free_async_buffers ( rtlsdr_dev_t * dev )
{
{
int i ;
unsigned int i ;
if ( ! dev )
if ( ! dev )
return - 1 ;
return - 1 ;
@ -878,7 +977,8 @@ static int _rtlsdr_free_async_buffers(rtlsdr_dev_t *dev)
int rtlsdr_read_async ( rtlsdr_dev_t * dev , rtlsdr_read_async_cb_t cb , void * ctx ,
int rtlsdr_read_async ( rtlsdr_dev_t * dev , rtlsdr_read_async_cb_t cb , void * ctx ,
uint32_t buf_num , uint32_t buf_len )
uint32_t buf_num , uint32_t buf_len )
{
{
int i , r ;
unsigned int i ;
int r ;
struct timeval tv = { 1 , 0 } ;
struct timeval tv = { 1 , 0 } ;
if ( ! dev )
if ( ! dev )
@ -961,3 +1061,26 @@ int rtlsdr_cancel_async(rtlsdr_dev_t *dev)
return - 2 ;
return - 2 ;
}
}
uint32_t rtlsdr_get_tuner_clock ( void * dev ) {
if ( ! dev )
return 0 ;
return ( ( rtlsdr_dev_t * ) dev ) - > tun_xtal ;
}
int rtlsdr_i2c_write_fn ( void * dev , uint8_t addr , uint8_t * buf , int len )
{
if ( dev )
return rtlsdr_i2c_write ( ( ( rtlsdr_dev_t * ) dev ) , addr , buf , len ) ;
return - 1 ;
}
int rtlsdr_i2c_read_fn ( void * dev , uint8_t addr , uint8_t * buf , int len )
{
if ( dev )
return rtlsdr_i2c_read ( ( ( rtlsdr_dev_t * ) dev ) , addr , buf , len ) ;
return - 1 ;
}