use crate::error::RtlSdrError;
use crate::usb;
use super::R82xxPriv;
use super::constants::{NUM_REGS, REG_SHADOW_START, bitrev};
impl R82xxPriv {
pub(super) fn shadow_store(&mut self, reg: u8, val: &[u8]) {
let mut r = reg as i32 - i32::from(REG_SHADOW_START);
let mut offset = 0usize;
let mut len = val.len() as i32;
if r < 0 {
len += r;
offset = (-r) as usize;
r = 0;
}
if len <= 0 {
return;
}
let r = r as usize;
if len > (NUM_REGS - r) as i32 {
len = (NUM_REGS - r) as i32;
}
let len = len as usize;
self.regs[r..r + len].copy_from_slice(&val[offset..offset + len]);
}
pub(super) fn shadow_equal(&self, reg: u8, val: &[u8]) -> bool {
let r = reg as i32 - i32::from(REG_SHADOW_START);
let len = val.len() as i32;
if r < 0 || len < 0 || len > (NUM_REGS as i32 - r) {
return false;
}
let r = r as usize;
let len = len as usize;
self.regs[r..r + len] == val[..len]
}
pub(super) fn write(
&mut self,
handle: &rusb::DeviceHandle<rusb::GlobalContext>,
reg: u8,
val: &[u8],
) -> Result<(), RtlSdrError> {
if self.shadow_equal(reg, val) {
return Ok(());
}
let max_msg = self.max_i2c_msg_len;
let mut pos = 0usize;
let mut current_reg = reg;
let mut remaining = val.len();
while remaining > 0 {
let size = remaining.min(max_msg - 1);
self.buf[0] = current_reg;
self.buf[1..1 + size].copy_from_slice(&val[pos..pos + size]);
let rc = usb::i2c_write(handle, self.i2c_addr, &self.buf[..size + 1])?;
if rc != size + 1 {
return Err(RtlSdrError::Tuner(format!(
"i2c write failed: wrote {rc}, expected {}",
size + 1
)));
}
current_reg += size as u8;
remaining -= size;
pos += size;
}
self.shadow_store(reg, val);
Ok(())
}
pub(super) fn write_reg(
&mut self,
handle: &rusb::DeviceHandle<rusb::GlobalContext>,
reg: u8,
val: u8,
) -> Result<(), RtlSdrError> {
self.write(handle, reg, &[val])
}
pub(super) fn read_cache_reg(&self, reg: u8) -> Option<u8> {
let r = reg as i32 - i32::from(REG_SHADOW_START);
if r >= 0 && (r as usize) < NUM_REGS {
Some(self.regs[r as usize])
} else {
None
}
}
pub(super) fn write_reg_mask(
&mut self,
handle: &rusb::DeviceHandle<rusb::GlobalContext>,
reg: u8,
val: u8,
bit_mask: u8,
) -> Result<(), RtlSdrError> {
let cached = self
.read_cache_reg(reg)
.ok_or_else(|| RtlSdrError::Tuner(format!("no cached value for reg 0x{reg:02x}")))?;
let new_val = (cached & !bit_mask) | (val & bit_mask);
self.write(handle, reg, &[new_val])
}
pub(super) fn read(
&mut self,
handle: &rusb::DeviceHandle<rusb::GlobalContext>,
reg: u8,
out: &mut [u8],
) -> Result<(), RtlSdrError> {
self.buf[0] = reg;
let rc = usb::i2c_write(handle, self.i2c_addr, &self.buf[..1])?;
if rc != 1 {
return Err(RtlSdrError::Tuner(format!(
"i2c read addr write failed: {rc}"
)));
}
let rc = usb::i2c_read(handle, self.i2c_addr, &mut self.buf[1..1 + out.len()])?;
if rc != out.len() {
return Err(RtlSdrError::Tuner(format!(
"i2c read data failed: got {rc}, expected {}",
out.len()
)));
}
for (i, byte) in self.buf[1..1 + out.len()].iter().enumerate() {
out[i] = bitrev(*byte);
}
Ok(())
}
}