Skip to content

Commit 1645280

Browse files
authored
Merge pull request #40 from rust-embedded/cleanup/remove-sensors-from-crate
Remove sensors from crate and prepare release 0.4
2 parents a48b485 + 9271f56 commit 1645280

File tree

9 files changed

+649
-636
lines changed

9 files changed

+649
-636
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
name = "i2cdev"
44
build = "build.rs"
5-
version = "0.3.2"
5+
version = "0.4.0"
66
authors = ["Paul Osborne <[email protected]>"]
77
license = "MIT/Apache-2.0"
88
repository = "https://github.com/rust-embedded/rust-i2cdev"

README.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@ low-level system calls. The documentation for the i2cdev interace can
1313
be found at https://www.kernel.org/doc/Documentation/i2c/dev-interface and
1414
in the [lm-sensors projects](http://www.lm-sensors.org/).
1515

16+
Device driver developers should consider building on top of the
17+
[embedded-hal](https://crates.io/crates/embedded-hal) traits rather than
18+
directly coupling to this library. An implementation of those generic traits for
19+
Linux can be found in
20+
[linux-embedded-hal](https://crates.io/crates/linux-embedded-hal) which, at
21+
present, uses this crate as the backend for I2C.
22+
1623
Example/API
1724
-----------
1825

@@ -21,10 +28,7 @@ Nunchuck (which has an i2c interface).
2128
[Go View the Example](https://github.com/rust-embedded/rust-i2cdev/blob/master/examples/nunchuck.rs).
2229

2330
Here's a real quick example showing the guts of how you create
24-
device and start talking to it... This device only requires basic
25-
functions (read/write) which are done via the Read/Write traits (if
26-
you actually want to use the Wii Nunchuck you should use
27-
[`i2cdev::sensors::nunchuck::Nunchuck`][nunchuck]:
31+
device and start talking to it...
2832

2933
```rust,no_run,skeptic-template
3034
extern crate i2cdev;
@@ -59,8 +63,6 @@ fn i2cfun() -> Result<(), LinuxI2CError> {
5963
In addition to the Read/Write traits, the following methods are
6064
available via the [I2CDevice trait](https://rust-embedded.github.io/rust-i2cdev/i2cdev/core/trait.I2CDevice.html).
6165

62-
[nunchuck]: http://rust-embedded.github.io/rust-i2cdev/i2cdev/sensors/nunchuck/struct.Nunchuck.html
63-
6466
Features
6567
--------
6668

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)