@@ -52,6 +52,31 @@ pub struct Orientation {
5252 pub yaw : Angle ,
5353}
5454
55+ /// Represents a 3D vector
56+ #[ derive( Debug , Copy , Clone ) ]
57+ pub struct Vector3D {
58+ pub x : f64 ,
59+ pub y : f64 ,
60+ pub z : f64 ,
61+ }
62+
63+ /// Represents an RGB colour
64+ #[ cfg( feature = "led-matrix" ) ]
65+ pub use sensehat_screen:: color:: PixelColor as Colour ;
66+
67+ /// A collection of all the data from the IMU
68+ #[ derive( Debug , Default ) ]
69+ struct ImuData {
70+ timestamp : u64 ,
71+ fusion_pose : Option < Orientation > ,
72+ gyro : Option < Vector3D > ,
73+ accel : Option < Vector3D > ,
74+ compass : Option < Vector3D > ,
75+ pressure : Option < f64 > ,
76+ temperature : Option < f64 > ,
77+ humidity : Option < f64 > ,
78+ }
79+
5580/// Represents the Sense HAT itself
5681pub struct SenseHat < ' a > {
5782 /// LPS25H pressure sensor
@@ -61,7 +86,7 @@ pub struct SenseHat<'a> {
6186 /// LSM9DS1 IMU device
6287 accelerometer_chip : lsm9ds1:: Lsm9ds1 < ' a > ,
6388 /// Cached data
64- orientation : Orientation ,
89+ data : ImuData ,
6590}
6691
6792/// Errors that this crate can return
@@ -71,6 +96,8 @@ pub enum SenseHatError {
7196 GenericError ,
7297 I2CError ( LinuxI2CError ) ,
7398 LSM9DS1Error ( lsm9ds1:: Error ) ,
99+ ScreenError ,
100+ CharacterError ( std:: string:: FromUtf16Error )
74101}
75102
76103/// A shortcut for Results that can return `T` or `SenseHatError`
@@ -86,11 +113,7 @@ impl<'a> SenseHat<'a> {
86113 humidity_chip : hts221:: Hts221 :: new ( LinuxI2CDevice :: new ( "/dev/i2c-1" , 0x5f ) ?) ?,
87114 pressure_chip : lps25h:: Lps25h :: new ( LinuxI2CDevice :: new ( "/dev/i2c-1" , 0x5c ) ?) ?,
88115 accelerometer_chip : lsm9ds1:: Lsm9ds1 :: new ( ) ?,
89- orientation : Orientation {
90- roll : Angle :: from_degrees ( 0.0 ) ,
91- pitch : Angle :: from_degrees ( 0.0 ) ,
92- yaw : Angle :: from_degrees ( 0.0 ) ,
93- } ,
116+ data : ImuData :: default ( ) ,
94117 } )
95118 }
96119
@@ -148,18 +171,24 @@ impl<'a> SenseHat<'a> {
148171 pub fn get_orientation ( & mut self ) -> SenseHatResult < Orientation > {
149172 self . accelerometer_chip . set_fusion ( ) ;
150173 if self . accelerometer_chip . imu_read ( ) {
151- self . orientation = self . accelerometer_chip . get_imu_data ( ) ?;
174+ self . data = self . accelerometer_chip . get_imu_data ( ) ?;
175+ }
176+ match self . data . fusion_pose {
177+ Some ( o) => Ok ( o) ,
178+ None => Err ( SenseHatError :: NotReady )
152179 }
153- Ok ( self . orientation )
154180 }
155181
156182 /// Get the compass heading (ignoring gyro and magnetometer)
157183 pub fn get_compass ( & mut self ) -> SenseHatResult < Angle > {
158184 self . accelerometer_chip . set_compass_only ( ) ;
159185 if self . accelerometer_chip . imu_read ( ) {
160186 // Don't cache this data
161- let orientation = self . accelerometer_chip . get_imu_data ( ) ?;
162- Ok ( orientation. yaw )
187+ let data = self . accelerometer_chip . get_imu_data ( ) ?;
188+ match data. fusion_pose {
189+ Some ( o) => Ok ( o. yaw ) ,
190+ None => Err ( SenseHatError :: NotReady )
191+ }
163192 } else {
164193 Err ( SenseHatError :: NotReady )
165194 }
@@ -170,8 +199,11 @@ impl<'a> SenseHat<'a> {
170199 pub fn get_gyro ( & mut self ) -> SenseHatResult < Orientation > {
171200 self . accelerometer_chip . set_gyro_only ( ) ;
172201 if self . accelerometer_chip . imu_read ( ) {
173- let orientation = self . accelerometer_chip . get_imu_data ( ) ?;
174- Ok ( orientation)
202+ let data = self . accelerometer_chip . get_imu_data ( ) ?;
203+ match data. fusion_pose {
204+ Some ( o) => Ok ( o) ,
205+ None => Err ( SenseHatError :: NotReady )
206+ }
175207 } else {
176208 Err ( SenseHatError :: NotReady )
177209 }
@@ -182,12 +214,61 @@ impl<'a> SenseHat<'a> {
182214 pub fn get_accel ( & mut self ) -> SenseHatResult < Orientation > {
183215 self . accelerometer_chip . set_accel_only ( ) ;
184216 if self . accelerometer_chip . imu_read ( ) {
185- let orientation = self . accelerometer_chip . get_imu_data ( ) ?;
186- Ok ( orientation)
217+ let data = self . accelerometer_chip . get_imu_data ( ) ?;
218+ match data. fusion_pose {
219+ Some ( o) => Ok ( o) ,
220+ None => Err ( SenseHatError :: NotReady )
221+ }
187222 } else {
188223 Err ( SenseHatError :: NotReady )
189224 }
190225 }
226+
227+ /// Returns a vector representing the current acceleration in Gs.
228+ pub fn get_accel_raw ( & mut self ) -> SenseHatResult < Vector3D > {
229+ self . accelerometer_chip . set_accel_only ( ) ;
230+ if self . accelerometer_chip . imu_read ( ) {
231+ self . data = self . accelerometer_chip . get_imu_data ( ) ?;
232+ }
233+ match self . data . accel {
234+ Some ( a) => Ok ( a) ,
235+ None => Err ( SenseHatError :: NotReady )
236+ }
237+ }
238+
239+ /// Displays a scrolling message on the LED matrix.
240+ ///
241+ /// Blocks until the entire message has scrolled past.
242+ #[ cfg( feature = "led-matrix" ) ]
243+ pub fn text ( & mut self , message : & str , fg : Colour , bg : Colour ) -> SenseHatResult < ( ) > {
244+ // Connect to our LED Matrix screen.
245+ let mut screen = sensehat_screen:: Screen :: open ( "/dev/fb1" ) . map_err ( |_| SenseHatError :: ScreenError ) ?;
246+ // Get the default `FontCollection`.
247+ let fonts = sensehat_screen:: FontCollection :: new ( ) ;
248+ // Create a sanitized `FontString`.
249+ let sanitized = fonts. sanitize_str ( message) ?;
250+ // Render the `FontString` as a vector of pixel frames.
251+ let pixel_frames = sanitized. pixel_frames ( fg, bg) ;
252+ // Create a `Scroll` from the pixel frame vector.
253+ let scroll = sensehat_screen:: Scroll :: new ( & pixel_frames) ;
254+ // Consume the `FrameSequence` returned by the `left_to_right` method.
255+ scroll. right_to_left ( ) . for_each ( |frame| {
256+ screen. write_frame ( & frame. frame_line ( ) ) ;
257+ :: std:: thread:: sleep ( :: std:: time:: Duration :: from_millis ( 100 ) ) ;
258+ } ) ;
259+ Ok ( ( ) )
260+ }
261+
262+ /// Clears the LED matrix
263+ #[ cfg( feature = "led-matrix" ) ]
264+ pub fn clear ( & mut self ) -> SenseHatResult < ( ) > {
265+ // Connect to our LED Matrix screen.
266+ let mut screen = sensehat_screen:: Screen :: open ( "/dev/fb1" ) . map_err ( |_| SenseHatError :: ScreenError ) ?;
267+ // Send a blank image to clear the screen
268+ const OFF : [ u8 ; 128 ] = [ 0x00 ; 128 ] ;
269+ screen. write_frame ( & sensehat_screen:: FrameLine :: from_slice ( & OFF ) ) ;
270+ Ok ( ( ) )
271+ }
191272}
192273
193274impl From < LinuxI2CError > for SenseHatError {
@@ -202,4 +283,11 @@ impl From<lsm9ds1::Error> for SenseHatError {
202283 }
203284}
204285
286+ impl From < std:: string:: FromUtf16Error > for SenseHatError {
287+ fn from ( err : std:: string:: FromUtf16Error ) -> SenseHatError {
288+ SenseHatError :: CharacterError ( err)
289+ }
290+ }
291+
292+
205293// End of file
0 commit comments