diff options
| author | Steve Markgraf <steve@steve-m.de> | 2012-05-17 21:33:53 +0200 |
|---|---|---|
| committer | Steve Markgraf <steve@steve-m.de> | 2012-05-17 21:33:53 +0200 |
| commit | c426e94093ef4b30620f88236077706abe4b6832 (patch) | |
| tree | f624d8381f0d2711b439a0ae8be82d2547d73c9b /src/rtl-sdr.c | |
| parent | b345963947b451f6517dde68d311dd9a49da816b (diff) | |
rename rtl-sdr.c to librtlsdr.c
Having rtl_sdr.c for the application and rtl-sdr.c for the lib
caused a bit of confusion...
Signed-off-by: Steve Markgraf <steve@steve-m.de>
Diffstat (limited to 'src/rtl-sdr.c')
| -rw-r--r-- | src/rtl-sdr.c | 1153 |
1 files changed, 0 insertions, 1153 deletions
diff --git a/src/rtl-sdr.c b/src/rtl-sdr.c deleted file mode 100644 index 6a9539b..0000000 --- a/src/rtl-sdr.c +++ /dev/null @@ -1,1153 +0,0 @@ -/* - * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver - * Copyright (C) 2012 by Steve Markgraf <steve@steve-m.de> - * Copyright (C) 2012 by Dimitri Stolnikov <horiz0n@gmx.net> - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <errno.h> -#include <signal.h> -#include <string.h> -#include <stdio.h> -#include <stdlib.h> -#include <math.h> -#ifndef _WIN32 -#include <unistd.h> -#define min(a, b) (((a) < (b)) ? (a) : (b)) -#endif - -#include <libusb.h> - -/* - * All libusb callback functions should be marked with the LIBUSB_CALL macro - * to ensure that they are compiled with the same calling convention as libusb. - * - * If the macro isn't available in older libusb versions, we simply define it. - */ -#ifndef LIBUSB_CALL -#define LIBUSB_CALL -#endif - -#include "rtl-sdr.h" -#include "tuner_e4k.h" -#include "tuner_fc0012.h" -#include "tuner_fc0013.h" -#include "tuner_fc2580.h" - -typedef struct rtlsdr_tuner { - /* tuner interface */ - int (*init)(void *); - int (*exit)(void *); - int (*set_freq)(void *, uint32_t freq /* Hz */); - int (*set_bw)(void *, int bw /* Hz */); - int (*set_gain)(void *, int gain /* dB */); - int (*set_gain_mode)(void *, int manual); -} 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 */ - int corr; /* ppm */ - int gain; /* dB */ - struct e4k_state e4k_s; -}; - -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 */ -int e4000_init(void *dev) { - rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; - devt->e4k_s.i2c_addr = E4K_I2C_ADDR; - devt->e4k_s.vco.fosc = devt->tun_xtal; - devt->e4k_s.rtl_dev = dev; - return e4k_init(&devt->e4k_s); -} -int e4000_exit(void *dev) { return 0; } -int e4000_set_freq(void *dev, uint32_t freq) { - rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; - return e4k_tune_freq(&devt->e4k_s, freq); -} -int e4000_set_bw(void *dev, int bw) { - return 0; -} -int e4000_set_gain(void *dev, int gain) { - int rc; - rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; - int mixgain = (gain > 340) ? 12 : 4; - int enhgain = (gain - 420); - if(e4k_set_lna_gain(&devt->e4k_s, min(300, gain - 40)) == -EINVAL) - return -1; - if(e4k_mixer_gain_set(&devt->e4k_s, mixgain) == -EINVAL) - return -1; - if(enhgain >= 0) - if(e4k_set_enh_gain(&devt->e4k_s, enhgain) == -EINVAL) - return -1; - - return 0; -} - -int e4000_set_gain_mode(void *dev, int manual) { - rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; - e4k_enable_manual_gain(&devt->e4k_s, manual); - return 0; -} - -int fc0012_init(void *dev) { return FC0012_Open(dev); } -int fc0012_exit(void *dev) { return 0; } -int fc0012_set_freq(void *dev, uint32_t freq) { - /* select V-band/U-band filter */ - rtlsdr_set_gpio_bit(dev, 6, (freq > 300000000) ? 1 : 0); - return FC0012_SetFrequency(dev, freq/1000, 6); -} -int fc0012_set_bw(void *dev, int bw) { - return FC0012_SetFrequency(dev, ((rtlsdr_dev_t *) dev)->freq/1000, 6); -} -int fc0012_set_gain(void *dev, int gain) { return 0; } -int fc0012_set_gain_mode(void *dev, int manual) { return 0; } - -int fc0013_init(void *dev) { return FC0013_Open(dev); } -int fc0013_exit(void *dev) { return 0; } -int fc0013_set_freq(void *dev, uint32_t freq) { - return FC0013_SetFrequency(dev, freq/1000, 6); -} -int fc0013_set_bw(void *dev, int bw) { - return FC0013_SetFrequency(dev, ((rtlsdr_dev_t *) dev)->freq/1000, 6); -} -int fc0013_set_gain(void *dev, int gain) { return 0; } -int fc0013_set_gain_mode(void *dev, int manual) { return 0; } - -int fc2580_init(void *dev) { return fc2580_Initialize(dev); } -int fc2580_exit(void *dev) { return 0; } -int _fc2580_set_freq(void *dev, uint32_t freq) { - 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_mode(void *dev, int manual) { return 0; } - -enum rtlsdr_tuners { - RTLSDR_TUNER_E4000, - RTLSDR_TUNER_FC0012, - RTLSDR_TUNER_FC0013, - RTLSDR_TUNER_FC2580 -}; - -static rtlsdr_tuner_t tuners[] = { - { - e4000_init, e4000_exit, - e4000_set_freq, e4000_set_bw, e4000_set_gain, - e4000_set_gain_mode - }, - { - fc0012_init, fc0012_exit, - fc0012_set_freq, fc0012_set_bw, fc0012_set_gain, - fc0012_set_gain_mode - }, - { - fc0013_init, fc0013_exit, - fc0013_set_freq, fc0013_set_bw, fc0013_set_gain, - fc0013_set_gain_mode - }, - { - fc2580_init, fc2580_exit, - _fc2580_set_freq, fc2580_set_bw, fc2580_set_gain, - fc2580_set_gain_mode - }, -}; - -typedef struct rtlsdr_dongle { - uint16_t vid; - uint16_t pid; - const char *name; -} rtlsdr_dongle_t; - -/* - * Please add your device here and send a patch to osmocom-sdr@lists.osmocom.org - */ -static rtlsdr_dongle_t known_devices[] = { - { 0x0bda, 0x2832, "Generic RTL2832U (e.g. hama nano)" }, - { 0x0bda, 0x2838, "ezcap USB 2.0 DVB-T/DAB/FM dongle" }, - { 0x0ccd, 0x00a9, "Terratec Cinergy T Stick Black (rev 1)" }, - { 0x0ccd, 0x00b3, "Terratec NOXON DAB/DAB+ USB dongle (rev 1)" }, - { 0x0ccd, 0x00d3, "Terratec Cinergy T Stick RC (Rev.3)" }, - { 0x0ccd, 0x00d7, "Terratec T Stick PLUS" }, - { 0x0ccd, 0x00e0, "Terratec NOXON DAB/DAB+ USB dongle (rev 2)" }, - { 0x185b, 0x0620, "Compro Videomate U620F"}, - { 0x185b, 0x0650, "Compro Videomate U650F"}, - { 0x185b, 0x0680, "Compro Videomate U680F"}, - { 0x1f4d, 0xb803, "GTek T803" }, - { 0x1f4d, 0xc803, "Lifeview LV5TDeluxe" }, - { 0x1b80, 0xd3a4, "Twintech UT-40" }, - { 0x1d19, 0x1101, "Dexatek DK DVB-T Dongle (Logilink VG0002A)" }, - { 0x1d19, 0x1102, "Dexatek DK DVB-T Dongle (MSI DigiVox mini II V3.0)" }, - { 0x1d19, 0x1103, "Dexatek Technology Ltd. DK 5217 DVB-T Dongle" }, - { 0x0458, 0x707f, "Genius TVGo DVB-T03 USB dongle (Ver. B)" }, - { 0x1b80, 0xd393, "GIGABYTE GT-U7300" }, - { 0x1b80, 0xd394, "DIKOM USB-DVBT HD" }, - { 0x1b80, 0xd395, "Peak 102569AGPK" }, - { 0x1b80, 0xd39d, "SVEON STV20 DVB-T USB & FM" }, -}; - -#define DEFAULT_BUF_NUMBER 32 -#define DEFAULT_BUF_LENGTH (16 * 32 * 512) - -#define DEF_RTL_XTAL_FREQ 28800000 -#define MIN_RTL_XTAL_FREQ (DEF_RTL_XTAL_FREQ - 1000) -#define MAX_RTL_XTAL_FREQ (DEF_RTL_XTAL_FREQ + 1000) - -#define MAX_SAMP_RATE 3200000 - -#define CTRL_IN (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN) -#define CTRL_OUT (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT) -#define CTRL_TIMEOUT 300 -#define BULK_TIMEOUT 0 - -enum usb_reg { - USB_SYSCTL = 0x2000, - USB_CTRL = 0x2010, - USB_STAT = 0x2014, - USB_EPA_CFG = 0x2144, - USB_EPA_CTL = 0x2148, - USB_EPA_MAXPKT = 0x2158, - USB_EPA_MAXPKT_2 = 0x215a, - USB_EPA_FIFO_CFG = 0x2160, -}; - -enum sys_reg { - DEMOD_CTL = 0x3000, - GPO = 0x3001, - GPI = 0x3002, - GPOE = 0x3003, - GPD = 0x3004, - SYSINTE = 0x3005, - SYSINTS = 0x3006, - GP_CFG0 = 0x3007, - GP_CFG1 = 0x3008, - SYSINTE_1 = 0x3009, - SYSINTS_1 = 0x300a, - DEMOD_CTL_1 = 0x300b, - IR_SUSPEND = 0x300c, -}; - -enum blocks { - DEMODB = 0, - USBB = 1, - SYSB = 2, - TUNB = 3, - ROMB = 4, - IRB = 5, - IICB = 6, -}; - -int rtlsdr_read_array(rtlsdr_dev_t *dev, uint8_t block, uint16_t addr, uint8_t *array, uint8_t len) -{ - int r; - uint16_t index = (block << 8); - - r = libusb_control_transfer(dev->devh, CTRL_IN, 0, addr, index, array, len, CTRL_TIMEOUT); - - return r; -} - -int rtlsdr_write_array(rtlsdr_dev_t *dev, uint8_t block, uint16_t addr, uint8_t *array, uint8_t len) -{ - int r; - uint16_t index = (block << 8) | 0x10; - - r = libusb_control_transfer(dev->devh, CTRL_OUT, 0, addr, index, array, len, CTRL_TIMEOUT); - - return r; -} - -int rtlsdr_i2c_write_reg(rtlsdr_dev_t *dev, uint8_t i2c_addr, uint8_t reg, uint8_t val) -{ - uint16_t addr = i2c_addr; - uint8_t data[2]; - - data[0] = reg; - data[1] = val; - return rtlsdr_write_array(dev, IICB, addr, (uint8_t *)&data, 2); -} - -uint8_t rtlsdr_i2c_read_reg(rtlsdr_dev_t *dev, uint8_t i2c_addr, uint8_t reg) -{ - uint16_t addr = i2c_addr; - uint8_t data; - - rtlsdr_write_array(dev, IICB, addr, ®, 1); - rtlsdr_read_array(dev, IICB, addr, &data, 1); - - return data; -} - -/* TODO clean this up again */ -int e4k_reg_write(struct e4k_state *e4k, uint8_t reg, uint8_t val) -{ - return rtlsdr_i2c_write_reg((rtlsdr_dev_t*)e4k->rtl_dev, e4k->i2c_addr, reg, val);} - -uint8_t e4k_reg_read(struct e4k_state *e4k, uint8_t reg) -{ - return rtlsdr_i2c_read_reg((rtlsdr_dev_t*)e4k->rtl_dev, e4k->i2c_addr, reg); -} - -int rtlsdr_i2c_write(rtlsdr_dev_t *dev, uint8_t i2c_addr, uint8_t *buffer, int len) -{ - uint16_t addr = i2c_addr; - - if (!dev) - return -1; - - return rtlsdr_write_array(dev, IICB, addr, buffer, len); -} - -int rtlsdr_i2c_read(rtlsdr_dev_t *dev, uint8_t i2c_addr, uint8_t *buffer, int len) -{ - uint16_t addr = i2c_addr; - - if (!dev) - return -1; - - return rtlsdr_read_array(dev, IICB, addr, buffer, len); -} - -uint16_t rtlsdr_read_reg(rtlsdr_dev_t *dev, uint8_t block, uint16_t addr, uint8_t len) -{ - int r; - unsigned char data[2]; - uint16_t index = (block << 8); - uint16_t reg; - - r = libusb_control_transfer(dev->devh, CTRL_IN, 0, addr, index, data, len, CTRL_TIMEOUT); - - if (r < 0) - fprintf(stderr, "%s failed with %d\n", __FUNCTION__, r); - - reg = (data[1] << 8) | data[0]; - - return reg; -} - -void rtlsdr_write_reg(rtlsdr_dev_t *dev, uint8_t block, uint16_t addr, uint16_t val, uint8_t len) -{ - int r; - unsigned char data[2]; - - uint16_t index = (block << 8) | 0x10; - - if (len == 1) - data[0] = val & 0xff; - else - data[0] = val >> 8; - - data[1] = val & 0xff; - - r = libusb_control_transfer(dev->devh, CTRL_OUT, 0, addr, index, data, len, CTRL_TIMEOUT); - - if (r < 0) - fprintf(stderr, "%s failed with %d\n", __FUNCTION__, r); -} - -uint16_t rtlsdr_demod_read_reg(rtlsdr_dev_t *dev, uint8_t page, uint16_t addr, uint8_t len) -{ - int r; - unsigned char data[2]; - - uint16_t index = page; - uint16_t reg; - addr = (addr << 8) | 0x20; - - r = libusb_control_transfer(dev->devh, CTRL_IN, 0, addr, index, data, len, CTRL_TIMEOUT); - - if (r < 0) - fprintf(stderr, "%s failed with %d\n", __FUNCTION__, r); - - reg = (data[1] << 8) | data[0]; - - return reg; -} - -void rtlsdr_demod_write_reg(rtlsdr_dev_t *dev, uint8_t page, uint16_t addr, uint16_t val, uint8_t len) -{ - int r; - unsigned char data[2]; - uint16_t index = 0x10 | page; - addr = (addr << 8) | 0x20; - - if (len == 1) - data[0] = val & 0xff; - else - data[0] = val >> 8; - - data[1] = val & 0xff; - - r = libusb_control_transfer(dev->devh, CTRL_OUT, 0, addr, index, data, len, CTRL_TIMEOUT); - - if (r < 0) - fprintf(stderr, "%s failed with %d\n", __FUNCTION__, r); - - rtlsdr_demod_read_reg(dev, 0x0a, 0x01, 1); -} - -void rtlsdr_set_gpio_bit(rtlsdr_dev_t *dev, uint8_t gpio, int val) -{ - uint8_t r; - - 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); -} - -void rtlsdr_set_gpio_output(rtlsdr_dev_t *dev, uint8_t gpio) -{ - int r; - gpio = 1 << gpio; - - r = rtlsdr_read_reg(dev, SYSB, GPD, 1); - rtlsdr_write_reg(dev, SYSB, GPO, r & ~gpio, 1); - r = rtlsdr_read_reg(dev, SYSB, GPOE, 1); - rtlsdr_write_reg(dev, SYSB, GPOE, r | gpio, 1); -} - -void rtlsdr_set_i2c_repeater(rtlsdr_dev_t *dev, int on) -{ - rtlsdr_demod_write_reg(dev, 1, 0x01, on ? 0x18 : 0x10, 1); -} - -void rtlsdr_init_baseband(rtlsdr_dev_t *dev) -{ - unsigned int i; - - /* default FIR coefficients used for DAB/FM by the Windows driver, - * the DVB driver uses different ones */ - uint8_t fir_coeff[] = { - 0xca, 0xdc, 0xd7, 0xd8, 0xe0, 0xf2, 0x0e, 0x35, 0x06, 0x50, - 0x9c, 0x0d, 0x71, 0x11, 0x14, 0x71, 0x74, 0x19, 0x41, 0xa5, - }; - - /* initialize USB */ - rtlsdr_write_reg(dev, USBB, USB_SYSCTL, 0x09, 1); - rtlsdr_write_reg(dev, USBB, USB_EPA_MAXPKT, 0x0002, 2); - rtlsdr_write_reg(dev, USBB, USB_EPA_CTL, 0x1002, 2); - - /* poweron demod */ - rtlsdr_write_reg(dev, SYSB, DEMOD_CTL_1, 0x22, 1); - rtlsdr_write_reg(dev, SYSB, DEMOD_CTL, 0xe8, 1); - - /* reset demod (bit 3, soft_rst) */ - rtlsdr_demod_write_reg(dev, 1, 0x01, 0x14, 1); - rtlsdr_demod_write_reg(dev, 1, 0x01, 0x10, 1); - - /* disable spectrum inversion and adjacent channel rejection */ - rtlsdr_demod_write_reg(dev, 1, 0x15, 0x00, 1); - rtlsdr_demod_write_reg(dev, 1, 0x16, 0x0000, 2); - - /* set IF-frequency to 0 Hz */ - rtlsdr_demod_write_reg(dev, 1, 0x19, 0x0000, 2); - - /* set FIR coefficients */ - for (i = 0; i < sizeof (fir_coeff); i++) - rtlsdr_demod_write_reg(dev, 1, 0x1c + i, fir_coeff[i], 1); - - rtlsdr_demod_write_reg(dev, 0, 0x19, 0x25, 1); - - /* init FSM state-holding register */ - rtlsdr_demod_write_reg(dev, 1, 0x93, 0xf0, 1); - - /* disable AGC (en_dagc, bit 0) */ - rtlsdr_demod_write_reg(dev, 1, 0x11, 0x00, 1); - - /* disable PID filter (enable_PID = 0) */ - rtlsdr_demod_write_reg(dev, 0, 0x61, 0x60, 1); - - /* opt_adc_iq = 0, default ADC_I/ADC_Q datapath */ - rtlsdr_demod_write_reg(dev, 0, 0x06, 0x80, 1); - - /* Enable Zero-IF mode (en_bbin bit), DC cancellation (en_dc_est), - * IQ estimation/compensation (en_iq_comp, en_iq_est) */ - rtlsdr_demod_write_reg(dev, 1, 0xb1, 0x1b, 1); -} - -int rtlsdr_deinit_baseband(rtlsdr_dev_t *dev) -{ - int r = 0; - - if (!dev) - return -1; - - if (dev->tuner && dev->tuner->exit) { - rtlsdr_set_i2c_repeater(dev, 1); - r = dev->tuner->exit(dev); /* deinitialize tuner */ - rtlsdr_set_i2c_repeater(dev, 0); - } - - /* poweroff demodulator and ADCs */ - 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 > 0 && - (rtl_freq < MIN_RTL_XTAL_FREQ || rtl_freq > MAX_RTL_XTAL_FREQ)) - return -2; - - if (dev->rtl_xtal != rtl_freq) { - if (0 == rtl_freq) - rtl_freq = DEF_RTL_XTAL_FREQ; - - dev->rtl_xtal = rtl_freq; - - /* update xtal-dependent settings */ - if (dev->rate) - r = rtlsdr_set_sample_rate(dev, dev->rate); - } - - if (dev->tun_xtal != tuner_freq) { - if (0 == tuner_freq) - tuner_freq = dev->rtl_xtal; - - dev->tun_xtal = tuner_freq; - - /* 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 r = -1; - double f = (double) freq; - - if (!dev || !dev->tuner) - return -1; - - if (dev->tuner->set_freq) { - f *= 1.0 + dev->corr / 1e6; - - rtlsdr_set_i2c_repeater(dev, 1); - r = dev->tuner->set_freq(dev, (uint32_t) f); - rtlsdr_set_i2c_repeater(dev, 0); - - if (!r) - dev->freq = freq; - else - dev->freq = 0; - } - - return r; -} - -uint32_t rtlsdr_get_center_freq(rtlsdr_dev_t *dev) -{ - if (!dev || !dev->tuner) - return 0; - - return dev->freq; -} - -int rtlsdr_set_freq_correction(rtlsdr_dev_t *dev, int ppm) -{ - int r; - - if (!dev || !dev->tuner) - return -1; - - if (dev->corr == ppm) - return -1; - - dev->corr = ppm; - - /* retune to apply new correction value */ - r = rtlsdr_set_center_freq(dev, dev->freq); - - return r; -} - -int rtlsdr_get_freq_correction(rtlsdr_dev_t *dev) -{ - if (!dev || !dev->tuner) - return 0; - - return dev->corr; -} - -int rtlsdr_set_tuner_gain(rtlsdr_dev_t *dev, int gain) -{ - int r = 0; - - if (!dev || !dev->tuner) - return -1; - - if (dev->tuner->set_gain) { - rtlsdr_set_i2c_repeater(dev, 1); - r = dev->tuner->set_gain((void *)dev, gain); - rtlsdr_set_i2c_repeater(dev, 0); - } - - if (!r) - dev->gain = gain; - else - dev->gain = 0; - - return r; -} - -int rtlsdr_get_tuner_gain(rtlsdr_dev_t *dev) -{ - if (!dev || !dev->tuner) - return 0; - - return dev->gain; -} - -int rtlsdr_set_tuner_gain_mode(rtlsdr_dev_t *dev, int mode) -{ - int r = 0; - - if (!dev || !dev->tuner) - return -1; - - if (dev->tuner->set_gain_mode) { - rtlsdr_set_i2c_repeater(dev, 1); - r = dev->tuner->set_gain_mode((void *)dev, mode); - rtlsdr_set_i2c_repeater(dev, 0); - } - - return r; -} - -int rtlsdr_set_sample_rate(rtlsdr_dev_t *dev, uint32_t samp_rate) -{ - uint16_t tmp; - uint32_t rsamp_ratio; - double real_rate; - - if (!dev) - return -1; - - /* check for the maximum rate the resampler supports */ - if (samp_rate > MAX_SAMP_RATE) - samp_rate = MAX_SAMP_RATE; - - rsamp_ratio = (dev->rtl_xtal * pow(2, 22)) / samp_rate; - rsamp_ratio &= ~3; - - real_rate = (dev->rtl_xtal * pow(2, 22)) / rsamp_ratio; - - if ( ((double)samp_rate) != real_rate ) - fprintf(stderr, "Exact sample rate is: %f Hz\n", real_rate); - - if (dev->tuner && dev->tuner->set_bw) { - rtlsdr_set_i2c_repeater(dev, 1); - dev->tuner->set_bw(dev, real_rate); - rtlsdr_set_i2c_repeater(dev, 0); - } - - dev->rate = samp_rate; - - tmp = (rsamp_ratio >> 16); - rtlsdr_demod_write_reg(dev, 1, 0x9f, tmp, 2); - tmp = rsamp_ratio & 0xffff; - rtlsdr_demod_write_reg(dev, 1, 0xa1, tmp, 2); - - /* reset demod (bit 3, soft_rst) */ - rtlsdr_demod_write_reg(dev, 1, 0x01, 0x14, 1); - rtlsdr_demod_write_reg(dev, 1, 0x01, 0x10, 1); - - return 0; -} - -uint32_t rtlsdr_get_sample_rate(rtlsdr_dev_t *dev) -{ - if (!dev) - return 0; - - return dev->rate; -} - -rtlsdr_dongle_t *find_known_device(uint16_t vid, uint16_t pid) -{ - unsigned int i; - rtlsdr_dongle_t *device = NULL; - - for (i = 0; i < sizeof(known_devices)/sizeof(rtlsdr_dongle_t); i++ ) { - if (known_devices[i].vid == vid && known_devices[i].pid == pid) { - device = &known_devices[i]; - break; - } - } - - return device; -} - -uint32_t rtlsdr_get_device_count(void) -{ - int i; - libusb_context *ctx; - libusb_device **list; - uint32_t device_count = 0; - struct libusb_device_descriptor dd; - ssize_t cnt; - - libusb_init(&ctx); - - cnt = libusb_get_device_list(ctx, &list); - - for (i = 0; i < cnt; i++) { - libusb_get_device_descriptor(list[i], &dd); - - if (find_known_device(dd.idVendor, dd.idProduct)) - device_count++; - } - - libusb_free_device_list(list, 1); - - libusb_exit(ctx); - - return device_count; -} - -const char *rtlsdr_get_device_name(uint32_t index) -{ - int i; - libusb_context *ctx; - libusb_device **list; - struct libusb_device_descriptor dd; - rtlsdr_dongle_t *device = NULL; - uint32_t device_count = 0; - ssize_t cnt; - - libusb_init(&ctx); - - cnt = libusb_get_device_list(ctx, &list); - - for (i = 0; i < cnt; i++) { - libusb_get_device_descriptor(list[i], &dd); - - device = find_known_device(dd.idVendor, dd.idProduct); - - if (device) { - device_count++; - - if (index == device_count - 1) - break; - } - } - - libusb_free_device_list(list, 1); - - libusb_exit(ctx); - - if (device) - return device->name; - else - return ""; -} - -int rtlsdr_open(rtlsdr_dev_t **out_dev, uint32_t index) -{ - int r; - int i; - libusb_device **list; - rtlsdr_dev_t *dev = NULL; - libusb_device *device = NULL; - uint32_t device_count = 0; - struct libusb_device_descriptor dd; - uint8_t reg; - ssize_t cnt; - - dev = malloc(sizeof(rtlsdr_dev_t)); - if (NULL == dev) - return -ENOMEM; - - memset(dev, 0, sizeof(rtlsdr_dev_t)); - - libusb_init(&dev->ctx); - - cnt = libusb_get_device_list(dev->ctx, &list); - - for (i = 0; i < cnt; i++) { - device = list[i]; - - libusb_get_device_descriptor(list[i], &dd); - - if (find_known_device(dd.idVendor, dd.idProduct)) { - device_count++; - } - - if (index == device_count - 1) - break; - - device = NULL; - } - - if (!device) { - r = -1; - goto err; - } - - r = libusb_open(device, &dev->devh); - if (r < 0) { - libusb_free_device_list(list, 1); - fprintf(stderr, "usb_open error %d\n", r); - goto err; - } - - libusb_free_device_list(list, 1); - - r = libusb_claim_interface(dev->devh, 0); - if (r < 0) { - fprintf(stderr, "usb_claim_interface error %d\n", r); - goto err; - } - - dev->rtl_xtal = DEF_RTL_XTAL_FREQ; - - rtlsdr_init_baseband(dev); - - /* Probe tuners */ - rtlsdr_set_i2c_repeater(dev, 1); - - reg = rtlsdr_i2c_read_reg(dev, E4K_I2C_ADDR, E4K_CHECK_ADDR); - if (reg == E4K_CHECK_VAL) { - fprintf(stderr, "Found Elonics E4000 tuner\n"); - dev->tuner = &tuners[RTLSDR_TUNER_E4000]; - goto found; - } - - reg = rtlsdr_i2c_read_reg(dev, FC0013_I2C_ADDR, FC0013_CHECK_ADDR); - if (reg == FC0013_CHECK_VAL) { - fprintf(stderr, "Found Fitipower FC0013 tuner\n"); - dev->tuner = &tuners[RTLSDR_TUNER_FC0013]; - goto found; - } - - /* initialise GPIOs */ - rtlsdr_set_gpio_output(dev, 5); - - /* reset tuner before probing */ - rtlsdr_set_gpio_bit(dev, 5, 1); - rtlsdr_set_gpio_bit(dev, 5, 0); - - reg = rtlsdr_i2c_read_reg(dev, FC2580_I2C_ADDR, FC2580_CHECK_ADDR); - if ((reg & 0x7f) == FC2580_CHECK_VAL) { - fprintf(stderr, "Found FCI 2580 tuner\n"); - dev->tuner = &tuners[RTLSDR_TUNER_FC2580]; - goto found; - } - - reg = rtlsdr_i2c_read_reg(dev, FC0012_I2C_ADDR, FC0012_CHECK_ADDR); - if (reg == FC0012_CHECK_VAL) { - fprintf(stderr, "Found Fitipower FC0012 tuner\n"); - rtlsdr_set_gpio_output(dev, 6); - dev->tuner = &tuners[RTLSDR_TUNER_FC0012]; - goto found; - } - -found: - if (dev->tuner) { - dev->tun_xtal = dev->rtl_xtal; - - if (dev->tuner->init) - r = dev->tuner->init(dev); - } - - rtlsdr_set_i2c_repeater(dev, 0); - - *out_dev = dev; - - return 0; -err: - if (dev) { - if (dev->ctx) - libusb_exit(dev->ctx); - - free(dev); - } - - return r; -} - -int rtlsdr_close(rtlsdr_dev_t *dev) -{ - if (!dev) - return -1; - - rtlsdr_deinit_baseband(dev); - - libusb_release_interface(dev->devh, 0); - libusb_close(dev->devh); - - libusb_exit(dev->ctx); - - free(dev); - - return 0; -} - -int rtlsdr_reset_buffer(rtlsdr_dev_t *dev) -{ - if (!dev) - return -1; - - rtlsdr_write_reg(dev, USBB, USB_EPA_CTL, 0x1002, 2); - rtlsdr_write_reg(dev, USBB, USB_EPA_CTL, 0x0000, 2); - - return 0; -} - -int rtlsdr_read_sync(rtlsdr_dev_t *dev, void *buf, int len, int *n_read) -{ - if (!dev) - return -1; - - return libusb_bulk_transfer(dev->devh, 0x81, buf, len, n_read, BULK_TIMEOUT); -} - -static void LIBUSB_CALL _libusb_callback(struct libusb_transfer *xfer) -{ - rtlsdr_dev_t *dev = (rtlsdr_dev_t *)xfer->user_data; - - if (LIBUSB_TRANSFER_COMPLETED == xfer->status) { - if (dev->cb) - dev->cb(xfer->buffer, xfer->actual_length, dev->cb_ctx); - - libusb_submit_transfer(xfer); /* resubmit transfer */ - } else { - /*fprintf(stderr, "transfer status: %d\n", xfer->status);*/ - rtlsdr_cancel_async(dev); /* abort async loop */ - } -} - -int rtlsdr_wait_async(rtlsdr_dev_t *dev, rtlsdr_read_async_cb_t cb, void *ctx) -{ - return rtlsdr_read_async(dev, cb, ctx, 0, 0); -} - -static int _rtlsdr_alloc_async_buffers(rtlsdr_dev_t *dev) -{ - unsigned int i; - - if (!dev) - return -1; - - if (!dev->xfer) { - dev->xfer = malloc(dev->xfer_buf_num * - sizeof(struct libusb_transfer *)); - - for(i = 0; i < dev->xfer_buf_num; ++i) - dev->xfer[i] = libusb_alloc_transfer(0); - } - - if (!dev->xfer_buf) { - dev->xfer_buf = malloc(dev->xfer_buf_num * - sizeof(unsigned char *)); - - for(i = 0; i < dev->xfer_buf_num; ++i) - dev->xfer_buf[i] = malloc(dev->xfer_buf_len); - } - - return 0; -} - -static int _rtlsdr_free_async_buffers(rtlsdr_dev_t *dev) -{ - unsigned int i; - - if (!dev) - return -1; - - if (dev->xfer) { - for(i = 0; i < dev->xfer_buf_num; ++i) { - if (dev->xfer[i]) { - libusb_free_transfer(dev->xfer[i]); - } - } - - free(dev->xfer); - dev->xfer = NULL; - } - - if (dev->xfer_buf) { - for(i = 0; i < dev->xfer_buf_num; ++i) { - if (dev->xfer_buf[i]) - free(dev->xfer_buf[i]); - } - - free(dev->xfer_buf); - dev->xfer_buf = NULL; - } - - return 0; -} - -int rtlsdr_read_async(rtlsdr_dev_t *dev, rtlsdr_read_async_cb_t cb, void *ctx, - uint32_t buf_num, uint32_t buf_len) -{ - unsigned int i; - int r; - struct timeval tv = { 1, 0 }; - - if (!dev) - return -1; - - dev->cb = cb; - dev->cb_ctx = ctx; - - if (buf_num > 0) - dev->xfer_buf_num = buf_num; - else - dev->xfer_buf_num = DEFAULT_BUF_NUMBER; - - if (buf_len > 0 && buf_len % 512 == 0) /* len must be multiple of 512 */ - dev->xfer_buf_len = buf_len; - else - dev->xfer_buf_len = DEFAULT_BUF_LENGTH; - - _rtlsdr_alloc_async_buffers(dev); - - for(i = 0; i < dev->xfer_buf_num; ++i) { - libusb_fill_bulk_transfer(dev->xfer[i], - dev->devh, - 0x81, - dev->xfer_buf[i], - dev->xfer_buf_len, - _libusb_callback, - (void *)dev, - BULK_TIMEOUT); - - libusb_submit_transfer(dev->xfer[i]); - } - - dev->async_status = RTLSDR_RUNNING; - - while (RTLSDR_INACTIVE != dev->async_status) { - r = libusb_handle_events_timeout(dev->ctx, &tv); - if (r < 0) { - /*fprintf(stderr, "handle_events returned: %d\n", r);*/ - if (r == LIBUSB_ERROR_INTERRUPTED) /* stray signal */ - continue; - break; - } - - if (RTLSDR_CANCELING == dev->async_status) { - dev->async_status = RTLSDR_INACTIVE; - - if (!dev->xfer) - break; - - for(i = 0; i < dev->xfer_buf_num; ++i) { - if (!dev->xfer[i]) - continue; - - if (dev->xfer[i]->status == LIBUSB_TRANSFER_COMPLETED) { - libusb_cancel_transfer(dev->xfer[i]); - dev->async_status = RTLSDR_CANCELING; - } - } - - if (RTLSDR_INACTIVE == dev->async_status) - break; - } - } - - _rtlsdr_free_async_buffers(dev); - - return r; -} - -int rtlsdr_cancel_async(rtlsdr_dev_t *dev) -{ - if (!dev) - return -1; - - if (RTLSDR_RUNNING == dev->async_status) { - dev->async_status = RTLSDR_CANCELING; - return 0; - } - - 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; -} |
