use embedded_hal::i2c::I2c;
const CMD_FAST_WRITE: u8 = 0x00;
const CMD_WRITE_DAC_EEPROM: u8 = 0x60;
const ADDR_GENERAL_CALL: u8 = 0x00;
const GC_RESET: u8 = 0x06;
const GC_WAKE: u8 = 0x09;
pub struct Mcp4725Minimal<I2C> {
i2c: I2C,
addr: u8,
}
impl<I2C: I2c> Mcp4725Minimal<I2C> {
pub fn new(i2c: I2C, addr: u8) -> Result<Self, I2C::Error> {
Ok(Self { i2c, addr })
}
pub fn set_voltage(&mut self, fraction: f32) -> Result<(), I2C::Error> {
let f = fraction.max(0.0).min(1.0);
let code = (f * 4095.0)as u16;
self._fast_write(code, 0)
}
pub fn set_raw(&mut self, code: u16) -> Result<(), I2C::Error> {
let code = code.min(4095);
self._fast_write(code, 0)
}
fn _fast_write(&mut self, code: u16, pd_mode: u8) -> Result<(), I2C::Error> {
let buf = [
((pd_mode & 0x03) << 4) as u8 | ((code >> 8) & 0x0F) as u8,
(code & 0xFF) as u8,
];
self.i2c.write(self.addr, &buf)
}
}
pub struct Mcp4725Full<I2C> {
inner: Mcp4725Minimal<I2C>,
}
impl<I2C: I2c> Mcp4725Full<I2C> {
pub fn new(i2c: I2C, addr: u8) -> Result<Self, I2C::Error> {
Ok(Self { inner: Mcp4725Minimal::new(i2c, addr)? })
}
pub fn set_voltage(&mut self, fraction: f32) -> Result<(), I2C::Error> {
self.inner.set_voltage(fraction)
}
pub fn set_raw(&mut self, code: u16) -> Result<(), I2C::Error> {
self.inner.set_raw(code)
}
pub fn set_voltage_eeprom(&mut self, fraction: f32) -> Result<(), I2C::Error> {
let f = fraction.max(0.0).min(1.0);
let code = (f * 4095.0)as u16;
self._write_dac_eeprom(code, 0)
}
pub fn set_raw_eeprom(&mut self, code: u16) -> Result<(), I2C::Error> {
let code = code.min(4095);
self._write_dac_eeprom(code, 0)
}
pub fn read(&mut self) -> Result<(u16, f32, u8, u16, u8, bool), I2C::Error> {
let mut buf = [0u8; 5];
self.inner.i2c.write_read(self.inner.addr, &[0x00], &mut buf)?;
let code = (((buf[1] & 0x0F) as u16) << 8) | buf[2] as u16;
let voltage_fraction = code as f32 / 4095.0;
let power_down = (buf[0] >> 2) & 0x03;
let eeprom_code = (((buf[3] & 0x0F) as u16) << 8) | buf[4] as u16;
let eeprom_power_down = (buf[3] >> 6) & 0x03;
let eeprom_ready = (buf[0] & 0x80) != 0;
Ok((code, voltage_fraction, power_down, eeprom_code, eeprom_power_down, eeprom_ready))
}
pub fn set_power_down(&mut self, mode: u8) -> Result<(), I2C::Error> {
let mode = mode.min(3);
let code = self._read_dac_code()?;
self.inner._fast_write(code, mode)
}
pub fn wake_up(&mut self) -> Result<(), I2C::Error> {
self.inner.i2c.write(ADDR_GENERAL_CALL, &[GC_WAKE])
}
pub fn reset(&mut self) -> Result<(), I2C::Error> {
self.inner.i2c.write(ADDR_GENERAL_CALL, &[GC_RESET])
}
pub fn is_eeprom_ready(&mut self) -> Result<bool, I2C::Error> {
let mut buf = [0u8; 1];
self.inner.i2c.write_read(self.inner.addr, &[0x00], &mut buf)?;
Ok((buf[0] & 0x80) != 0)
}
fn _write_dac_eeprom(&mut self, code: u16, pd_mode: u8) -> Result<(), I2C::Error> {
let buf = [
CMD_WRITE_DAC_EEPROM | ((pd_mode & 0x03) << 1),
(code >> 4) as u8,
((code & 0x0F) << 4) as u8,
];
self.inner.i2c.write(self.inner.addr, &buf)
}
fn _read_dac_code(&mut self) -> Result<u16, I2C::Error> {
let mut buf = [0u8; 2];
self.inner.i2c.write_read(self.inner.addr, &[0x00], &mut buf)?;
Ok(((buf[0] & 0x0F) as u16) << 8 | buf[1] as u16)
}
}