#[cfg(feature = "lux_as_f32")]
use crate::calculate_raw_threshold_value;
#[cfg(feature = "lux_as_f32")]
use crate::correction::{correct_high_lux, get_lux_raw_conversion_factor};
use crate::{
Config, Error, FaultCount, Gain, IntegrationTime, InterruptStatus, PowerSavingMode, Veml7700,
DEVICE_ADDRESS,
};
use embedded_hal::i2c::{ErrorType, I2c, SevenBitAddress};
struct Register;
impl Register {
const ALS_CONF: u8 = 0x00;
const ALS_WH: u8 = 0x01;
const ALS_WL: u8 = 0x02;
const PSM: u8 = 0x03;
const ALS: u8 = 0x04;
const WHITE: u8 = 0x05;
const ALS_INT: u8 = 0x06;
}
struct BitFlags;
impl BitFlags {
const ALS_SD: u16 = 0x01;
const ALS_INT_EN: u16 = 0x02;
const PSM_EN: u16 = 0x01;
const INT_TH_LOW: u16 = 1 << 15;
const INT_TH_HIGH: u16 = 1 << 14;
}
impl Config {
fn with_high(self, mask: u16) -> Self {
Config {
bits: self.bits | mask,
}
}
fn with_low(self, mask: u16) -> Self {
Config {
bits: self.bits & !mask,
}
}
}
impl<I2C> Veml7700<I2C>
where
I2C: I2c<SevenBitAddress>,
I2C::Error: Into<Error<I2C::Error>>,
{
pub fn new(i2c: I2C) -> Self {
Veml7700 {
i2c,
config: Config {
bits: BitFlags::ALS_SD,
},
gain: Gain::One,
it: IntegrationTime::_100ms,
}
}
pub fn destroy(self) -> I2C {
self.i2c
}
}
impl<I2C> Veml7700<I2C>
where
I2C: I2c<SevenBitAddress>,
I2C::Error: Into<Error<I2C::Error>>,
{
pub fn enable(&mut self) -> Result<(), Error<I2C::Error>> {
let config = self.config.with_low(BitFlags::ALS_SD);
self.set_config(config)
}
pub fn disable(&mut self) -> Result<(), Error<I2C::Error>> {
let config = self.config.with_high(BitFlags::ALS_SD);
self.set_config(config)
}
pub fn set_integration_time(&mut self, it: IntegrationTime) -> Result<(), Error<I2C::Error>> {
let mask = match it {
IntegrationTime::_25ms => 0b1100,
IntegrationTime::_50ms => 0b1000,
IntegrationTime::_100ms => 0b0000,
IntegrationTime::_200ms => 0b0001,
IntegrationTime::_400ms => 0b0010,
IntegrationTime::_800ms => 0b0011,
};
let config = self.config.bits & !(0b1111 << 6) | (mask << 6);
self.set_config(Config { bits: config })?;
self.it = it;
Ok(())
}
pub fn set_gain(&mut self, gain: Gain) -> Result<(), Error<I2C::Error>> {
let mask = match gain {
Gain::One => 0,
Gain::Two => 1,
Gain::OneEighth => 2,
Gain::OneQuarter => 3,
};
let config = self.config.bits & !(0b11 << 11) | mask << 11;
self.set_config(Config { bits: config })?;
self.gain = gain;
Ok(())
}
pub fn set_fault_count(&mut self, fc: FaultCount) -> Result<(), Error<I2C::Error>> {
let mask = match fc {
FaultCount::One => 0,
FaultCount::Two => 1,
FaultCount::Four => 2,
FaultCount::Eight => 3,
};
let config = self.config.bits & !(0b11 << 4) | mask << 4;
self.set_config(Config { bits: config })
}
pub fn enable_interrupts(&mut self) -> Result<(), Error<I2C::Error>> {
let config = self.config.with_high(BitFlags::ALS_INT_EN);
self.set_config(config)
}
pub fn disable_interrupts(&mut self) -> Result<(), Error<I2C::Error>> {
let config = self.config.with_low(BitFlags::ALS_INT_EN);
self.set_config(config)
}
pub fn set_high_threshold_raw(&mut self, threshold: u16) -> Result<(), Error<I2C::Error>> {
Ok(self.write_register(Register::ALS_WH, threshold)?)
}
pub fn set_low_threshold_raw(&mut self, threshold: u16) -> Result<(), Error<I2C::Error>> {
Ok(self.write_register(Register::ALS_WL, threshold)?)
}
#[cfg(feature = "lux_as_f32")]
pub fn set_high_threshold_lux(&mut self, lux: f32) -> Result<(), Error<I2C::Error>> {
let raw = self.calculate_raw_threshold_value(lux);
self.set_high_threshold_raw(raw)
}
#[cfg(feature = "lux_as_f32")]
pub fn set_low_threshold_lux(&mut self, lux: f32) -> Result<(), Error<I2C::Error>> {
let raw = self.calculate_raw_threshold_value(lux);
self.set_low_threshold_raw(raw)
}
#[cfg(feature = "lux_as_f32")]
pub fn calculate_raw_threshold_value(&self, lux: f32) -> u16 {
calculate_raw_threshold_value(self.it, self.gain, lux)
}
pub fn enable_power_saving(&mut self, psm: PowerSavingMode) -> Result<(), Error<I2C::Error>> {
let mask = match psm {
PowerSavingMode::One => 0,
PowerSavingMode::Two => 1,
PowerSavingMode::Three => 2,
PowerSavingMode::Four => 3,
};
let value = BitFlags::PSM_EN | mask << 1;
Ok(self.write_register(Register::PSM, value)?)
}
pub fn disable_power_saving(&mut self) -> Result<(), Error<I2C::Error>> {
Ok(self.write_register(Register::PSM, 0)?)
}
fn set_config(&mut self, config: Config) -> Result<(), Error<I2C::Error>> {
self.write_register(Register::ALS_CONF, config.bits)?;
self.config = config;
Ok(())
}
fn write_register(
&mut self,
register: u8,
value: u16,
) -> Result<(), <I2C as ErrorType>::Error> {
self.i2c
.write(DEVICE_ADDRESS, &[register, value as u8, (value >> 8) as u8])
}
}
impl<I2C> Veml7700<I2C>
where
I2C: I2c<SevenBitAddress>,
I2C::Error: Into<Error<I2C::Error>>,
{
pub fn read_interrupt_status(&mut self) -> Result<InterruptStatus, Error<I2C::Error>> {
let data = self.read_register(Register::ALS_INT)?;
Ok(InterruptStatus {
was_too_low: (data & BitFlags::INT_TH_LOW) != 0,
was_too_high: (data & BitFlags::INT_TH_HIGH) != 0,
})
}
pub fn read_raw(&mut self) -> Result<u16, Error<I2C::Error>> {
self.read_register(Register::ALS)
}
#[cfg(feature = "lux_as_f32")]
pub fn read_lux(&mut self) -> Result<f32, Error<I2C::Error>> {
let raw = self.read_register(Register::ALS)?;
Ok(self.convert_raw_als_to_lux(raw))
}
#[cfg(feature = "lux_as_f32")]
pub fn convert_raw_als_to_lux(&self, raw_als: u16) -> f32 {
convert_raw_als_to_lux(self.it, self.gain, raw_als)
}
pub fn read_white(&mut self) -> Result<u16, Error<I2C::Error>> {
self.read_register(Register::WHITE)
}
fn read_register(&mut self, register: u8) -> Result<u16, Error<I2C::Error>> {
let mut data = [0; 2];
self.i2c
.write_read(DEVICE_ADDRESS, &[register], &mut data)
.map_err(Error::I2C)
.and(Ok(u16::from(data[0]) | u16::from(data[1]) << 8))
}
}
#[cfg(feature = "lux_as_f32")]
pub fn convert_raw_als_to_lux(it: IntegrationTime, gain: Gain, raw_als: u16) -> f32 {
let factor = get_lux_raw_conversion_factor(it, gain);
let lux = f32::from(raw_als) * factor;
if (gain == Gain::OneQuarter || gain == Gain::OneEighth) && lux > 1000.0 {
correct_high_lux(lux)
} else {
lux
}
}