1
- //! # A driver for the Raspberry Pi Sense HAT
1
+ //! # Rust support for the Raspberry Pi Sense HAT.
2
2
//!
3
- //! The [Sense HAT](https://www.raspberrypi.org/products/sense-hat/) is a
4
- //! sensor board for the Raspberry Pi. It features an LED matrix, a humidity
5
- //! and temperature sensor, a pressure and temperature sensor and a gyroscope.
3
+ //! The [Raspberry Pi Sense
4
+ //! HAT](https://www.raspberrypi.org/products/sense-hat/) is a sensor board
5
+ //! for the Raspberry Pi. It features an LED matrix, a humidity and
6
+ //! temperature sensor, a pressure and temperature sensor, a joystick and a
7
+ //! gyroscope. See <https://www.raspberrypi.org/products/sense-hat/> for
8
+ //! details on the Sense HAT.
6
9
//!
7
- //! Supported components:
10
+ //! See <https://github.com/RPi-Distro/python-sense-hat> for the official
11
+ //! Python driver. This one tries to follow the same API as the Python
12
+ //! version.
13
+ //!
14
+ //! See <https://github.com/thejpster/pi-workshop-rs/> for some workshop
15
+ //! materials which use this driver.
16
+ //!
17
+ //! ## Supported components:
8
18
//!
9
19
//! * Humidity and Temperature Sensor (an HTS221)
10
20
//! * Pressure and Temperature Sensor (a LPS25H)
11
21
//! * Gyroscope (an LSM9DS1, requires the RTIMU library)
22
+ //! * LED matrix (partial support for scrolling text only)
12
23
//!
13
- //! Currently unsupported components:
24
+ //! ## Currently unsupported components:
14
25
//!
15
- //! * LED matrix
16
26
//! * Joystick
27
+ //!
28
+ //! ## Example use
29
+ //!
30
+ //! ```
31
+ //! use sensehat::{Colour, SenseHat};
32
+ //! if let Ok(mut hat) = SenseHat::new() {
33
+ //! println!("{:?}", hat.get_pressure());
34
+ //! hat.text("Hi!", Colour::RED, Colour::WHITE).unwrap();
35
+ //! }
36
+ //! ```
17
37
18
38
extern crate byteorder;
19
39
extern crate i2cdev;
20
40
extern crate measurements;
41
+ #[ cfg( feature = "led-matrix" ) ]
42
+ extern crate tint;
21
43
22
44
#[ cfg( feature = "rtimu" ) ]
23
45
extern crate libc;
@@ -44,27 +66,31 @@ mod lsm9ds1_dummy;
44
66
#[ cfg( not( feature = "rtimu" ) ) ]
45
67
use lsm9ds1_dummy as lsm9ds1;
46
68
47
- /// Represents an orientation from the IMU
69
+ #[ cfg( feature = "led-matrix" ) ]
70
+ use sensehat_screen:: color:: PixelColor ;
71
+
72
+ /// Represents an orientation from the IMU.
48
73
#[ derive( Debug , Copy , Clone ) ]
49
74
pub struct Orientation {
50
75
pub roll : Angle ,
51
76
pub pitch : Angle ,
52
77
pub yaw : Angle ,
53
78
}
54
79
55
- /// Represents a 3D vector
80
+ /// Represents a 3D vector.
56
81
#[ derive( Debug , Copy , Clone ) ]
57
82
pub struct Vector3D {
58
83
pub x : f64 ,
59
84
pub y : f64 ,
60
85
pub z : f64 ,
61
86
}
62
87
63
- /// Represents an RGB colour
88
+ /// Represents an RGB colour.
64
89
#[ cfg( feature = "led-matrix" ) ]
65
- pub use sensehat_screen:: color:: PixelColor as Colour ;
90
+ #[ derive( Debug , Copy , Clone , PartialEq ) ]
91
+ pub struct Colour ( PixelColor ) ;
66
92
67
- /// A collection of all the data from the IMU
93
+ /// A collection of all the data from the IMU.
68
94
#[ derive( Debug , Default ) ]
69
95
struct ImuData {
70
96
timestamp : u64 ,
@@ -77,30 +103,30 @@ struct ImuData {
77
103
humidity : Option < f64 > ,
78
104
}
79
105
80
- /// Represents the Sense HAT itself
106
+ /// Represents the Sense HAT itself.
81
107
pub struct SenseHat < ' a > {
82
- /// LPS25H pressure sensor
108
+ /// LPS25H pressure sensor.
83
109
pressure_chip : lps25h:: Lps25h < LinuxI2CDevice > ,
84
- /// HTS221 humidity sensor
110
+ /// HTS221 humidity sensor.
85
111
humidity_chip : hts221:: Hts221 < LinuxI2CDevice > ,
86
- /// LSM9DS1 IMU device
112
+ /// LSM9DS1 IMU device.
87
113
accelerometer_chip : lsm9ds1:: Lsm9ds1 < ' a > ,
88
- /// Cached data
114
+ /// Cached accelerometer data.
89
115
data : ImuData ,
90
116
}
91
117
92
- /// Errors that this crate can return
118
+ /// Errors that this crate can return.
93
119
#[ derive( Debug ) ]
94
120
pub enum SenseHatError {
95
121
NotReady ,
96
122
GenericError ,
97
123
I2CError ( LinuxI2CError ) ,
98
124
LSM9DS1Error ( lsm9ds1:: Error ) ,
99
125
ScreenError ,
100
- CharacterError ( std:: string:: FromUtf16Error )
126
+ CharacterError ( std:: string:: FromUtf16Error ) ,
101
127
}
102
128
103
- /// A shortcut for Results that can return `T` or `SenseHatError`
129
+ /// A shortcut for Results that can return `T` or `SenseHatError`.
104
130
pub type SenseHatResult < T > = Result < T , SenseHatError > ;
105
131
106
132
impl < ' a > SenseHat < ' a > {
@@ -175,7 +201,7 @@ impl<'a> SenseHat<'a> {
175
201
}
176
202
match self . data . fusion_pose {
177
203
Some ( o) => Ok ( o) ,
178
- None => Err ( SenseHatError :: NotReady )
204
+ None => Err ( SenseHatError :: NotReady ) ,
179
205
}
180
206
}
181
207
@@ -187,7 +213,7 @@ impl<'a> SenseHat<'a> {
187
213
let data = self . accelerometer_chip . get_imu_data ( ) ?;
188
214
match data. fusion_pose {
189
215
Some ( o) => Ok ( o. yaw ) ,
190
- None => Err ( SenseHatError :: NotReady )
216
+ None => Err ( SenseHatError :: NotReady ) ,
191
217
}
192
218
} else {
193
219
Err ( SenseHatError :: NotReady )
@@ -202,7 +228,7 @@ impl<'a> SenseHat<'a> {
202
228
let data = self . accelerometer_chip . get_imu_data ( ) ?;
203
229
match data. fusion_pose {
204
230
Some ( o) => Ok ( o) ,
205
- None => Err ( SenseHatError :: NotReady )
231
+ None => Err ( SenseHatError :: NotReady ) ,
206
232
}
207
233
} else {
208
234
Err ( SenseHatError :: NotReady )
@@ -217,7 +243,7 @@ impl<'a> SenseHat<'a> {
217
243
let data = self . accelerometer_chip . get_imu_data ( ) ?;
218
244
match data. fusion_pose {
219
245
Some ( o) => Ok ( o) ,
220
- None => Err ( SenseHatError :: NotReady )
246
+ None => Err ( SenseHatError :: NotReady ) ,
221
247
}
222
248
} else {
223
249
Err ( SenseHatError :: NotReady )
@@ -232,26 +258,36 @@ impl<'a> SenseHat<'a> {
232
258
}
233
259
match self . data . accel {
234
260
Some ( a) => Ok ( a) ,
235
- None => Err ( SenseHatError :: NotReady )
261
+ None => Err ( SenseHatError :: NotReady ) ,
236
262
}
237
263
}
238
264
239
- /// Displays a scrolling message on the LED matrix.
265
+ /// Displays a scrolling message on the LED matrix. Blocks until the
266
+ /// entire message has scrolled past.
240
267
///
241
- /// Blocks until the entire message has scrolled past.
268
+ /// The `fg` and `bg` values set the foreground and background colours.
269
+ /// You can either specify:
270
+ /// * a constant colour like `Colour::WHITE`,
271
+ /// * a string from the [W3C basic keywords](https://www.w3.org/TR/css-color-3/#html4) like `"white"` or `"purple"`, or
272
+ /// * an RGB 8-bit triple like `(0, 0xFF, 0)`.
242
273
#[ cfg( feature = "led-matrix" ) ]
243
- pub fn text ( & mut self , message : & str , fg : Colour , bg : Colour ) -> SenseHatResult < ( ) > {
274
+ pub fn text < FG , BG > ( & mut self , message : & str , fg : FG , bg : BG ) -> SenseHatResult < ( ) >
275
+ where
276
+ FG : Into < Colour > ,
277
+ BG : Into < Colour > ,
278
+ {
244
279
// Connect to our LED Matrix screen.
245
- let mut screen = sensehat_screen:: Screen :: open ( "/dev/fb1" ) . map_err ( |_| SenseHatError :: ScreenError ) ?;
280
+ let mut screen =
281
+ sensehat_screen:: Screen :: open ( "/dev/fb1" ) . map_err ( |_| SenseHatError :: ScreenError ) ?;
246
282
// Get the default `FontCollection`.
247
283
let fonts = sensehat_screen:: FontCollection :: new ( ) ;
248
284
// Create a sanitized `FontString`.
249
285
let sanitized = fonts. sanitize_str ( message) ?;
250
286
// Render the `FontString` as a vector of pixel frames.
251
- let pixel_frames = sanitized. pixel_frames ( fg, bg) ;
287
+ let pixel_frames = sanitized. pixel_frames ( fg. into ( ) . 0 , bg. into ( ) . 0 ) ;
252
288
// Create a `Scroll` from the pixel frame vector.
253
289
let scroll = sensehat_screen:: Scroll :: new ( & pixel_frames) ;
254
- // Consume the `FrameSequence` returned by the `left_to_right ` method.
290
+ // Consume the `FrameSequence` returned by the `right_to_left ` method.
255
291
scroll. right_to_left ( ) . for_each ( |frame| {
256
292
screen. write_frame ( & frame. frame_line ( ) ) ;
257
293
:: std:: thread:: sleep ( :: std:: time:: Duration :: from_millis ( 100 ) ) ;
@@ -263,7 +299,8 @@ impl<'a> SenseHat<'a> {
263
299
#[ cfg( feature = "led-matrix" ) ]
264
300
pub fn clear ( & mut self ) -> SenseHatResult < ( ) > {
265
301
// Connect to our LED Matrix screen.
266
- let mut screen = sensehat_screen:: Screen :: open ( "/dev/fb1" ) . map_err ( |_| SenseHatError :: ScreenError ) ?;
302
+ let mut screen =
303
+ sensehat_screen:: Screen :: open ( "/dev/fb1" ) . map_err ( |_| SenseHatError :: ScreenError ) ?;
267
304
// Send a blank image to clear the screen
268
305
const OFF : [ u8 ; 128 ] = [ 0x00 ; 128 ] ;
269
306
screen. write_frame ( & sensehat_screen:: FrameLine :: from_slice ( & OFF ) ) ;
@@ -289,5 +326,52 @@ impl From<std::string::FromUtf16Error> for SenseHatError {
289
326
}
290
327
}
291
328
329
+ #[ cfg( feature = "led-matrix" ) ]
330
+ impl < ' a > Into < Colour > for & ' a str {
331
+ fn into ( self ) -> Colour {
332
+ let rgb = tint:: Color :: name ( self ) . unwrap ( ) ;
333
+ Colour ( rgb. to_rgb255 ( ) . into ( ) )
334
+ }
335
+ }
336
+
337
+ #[ cfg( feature = "led-matrix" ) ]
338
+ impl < ' a > Into < Colour > for ( u8 , u8 , u8 ) {
339
+ fn into ( self ) -> Colour {
340
+ Colour ( self . into ( ) )
341
+ }
342
+ }
343
+
344
+ #[ cfg( feature = "led-matrix" ) ]
345
+ impl Colour {
346
+ pub const WHITE : Colour = Colour ( PixelColor :: WHITE ) ;
347
+ pub const RED : Colour = Colour ( PixelColor :: RED ) ;
348
+ pub const GREEN : Colour = Colour ( PixelColor :: GREEN ) ;
349
+ pub const BLUE : Colour = Colour ( PixelColor :: BLUE ) ;
350
+ pub const BLACK : Colour = Colour ( PixelColor :: BLACK ) ;
351
+ pub const YELLOW : Colour = Colour ( PixelColor :: YELLOW ) ;
352
+ pub const MAGENTA : Colour = Colour ( PixelColor :: MAGENTA ) ;
353
+ pub const CYAN : Colour = Colour ( PixelColor :: CYAN ) ;
354
+ }
355
+
356
+ #[ cfg( test) ]
357
+ mod test {
358
+ use super :: * ;
359
+
360
+ #[ cfg( feature = "led-matrix" ) ]
361
+ #[ test]
362
+ fn check_colours_string ( ) {
363
+ let colour_str: Colour = "red" . into ( ) ;
364
+ let colour_const: Colour = Colour :: RED ;
365
+ assert_eq ! ( colour_str, colour_const) ;
366
+ }
367
+
368
+ #[ cfg( feature = "led-matrix" ) ]
369
+ #[ test]
370
+ fn check_colours_tuple ( ) {
371
+ let colour_tuple: Colour = ( 0xFF , 0 , 0 ) . into ( ) ;
372
+ let colour_const: Colour = Colour :: RED ;
373
+ assert_eq ! ( colour_tuple, colour_const) ;
374
+ }
375
+ }
292
376
293
377
// End of file
0 commit comments