use crate::error::{RtlSdrError, TunerError};
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(TunerError::I2cTransferFailed {
operation: "write",
got: rc,
expected: size + 1,
}
.into());
}
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(TunerError::ShadowCacheMiss { reg })?;
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(TunerError::I2cTransferFailed {
operation: "read addr",
got: rc,
expected: 1,
}
.into());
}
let rc = usb::i2c_read(handle, self.i2c_addr, &mut self.buf[1..1 + out.len()])?;
if rc != out.len() {
return Err(TunerError::I2cTransferFailed {
operation: "read data",
got: rc,
expected: out.len(),
}
.into());
}
for (i, byte) in self.buf[1..1 + out.len()].iter().enumerate() {
out[i] = bitrev(*byte);
}
Ok(())
}
}