use super::{Tuner, TunerGain, TunerInfo};
use crate::device::Device;
use crate::error::Result;
use crate::error::RtlsdrError::RtlsdrErr;
use log::info;
const R820T_I2C_ADDR: u16 = 0x34;
const VER_NUM: u8 = 49;
pub const R82XX_IF_FREQ: u32 = 3570000;
const NUM_REGS: usize = 35;
const RW_REG_START: usize = 5; const NUM_CACHE_REGS: usize = NUM_REGS - RW_REG_START; const MAX_I2C_MSG_LEN: usize = 8;
const REG_INIT: [u8; NUM_CACHE_REGS] = [
0x83, 0x32, 0x75,
0xc0, 0x40, 0xd6, 0x6c,
0xf5, 0x63, 0x75, 0x68,
0x6c, 0x83, 0x80, 0x00,
0x0f, 0x00, 0xc0, 0x30,
0x48, 0xcc, 0x60, 0x00,
0x54, 0xae, 0x4a, 0xc0,
0x00, 0x00, 0x00,
];
const _VGA_BASE_GAIN: i32 = -47;
const GAINS: [i32; 29] = [
0, 9, 14, 27, 37, 77, 87, 125, 144, 157, 166, 197, 207, 229, 254, 280, 297, 328, 338, 364, 372,
386, 402, 421, 434, 439, 445, 480, 496,
];
const _R82XX_VGA_GAIN_STEPS: [i32; 16] = [
0, 26, 26, 30, 42, 35, 24, 13, 14, 32, 36, 34, 35, 37, 35, 36,
];
const R82XX_LNA_GAIN_STEPS: [i32; 16] =
[0, 9, 13, 40, 38, 13, 31, 22, 26, 31, 26, 14, 19, 5, 35, 13];
const R82XX_MIXER_GAIN_STEPS: [i32; 16] =
[0, 5, 10, 10, 19, 9, 10, 25, 17, 10, 8, 16, 13, 6, 3, -8];
struct FreqRange {
freq: u32, open_d: u8, rf_mux_ploy: u8, tf_c: u8, xtal_cap20p: u8, xtal_cap10p: u8,
xtal_cap0p: u8,
}
const FREQ_RANGES: [FreqRange; 21] = [
FreqRange {
freq: 0,
open_d: 0x08,
rf_mux_ploy: 0x02,
tf_c: 0xdf,
xtal_cap20p: 0x02,
xtal_cap10p: 0x01,
xtal_cap0p: 0x00,
},
FreqRange {
freq: 50,
open_d: 0x08,
rf_mux_ploy: 0x02,
tf_c: 0xbe,
xtal_cap20p: 0x02,
xtal_cap10p: 0x01,
xtal_cap0p: 0x00,
},
FreqRange {
freq: 55,
open_d: 0x08,
rf_mux_ploy: 0x02,
tf_c: 0x8b,
xtal_cap20p: 0x02,
xtal_cap10p: 0x01,
xtal_cap0p: 0x00,
},
FreqRange {
freq: 60,
open_d: 0x08,
rf_mux_ploy: 0x02,
tf_c: 0x7b,
xtal_cap20p: 0x02,
xtal_cap10p: 0x01,
xtal_cap0p: 0x00,
},
FreqRange {
freq: 65,
open_d: 0x08,
rf_mux_ploy: 0x02,
tf_c: 0x69,
xtal_cap20p: 0x02,
xtal_cap10p: 0x01,
xtal_cap0p: 0x00,
},
FreqRange {
freq: 70,
open_d: 0x08,
rf_mux_ploy: 0x02,
tf_c: 0x58,
xtal_cap20p: 0x02,
xtal_cap10p: 0x01,
xtal_cap0p: 0x00,
},
FreqRange {
freq: 75,
open_d: 0x00,
rf_mux_ploy: 0x02,
tf_c: 0x44,
xtal_cap20p: 0x02,
xtal_cap10p: 0x01,
xtal_cap0p: 0x00,
},
FreqRange {
freq: 80,
open_d: 0x00,
rf_mux_ploy: 0x02,
tf_c: 0x44,
xtal_cap20p: 0x02,
xtal_cap10p: 0x01,
xtal_cap0p: 0x00,
},
FreqRange {
freq: 90,
open_d: 0x00,
rf_mux_ploy: 0x02,
tf_c: 0x34,
xtal_cap20p: 0x01,
xtal_cap10p: 0x01,
xtal_cap0p: 0x00,
},
FreqRange {
freq: 100,
open_d: 0x00,
rf_mux_ploy: 0x02,
tf_c: 0x34,
xtal_cap20p: 0x01,
xtal_cap10p: 0x01,
xtal_cap0p: 0x00,
},
FreqRange {
freq: 110,
open_d: 0x00,
rf_mux_ploy: 0x02,
tf_c: 0x24,
xtal_cap20p: 0x01,
xtal_cap10p: 0x01,
xtal_cap0p: 0x00,
},
FreqRange {
freq: 120,
open_d: 0x00,
rf_mux_ploy: 0x02,
tf_c: 0x24,
xtal_cap20p: 0x01,
xtal_cap10p: 0x01,
xtal_cap0p: 0x00,
},
FreqRange {
freq: 140,
open_d: 0x00,
rf_mux_ploy: 0x02,
tf_c: 0x14,
xtal_cap20p: 0x01,
xtal_cap10p: 0x01,
xtal_cap0p: 0x00,
},
FreqRange {
freq: 180,
open_d: 0x00,
rf_mux_ploy: 0x02,
tf_c: 0x13,
xtal_cap20p: 0x00,
xtal_cap10p: 0x00,
xtal_cap0p: 0x00,
},
FreqRange {
freq: 220,
open_d: 0x00,
rf_mux_ploy: 0x02,
tf_c: 0x13,
xtal_cap20p: 0x00,
xtal_cap10p: 0x00,
xtal_cap0p: 0x00,
},
FreqRange {
freq: 250,
open_d: 0x00,
rf_mux_ploy: 0x02,
tf_c: 0x11,
xtal_cap20p: 0x00,
xtal_cap10p: 0x00,
xtal_cap0p: 0x00,
},
FreqRange {
freq: 280,
open_d: 0x00,
rf_mux_ploy: 0x02,
tf_c: 0x00,
xtal_cap20p: 0x00,
xtal_cap10p: 0x00,
xtal_cap0p: 0x00,
},
FreqRange {
freq: 310,
open_d: 0x00,
rf_mux_ploy: 0x41,
tf_c: 0x00,
xtal_cap20p: 0x00,
xtal_cap10p: 0x00,
xtal_cap0p: 0x00,
},
FreqRange {
freq: 450,
open_d: 0x00,
rf_mux_ploy: 0x41,
tf_c: 0x00,
xtal_cap20p: 0x00,
xtal_cap10p: 0x00,
xtal_cap0p: 0x00,
},
FreqRange {
freq: 588,
open_d: 0x00,
rf_mux_ploy: 0x40,
tf_c: 0x00,
xtal_cap20p: 0x00,
xtal_cap10p: 0x00,
xtal_cap0p: 0x00,
},
FreqRange {
freq: 650,
open_d: 0x00,
rf_mux_ploy: 0x40,
tf_c: 0x00,
xtal_cap20p: 0x00,
xtal_cap10p: 0x00,
xtal_cap0p: 0x00,
},
];
#[allow(dead_code)]
enum TunerType {
Radio,
AnalogTv,
DigitalTv,
}
#[derive(Debug)]
#[allow(dead_code)]
enum XtalCapValue {
XtalLowCap30p,
XtalLowCap20p,
XtalLowCap10p,
XtalLowCap0p,
XtalHighCap0p,
}
#[allow(dead_code)]
const XTAL_CAPACITOR_VALUES: [u8; 5] = [
0x0b, 0x02, 0x01, 0x00, 0x10, ];
#[allow(dead_code)]
enum DeliverySystem {
SysUndefined,
SysDvbt,
SysDvbt2,
SysIsdbt,
}
#[derive(Debug)]
pub struct R820T {
pub info: TunerInfo,
regs: [u8; NUM_CACHE_REGS],
pub freq: u32,
int_freq: u32,
xtal_cap_sel: XtalCapValue,
xtal: u32,
use_predetect: bool,
has_lock: bool,
fil_cal_code: u8,
init_done: bool,
}
pub const TUNER_ID: &str = "r820t";
pub const TUNER_INFO: TunerInfo = TunerInfo {
id: TUNER_ID,
name: "Rafael Micro R820T",
i2c_addr: 0x34,
check_addr: 0x00,
check_val: 0x69,
};
impl R820T {
pub fn new(_handle: &mut Device) -> R820T {
R820T {
info: TUNER_INFO,
regs: REG_INIT,
freq: 0,
int_freq: 0,
xtal_cap_sel: XtalCapValue::XtalLowCap30p,
xtal: 0,
has_lock: false,
init_done: false,
use_predetect: false,
fil_cal_code: 0,
}
}
}
impl Tuner for R820T {
fn init(&mut self, handle: &Device) -> Result<()> {
self.use_predetect = false;
self.xtal_cap_sel = XtalCapValue::XtalHighCap0p;
self.write_regs(handle, 0x05, ®_INIT)?;
self.set_tv_standard(handle, 3, TunerType::DigitalTv)?;
self.sysfreq_sel(handle, 0, TunerType::DigitalTv, DeliverySystem::SysDvbt)?;
self.init_done = true;
Ok(())
}
fn get_info(&self) -> Result<TunerInfo> {
Ok(self.info)
}
fn get_gains(&self) -> Result<Vec<i32>> {
Ok(GAINS.to_vec())
}
fn read_gain(&self, handle: &Device) -> Result<i32> {
let mut data: [u8; 4] = [0; 4];
self.read_reg(handle, 0x00, &mut data, 4)?;
let gain = ((data[3] & 0x0f) << 1) + ((data[3] & 0xf0) >> 4);
Ok(gain as i32)
}
fn set_gain(&mut self, handle: &Device, mode: TunerGain) -> Result<()> {
match mode {
TunerGain::Auto => {
self.write_reg_mask(handle, 0x05, 0, 0x10)?;
self.write_reg_mask(handle, 0x07, 0x10, 0x10)?;
self.write_reg_mask(handle, 0x0c, 0x0b, 0x9f)?;
}
TunerGain::Manual(gain) => {
let mut data: [u8; 4] = [0; 4];
self.write_reg_mask(handle, 0x05, 0x10, 0x10)?;
self.write_reg_mask(handle, 0x07, 0, 0x10)?;
self.read_reg(handle, 0x00, &mut data, 4)?;
self.write_reg_mask(handle, 0x0c, 0x08, 0x9f)?;
let mut total_gain: i32 = 0;
let mut mix_index: u8 = 0;
let mut lna_index: u8 = 0;
for _ in 0..15 {
if total_gain >= gain {
break;
}
lna_index += 1;
total_gain += R82XX_LNA_GAIN_STEPS[lna_index as usize];
if total_gain >= gain {
break;
}
mix_index += 1;
total_gain += R82XX_MIXER_GAIN_STEPS[mix_index as usize];
}
self.write_reg_mask(handle, 0x05, lna_index, 0x0f)?;
self.write_reg_mask(handle, 0x07, mix_index, 0x0f)?;
}
}
Ok(())
}
fn set_freq(&mut self, handle: &Device, freq: u32) -> Result<()> {
info!("set_freq - freq: {}", freq);
let lo_freq = freq + self.int_freq;
info!("set_freq - lo_freq: {}", lo_freq);
self.set_mux(handle, lo_freq)?;
self.set_pll(handle, lo_freq)?;
Ok(())
}
fn set_bandwidth(&mut self, handle: &Device, bw_in: u32, _rate: u32) -> Result<()> {
let mut bw: i32 = bw_in as i32;
const FILT_HP_BW1: i32 = 350_000;
const FILT_HP_BW2: i32 = 380_000;
const R82XX_IF_LOW_PASS_BW_TABLE: [i32; 10] = [
1_700_000, 1_600_000, 1_550_000, 1_450_000, 1_200_000, 900_000, 700_000, 550_000,
450_000, 350_000,
];
let (reg_0a, reg_0b): (u8, u8) = if bw > 7_000_000 {
self.int_freq = 4_570_000;
(0x10, 0x0b)
} else if bw > 6_000_000 {
self.int_freq = 4_570_000;
(0x10, 0x2a)
} else if bw > R82XX_IF_LOW_PASS_BW_TABLE[0] + FILT_HP_BW1 + FILT_HP_BW2 {
self.int_freq = 3_570_000;
(0x10, 0x6b)
} else {
self.int_freq = 2_300_000;
let (reg_0a, mut reg_0b): (u8, u8) = (0x00, 0x80);
let mut real_bw = 0;
if bw > R82XX_IF_LOW_PASS_BW_TABLE[0] + FILT_HP_BW1 {
bw -= FILT_HP_BW2;
self.int_freq += FILT_HP_BW2 as u32;
real_bw += FILT_HP_BW2;
} else {
reg_0b |= 0x20;
}
if bw > R82XX_IF_LOW_PASS_BW_TABLE[0] {
bw -= FILT_HP_BW1;
self.int_freq += FILT_HP_BW1 as u32;
real_bw += FILT_HP_BW1;
} else {
reg_0b |= 0x40;
}
let mut lp_idx = 0;
for (i, freq) in R82XX_IF_LOW_PASS_BW_TABLE.iter().enumerate() {
lp_idx = i;
if bw > *freq {
break;
}
}
lp_idx -= 1;
reg_0b |= (15 - lp_idx) as u8;
real_bw += R82XX_IF_LOW_PASS_BW_TABLE[lp_idx];
self.int_freq -= (real_bw / 2) as u32;
(reg_0a, reg_0b)
};
self.write_reg_mask(handle, 0x0a, reg_0a, 0x10)?;
self.write_reg_mask(handle, 0x0b, reg_0b, 0xef)?;
Ok(())
}
fn get_if_freq(&self) -> Result<u32> {
Ok(self.int_freq)
}
fn get_xtal_freq(&self) -> Result<u32> {
Ok(self.xtal)
}
fn set_xtal_freq(&mut self, freq: u32) -> Result<()> {
self.xtal = freq;
Ok(())
}
fn exit(&mut self, handle: &Device) -> Result<()> {
if !self.init_done {
return Ok(());
}
self.write_regs(handle, 0x06, &[0xb1])?;
self.write_regs(handle, 0x05, &[0xa0])?;
self.write_regs(handle, 0x07, &[0x3a])?;
self.write_regs(handle, 0x08, &[0x40])?;
self.write_regs(handle, 0x09, &[0xc0])?;
self.write_regs(handle, 0x0a, &[0x36])?;
self.write_regs(handle, 0x0c, &[0x35])?;
self.write_regs(handle, 0x0f, &[0x68])?;
self.write_regs(handle, 0x11, &[0x03])?;
self.write_regs(handle, 0x17, &[0xf4])?;
self.write_regs(handle, 0x19, &[0x0c])?;
Ok(())
}
}
impl R820T {
fn set_mux(&mut self, handle: &Device, freq: u32) -> Result<()> {
let freq_mhz = freq / 1_000_000;
let range = {
let mut r: &FreqRange = &FREQ_RANGES[0];
for range in FREQ_RANGES.iter() {
if freq_mhz < range.freq {
break;
}
r = range;
}
r
};
self.write_reg_mask(handle, 0x17, range.open_d, 0x08)?;
self.write_reg_mask(handle, 0x1a, range.rf_mux_ploy, 0xc3)?;
self.write_regs(handle, 0x1b, &[range.tf_c])?;
let val = match self.xtal_cap_sel {
XtalCapValue::XtalLowCap30p | XtalCapValue::XtalLowCap20p => range.xtal_cap20p | 0x08,
XtalCapValue::XtalLowCap10p => range.xtal_cap10p | 0x08,
XtalCapValue::XtalHighCap0p => range.xtal_cap0p,
XtalCapValue::XtalLowCap0p => range.xtal_cap0p | 0x08,
};
self.write_reg_mask(handle, 0x10, val, 0x0b)?;
self.write_reg_mask(handle, 0x08, 0x00, 0x3f)?;
self.write_reg_mask(handle, 0x09, 0x00, 0x3f)?;
Ok(())
}
fn set_pll(&mut self, handle: &Device, freq: u32) -> Result<()> {
let freq_khz = (freq + 500) / 1000;
info!("freq (kHz): {}", freq_khz);
let pll_ref = self.xtal;
let pll_ref_khz = (self.xtal + 500) / 1000;
let refdiv2 = 0;
self.write_reg_mask(handle, 0x10, refdiv2, 0x10)?;
self.write_reg_mask(handle, 0x1a, 0x00, 0x0c)?;
#[cfg(feature = "rtl_sdr_blog")]
self.write_reg_mask(handle, 0x12, 0x06, 0xff)?;
#[cfg(not(feature = "rtl_sdr_blog"))]
self.write_reg_mask(handle, 0x12, 0x80, 0xe0)?;
let vco_min: u32 = 1770000;
let vco_max: u32 = vco_min * 2;
let mut mix_div: u8 = 2;
let mut div_num: u8 = 0;
while mix_div <= 64 {
if ((freq_khz * mix_div as u32) >= vco_min) && ((freq_khz * mix_div as u32) < vco_max) {
let mut div_buf = mix_div;
while div_buf > 2 {
div_buf >>= 1;
div_num += 1;
}
break;
}
mix_div <<= 1;
}
let mut data: [u8; 5] = [0; 5];
self.read_reg(handle, 0x00, &mut data, 5)?;
let vco_power_ref = 2;
let vco_fine_tune = (data[4] & 0x30) >> 4;
match vco_fine_tune.cmp(&vco_power_ref) {
std::cmp::Ordering::Greater => div_num -= 1,
std::cmp::Ordering::Less => div_num += 1,
_ => (),
}
self.write_reg_mask(handle, 0x10, div_num << 5, 0xe0)?;
let vco_freq = freq as u64 * mix_div as u64;
info!("vco_freq: {}", vco_freq);
let nint = (vco_freq / (2 * pll_ref as u64)) as u8;
info!("nint: {}", nint);
let mut vco_fra = ((vco_freq - 2 * pll_ref as u64 * nint as u64) / 1000) as u32;
if nint > ((128 / vco_power_ref) - 1) {
return Err(RtlsdrErr(format!(
"[R82xx] No valid PLL values for {freq} Hz!"
)));
}
let ni = ((nint as i32).overflowing_sub(13).0 / 4) as u8;
let si = (nint as i32 - 4 * ni as i32 - 13) as u8;
info!(
"ni: {}, si: {}, reg: {}",
ni,
si,
ni.overflowing_add(si << 6).0
);
self.write_regs(handle, 0x14, &[ni.overflowing_add(si << 6).0])?;
if vco_fra == 0 {
self.write_reg_mask(handle, 0x12, 0x08, 0x08)?;
} else {
self.write_reg_mask(handle, 0x12, 0x00, 0x08)?;
}
let mut sdm = 0;
let mut n_sdm = 2;
while vco_fra > 1 {
if vco_fra > (2 * pll_ref_khz / n_sdm) {
sdm += 32768 / (n_sdm / 2);
vco_fra -= 2 * pll_ref_khz / n_sdm;
if n_sdm >= 0x8000 {
break;
}
}
n_sdm <<= 1;
}
self.write_regs(handle, 0x16, &[(sdm >> 8) as u8])?;
self.write_regs(handle, 0x15, &[(sdm & 0xff) as u8])?;
for i in 0..2 {
self.read_reg(handle, 0x00, &mut data, 3)?;
if data[2] & 0x40 != 0 {
break;
}
if i == 0 {
#[cfg(feature = "rtl_sdr_blog")]
self.write_reg_mask(handle, 0x12, 0x06, 0xff)?;
#[cfg(not(feature = "rtl_sdr_blog"))]
self.write_reg_mask(handle, 0x12, 0x80, 0xe0)?;
}
}
if (data[2] & 0x40) == 0 {
info!("[R82xx] PLL not locked!");
self.has_lock = false;
return Ok(());
}
self.has_lock = true;
self.write_reg_mask(handle, 0x1a, 0x08, 0x08)?;
Ok(())
}
#[allow(unused_variables, unused_assignments)]
fn sysfreq_sel(
&mut self,
handle: &Device,
freq: u32,
tuner_type: TunerType,
delivery_system: DeliverySystem,
) -> Result<()> {
let mixer_top;
let lna_top;
let cp_cur;
#[allow(unused_mut)]
let mut div_buf_cur;
let lna_vth_l;
let mixer_vth_l;
let air_cable1_in;
let cable2_in;
let pre_dect;
let lna_discharge;
let filter_cur;
match delivery_system {
DeliverySystem::SysDvbt => {
if (freq == 506000000) || (freq == 666000000) || (freq == 818000000) {
mixer_top = 0x14;
lna_top = 0xe5;
cp_cur = 0x28;
div_buf_cur = 0x20;
} else {
mixer_top = 0x24;
lna_top = 0xe5;
cp_cur = 0x38;
div_buf_cur = 0x30;
}
lna_vth_l = 0x53;
mixer_vth_l = 0x75;
air_cable1_in = 0x00;
cable2_in = 0x00;
pre_dect = 0x40;
lna_discharge = 14;
filter_cur = 0x40;
}
DeliverySystem::SysDvbt2 => {
mixer_top = 0x24;
lna_top = 0xe5;
lna_vth_l = 0x53;
mixer_vth_l = 0x75;
air_cable1_in = 0x00;
cable2_in = 0x00;
pre_dect = 0x40;
lna_discharge = 14;
cp_cur = 0x38;
div_buf_cur = 0x30;
filter_cur = 0x40;
}
DeliverySystem::SysIsdbt => {
mixer_top = 0x24;
lna_top = 0xe5;
lna_vth_l = 0x75;
mixer_vth_l = 0x75;
air_cable1_in = 0x00;
cable2_in = 0x00;
pre_dect = 0x40;
lna_discharge = 14;
cp_cur = 0x38;
div_buf_cur = 0x30;
filter_cur = 0x40;
}
DeliverySystem::SysUndefined => {
mixer_top = 0x24;
lna_top = 0xe5;
lna_vth_l = 0x53;
mixer_vth_l = 0x75;
air_cable1_in = 0x00;
cable2_in = 0x00;
pre_dect = 0x40;
lna_discharge = 14;
cp_cur = 0x38;
div_buf_cur = 0x30;
filter_cur = 0x40;
}
}
if self.use_predetect {
self.write_reg_mask(handle, 0x06, pre_dect, 0x40)?;
}
self.write_reg_mask(handle, 0x1d, lna_top, 0xc7)?;
self.write_reg_mask(handle, 0x1c, mixer_top, 0xf8)?;
self.write_regs(handle, 0x0d, &[lna_vth_l])?;
self.write_regs(handle, 0x0e, &[mixer_vth_l])?;
self.write_reg_mask(handle, 0x05, air_cable1_in, 0x60)?;
self.write_reg_mask(handle, 0x06, cable2_in, 0x08)?;
self.write_reg_mask(handle, 0x11, cp_cur, 0x38)?;
#[cfg(feature = "rtl_sdr_blog")]
{
div_buf_cur = 0xa0;
}
self.write_reg_mask(handle, 0x17, div_buf_cur, 0x30)?;
self.write_reg_mask(handle, 0x0a, filter_cur, 0x60)?;
if !matches!(tuner_type, TunerType::AnalogTv) {
self.write_reg_mask(handle, 0x1d, 0, 0x38)?;
self.write_reg_mask(handle, 0x1c, 0, 0x04)?;
self.write_reg_mask(handle, 0x06, 0, 0x40)?;
self.write_reg_mask(handle, 0x1a, 0x30, 0x30)?;
self.write_reg_mask(handle, 0x1d, 0x18, 0x38)?;
self.write_reg_mask(handle, 0x1c, mixer_top, 0x04)?;
self.write_reg_mask(handle, 0x1e, lna_discharge, 0x1f)?;
self.write_reg_mask(handle, 0x1a, 0x20, 0x30)?;
} else {
self.write_reg_mask(handle, 0x06, 0, 0x40)?;
self.write_reg_mask(handle, 0x1d, lna_top, 0x38)?;
self.write_reg_mask(handle, 0x1c, mixer_top, 0x04)?;
self.write_reg_mask(handle, 0x1e, lna_discharge, 0x1f)?;
self.write_reg_mask(handle, 0x1a, 0x00, 0x30)?;
self.write_reg_mask(handle, 0x10, 0x00, 0x04)?;
}
Ok(())
}
fn set_tv_standard(&mut self, handle: &Device, _bw: u32, tuner_type: TunerType) -> Result<()> {
let if_khz = 3570;
let filt_cal_lo = 56000;
let filt_gain = 0x10;
let img_r = 0x00;
let filt_q = 0x10;
let hp_cor = 0x6b;
let ext_enable = 0x60;
let loop_through = 0x01;
let lt_att = 0x00;
let flt_ext_widest = 0x00;
let polyfil_cur = 0x60;
self.regs.copy_from_slice(®_INIT[0..NUM_CACHE_REGS]);
self.write_reg_mask(handle, 0x0c, 0x00, 0x0f)?;
self.write_reg_mask(handle, 0x13, VER_NUM, 0x3f)?;
if !matches!(tuner_type, TunerType::AnalogTv) {
self.write_reg_mask(handle, 0x1d, 0x00, 0x38)?;
}
self.int_freq = if_khz * 1000;
let need_calibration = true;
if need_calibration {
for _ in 0..2 {
self.write_reg_mask(handle, 0x0b, hp_cor, 0x60)?;
self.write_reg_mask(handle, 0x0f, 0x04, 0x04)?;
self.write_reg_mask(handle, 0x10, 0x00, 0x03)?;
self.set_pll(handle, filt_cal_lo * 1000)?;
self.write_reg_mask(handle, 0x0b, 0x10, 0x10)?;
self.write_reg_mask(handle, 0x0b, 0x00, 0x10)?;
self.write_reg_mask(handle, 0x0f, 0x00, 0x04)?;
let mut data: [u8; 5] = [0; 5];
self.read_reg(handle, 0x00, &mut data, 5)?;
self.fil_cal_code = data[4] & 0x0f;
if self.fil_cal_code != 0x0f {
break;
}
}
if self.fil_cal_code == 0x0f {
self.fil_cal_code = 0;
}
}
self.write_reg_mask(handle, 0x0a, filt_q | self.fil_cal_code, 0x1f)?;
self.write_reg_mask(handle, 0x0b, hp_cor, 0xef)?;
self.write_reg_mask(handle, 0x07, img_r, 0x80)?;
self.write_reg_mask(handle, 0x06, filt_gain, 0x30)?;
self.write_reg_mask(handle, 0x1e, ext_enable, 0x60)?;
self.write_reg_mask(handle, 0x05, loop_through, 0x80)?;
self.write_reg_mask(handle, 0x1f, lt_att, 0x80)?;
self.write_reg_mask(handle, 0x0f, flt_ext_widest, 0x80)?;
self.write_reg_mask(handle, 0x19, polyfil_cur, 0x60)?;
Ok(())
}
fn _xtal_check(&mut self, handle: &Device) -> Result<u8> {
let mut data: [u8; 3] = [0; 3];
for (i, r) in REG_INIT
.iter()
.enumerate()
.take(NUM_REGS)
.skip(RW_REG_START)
{
self.regs[i] = *r;
}
self.write_reg_mask(handle, 0x10, 0x0b, 0x0b)?;
self.write_reg_mask(handle, 0x1a, 0x00, 0x0c)?;
self.write_reg_mask(handle, 0x13, 0x7f, 0x7f)?;
self.write_reg_mask(handle, 0x13, 0x00, 0x40)?;
for cap_val in XTAL_CAPACITOR_VALUES.iter() {
self.write_reg_mask(handle, 0x10, *cap_val, 0x1b)?;
self.read_reg(handle, 0x00, &mut data, 3)?;
if data[2] & 0x40 == 0 {
continue;
}
let val = data[2] & 0x3f;
if (self.xtal == 16_000_000 && !(23..=29).contains(&val)) || val != 0x3f {
return Ok(*cap_val);
}
}
Err(RtlsdrErr(
"Unable to find good xtal capacitor value!".to_string(),
))
}
fn write_reg_mask(&mut self, handle: &Device, reg: usize, val: u8, bit_mask: u8) -> Result<()> {
let rc = self.read_cache_reg(reg);
let applied: u8 = (rc & !bit_mask) | (val & bit_mask);
self.write_regs(handle, reg, &[applied])
}
fn read_cache_reg(&self, reg: usize) -> u8 {
assert!(reg >= RW_REG_START); let index = reg - RW_REG_START;
assert!(index < NUM_CACHE_REGS); self.regs[index]
}
fn write_regs(&mut self, handle: &Device, reg: usize, val: &[u8]) -> Result<()> {
self.reg_cache_store(reg, val);
let mut len = val.len();
let mut val_index = 0;
let mut reg_index = reg;
loop {
let size = if len > MAX_I2C_MSG_LEN - 1 {
MAX_I2C_MSG_LEN
} else {
len
};
let mut buf: Vec<u8> = vec![0; size + 1];
buf[0] = reg_index as u8;
buf[1..].copy_from_slice(&val[val_index..val_index + size]);
handle.i2c_write(R820T_I2C_ADDR, &buf)?;
val_index += size;
reg_index += size;
len -= size;
if len == 0 {
break;
}
}
Ok(())
}
fn read_reg(&self, handle: &Device, reg: usize, buf: &mut [u8], len: u8) -> Result<()> {
assert!(buf.len() >= len as usize);
handle.i2c_write(R820T_I2C_ADDR, &[reg as u8])?;
handle.i2c_read(R820T_I2C_ADDR, buf, len)?;
for b in buf {
*b = bit_reverse(*b);
}
Ok(())
}
fn reg_cache_store(&mut self, mut reg: usize, val: &[u8]) {
assert!(reg >= RW_REG_START);
reg -= RW_REG_START;
assert!(reg + val.len() <= NUM_CACHE_REGS);
self.regs[reg..reg + val.len()].copy_from_slice(val);
}
}
fn bit_reverse(byte: u8) -> u8 {
const LUT: [u8; 16] = [
0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf,
];
(LUT[(byte & 0xf) as usize] << 4) | LUT[(byte >> 4) as usize]
}