gp2y0e02b 0.2.1

A rust driver for the GP2Y0E02B (SHARP I2C Distance Measuring Sensor, 4-50cm)
Documentation
#![no_std]

//! Manages a new GP2Y0E02B, SHARP I2C Distance Measuring Sensor, 4-50cm

#![deny(
    missing_copy_implementations,
    missing_debug_implementations,
    missing_docs,
    trivial_casts,
    unstable_features,
    unused_import_braces,
    unused_qualifications,
    warnings
)]
#![allow(dead_code)]
#![allow(clippy::uninit_assumed_init, clippy::upper_case_acronyms)]

extern crate cast;
extern crate embedded_hal as ehal;
extern crate generic_array;
extern crate nb;

use ehal::blocking::i2c::{Read, Write, WriteRead};

const WRITE_ADDRESS: u8 = 0x80;
const READ_ADDRESS: u8 = WRITE_ADDRESS >> 1;

/// Register Map (Bank0) from <http://www.robot-electronics.co.uk/files/gp2y0e02_03_appl_e.pdf>
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug)]
pub enum Register {
    /// Hold Bit
    /// 0x00=Hold
    /// 0x01=Device enable normally
    /// Register avoid update during Hold.
    HOLD_BIT = 0x03,

    /// Maximum Emitting Pulse Width
    /// 0x07=320us, 0x06=240us, 0x05=160us, 0x04=80us, 0x03=40us
    MAXIMUM_EMITTING_PULSE_WIDTH = 0x13,

    ///Spot Symmetry Threshold
    SPOT_SYMMETRY_THRESHOLD = 0x1C,

    /// Signal Intensity Threshold
    /// Default is set in each sensor by E-Fuse.
    SIGNAL_INTENSITY_THRESHOLD = 0x2F,

    /// Maximum Spot Size Threshold
    MAXIMUM_SPOT_SIZE_THRESHOLD = 0x33,

    /// Minimum Spot Size Threshold
    /// Default is set in each sensor by E-Fuse.
    MINIMUM_SPOT_SIZE_THRESHOLD = 0x34,

    /// Shift Bit
    /// 0x01=Maximum Display 128cm
    /// 0x02=Maximum Display 64cm
    /// Default to 0x02
    SHIFT_BIT = 0x35,

    /// Median Filter
    /// 0x00= Data number of median calculation 7
    /// 0x10= Data number of median calculation 5
    /// 0x20= Data number of median calculation 9
    /// 0x30= Data number of median calculation 1
    MEDIAN_FILTER = 0x3F,

    /// SRAM Access
    /// 0x10=Access SRAM
    SRAM_ACCESS = 0x4C,

    /// Distance\[11:4\]
    /// Distance Value =(Distance\[11:4\]*16+Distance\[3:0\])/16/2^n
    /// n : Shift Bit (Register 0x35)
    DISTANCE_11_4 = 0x5E,

    /// Distance\[3:0\]
    /// Distance Value =(Distance\[11:4\]*16+Distance\[3:0\])/16/2^n
    /// n : Shift Bit (Register 0x35)
    DISTANCE_3_0 = 0x5F,

    /// AE\[15:8\]
    /// AE=AE\[15:8\]*256 + AE\[7:0\]
    /// Before read out,
    /// it need to write Address(0xEC) = Data(0xFF)
    AE_15_8 = 0x64,

    /// AE\[7:0\]
    /// AE=AE\[15:8\]*256 + AE\[7:0\]
    /// Before read out,
    /// it need to write Address(0xEC) = Data(0xFF)
    AE_7_0 = 0x65,

    /// AG\[7:0\]
    /// AE=AE\[15:8\]*256 + AE\[7:0\]
    /// Before read out,
    /// it need to write Address(0xEC) = Data(0xFF)
    AG_7_0 = 0x67,

    /// Cover Compensation\[5:0\]
    ///  Cover compensation coefficient =
    /// Cover Comp.\[10:6\]*64 + Cover Comp.\[5:0\]
    /// Cover Comp.\[5:0\] is assigned in Reg Field\[7:2\] of
    /// register 0x8D. So, it need to shift 2 bits toward right.
    COVER_COMPENSATION_5_0 = 0x8D,

    /// Cover Compensation\[10:6\]
    ///  Cover compensation coefficient =
    /// Cover Comp.\[10:6\]*64 + Cover Comp.\[5:0\]
    /// Cover Comp.\[5:0\] is assigned in Reg Field\[7:2\] of
    /// register 0x8D. So, it need to shift 2 bits toward right.
    COVER_COMPENSATION_10_6 = 0x8E,

    /// Cover Compensation Enable Bit
    /// 0x02=Enable
    /// 0x03=Disable
    COVER_COMPENSATION_ENABLE_BIT = 0x8F,

    /// Read out Image Sensor Data
    /// 0x00=Disable
    /// 0x10=Low Level (L)
    /// 0x11=Middle Level (M)
    /// 0x12=High Level (H)
    /// Intensity=H*65536 + M*256 + L
    READ_OUT_IMAGE_SENSOR_DATA = 0x90,

    /// Signal Accumulation Number
    /// 0x00=1 time accumulation
    /// 0x01=5 times accumulation
    /// 0x02=30 times accumulation
    /// 0x03=10 times accumulation
    SIGNAL_ACCUMULATION_NUMBER = 0xA8,

    /// Enable Bit (Signal Intensity)
    /// 0x00=enable (Default)
    /// 0x01=disable
    ENABLE_BIT_SIGNAL_INTENSITY = 0xBC,

    /// Enable Bit (Minimum spot size)
    /// 0x00=enable (Default)
    /// 0x01=disable
    ENABLE_BIT_MINIMUM_SPOT_SIZE = 0xBD,

