1#![allow(dead_code)]
13
14extern crate i2cdev;
15extern crate i2csensors;
16extern crate byteorder;
17
18use i2csensors::{Magnetometer,Accelerometer};
19use i2csensors::Vec3;
20use std::thread;
21use std::time::Duration;
22use std::error::Error;
23use i2cdev::core::I2CDevice;
24use byteorder::{ByteOrder, LittleEndian};
25#[cfg(any(target_os = "linux", target_os = "android"))]
26use i2cdev::linux::{LinuxI2CDevice,LinuxI2CError};
27
28pub const LSM303D_I2C_ADDR: u16 = 0x1E;
29
30const LSM303D_WHO_AM_I: u8 = 0x0F;
31const LSM303D_ID: u8 = 0b01001001;
32
33const LSM303D_INCREMENT_BIT: u8 = 0x80;
34const LSM303D_OUT_MAG: u8 = 0x08;
35const LSM303D_OUT_ACC: u8 = 0x28;
36
37const LSM303D_CTRL1: u8 = 0x20;
38const LSM303D_CTRL2: u8 = 0x21;
39const LSM303D_CTRL5: u8 = 0x24;
40const LSM303D_CTRL6: u8 = 0x25;
41const LSM303D_CTRL7: u8 = 0x26;
42
43#[derive(Debug, Copy, Clone)]
44pub enum LSM303DAccelerometerUpdateRate {
45 PowerDown = 0b0000,
46 Hz3_125 = 0b0001,
47 Hz6_25 = 0b0010,
48 Hz12_5 = 0b0011,
49 Hz25 = 0b0100,
50 Hz50 = 0b0101,
51 Hz100 = 0b0110,
52 Hz200 = 0b0111,
53 Hz400 = 0b1000,
54 Hz800 = 0b1001,
55 Hz1600 = 0b1010
56}
57
58#[derive(Debug, Copy, Clone)]
59pub enum LSM303DAccelerometerFilterBandwidth {
60 Hz773 = 0b00,
61 Hz194 = 0b01,
62 Hz362 = 0b10,
63 Hz50 = 0b11
64}
65
66#[derive(Debug, Copy, Clone)]
67pub enum LSM303DAccelerometerFS {
68 g2 = 0b000,
69 g4 = 0b001,
70 g6 = 0b010,
71 g8 = 0b011,
72 g16 = 0b100
73}
74
75#[derive(Debug, Copy, Clone)]
76pub enum LSM303DMagnetometerMode {
77 ContinuousConversion = 0b00,
78 SingleConversion = 0b01,
79 PowerDown = 0b10
80}
81
82#[derive(Debug, Copy, Clone)]
83pub enum LSM303DMagnetometerResolution {
84 Low = 0b00,
85 MediumLow = 0b01,
86 MediumHigh = 0b10,
87 High = 0b11
88}
89
90#[derive(Debug, Copy, Clone)]
91pub enum LSM303DMagnetometerUpdateRate {
92 Hz3_125 = 0b000,
93 Hz6_25 = 0b001,
94 Hz12_5 = 0b010,
95 Hz25 = 0b011,
96 Hz50 = 0b100,
97 Hz100 = 0b101
98}
99
100#[derive(Debug, Copy, Clone)]
101pub enum LSM303DMagnetometerFS {
102 gauss2 = 0b00,
103 gauss4 = 0b01,
104 gauss8 = 0b10,
105 gauss12 = 0b11
106}
107
108#[derive(Debug, Copy, Clone)]
110pub struct LSM303DSettings {
111 pub continuous_update: bool,
113 pub accelerometer_data_rate: LSM303DAccelerometerUpdateRate,
116 pub accelerometer_anti_alias_filter_bandwidth: LSM303DAccelerometerFilterBandwidth,
117 pub azen: bool,
119 pub ayen: bool,
121 pub axen: bool,
123 pub accelerometer_sensitivity: LSM303DAccelerometerFS,
125 pub magnetometer_resolution: LSM303DMagnetometerResolution,
127 pub magnetometer_data_rate: LSM303DMagnetometerUpdateRate,
129 pub magnetometer_low_power_mode: bool,
130 pub magnetometer_mode: LSM303DMagnetometerMode,
131 pub magnetometer_sensitivity: LSM303DMagnetometerFS
133}
134
135#[cfg(any(target_os = "linux", target_os = "android"))]
137pub fn get_linux_lsm303d_i2c_device() -> Result<LinuxI2CDevice,LinuxI2CError> {
138 let device = try!(LinuxI2CDevice::new("/dev/i2c-1", LSM303D_I2C_ADDR));
139 Ok(device)
140}
141
142pub struct LSM303D<T: I2CDevice + Sized> {
143 accelerometer_magnetometer: T,
144 m_gain: f32,
145 a_gain: f32
146}
147
148impl<T> LSM303D<T>
149 where T: I2CDevice + Sized
150{
151 #[cfg(any(target_os = "linux", target_os = "android"))]
152 pub fn new(mut accel_mag: T, mut accel_mag_settings: LSM303DSettings) -> Result<LSM303D<T>, T::Error> {
153 assert!(try!(accel_mag.smbus_read_byte_data(LSM303D_WHO_AM_I)) == LSM303D_ID, "LSM303D ID didn't match for device at given I2C address.");
154
155 let mut ctrl_reg1: u8 = 0_u8 | ((accel_mag_settings.accelerometer_data_rate as u8) << 4);
156 if !accel_mag_settings.continuous_update {
157 ctrl_reg1 |= 0b00001000;
158 }
159 if accel_mag_settings.axen { ctrl_reg1 |= 0b001 };
160 if accel_mag_settings.ayen { ctrl_reg1 |= 0b010 };
161 if accel_mag_settings.azen { ctrl_reg1 |= 0b100 };
162 try!(accel_mag.smbus_write_byte_data(LSM303D_CTRL1, ctrl_reg1));
163
164 let mut ctrl_reg2: u8 = 0_u8 | ((accel_mag_settings.accelerometer_sensitivity as u8) << 3) | ((accel_mag_settings.accelerometer_anti_alias_filter_bandwidth as u8) << 6);
165 try!(accel_mag.smbus_write_byte_data(LSM303D_CTRL2, ctrl_reg2));
166
167 let mut ctrl_reg5: u8 = 0_u8 | ((accel_mag_settings.magnetometer_resolution as u8) << 5) | ((accel_mag_settings.magnetometer_data_rate as u8) << 2); try!(accel_mag.smbus_write_byte_data(LSM303D_CTRL5, ctrl_reg5));
169
170 let mut ctrl_reg6: u8 = 0_u8 | ((accel_mag_settings.magnetometer_sensitivity as u8) << 5);
171 try!(accel_mag.smbus_write_byte_data(LSM303D_CTRL6, ctrl_reg6));
172
173 let mut ctrl_reg7: u8 = 0_u8 | (accel_mag_settings.magnetometer_mode as u8);
174 if accel_mag_settings.magnetometer_low_power_mode {
175 ctrl_reg7 |= 0b00000100;
176 }
177 try!(accel_mag.smbus_write_byte_data(LSM303D_CTRL7, ctrl_reg7));
178
179 let mut a_gain: f32;
180 let mut m_gain: f32;
181
182 match accel_mag_settings.magnetometer_sensitivity {
183 LSM303DMagnetometerFS::gauss2 => {
184 m_gain = 0.08;
185 },
186 LSM303DMagnetometerFS::gauss4 => {
187 m_gain = 0.160;
188 },
189 LSM303DMagnetometerFS::gauss8 => {
190 m_gain = 0.320;
191 },
192 LSM303DMagnetometerFS::gauss12 => {
193 m_gain = 0.479;
194 }
195 }
196
197 match accel_mag_settings.accelerometer_sensitivity {
198 LSM303DAccelerometerFS::g2 => {
199 a_gain = 0.061;
200 },
201 LSM303DAccelerometerFS::g4 => {
202 a_gain = 0.122;
203 },
204 LSM303DAccelerometerFS::g6 => {
205 a_gain = 0.183;
206 },
207 LSM303DAccelerometerFS::g8 => {
208 a_gain = 0.244;
209 },
210 LSM303DAccelerometerFS::g16 => {
211 a_gain = 0.732;
212 }
213 }
214
215 Ok(LSM303D {
216 accelerometer_magnetometer: accel_mag,
217 m_gain: m_gain / 1000.0,
218 a_gain: a_gain / 1000.0
219 })
220 }
221
222 #[cfg(any(target_os = "linux", target_os = "android"))]
223 fn magnetometer_read_raw(&mut self) -> Result<(i16, i16, i16), T::Error> {
224 let mut buf: [u8; 6] = [0;6];
225 try!(self.accelerometer_magnetometer.write(&[LSM303D_INCREMENT_BIT | LSM303D_OUT_MAG]));
226 try!(self.accelerometer_magnetometer.read(&mut buf));
227 let x_raw = LittleEndian::read_i16(&buf[0..2]);
228 let y_raw = LittleEndian::read_i16(&buf[2..4]);
229 let z_raw = LittleEndian::read_i16(&buf[4..6]);
230 Ok((x_raw, y_raw, z_raw))
231 }
232
233 #[cfg(any(target_os = "linux", target_os = "android"))]
234 fn accelerometer_read_raw(&mut self) -> Result<(i16, i16, i16), T::Error> {
235 let mut buf: [u8; 6] = [0;6];
236 try!(self.accelerometer_magnetometer.write(&[LSM303D_INCREMENT_BIT | LSM303D_OUT_ACC]));
237 try!(self.accelerometer_magnetometer.read(&mut buf));
238 let x_raw = LittleEndian::read_i16(&buf[0..2]);
239 let y_raw = LittleEndian::read_i16(&buf[2..4]);
240 let z_raw = LittleEndian::read_i16(&buf[4..6]);
241 Ok((x_raw, y_raw, z_raw))
242 }
243}
244
245impl<T> Magnetometer for LSM303D<T>
246 where T: I2CDevice + Sized
247{
248 type Error = T::Error;
249
250 #[cfg(not(any(target_os = "linux", target_os = "android")))]
251 fn magnetic_reading(&mut self) -> Result<Vec3, T::Error> {
252 Ok(Vec3::zeros())
253 }
254
255 #[cfg(any(target_os = "linux", target_os = "android"))]
257 fn magnetic_reading(&mut self) -> Result<Vec3, T::Error> {
258 let (x_raw, y_raw, z_raw) = try!(self.magnetometer_read_raw());
259 Ok(Vec3 {
260 x: x_raw as f32 * self.m_gain,
261 y: y_raw as f32 * self.m_gain,
262 z: z_raw as f32 * self.m_gain
263 })
264 }
265}
266
267impl<T> Accelerometer for LSM303D<T>
268 where T: I2CDevice + Sized
269{
270 type Error = T::Error;
271
272 #[cfg(not(any(target_os = "linux", target_os = "android")))]
273 fn acceleration_reading(&mut self) -> Result<Vec3, T::Error> {
274 Ok(Vec3::zeros())
275 }
276
277 #[cfg(any(target_os = "linux", target_os = "android"))]
279 fn acceleration_reading(&mut self) -> Result<Vec3, T::Error> {
280 let (x_raw, y_raw, z_raw) = try!(self.accelerometer_read_raw());
281 Ok(Vec3 {
282 x: x_raw as f32 * self.a_gain,
283 y: y_raw as f32 * self.a_gain,
284 z: z_raw as f32 * self.a_gain
285 })
286 }
287}
288
289#[cfg(test)]
290mod tests {
291 #[test]
292 fn it_works() {
293 }
294}