Skip to content

Commit 9b2b6c0

Browse files
committed
More options for colours.
The `Colour` struct has private internals to help fix the API. Use `tint` to convert strings to colours. Also updated README.
1 parent 4e4a607 commit 9b2b6c0

File tree

3 files changed

+147
-38
lines changed

3 files changed

+147
-38
lines changed

Cargo.toml

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "sensehat"
3-
version = "0.5.0"
3+
version = "1.0.0"
44
authors = ["Jonathan Pallant <[email protected]>"]
55
license-file = "LICENSE.md"
66
documentation = "https://docs.rs/crate/sensehat"
@@ -14,7 +14,8 @@ measurements = "0.10.2"
1414
i2cdev = "0.4.0"
1515
byteorder = "1.0"
1616
libc = { version = "0.2", optional = true }
17-
sensehat-screen = { version = "0.1", optional = true }
17+
sensehat-screen = { version = "0.2", optional = true }
18+
tint = { version = "1.0", optional = true }
1819

1920
[build-dependencies]
2021
gcc = "0.3"
@@ -25,7 +26,7 @@ gcc = "0.3"
2526
default = ["rtimu", "led-matrix"]
2627
# Extra packages required by these features.
2728
rtimu = ["libc"]
28-
led-matrix = ["sensehat-screen"]
29+
led-matrix = ["sensehat-screen", "tint"]
2930

3031
[package.metadata.docs.rs]
3132
features = ["led-matrix"]

README.md

+27-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,33 @@
11
# sensehat-rs
22

