mpu9250_dmp/
lib.rs

1//! A library for the MPU-9250 9-axis IMU.
2//! The MPU9250 is a combo package that includes the MPU-6500 and AK8963.
3pub mod dmp;
4mod dmp_constants;
5
6extern crate ak8963;
7use ak8963::Ak8963Reg;
8extern crate byteorder;
9use byteorder::{BigEndian, ByteOrder};
10extern crate i2cdev;
11use i2cdev::core::*;
12use i2cdev::linux::{LinuxI2CDevice, LinuxI2CError};
13#[macro_use]
14extern crate ndarray;
15use ndarray::prelude::*;
16use std::convert::From;
17use std::thread;
18use std::time;
19
20pub const G: f32 = 9.80665;
21
22pub const MPU9250_SLAVE_ADDR: u16 = 0x68;
23
24pub(crate) fn get_i2c_bus_path(i2c_bus: i32) -> String {
25    format!("/dev/i2c-{}", i2c_bus)
26}
27
28#[allow(dead_code)]
29#[derive(Clone, Copy)]
30enum Mpu9250Reg {
31    SmplrtDiv = 0x019,
32    Config = 0x1a,
33    GyroConfig = 0x1b,
34    AccelConfig = 0x1c,
35    AccelConfig2 = 0x1d,
36    FifoEn = 0x23,
37    I2cMstCtrl = 0x24,
38    I2cSlv0Addr = 0x25,
39    I2cSlv0Reg = 0x26,
40    I2cSlv0Ctrl = 0x27,
41    #[allow(dead_code)]
42    I2cSlv4Ctrl = 0x34,
43    IntPinCfg = 0x37,
44    IntEnable = 0x38,
45    #[allow(dead_code)]
46    AccelXoutH = 0x3b,
47    #[allow(dead_code)]
48    GyroConfigXoutH = 0x43,
49    I2cMstDelayCtrl = 0x67,
50    UserCtrl = 0x6a,
51    PwrMgmt1 = 0x6b,
52    FifoCountH = 0x72,
53    FifoRw = 0x74,
54    WhoAmI = 0x75,
55}
56
57impl Mpu9250Reg {
58    pub fn addr(&self) -> u8 {
59        *self as u8
60    }
61}
62
63pub trait Register {
64    fn mask(&self) -> u8;
65}
66
67enum RegI2cMstCtrl {
68    /// Full speed i2c
69    Speed400kHz,
70    I2cMstPNsr,
71    MultMstEn,
72}
73
74impl Register for RegI2cMstCtrl {
75    fn mask(&self) -> u8 {
76        match *self {
77            RegI2cMstCtrl::Speed400kHz => 0x0d,
78            RegI2cMstCtrl::I2cMstPNsr => 1 << 4,
79            RegI2cMstCtrl::MultMstEn => 1 << 7,
80        }
81    }
82}
83
84enum RegI2cSlv0Addr {
85    I2cSlv0Rnw,
86}
87
88impl Register for RegI2cSlv0Addr {
89    fn mask(&self) -> u8 {
90        match *self {
91            RegI2cSlv0Addr::I2cSlv0Rnw => 1 << 7,
92        }
93    }
94}
95
96enum RegI2cSlv0Ctrl {
97    I2cSlv0En,
98}
99
100impl Register for RegI2cSlv0Ctrl {
101    fn mask(&self) -> u8 {
102        match *self {
103            RegI2cSlv0Ctrl::I2cSlv0En => 1 << 7,
104        }
105    }
106}
107
108enum RegPwrMgmt1 {
109    Hreset,
110    Sleep,
111}
112
113impl Register for RegPwrMgmt1 {
114    fn mask(&self) -> u8 {
115        match *self {
116            RegPwrMgmt1::Sleep => 1 << 6,
117            RegPwrMgmt1::Hreset => 1 << 7,
118        }
119    }
120}
121
122enum RegIntPinCfg {
123    BypassEn,
124    Actl, // NOTE: Active Low!
125}
126
127impl Register for RegIntPinCfg {
128    fn mask(&self) -> u8 {
129        match *self {
130            RegIntPinCfg::BypassEn => 1 << 1,
131            RegIntPinCfg::Actl => 1 << 7,
132        }
133    }
134}
135
136#[allow(dead_code)]
137enum RegFifoEn {
138    Slv0,
139    Accel,
140    GyroZ,
141    GyroY,
142    GyroX,
143    Temp,
144}
145
146impl Register for RegFifoEn {
147    fn mask(&self) -> u8 {
148        match *self {
149            RegFifoEn::Slv0 => 1,
150            RegFifoEn::Accel => 1 << 3,
151            RegFifoEn::GyroZ => 1 << 4,
152            RegFifoEn::GyroY => 1 << 5,
153            RegFifoEn::GyroX => 1 << 6,
154            RegFifoEn::Temp => 1 << 7,
155        }
156    }
157}
158
159enum RegUserCtrl {
160    FifoRst,
161    DmpRst,
162    I2cMstEn,
163    FifoEn,
164    DmpEn,
165}
166
167impl Register for RegUserCtrl {
168    fn mask(&self) -> u8 {
169        match *self {
170            RegUserCtrl::FifoRst => 1 << 2,
171            RegUserCtrl::DmpRst => 1 << 3,
172            RegUserCtrl::I2cMstEn => 1 << 5,
173            RegUserCtrl::FifoEn => 1 << 6,
174            RegUserCtrl::DmpEn => 1 << 7,
175        }
176    }
177}
178
179enum RegIntEnable {
180    DmpIntEn,
181}
182
183impl Register for RegIntEnable {
184    fn mask(&self) -> u8 {
185        match *self {
186            RegIntEnable::DmpIntEn => 1 << 1,
187        }
188    }
189}
190
191#[allow(dead_code)]
192enum RegI2cMstDelayCtrl {
193    I2cSlv0DlyEn,
194    I2cSlv1DlyEn,
195    I2cSlv2DlyEn,
196    I2cSlv3DlyEn,
197    I2cSlv4DlyEn,
198    DelayEsShadow,
199}
200
201impl Register for RegI2cMstDelayCtrl {
202    fn mask(&self) -> u8 {
203        match *self {
204            RegI2cMstDelayCtrl::I2cSlv0DlyEn => 1,
205            RegI2cMstDelayCtrl::I2cSlv1DlyEn => 1 << 1,
206            RegI2cMstDelayCtrl::I2cSlv2DlyEn => 1 << 2,
207            RegI2cMstDelayCtrl::I2cSlv3DlyEn => 1 << 3,
208            RegI2cMstDelayCtrl::I2cSlv4DlyEn => 1 << 4,
209            RegI2cMstDelayCtrl::DelayEsShadow => 1 << 7,
210        }
211    }
212}
213
214#[allow(dead_code)]
215#[derive(Copy, Clone, Debug)]
216pub enum AccelFsr {
217    Opt2G,
218    Opt4G,
219    Opt8G,
220    Opt16G,
221}
222
223/// The full-scale range of the accelerometer.
224/// 2G gives the highest sensitivity, but saturates at +-2G.
225/// 16G gives the lowest sensitivity, but has the largest range.
226impl AccelFsr {
227    /// Sensitivity is the measurement of the LSB.
228    pub fn get_sensitivity_g(&self) -> f32 {
229        return match *self {
230            AccelFsr::Opt2G => 2.0,
231            AccelFsr::Opt4G => 4.0,
232            AccelFsr::Opt8G => 8.0,
233            AccelFsr::Opt16G => 16.0,
234        } / 32768.0;
235    }
236
237    // Returns sensitivity in m/s/s.
238    pub fn get_sensitivity_mss(&self) -> f32 {
239        // Repeat code from get_sensitivity_g to reduce floating point
240        // precision loss from floating point math.
241        return match *self {
242            AccelFsr::Opt2G => 2.0,
243            AccelFsr::Opt4G => 4.0,
244            AccelFsr::Opt8G => 8.0,
245            AccelFsr::Opt16G => 16.0,
246        } * G / 32768.0;
247    }
248}
249
250#[allow(dead_code)]
251#[derive(Copy, Clone, Debug)]
252pub enum AccelDlpf {
253    OptOff,
254    Opt184,
255    Opt92,
256    Opt41,
257    Opt20,
258    Opt10,
259    Opt5,
260}
261
262/// The full-scale range of the gyroscope.
263/// 250 gives the highest resolution, but saturates at +-250 degrees per second.
264/// 2000 gives the lowest resolution, but saturates at +-2000dps.
265#[allow(dead_code)]
266#[derive(Copy, Clone, Debug)]
267pub enum GyroFsr {
268    Opt250,
269    Opt500,
270    Opt1000,
271    Opt2000,
272}
273
274impl GyroFsr {
275    pub fn get_scalar(&self) -> f32 {
276        return match *self {
277            GyroFsr::Opt250 => 250.0,
278            GyroFsr::Opt500 => 500.0,
279            GyroFsr::Opt1000 => 1000.0,
280            GyroFsr::Opt2000 => 2000.0,
281        } / 32768.0;
282    }
283}
284
285#[allow(dead_code)]
286#[derive(Copy, Clone, Debug)]
287pub enum GyroDlpf {
288    OptOff,
289    Opt184,
290    Opt92,
291    Opt41,
292    Opt20,
293    Opt10,
294    Opt5,
295}
296
297pub struct Mpu9250 {
298    i2c_dev: LinuxI2CDevice,
299    pub accel_fsr: AccelFsr,
300    pub gyro_fsr: GyroFsr,
301    pub debug: bool,
302    pub ak8963_i2c_addr: u16,
303}
304
305impl Mpu9250 {
306    /// Connects to MPU-9250 and checks the WHOAMI.
307    ///
308    /// If i2c_addr is None, defaults to 0x68. From the datasheet, the chip can
309    /// be configured to respond to 0x68 or 0x69.
310    ///
311    /// If whoami is None, defaults to 0x71 per datasheet, but it is
312    /// configurable on the chip.
313    ///
314    /// If ak8963_i2c_addr is None, defaults to 0x0c.
315    ///
316    /// Configures the MPU-9250 to:
317    /// * Acceleration full-scale range: 2G
318    /// * Gyroscope full-scale range: 2000dps
319    pub fn new(
320        i2c_bus: i32,
321        i2c_addr: Option<u16>,
322        whoami: Option<u8>,
323        ak8963_i2c_addr: Option<u16>,
324    ) -> Result<Self, LinuxI2CError> {
325        let mut i2c_dev = LinuxI2CDevice::new(get_i2c_bus_path(i2c_bus), i2c_addr.unwrap_or(0x68))?;
326
327        let mut buf1 = [0u8; 1];
328        i2c_dev.write(&[Mpu9250Reg::WhoAmI.addr()])?;
329        i2c_dev.read(&mut buf1)?;
330        if buf1[0] != whoami.unwrap_or(0x71) {
331            panic!("Unexpected WHOAMI value: {:?}", buf1[0]);
332        }
333
334        let mut mpu = Self {
335            i2c_dev,
336            accel_fsr: AccelFsr::Opt2G,
337            gyro_fsr: GyroFsr::Opt2000,
338            debug: false,
339            ak8963_i2c_addr: ak8963_i2c_addr.unwrap_or(0x0c),
340        };
341        mpu.write_config()?;
342        Ok(mpu)
343    }
344
345    /// Debug mode prints various messages to stdout.
346    pub fn set_debug(&mut self, debug: bool) {
347        self.debug = debug;
348    }
349
350    /// Writes the accel and gyro FSRs to the device.
351    pub fn write_config(&mut self) -> Result<(), LinuxI2CError> {
352        let accel_fsr = self.accel_fsr.clone();
353        self.write_accel_fsr(accel_fsr)?;
354        let gyro_fsr = self.gyro_fsr.clone();
355        self.write_gyro_fsr(gyro_fsr)?;
356        Ok(())
357    }
358
359    pub fn write_accel_fsr(&mut self, accel_fsr: AccelFsr) -> Result<(), LinuxI2CError> {
360        let accel_config_byte: u8 = match accel_fsr {
361            AccelFsr::Opt2G => 0,
362            AccelFsr::Opt4G => 1,
363            AccelFsr::Opt8G => 2,
364            AccelFsr::Opt16G => 3,
365        } << 3;
366        self.i2c_dev
367            .write(&[Mpu9250Reg::AccelConfig.addr(), accel_config_byte])?;
368        self.accel_fsr = accel_fsr;
369        Ok(())
370    }
371
372    pub fn write_accel_dlpf(&mut self, accel_dlpf: AccelDlpf) -> Result<(), LinuxI2CError> {
373        let accel_config_2_byte: u8 = match accel_dlpf {
374            AccelDlpf::OptOff => 7,
375            AccelDlpf::Opt184 => 1,
376            AccelDlpf::Opt92 => 2,
377            AccelDlpf::Opt41 => 3,
378            AccelDlpf::Opt20 => 4,
379            AccelDlpf::Opt10 => 5,
380            AccelDlpf::Opt5 => 6,
381        };
382        self.i2c_dev
383            .write(&[Mpu9250Reg::AccelConfig2.addr(), accel_config_2_byte])?;
384        Ok(())
385    }
386
387    pub fn write_gyro_fsr(&mut self, gyro_fsr: GyroFsr) -> Result<(), LinuxI2CError> {
388        let gyro_config_byte: u8 = match gyro_fsr {
389            GyroFsr::Opt250 => 0,
390            GyroFsr::Opt500 => 1,
391            GyroFsr::Opt1000 => 2,
392            GyroFsr::Opt2000 => 3,
393        } << 3;
394        self.i2c_dev
395            .write(&[Mpu9250Reg::GyroConfig.addr(), gyro_config_byte])?;
396        self.gyro_fsr = gyro_fsr;
397        Ok(())
398    }
399
400    pub fn write_gyro_dlpf(&mut self, gyro_dlpf: GyroDlpf) -> Result<(), LinuxI2CError> {
401        let config_byte: u8 = match gyro_dlpf {
402            GyroDlpf::OptOff => 7,
403            GyroDlpf::Opt184 => 1,
404            GyroDlpf::Opt92 => 2,
405            GyroDlpf::Opt41 => 3,
406            GyroDlpf::Opt20 => 4,
407            GyroDlpf::Opt10 => 5,
408            GyroDlpf::Opt5 => 6,
409        };
410        self.i2c_dev
411            .write(&[Mpu9250Reg::Config.addr(), config_byte])?;
412        // Empirically, it takes around ~100-120ms for the gyro registers to
413        // contain non-zero values.
414        self.wait_for_nonzero_gyro()?;
415        Ok(())
416    }
417
418    /// When the gyro isn't initialized, the register values read zero. This
419    /// makes it easy to wait for the gyro to initialize. TODO: Is there a
420    /// ready bit we should be checking instead?
421    pub fn wait_for_nonzero_gyro(&mut self) -> Result<(), LinuxI2CError> {
422        loop {
423            let sample = self.read_sample()?;
424            if sample.gyro == array![0.0, 0.0, 0.0] {
425                thread::sleep(time::Duration::from_millis(10));
426            } else {
427                return Ok(());
428            }
429        }
430    }
431
432    /// Reads from dedicated accel & gyro registers. (Not from FIFO)
433    pub fn read_sample(&mut self) -> Result<Mpu9250Sample, LinuxI2CError> {
434        let mut buf: [u8; 14] = [0u8; 14];
435        self.i2c_dev.write(&[Mpu9250Reg::AccelXoutH.addr()])?;
436        self.i2c_dev.read(&mut buf)?;
437
438        Ok(Self::parse_accel_and_gyro_and_temp(
439            &buf,
440            self.accel_fsr.get_sensitivity_mss(),
441            self.gyro_fsr.get_scalar(),
442        ))
443    }
444
445    /// data should be a 12-byte slice.
446    /// accel: [0,5]
447    /// gyro: [6,11]
448    pub(crate) fn parse_accel_and_gyro(
449        data: &[u8],
450        accel_fsr_scalar: f32,
451        gyro_fsr_scalar: f32,
452    ) -> Mpu9250Sample {
453        let accel_v_raw = Self::buffer_to_array1x3_i16(&data[0..6]);
454        let gyro_v_raw = Self::buffer_to_array1x3_i16(&data[6..12]);
455
456        let accel_v = accel_fsr_scalar * accel_v_raw.map(|e| *e as f32);
457        let gyro_v = gyro_fsr_scalar * gyro_v_raw.map(|e| *e as f32);
458
459        Mpu9250Sample {
460            accel: accel_v,
461            accel_raw: accel_v_raw,
462            gyro: gyro_v,
463            gyro_raw: gyro_v_raw,
464        }
465    }
466
467    /// data should be a 14-byte slice.
468    /// accel: [0,5]
469    /// temp: [6,7]
470    /// gyro: [5,13]
471    pub(crate) fn parse_accel_and_gyro_and_temp(
472        data: &[u8],
473        accel_fsr_scalar: f32,
474        gyro_fsr_scalar: f32,
475    ) -> Mpu9250Sample {
476        // TODO: Does not parse temp right now.
477        let accel_v_raw = Self::buffer_to_array1x3_i16(&data[0..6]);
478        let gyro_v_raw = Self::buffer_to_array1x3_i16(&data[8..14]);
479
480        let accel_v = accel_fsr_scalar * accel_v_raw.map(|e| *e as f32);
481        let gyro_v = gyro_fsr_scalar * gyro_v_raw.map(|e| *e as f32);
482
483        Mpu9250Sample {
484            accel: accel_v,
485            accel_raw: accel_v_raw,
486            gyro: gyro_v,
487            gyro_raw: gyro_v_raw,
488        }
489    }
490
491    /// By enabling bypass, the magnetometer will be directly accessible over
492    /// the i2c bus.
493    pub fn enable_bypass(&mut self) -> Result<(), LinuxI2CError> {
494        self.i2c_dev.write(&[Mpu9250Reg::UserCtrl.addr(), 0])?;
495        self.i2c_dev.write(&[
496            Mpu9250Reg::IntPinCfg.addr(),
497            RegIntPinCfg::Actl.mask() | RegIntPinCfg::BypassEn.mask(),
498        ])?;
499        return Ok(());
500    }
501
502    pub fn disable_bypass(&mut self) -> Result<(), LinuxI2CError> {
503        self.i2c_dev
504            .write(&[Mpu9250Reg::UserCtrl.addr(), RegUserCtrl::I2cMstEn.mask()])?;
505        self.i2c_dev
506            .write(&[Mpu9250Reg::IntPinCfg.addr(), RegIntPinCfg::Actl.mask()])?;
507        Ok(())
508    }
509
510    fn buffer_to_array1x3_i16(buf: &[u8]) -> Array1<i16> {
511        array![
512            BigEndian::read_i16(&buf[0..2]),
513            BigEndian::read_i16(&buf[2..4]),
514            BigEndian::read_i16(&buf[4..6])
515        ]
516    }
517
518    /// After resetting the device, the FSR and DLPF values will need to be
519    /// set again.
520    pub fn reset(&mut self) -> Result<(), LinuxI2CError> {
521        // Write the reset bit
522        self.i2c_dev
523            .write(&[Mpu9250Reg::PwrMgmt1.addr(), RegPwrMgmt1::Hreset.mask()])?;
524
525        // Turn off all other power mgmt features
526        self.i2c_dev.write(&[Mpu9250Reg::PwrMgmt1.addr(), 0u8])?;
527
528        thread::sleep(time::Duration::from_millis(100));
529        Ok(())
530    }
531
532    pub fn power_off(&mut self) -> Result<(), LinuxI2CError> {
533        // Write the reset bit
534        self.i2c_dev
535            .write(&[Mpu9250Reg::PwrMgmt1.addr(), RegPwrMgmt1::Hreset.mask()])?;
536        // Write the sleep bit
537        self.i2c_dev
538            .write(&[Mpu9250Reg::PwrMgmt1.addr(), RegPwrMgmt1::Sleep.mask()])?;
539        Ok(())
540    }
541
542    pub fn dmp_enable(&mut self) -> Result<(), LinuxI2CError> {
543        self.dmp_interrupt_disable()?;
544
545        self.disable_bypass()?;
546
547        // TODO: Test if this really purges FIFO items
548        self.i2c_dev.write(&[Mpu9250Reg::FifoEn.addr(), 0])?;
549
550        self.dmp_interrupt_enable()?;
551
552        self.reset_fifo()?;
553        Ok(())
554    }
555
556    pub fn dmp_disable(&mut self) -> Result<(), LinuxI2CError> {
557        self.dmp_interrupt_disable()?;
558        self.i2c_dev.write(&[Mpu9250Reg::FifoEn.addr(), 0])?;
559        self.reset_fifo()?;
560        Ok(())
561    }
562
563    pub fn dmp_interrupt_enable(&mut self) -> Result<(), LinuxI2CError> {
564        self.i2c_dev
565            .write(&[Mpu9250Reg::IntEnable.addr(), RegIntEnable::DmpIntEn.mask()])?;
566        // Disable all other FIFO features (except for the DMP)
567        self.i2c_dev.write(&[Mpu9250Reg::FifoEn.addr(), 0])?;
568        Ok(())
569    }
570
571    pub fn dmp_interrupt_disable(&mut self) -> Result<(), LinuxI2CError> {
572        self.i2c_dev.write(&[Mpu9250Reg::IntEnable.addr(), 0])?;
573        // Disable all other FIFO features (except for the DMP)
574        self.i2c_dev.write(&[Mpu9250Reg::FifoEn.addr(), 0])?;
575        Ok(())
576    }
577
578    /// Sets up mag interface on Slv0 interface.
579    ///
580    /// Does not enable fifo. You must still call enable_fifo() to begin
581    /// populating the fifo with mag data.
582    ///
583    /// Assumes mag is connected to Slv0.
584    pub fn setup_mag_in_fifo(&mut self) -> Result<(), LinuxI2CError> {
585        // Enable master and clock speed
586        self.i2c_dev.write(&[
587            Mpu9250Reg::I2cMstCtrl.addr(),
588            RegI2cMstCtrl::Speed400kHz.mask()
589                | RegI2cMstCtrl::MultMstEn.mask()
590                | RegI2cMstCtrl::I2cMstPNsr.mask(),
591        ])?;
592
593        // Set slave 0 address to magnetometer i2c address
594        self.i2c_dev.write(&[
595            Mpu9250Reg::I2cSlv0Addr.addr(),
596            RegI2cSlv0Addr::I2cSlv0Rnw.mask() | self.ak8963_i2c_addr as u8,
597        ])?;
598
599        // Set mag data register to read from
600        self.i2c_dev
601            .write(&[Mpu9250Reg::I2cSlv0Reg.addr(), Ak8963Reg::Hxl.addr()])?;
602
603        // Read 7 bytes from slave 0.
604        self.i2c_dev.write(&[
605            Mpu9250Reg::I2cSlv0Ctrl.addr(),
606            RegI2cSlv0Ctrl::I2cSlv0En.mask() | 0x07,
607        ])?;
608
609        // TEST: Couldn't get this to work. It's supposed to cause slaves to
610        // be sampled less frequently than the sample rate. Don't need it.
611        //self.i2c_dev.write(&[Mpu9250Reg::I2cMstDelayCtrl.addr(), RegI2cMstDelayCtrl::I2cSlv0DlyEn.mask()])?;
612        //self.i2c_dev.write(&[Mpu9250Reg::I2cSlv4Ctrl.addr(), 100u8])?;
613
614        Ok(())
615    }
616
617    /// rate is specified as the number of samples per second (Hz).
618    /// It controls the rate the FIFO is populated by the MPU. It also sets
619    /// the upper bound rate the FIFO is populated by the DMP.
620    /// Note: Per the docs, this only works if internal sampling is set to
621    /// 1kHz.
622    pub fn set_sample_rate(&mut self, rate: u16) -> Result<(), LinuxI2CError> {
623        if rate > 1000 || rate < 4 {
624            panic!("Error: Invalid sample rate.");
625        }
626
627        // Derived from: Sample Rate = Internal Sample Rate / (1 + SMPLRT_DIV)
628        let smplrt_div = (1000 / rate) as u8 - 1;
629        self.i2c_dev
630            .write(&[Mpu9250Reg::SmplrtDiv.addr(), smplrt_div])?;
631        Ok(())
632    }
633
634    /// Disables and then re-enables the fifo.
635    /// This clears the contents of the fifo.
636    pub fn reset_fifo(&mut self) -> Result<(), LinuxI2CError> {
637        self.disable_fifo()?;
638        self.enable_fifo()?;
639        Ok(())
640    }
641
642    /// Enables interrupt and fifo.
643    pub fn enable_fifo(&mut self) -> Result<(), LinuxI2CError> {
644        self.i2c_dev
645            .write(&[Mpu9250Reg::IntEnable.addr(), RegIntEnable::DmpIntEn.mask()])?;
646        self.i2c_dev
647            .write(&[Mpu9250Reg::FifoEn.addr(), RegFifoEn::Slv0.mask()])?;
648        self.i2c_dev.write(&[
649            Mpu9250Reg::UserCtrl.addr(),
650            RegUserCtrl::I2cMstEn.mask() | RegUserCtrl::FifoEn.mask() | RegUserCtrl::DmpEn.mask(),
651        ])?;
652
653        Ok(())
654    }
655
656    /// Disables interrupt and fifo.
657    /// Also resets the fifo and dmp.
658    pub fn disable_fifo(&mut self) -> Result<(), LinuxI2CError> {
659        self.i2c_dev.write(&[Mpu9250Reg::IntEnable.addr(), 0])?;
660        self.i2c_dev.write(&[Mpu9250Reg::FifoEn.addr(), 0])?;
661        self.i2c_dev.write(&[
662            Mpu9250Reg::UserCtrl.addr(),
663            RegUserCtrl::FifoRst.mask() | RegUserCtrl::DmpRst.mask(),
664        ])?;
665        Ok(())
666    }
667
668    /// Returns the number of bytes in the fifo.
669    fn read_fifo_byte_count(&mut self) -> Result<u16, LinuxI2CError> {
670        let mut data = [0u8; 2];
671        self.i2c_dev.write(&[Mpu9250Reg::FifoCountH.addr()])?;
672        self.i2c_dev.read(&mut data)?;
673
674        // Technically only bits 0-12 are valid, so let's be paranoid and
675        // zero out higher bits.
676        data[0] = data[0] & 0x1f;
677        let length: u16 = BigEndian::read_u16(&data);
678        if self.debug {
679            println!("FIFO byte count: {:?}", length);
680        }
681        Ok(length)
682    }
683
684    /// Reads exactly count bytes from the fifo.
685    pub fn read_fifo_strict(&mut self, count: u16) -> Result<Vec<u8>, FifoReadError> {
686        let available_bytes = self.read_fifo_byte_count()?;
687        if available_bytes < count {
688            return Err(FifoReadError::InsufficientData(available_bytes));
689        }
690
691        let mut data = vec![0; count as usize];
692        self.i2c_dev.write(&[Mpu9250Reg::FifoRw.addr()])?;
693        self.i2c_dev.read(&mut data)?;
694        Ok(data)
695    }
696}
697
698#[derive(Clone, Debug)]
699pub struct Mpu9250Sample {
700    pub accel: Array1<f32>,
701    pub accel_raw: Array1<i16>,
702    pub gyro: Array1<f32>,
703    pub gyro_raw: Array1<i16>,
704}
705
706#[derive(Debug)]
707pub enum FifoReadError {
708    InsufficientData(u16),
709    I2c(LinuxI2CError),
710}
711
712impl From<LinuxI2CError> for FifoReadError {
713    fn from(e: LinuxI2CError) -> Self {
714        FifoReadError::I2c(e)
715    }
716}
717
718#[cfg(test)]
719mod tests {
720    use super::Mpu9250;
721    use std::env;
722
723    fn get_i2c_bus() -> i32 {
724        match env::var("MPU9250_I2C_BUS") {
725            Ok(bus_string) => bus_string
726                .parse()
727                .expect("Could not convert MPU9250_I2C_BUS env var to i32."),
728            Err(_) => 1,
729        }
730    }
731
732    fn get_i2c_addr() -> Option<u16> {
733        match env::var("MPU9250_I2C_ADDR") {
734            Ok(addr_string) => Some(
735                addr_string
736                    .parse()
737                    .expect("Could not convert MPU9250_I2C_ADDR env var to u16."),
738            ),
739            Err(_) => None,
740        }
741    }
742
743    fn get_whoami() -> Option<u8> {
744        match env::var("MPU9250_WHOAMI") {
745            Ok(whoami_string) => Some(
746                whoami_string
747                    .parse()
748                    .expect("Could not convert MPU9250_WHOAMI env var to u8."),
749            ),
750            Err(_) => None,
751        }
752    }
753
754    fn get_ak8963_i2c_addr() -> Option<u16> {
755        match env::var("AK8963_I2C_ADDR") {
756            Ok(addr_string) => Some(
757                addr_string
758                    .parse()
759                    .expect("Could not convert AK8963_I2C_ADDR env var to u16."),
760            ),
761            Err(_) => None,
762        }
763    }
764
765    #[test]
766    fn basic() {
767        let mut mpu9250 = Mpu9250::new(
768            get_i2c_bus(),
769            get_i2c_addr(),
770            get_whoami(),
771            get_ak8963_i2c_addr(),
772        ).expect("Could not connect to MPU9250");
773        mpu9250.read_sample().unwrap();
774    }
775}