Skip to content

Commit 97c14ef

Browse files
committed
Remove "sensors" from crate, converting them back to examples
Including the sensor support in this crate did not make sense, but the code that exists is still pretty handy as a reference. This commit gets rid of all sensor traits and sensors from this crate and moves the code to live in examples as a reference (pretty directly pasted back into example files as a start). Signed-off-by: Paul Osborne <[email protected]>
1 parent a48b485 commit 97c14ef

File tree

7 files changed

+640
-629
lines changed

7 files changed

+640
-629
lines changed

examples/nunchuck.rs

Lines changed: 190 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,194 @@
77
// except according to those terms.
88

99
// Reads data from Wii Nunchuck
10+
//
11+
// NOTE: This code is provided as an example. Driver developers are encouraged
12+
// to use the embedded-hal traits if possible rather than coupling directly
13+
// to this library. An implementation of the embedded-hal I2C traits based
14+
// on this library may be found in the embedded-hal-linux project.
1015

11-
extern crate i2cdev;
1216
extern crate docopt;
17+
extern crate i2cdev;
1318

1419
#[cfg(any(target_os = "linux", target_os = "android"))]
1520
use i2cdev::linux::*;
21+
22+
#[cfg(any(target_os = "linux", taret_os = "android"))]
23+
mod nunchuck {
24+
use std::error::Error;
25+
use std::thread;
26+
use std::time::Duration;
27+
use std::fmt;
28+
29+
use i2cdev::core::I2CDevice;
30+
31+
pub const NUNCHUCK_SLAVE_ADDR: u16 = 0x52;
32+
33+
#[derive(Debug)]
34+
pub enum NunchuckError<E> {
35+
Error(E),
36+
ParseError,
37+
}
38+
39+
impl<E: Error> fmt::Display for NunchuckError<E> {
40+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
41+
match *self {
42+
NunchuckError::Error(ref e) => fmt::Display::fmt(e, f),
43+
NunchuckError::ParseError => fmt::Display::fmt(self.description(), f),
44+
}
45+
}
46+
}
47+
48+
impl<E: Error> Error for NunchuckError<E> {
49+
fn description(&self) -> &str {
50+
match *self {
51+
NunchuckError::Error(ref e) => e.description(),
52+
NunchuckError::ParseError => "Unable to Parse Data",
53+
}
54+
}
55+
56+
fn cause(&self) -> Option<&Error> {
57+
match *self {
58+
NunchuckError::Error(ref e) => Some(e),
59+
NunchuckError::ParseError => None,
60+
}
61+
}
62+
}
63+
64+
// TODO: Move Nunchuck code out to be an actual sensor and add tests
65+
66+
#[derive(Debug)]
67+
pub struct NunchuckReading {
68+
joystick_x: u8,
69+
joystick_y: u8,
70+
accel_x: u16, // 10-bit
71+
accel_y: u16, // 10-bit
72+
accel_z: u16, // 10-bit
73+
c_button_pressed: bool,
74+
z_button_pressed: bool,
75+
}
76+
77+
impl NunchuckReading {
78+
pub fn from_data(data: &[u8]) -> Option<NunchuckReading> {
79+
if data.len() < 6 {
80+
None
81+
} else {
82+
Some(NunchuckReading {
83+
joystick_x: data[0],
84+
joystick_y: data[1],
85+
accel_x: (data[2] as u16) << 2 | ((data[5] as u16 >> 6) & 0b11),
86+
accel_y: (data[3] as u16) << 2 | ((data[5] as u16 >> 4) & 0b11),
87+
accel_z: (data[4] as u16) << 2 | ((data[5] as u16 >> 2) & 0b11),
88+
c_button_pressed: (data[5] & 0b10) == 0,
89+
z_button_pressed: (data[5] & 0b01) == 0,
90+
})
91+
}
92+
}
93+
}
94+
95+
pub struct Nunchuck<T: I2CDevice> {
96+
i2cdev: T,
97+
}
98+
99+
impl<T> Nunchuck<T>
100+
where
101+
T: I2CDevice,
102+
{
103+
/// Create a new Wii Nunchuck
104+
///
105+
/// This method will open the provide i2c device file and will
106+
/// send the required init sequence in order to read data in
107+
/// the future.
108+
pub fn new(i2cdev: T) -> Result<Nunchuck<T>, T::Error> {
109+
let mut nunchuck = Nunchuck { i2cdev: i2cdev };
110+
try!(nunchuck.init());
111+
Ok(nunchuck)
112+
}
113+
114+
#[cfg(test)]
115+
pub fn get_i2cdev(&mut self) -> &mut T {
116+
&mut self.i2cdev
117+
}
118+
119+
/// Send the init sequence to the Wii Nunchuck
120+
pub fn init(&mut self) -> Result<(), T::Error> {
121+
// These registers must be written; the documentation is a bit
122+
// lacking but it appears this is some kind of handshake to
123+
// perform unencrypted data tranfers
124+
try!(self.i2cdev.smbus_write_byte_data(0xF0, 0x55));
125+
try!(self.i2cdev.smbus_write_byte_data(0xFB, 0x00));
126+
Ok(())
127+
}
128+
129+
pub fn read(&mut self) -> Result<NunchuckReading, NunchuckError<T::Error>> {
130+
let mut buf: [u8; 6] = [0; 6];
131+
132+
// tell the nunchuck to prepare a sample
133+
try!(
134+
self.i2cdev
135+
.smbus_write_byte(0x00)
136+
.map_err(NunchuckError::Error)
137+
);
138+
139+
// now, read it!
140+
thread::sleep(Duration::from_millis(10));
141+
try!(self.i2cdev.read(&mut buf).map_err(NunchuckError::Error));
142+
NunchuckReading::from_data(&buf).ok_or(NunchuckError::ParseError)
143+
}
144+
}
145+
146+
#[cfg(test)]
147+
mod test {
148+
use super::*;
149+
use i2cdev::core::I2CDevice;
150+
use i2cdev::mock::MockI2CDevice;
151+
152+
#[test]
153+
fn test_intialization() {
154+
// write out some "bad" values to start out with so we know the
155+
// write happens
156+
let mut i2cdev = MockI2CDevice::new();
157+
i2cdev.smbus_write_byte_data(0xF0, 0xFF).unwrap();
158+
i2cdev.smbus_write_byte_data(0xFB, 0xFF).unwrap();
159+
160+
// these values must be written out for things to work
161+
let mut dev = Nunchuck::new(i2cdev).unwrap();
162+
assert_eq!(dev.get_i2cdev().smbus_read_byte_data(0xF0).unwrap(), 0x55);
163+
assert_eq!(dev.get_i2cdev().smbus_read_byte_data(0xFB).unwrap(), 0x00);
164+
}
165+
166+
#[test]
167+
fn test_read_zeroed_out() {
168+
let mut dev = Nunchuck::new(MockI2CDevice::new()).unwrap();
169+
let reading = dev.read().unwrap();
170+
assert_eq!(reading.joystick_x, 0);
171+
assert_eq!(reading.joystick_y, 0);
172+
assert_eq!(reading.accel_x, 0);
173+
assert_eq!(reading.accel_y, 0);
174+
assert_eq!(reading.accel_z, 0);
175+
assert_eq!(reading.c_button_pressed, true);
176+
assert_eq!(reading.z_button_pressed, true);
177+
}
178+
179+
#[test]
180+
fn test_read_sample_data() {
181+
let mut i2cdev = MockI2CDevice::new();
182+
i2cdev.write(&[0, 127, 128, 191, 129, 144, 71]).unwrap();
183+
let mut dev = Nunchuck::new(i2cdev).unwrap();
184+
let reading = dev.read().unwrap();
185+
assert_eq!(reading.joystick_x, 127);
186+
assert_eq!(reading.joystick_y, 128);
187+
assert_eq!(reading.accel_x, 765);
188+
assert_eq!(reading.accel_y, 516);
189+
assert_eq!(reading.accel_z, 577);
190+
assert_eq!(reading.c_button_pressed, false);
191+
assert_eq!(reading.z_button_pressed, false);
192+
}
193+
}
194+
}
195+
16196
#[cfg(any(target_os = "linux", target_os = "android"))]
17-
use i2cdev::sensors::nunchuck::*;
197+
use nunchuck::*;
18198