    /// Enable Bit (Maximum spot size)
    /// 0x00=enable
    /// 0x01=disable (Default)
    ENABLE_BIT_MAXIMUM_SPOT_SIZE = 0xBE,

    /// Enable Bit (Spot symmetry)
    /// 0x00=enable (Default)
    /// 0x01=disable
    ENABLE_BIT_SPOT_SYMMETRY = 0xBF,

    /// E-Fuse Target Address
    /// E-Fuse Read Out
    /// E-Fuse Enable Bit
    /// Specify E-Fuse address in the target bank.
    /// Ex. A\[0\]=0x00, B\[10\]=0x0A, C\[63\]=0x3F
    /// 1=load E-Fuse data to Register (Bank3)
    /// 0=Enable, 1=Disable
    E_FUSE_TARGET_ADDRESS_READ_OUT_ENABLE_BIT = 0xC8,

    /// E-Fuse Bit Number
    /// E-Fuse Bank Assign
    /// Assign bit number in the register 0xC9 \[7:4\]
    /// Assign bank select in the register 0xC9 \[3:0\].
    /// 1:BankA, 2:BankB, 3:BankC, 4:BankD, 5:BankE
    E_FUSE_BIT_NUMBER_BANK_ASSIGN = 0xC9,

    /// E-Fuse Program
    /// Enable Bit
    /// 0x00=Disable
    /// 0x01=Enable
    E_FUSE_PROGRAM_ENABLE_BIT = 0xCA,

    /// E-Fuse Program Data
    E_FUSE_PROGRAM_DATA = 0xCD,

    /// Active/Stand-by State Control
    /// 0x00=Active state
    /// 0x01=Stand-by state
    ACTIVE_STAND_BY_STATE_CONTROL = 0xE8,

    /// Clock Select
    /// 0x7F=auto clock
    /// 0xFF=manual clock
    CLOCK_SELECT = 0xEC,

    /// Software Reset
    /// 0x06=software reset
    SOFTWARE_RESET = 0xEE,

    /// Bank Select
    /// 0x00=Bank0
    /// 0x03=Bank3 (E-Fuse)
    BANK_SELECT = 0xEF,

    /// Right Edge Coordinate (C)
    /// Spot Size = C-A (=0xF8\[7:0\]-0xF9\[7:0\])
    /// Spot Symmetry=|(C-A)-2*B|
    /// (=|(0xF8\[7:0\]-0xF9\[7:0\])-2*0xFA\[7:0\])|)
    RIGHT_EDGE_COORDINATE = 0xF8,

    /// Left Edge Coordinate (A)
    /// Spot Size = C-A (=0xF8\[7:0\]-0xF9\[7:0\])
    /// Spot Symmetry=|(C-A)-2*B|
    /// (=|(0xF8\[7:0\]-0xF9\[7:0\])-2*0xFA\[7:0\])|)
    LEFT_EDGE_COORDINATE = 0xF9,

    /// Peak Coordinate (B)
    /// Spot Size = C-A (=0xF8\[7:0\]-0xF9\[7:0\])
    /// Spot Symmetry=|(C-A)-2*B|
    /// (=|(0xF8\[7:0\]-0xF9\[7:0\])-2*0xFA\[7:0\])|)
    PEAK_COORDINATE = 0xFA,
}

impl Register {
    /// Explicitly get address of a Register
    #[inline(always)]
    pub fn addr(self) -> u8 {
        self as u8
    }
}

/// Struct for GP2Y0E02B
#[derive(Debug, Copy, Clone)]
pub struct GP2Y0E02B<I2C> {
    com: I2C,
}

impl<I2C, E> GP2Y0E02B<I2C>
where
    I2C: Write<Error = E> + Read<Error = E> + WriteRead<Error = E>,
    E: core::fmt::Debug,
{
    /// Creates a new sensor
    pub fn new(i2c: I2C) -> Result<GP2Y0E02B<I2C>, E> {
        let chip = GP2Y0E02B { com: i2c };
        Ok(chip)
    }

    /// TODO
    pub fn read_register(&mut self, reg: Register) -> Result<u8, E> {
        self.read_byte(reg as u8)
    }

    /// TODO
    pub fn write_register(&mut self, reg: Register, byte: u8) -> Result<(), E> {
        self.write_byte(reg as u8, byte)
    }

    /// Reads and returns distance measurement in millimeters
    pub fn read_distance(&mut self) -> Result<f32, E> {
        //  let high = self.read_byte(Register::DISTANCE_11_4.addr()).unwrap() as f32;
        //  let low = self.read_byte(Register::DISTANCE_3_0.addr()).unwrap() as f32;
        let [high, low] = self.read_bytes(Register::DISTANCE_11_4.addr()).unwrap();
        let shift = self.read_byte(Register::SHIFT_BIT.addr()).unwrap() as u32;

        let v = (((high as f32 * 16.0) + low as f32) / 16.0) / (u16::pow(2, shift) as f32);

        Ok(v)
    }

    fn read_byte(&mut self, reg: u8) -> Result<u8, E> {
        let mut data: [u8; 1] = [0];
        self.com.write_read(READ_ADDRESS, &[reg], &mut data)?;

        Ok(data[0])
    }

    fn read_bytes(&mut self, reg: u8) -> Result<[u8; 2], E> {
        let mut data: [u8; 2] = [0, 0];
        self.com.write_read(READ_ADDRESS, &[reg], &mut data)?;

        Ok(data)
    }

    fn write_byte(&mut self, reg: u8, byte: u8) -> Result<(), E> {
        let mut buffer = [0];
        self.com
            .write_read(WRITE_ADDRESS, &[reg, byte], &mut buffer)
    }
}