pub const ANALOG_MAX_RANGE_CM: u16 = 800;
pub const ANALOG_MAX_ADC_VALUE: u16 = 4095;
#[cfg(feature = "analog")]
pub trait AdcReader {
type Error;
fn read(&mut self) -> Result<u16, Self::Error>;
}
#[cfg(feature = "analog")]
pub struct AnalogSensor<R: AdcReader> {
reader: R,
}
#[cfg(feature = "analog")]
impl<R: AdcReader> AnalogSensor<R> {
pub fn new(reader: R) -> Self {
Self { reader }
}
pub fn read_distance(&mut self, adc_max: u16, num_samples: usize) -> Result<f32, R::Error> {
let mut sum: u32 = 0;
for _ in 0..num_samples {
let reading = self.reader.read()?;
sum += reading as u32;
}
let average = (sum / num_samples as u32) as u16;
Ok(adc_to_distance_cm(average, adc_max))
}
}
#[inline]
pub fn adc_to_distance_cm(adc_raw: u16, adc_max: u16) -> f32 {
if adc_max == 0 {
return 0.0;
}
let ratio = ANALOG_MAX_RANGE_CM as f32 / adc_max as f32;
adc_raw as f32 * ratio
}
#[inline]
pub fn distance_cm_to_adc(distance_cm: u16, adc_max: u16) -> u16 {
if ANALOG_MAX_RANGE_CM == 0 {
return 0;
}
((distance_cm as u32 * adc_max as u32) / ANALOG_MAX_RANGE_CM as u32) as u16
}
#[inline]
pub fn voltage_mv_to_distance_cm(voltage_mv: u32, vcc_mv: u32) -> u16 {
if vcc_mv == 0 {
return 0;
}
((voltage_mv * ANALOG_MAX_RANGE_CM as u32) / vcc_mv) as u16
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_adc_midscale_12bit() {
let cm = adc_to_distance_cm(2048, 4095);
assert!((cm - 400.0).abs() < 2.5);
}
#[test]
fn test_adc_max() {
let cm = adc_to_distance_cm(4095, 4095);
assert!((cm - 800.0).abs() < 0.1);
}
#[test]
fn test_adc_zero() {
let cm = adc_to_distance_cm(0, 4095);
assert_eq!(cm, 0.0);
}
#[test]
fn test_voltage_half_vcc() {
let cm = voltage_mv_to_distance_cm(1650, 3300);
assert_eq!(cm, 400);
}
}