use core::fmt;
use embedded_hal::i2c::I2c as _;
use embedded_hal_bus::i2c::CriticalSectionDevice;
use crate::{
Error, I2cBus, I2cDevice,
convert::{microphone_gain_step, volume_register},
};
const ES8311: u8 = 0x18;
const ES8311_DAC_VOLUME: u8 = 0x32;
const ES8311_DAC_POWER: u8 = 0x12;
const ES8311_OUTPUT: u8 = 0x13;
const ES8311_CLOCKS: u8 = 0x01;
const CLOCKS_DAC: u8 = 0xB5;
const CLOCKS_DAC_ADC: u8 = 0xBF;
const ES8311_ADC_PGA: u8 = 0x14;
const MIC1: u8 = 0x10;
pub struct Codec {
device: I2cDevice,
microphone_gain: u8,
}
impl Codec {
pub fn set_volume(&mut self, percent: u8) -> Result<(), Error> {
self.write(&[[ES8311_DAC_VOLUME, volume_register(percent)]])
}
pub fn set_output(&mut self, on: bool) -> Result<(), Error> {
if on {
self.write(&[[ES8311_DAC_POWER, 0x00], [ES8311_OUTPUT, 0x10]])
} else {
self.write(&[[ES8311_OUTPUT, 0x00], [ES8311_DAC_POWER, 0x02]])
}
}
pub fn set_microphone(&mut self, on: bool) -> Result<(), Error> {
if on {
self.write(&[
[ES8311_CLOCKS, CLOCKS_DAC_ADC],
[0x0A, 0x0C], [0x0E, 0x02], [ES8311_ADC_PGA, MIC1 | self.microphone_gain],
[0x17, 0xBF], [0x1C, 0x6A], ])
} else {
self.write(&[[0x0E, 0x6A], [ES8311_CLOCKS, CLOCKS_DAC]])
}
}
pub fn set_microphone_gain(&mut self, db: u8) -> Result<(), Error> {
self.microphone_gain = microphone_gain_step(db);
self.write(&[[ES8311_ADC_PGA, MIC1 | self.microphone_gain]])
}
fn write(&mut self, writes: &[[u8; 2]]) -> Result<(), Error> {
writes
.iter()
.try_for_each(|write| self.device.write(ES8311, write).map_err(|_| Error::Codec))
}
}
pub fn codec(bus: &'static I2cBus) -> Result<Codec, Error> {
let mut codec = Codec {
device: CriticalSectionDevice::new(bus),
microphone_gain: 0,
};
codec.write(&[
[0x00, 0x80], [ES8311_CLOCKS, CLOCKS_DAC], [0x02, 0x18], [0x0D, 0x01], [ES8311_DAC_POWER, 0x00], [ES8311_OUTPUT, 0x10], [ES8311_DAC_VOLUME, 0xBF], [0x37, 0x08], ])?;
Ok(codec)
}
impl fmt::Debug for Codec {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Codec")
.field("microphone_gain_db", &(self.microphone_gain * 3))
.finish_non_exhaustive()
}
}