mc3479/
lib.rs

1#![no_std]
2//! # MC3479
3//!
4//! A Rust driver for the MEMSIC MC3479 16-bit 3-axis accelerometer.
5//!
6//! The device has two different operational states, standby and wake, and reconfiguring the device
7//! is only allowed in the standby state.  These two states are realized in the form of two
8//! different Rust types, [`StandbyState`] and [`WakeState`], with methods that allow for
9//! transitioning from one state to the other.
10//!
11//! ## Example
12//!
13//! ```rust
14//! # use embedded_hal::i2c::I2c;
15//! # use mc3479::{SampleRate, Range, TargetAddr};
16//! # fn example<I2C: I2c>(i2c: I2C) {
17//! let mut standby = match mc3479::StandbyState::new(i2c, TargetAddr::Addr0) {
18//!     Ok(standby) => standby,
19//!     Err((err, _i2c)) => {
20//!         panic!("Failed to initialize MC3479 driver: {err}");
21//!     },
22//! };
23//! standby.set_sample_rate(SampleRate::_1000Hz).unwrap();
24//! standby.set_range(Range::_8g).unwrap();
25//! standby.set_fifo_enabled(true).unwrap();
26//! let wake = match standby.wake() {
27//!     Ok(wake) => wake,
28//!     Err((err, _standby)) => panic!("Failed to transition to wake state: {err}"),
29//! };
30//! # }
31//! ```
32
33use core::{error::Error, fmt::Debug, fmt::Display};
34
35pub use crate::{
36    inner::{
37        fifo_control_register::FifoControl, fifo_status_register::FifoStatus,
38        range_register::Range, sample_rate_register::SampleRate,
39    },
40    standby_state::{InitializationError, StandbyState},
41    wake_state::WakeState,
42};
43
44mod inner;
45mod standby_state;
46mod wake_state;
47
48/// Expected chip ID of the device.
49pub const MC3479_CHIP_ID: u8 = 0xA4;
50
51/// # I2C address of the target
52///
53/// The device is available either at address 0x4C or 0x6C depending on whether or not the
54/// `DOUT_A6` pin is tied low or high.
55#[derive(Clone, Copy, Debug)]
56#[repr(u8)]
57pub enum TargetAddr {
58    Addr0 = 0x4C,
59    Addr1 = 0x6C,
60}
61
62#[derive(Clone, Copy, Debug)]
63pub enum Register {
64    DevStat = 0x05,
65    Mode = 0x07,
66    SampleRate = 0x08,
67    FifoStatus = 0x0A,
68    XoutLow = 0x0D,
69    ChipId = 0x18,
70    RangeAndScaleCtrl = 0x20,
71    FifoControl = 0x2D,
72}
73
74/// Accelerometer sensor values expressed in milli g-force.
75pub struct AccelerometerData {
76    pub x_mg: f32,
77    pub y_mg: f32,
78    pub z_mg: f32,
79}
80
81#[derive(Debug)]
82pub struct I2cReadError<I2cError> {
83    pub register: Register,
84    pub source: I2cError,
85}
86
87impl<I2cError> Display for I2cReadError<I2cError> {
88    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> ::core::fmt::Result {
89        write!(
90            f,
91            "Could not read from register {:?} ({:#X})",
92            self.register, self.register as u8,
93        )
94    }
95}
96
97impl<I2cError> Error for I2cReadError<I2cError>
98where
99    Self: Debug,
100{
101    // We can't implement `source` because `embedded_hal::i2c::Error` doesn't require
102    // `core::error::Error`
103}
104
105#[derive(Debug)]
106pub struct I2cWriteError<I2cError> {
107    pub register: Register,
108    pub source: I2cError,
109}
110
111impl<I2cError> Display for I2cWriteError<I2cError> {
112    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> ::core::fmt::Result {
113        write!(
114            f,
115            "Could not write to register {:?} ({:#X})",
116            self.register, self.register as u8,
117        )
118    }
119}
120
121impl<I2cError> Error for I2cWriteError<I2cError>
122where
123    Self: Debug,
124{
125    // We can't implement `source` because `embedded_hal::i2c::Error` doesn't require
126    // `core::error::Error`
127}