vl53l1x_simple/
lib.rs

1#![doc = include_str!("../README.md")]
2#![no_std]
3
4mod imp;
5mod reg;
6
7/// The default I2C address for the VL53L1X.
8pub const DEFAULT_ADDRESS: u8 = 0b010_1001;
9
10/// Possible errors that can occur during initialisation.
11#[derive(Debug)]
12pub enum InitialisationError<EI2C, EX> {
13    /// An error occurred on the I2C bus.
14    I2C(EI2C),
15    /// An error occurred setting the xshut pin.
16    XShut(EX),
17
18    /// The model ID read from the device was invalid.
19    InvalidModelId(u16),
20    /// The device timed out.
21    Timeout,
22    /// The timing budget was invalid.
23    InvalidTimingBudget,
24}
25
26/// A VL53L1X driver. Use the `new` function to create a new instance, then
27/// call `range` to get the current range, if available.
28pub struct Vl53l1x<I2C, X> {
29    i2c: I2C,
30    _x_shut: X,
31    address: u8,
32
33    fast_osc_frequency: u16,
34    osc_calibrate_val: u16,
35    distance_mode: imp::DistanceMode,
36    calibrated: bool,
37    saved_vhv_init: u8,
38    saved_vhv_timeout: u8,
39}
40
41impl<I2C, X, EI2C, EX> Vl53l1x<I2C, X>
42where
43    I2C: embedded_hal::i2c::I2c<Error = EI2C>,
44    X: embedded_hal::digital::OutputPin<Error = EX>,
45{
46    /// Create a new instance of the VL53L1X driver. This performs a reset of
47    /// the device and may fail if the device is not present. This will use the
48    /// `x_shut` pin to select the device to be reset, then it will change that
49    /// devices' address to the provided address.
50    ///
51    /// If these sensors are being used in an array, set all the xshut pins low
52    /// prior to calling this function which will allow this to only initialize
53    /// a single sensor.
54    ///
55    /// # Errors
56    /// Forwards any errors from the I2C bus and xshut pin, as well as any
57    /// initialisation errors from the device itself.
58    pub fn new(
59        i2c: I2C,
60        mut x_shut: X,
61        address: u8,
62        delay: &mut impl embedded_hal::delay::DelayNs,
63    ) -> Result<Self, InitialisationError<EI2C, EX>> {
64        // Reset the device by driving XSHUT low for 10ms.
65        x_shut.set_low().map_err(InitialisationError::XShut)?;
66        delay.delay_ms(10);
67        x_shut.set_high().map_err(InitialisationError::XShut)?;
68        delay.delay_ms(10);
69
70        let mut this = Self {
71            i2c,
72            _x_shut: x_shut,
73            address: DEFAULT_ADDRESS,
74
75            fast_osc_frequency: 0,
76            osc_calibrate_val: 0,
77            distance_mode: imp::DistanceMode::Long,
78            calibrated: false,
79            saved_vhv_init: 0,
80            saved_vhv_timeout: 0,
81        };
82
83        this.init(delay)?;
84
85        this.set_address(address)
86            .map_err(InitialisationError::I2C)?;
87
88        this.start_continuous(50)
89            .map_err(InitialisationError::I2C)?;
90
91        Ok(this)
92    }
93
94    /// Poll the device for a new range value. Returns `None` if the device is
95    /// still measuring.
96    ///
97    /// The range is returned in millimeters.
98    ///
99    /// # Errors
100    /// Forwards any errors from the I2C bus.
101    pub fn try_read(&mut self) -> Result<Option<u16>, EI2C> {
102        self.try_read_inner()
103    }
104}