19199
use std::env::args;
20200
use docopt::Docopt;
@@ -38,21 +218,19 @@ fn main() {}
38218
#[cfg(any(target_os = "linux", target_os = "android"))]
39219
fn main() {
40220
let args = Docopt::new(USAGE)
41-
.and_then(|d| d.argv(args().into_iter()).parse())
42-
.unwrap_or_else(|e| e.exit());
221+
.and_then(|d| d.argv(args().into_iter()).parse())
222+
.unwrap_or_else(|e| e.exit());
43223
let device = args.get_str("<device>");
44224
let i2cdev = LinuxI2CDevice::new(device, NUNCHUCK_SLAVE_ADDR).unwrap();
45225
match Nunchuck::new(i2cdev) {
46226
Err(err) => {
47227
println!("Unable to open {:?}, {:?}", device, err);
48228
}
49-
Ok(mut nunchuck) => {
50-
loop {
51-
match nunchuck.read() {
52-
Ok(reading) => println!("{:?}", reading),
53-
Err(err) => println!("Error: {:?}", err),
54-
};
55-
}
56-
}
229+
Ok(mut nunchuck) => loop {
230+
match nunchuck.read() {
231+
Ok(reading) => println!("{:?}", reading),
232+
Err(err) => println!("Error: {:?}", err),
233+
};
234+
},
57235
}
58236
}

0 commit comments

Comments
 (0)