#![no_std]
#![allow(dead_code)]
use embedded_hal::blocking::i2c;
mod regmap;
use regmap::*;
const TPA2016_I2C_ADDR: u8 = 0xB0 >> 1;
pub struct Tpa2016d2<I2C> {
i2c: I2C,
regmap: RegisterMap,
}
pub struct Faults {
pub fault_r: bool,
pub fault_l: bool,
pub thermal: bool,
}
pub enum CompressionRatio {
Ratio1 = 0b00,
Ratio2 = 0b01,
Ratio4 = 0b10,
Ratio8 = 0b11,
}
pub enum NoiseGateThreshold {
Ngt20mV = 0b11,
Ngt10mV = 0b10,
Ngt4mV = 0b01,
Ngt1mV = 0b00,
}
pub enum AgcPreset {
Pop,
Classical,
Jazz,
Rap,
Rock,
Voice,
}
impl<I2C, E> Tpa2016d2<I2C>
where
I2C: i2c::Write<Error = E> + i2c::WriteRead<Error = E>,
{
pub fn new(i2c: I2C) -> Tpa2016d2<I2C> {
let regmap = RegisterMap::default();
Tpa2016d2 { i2c, regmap }
}
pub fn sync(&mut self) -> Result<(), E> {
for i in 1..=7 {
let val = self.read_reg(i)?;
self.regmap.update_map(i, val);
}
Ok(())
}
pub fn release(self) -> I2C {
self.i2c
}
pub fn device_reg(&mut self, idx: u8) -> Result<u8, E> {
Ok(self.regmap.reg_as_byte(idx))
}
pub fn speaker_enable(&mut self, le: bool, re: bool) -> Result<(), E> {
self.regmap.reg1.SPK_EN_L = le;
self.regmap.reg1.SPK_EN_R = re;
self.write_regmap_reg(1)
}
pub fn get_faults(&mut self) -> Result<Faults, E> {
let val = self.read_reg(1)?;
self.regmap.update_map(1, val);
Ok(Faults {
fault_r: self.regmap.reg1.FAULT_R,
fault_l: self.regmap.reg1.FAULT_L,
thermal: self.regmap.reg1.Thermal,
})
}
pub fn disable_device(&mut self) -> Result<(), E> {
self.regmap.reg1.SWS = true;
self.write_regmap_reg(1)
}
pub fn noise_gate(&mut self, enable: bool) -> Result<(), E> {
self.regmap.reg1.NG_EN = enable;
self.write_regmap_reg(1)
}
pub fn set_attack_time(&mut self, val: u8) -> Result<(), E> {
self.regmap.atk_time.set(val);
self.write_regmap_reg(2)
}
pub fn set_release_time(&mut self, val: u8) -> Result<(), E> {
self.regmap.rel_time.set(val);
self.write_regmap_reg(3)
}
pub fn set_hold_time(&mut self, val: u8) -> Result<(), E> {
self.regmap.hold_time.set(val);
self.write_regmap_reg(4)
}
pub fn gain(&mut self, gain: u8) -> Result<(), E> {
self.regmap.fixedGain.set(gain);
self.write_regmap_reg(5)
}
pub fn noise_gate_threshold(&mut self, val: NoiseGateThreshold) -> Result<(), E> {
self.regmap.reg6.noise_gate_threshold = val as u8;
self.write_regmap_reg(6)
}
pub fn output_limiter_level(&mut self, val: u8) -> Result<(), E> {
self.regmap.reg6.output_limiter_level = val;
self.write_regmap_reg(6)
}
pub fn compression_ratio(&mut self, ratio: CompressionRatio) -> Result<(), E> {
self.regmap.reg7.compression_ratio = ratio as u8;
self.write_regmap_reg(7)
}
pub fn set_agc_preset(&mut self, preset: AgcPreset) -> Result<(), E> {
use AgcPreset::*;
use CompressionRatio::*;
let (cr, atk, rel_time, hold_time, fixed_gain, limiter_level) = match preset {
Pop => (Ratio4, 0b00_0010, 986, 137, 6, 0b11_1100),
Classical => (Ratio2, 0b00_0010, 1150, 137, 6, 0b11_1101),
Jazz => (Ratio2, 0b00_0110, 3288, 0, 6, 0b11_1101),
Rap => (Ratio4, 0b00_0010, 1640, 0, 6, 0b11_1100),
Rock => (Ratio2, 0b00_0011, 4110, 0, 6, 0b11_1101),
Voice => (Ratio4, 0b00_0010, 1640, 0, 6, 0b11_1110),
};
let rel_time = release_time_to_u6(rel_time);
let hold_time = hold_time_to_u6(hold_time);
self.regmap.atk_time.set(atk);
self.regmap.rel_time.set(rel_time);
self.regmap.hold_time.set(hold_time);
self.regmap.fixedGain.set(fixed_gain);
self.regmap.reg6.output_limiter_level = limiter_level;
self.regmap.reg7.compression_ratio = cr as u8;
for rid in 2..=7 {
self.write_regmap_reg(rid)?;
}
Ok(())
}
fn write_regmap_reg(&mut self, idx: u8) -> Result<(), E> {
let b = self.regmap.reg_as_byte(idx);
self.write_reg(idx, b)
}
fn read_reg(&mut self, regidx: u8) -> Result<u8, E> {
if regidx < 1 || regidx > 7 {
return Ok(0);
}
let mut regbuf = [0u8; 1];
self.i2c
.write_read(TPA2016_I2C_ADDR, &[regidx], &mut regbuf)?;
Ok(regbuf[0])
}
fn write_reg(&mut self, regaddr: u8, value: u8) -> Result<(), E> {
let regbuf = [regaddr, value];
self.i2c.write(TPA2016_I2C_ADDR, ®buf)
}
}
const fn release_time_to_u6(v: u32) -> u8 {
(v / 1644) as u8
}
const fn hold_time_to_u6(v: u32) -> u8 {
(v / 137) as u8
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn release_time_conv() {
let tests = [(1644, 0b00_0001), (4932, 0b00_0011), (103600, 0b11_1111)];
for &(input, bitval) in &tests {
let res = release_time_to_u6(input);
assert_eq!(res, bitval);
}
}
#[test]
fn hold_time_conv() {
let tests = [(137, 0b00_0001), (0411, 0b00_0011), (8631, 0b11_1111)];
for &(input, bitval) in &tests {
let res = hold_time_to_u6(input);
assert_eq!(res, bitval);
}
}
#[test]
fn test_register_defaults() {
let regmap = RegisterMap::default();
let r1 = regmap.reg_as_byte(1);
let r2 = regmap.reg_as_byte(2);
let r3 = regmap.reg_as_byte(3);
let r4 = regmap.reg_as_byte(4);
let r5 = regmap.reg_as_byte(5);
let r6 = regmap.reg_as_byte(6);
let r7 = regmap.reg_as_byte(7);
assert_eq!(r1, 0xC3);
assert_eq!(r2, 0x05);
assert_eq!(r3, 0x0B);
assert_eq!(r4, 0x00);
assert_eq!(r5, 0x06);
assert_eq!(r6, 0x3A);
assert_eq!(r7, 0xC2);
}
}