3-
Rust support for the Raspberry Pi Sense HAT
4-
5-
See <https://www.raspberrypi.org/products/sense-hat/> for details on the Sense HAT.
3+
Rust support for the [Raspberry Pi Sense
4+
HAT](https://www.raspberrypi.org/products/sense-hat/). The Sense HAT is a
5+
sensor board 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 details
8+
on the Sense HAT.
69

710
See <https://github.com/RPi-Distro/python-sense-hat> for the official Python driver. This one tries to follow the same API as the Python version.
811

912
See <https://github.com/thejpster/pi-workshop-rs/> for some workshop materials which use this driver.
13+
14+
## Supported components:
15+
16+
* Humidity and Temperature Sensor (an HTS221)
17+
* Pressure and Temperature Sensor (a LPS25H)
18+
* Gyroscope (an LSM9DS1, requires the RTIMU library)
19+
* LED matrix (partial support for scrolling text only)
20+
21+
## Currently unsupported components:
22+
23+
* Joystick
24+
25+
## Example use
26+
27+
```
28+
use sensehat::{Colour, SenseHat};
29+
if let Ok(mut hat) = SenseHat::new() {
30+
println!("{:?}", hat.get_pressure());
31+
hat.text("Hi!", Colour::RED, Colour::WHITE);
32+
}
33+
```

src/lib.rs

+116-32
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,45 @@
1-
//! # A driver for the Raspberry Pi Sense HAT
1+
//! # Rust support for the Raspberry Pi Sense HAT.
22
//!
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.
69
//!
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:
818
//!
919
//! * Humidity and Temperature Sensor (an HTS221)
1020
//! * Pressure and Temperature Sensor (a LPS25H)
1121
//! * Gyroscope (an LSM9DS1, requires the RTIMU library)
22+
//! * LED matrix (partial support for scrolling text only)
1223
//!
13-
//! Currently unsupported components:
24+
//! ## Currently unsupported components:
1425
//!
15-
//! * LED matrix
1626
//! * 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+
//! ```
1737
1838
extern crate byteorder;
1939
extern crate i2cdev;
2040
extern crate measurements;
41+
#[cfg(feature = "led-matrix")]
42+
extern crate tint;
2143

2244
#[cfg(feature = "rtimu")]
2345
extern crate libc;
@@ -44,27 +66,31 @@ mod lsm9ds1_dummy;
4466
#[cfg(not(feature = "rtimu"))]
4567
use lsm9ds1_dummy as lsm9ds1;
4668

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.
4873
#[derive(Debug, Copy, Clone)]
4974
pub struct Orientation {
5075
pub roll: Angle,
5176
pub pitch: Angle,
5277
pub yaw: Angle,
5378
}
5479

55-
/// Represents a 3D vector
80+
/// Represents a 3D vector.
5681
#[derive(Debug, Copy, Clone)]
5782
pub struct Vector3D {
5883
pub x: f64,
5984
pub y: f64,
6085
pub z: f64,
6186
}
6287

63-
/// Represents an RGB colour
88+
/// Represents an RGB colour.
6489
#[cfg(feature = "led-matrix")]
65-
pub use sensehat_screen::color::PixelColor as Colour;
90+
#[derive(Debug, Copy, Clone, PartialEq)]
91+
pub struct Colour(PixelColor);
6692

67-
/// A collection of all the data from the IMU
93+
/// A collection of all the data from the IMU.
6894
#[derive(Debug, Default)]
6995
struct ImuData {
7096
timestamp: u64,
@@ -77,30 +103,30 @@ struct ImuData {
77103
humidity: Option<f64>,
78104
}
79105

80-
/// Represents the Sense HAT itself
106+
/// Represents the Sense HAT itself.
81107
pub struct SenseHat<'a> {
82-
/// LPS25H pressure sensor
108+
/// LPS25H pressure sensor.
83109
pressure_chip: lps25h::Lps25h<LinuxI2CDevice>,
84-
/// HTS221 humidity sensor
110+
/// HTS221 humidity sensor.
85111
humidity_chip: hts221::Hts221<LinuxI2CDevice>,
86-
/// LSM9DS1 IMU device
112+
/// LSM9DS1 IMU device.
87113
accelerometer_chip: lsm9ds1::Lsm9ds1<'a>,
88-
/// Cached data
114+
/// Cached accelerometer data.
89115
data: ImuData,
90116
}
91117

92-
/// Errors that this crate can return
118+
/// Errors that this crate can return.
93119
#[derive(Debug)]
94120
pub enum SenseHatError {
95121
NotReady,
96122
GenericError,
97123
I2CError(LinuxI2CError),
98124
LSM9DS1Error(lsm9ds1::Error),
99125
ScreenError,
100-
CharacterError(std::string::FromUtf16Error)
126+
CharacterError(std::string::FromUtf16Error),
101127
}
102128

103-
/// A shortcut for Results that can return `T` or `SenseHatError`
129+
/// A shortcut for Results that can return `T` or `SenseHatError`.
104130
pub type SenseHatResult<T> = Result<T, SenseHatError>;
105131

106132
impl<'a> SenseHat<'a> {
@@ -175,7 +201,7 @@ impl<'a> SenseHat<'a> {
175201
}
176202
match self.data.fusion_pose {
177203
Some(o) => Ok(o),
178-
None => Err(SenseHatError::NotReady)
204+
None => Err(SenseHatError::NotReady),
179205
}
180206
}
181207

@@ -187,7 +213,7 @@ impl<'a> SenseHat<'a> {
187213
let data = self.accelerometer_chip.get_imu_data()?;
188214
match data.fusion_pose {
189215
Some(o) => Ok(o.yaw),
190-
None => Err(SenseHatError::NotReady)
216+
None => Err(SenseHatError::NotReady),
191217
}
192218
} else {
193219
Err(SenseHatError::NotReady)
@@ -202,7 +228,7 @@ impl<'a> SenseHat<'a> {
202228
let data = self.accelerometer_chip.get_imu_data()?;
203229
match data.fusion_pose {
204230
Some(o) => Ok(o),
205-
None => Err(SenseHatError::NotReady)
231+
None => Err(SenseHatError::NotReady),
206232
}
207233
} else {
208234
Err(SenseHatError::NotReady)
@@ -217,7 +243,7 @@ impl<'a> SenseHat<'a> {
217243
let data = self.accelerometer_chip.get_imu_data()?;
218244
match data.fusion_pose {
219245
Some(o) => Ok(o),
220-
None => Err(SenseHatError::NotReady)
246+
None => Err(SenseHatError::NotReady),
221247
}
222248
} else {
223249
Err(SenseHatError::NotReady)
@@ -232,26 +258,36 @@ impl<'a> SenseHat<'a> {
232258
}
233259
match self.data.accel {
234260
Some(a) => Ok(a),
235-
None => Err(SenseHatError::NotReady)
261+
None => Err(SenseHatError::NotReady),
236262
}
237263
}
238264

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.
240267
///
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)`.
242273
#[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+
{
244279
// 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)?;
246282
// Get the default `FontCollection`.
247283
let fonts = sensehat_screen::FontCollection::new();
248284
// Create a sanitized `FontString`.
249285
let sanitized = fonts.sanitize_str(message)?;
250286
// 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);
252288
// Create a `Scroll` from the pixel frame vector.
253289
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.
255291
scroll.right_to_left().for_each(|frame| {
256292
screen.write_frame(&frame.frame_line());
257293
::std::thread::sleep(::std::time::Duration::from_millis(100));
@@ -263,7 +299,8 @@ impl<'a> SenseHat<'a> {
263299
#[cfg(feature = "led-matrix")]
264300
pub fn clear(&mut self) -> SenseHatResult<()> {
265301
// 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)?;
267304
// Send a blank image to clear the screen
268305
const OFF: [u8; 128] = [0x00; 128];
269306
screen.write_frame(&sensehat_screen::FrameLine::from_slice(&OFF));
@@ -289,5 +326,52 @@ impl From<std::string::FromUtf16Error> for SenseHatError {
289326
}
290327
}
291328

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+
}
292376

293377
// End of file

0 commit comments

Comments
 (0)