This repository has been archived by the owner on Oct 26, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
orientation.rs
142 lines (122 loc) · 4.97 KB
/
orientation.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#![no_std]
#![no_main]
use embedded_graphics as eg;
use panic_halt as _;
use wio_terminal as wio;
use eg::image::{Image, ImageRaw, ImageRawLE};
use eg::pixelcolor::Rgb565;
use eg::prelude::*;
use eg::primitives::rectangle::Rectangle;
use eg::style::PrimitiveStyleBuilder;
use wio::accelerometer::{self, Tracker};
use wio::hal::clock::GenericClockController;
use wio::hal::delay::Delay;
use wio::pac::{CorePeripherals, Peripherals};
use wio::prelude::*;
use wio::{entry, Pins, Sets};
// The height and width of the RAW image of Ferris, which can be found at
// 'assets/ferris.raw'.
const IMG_HEIGHT: u32 = 64;
const IMG_WIDTH: u32 = 86;
#[entry]
fn main() -> ! {
let mut peripherals = Peripherals::take().unwrap();
let core = CorePeripherals::take().unwrap();
let mut clocks = GenericClockController::with_external_32kosc(
peripherals.GCLK,
&mut peripherals.MCLK,
&mut peripherals.OSC32KCTRL,
&mut peripherals.OSCCTRL,
&mut peripherals.NVMCTRL,
);
let mut delay = Delay::new(core.SYST, &mut clocks);
let pins = Pins::new(peripherals.PORT);
let mut sets: Sets = pins.split();
// Initialize the LIS3DH accelerometer, and create the orientation tracker.
// The calibration value for Tracker was obtained experimentally, as directed in
// the documentation.
let mut lis3dh = sets.accelerometer.init(
&mut clocks,
peripherals.SERCOM4,
&mut peripherals.MCLK,
&mut sets.port,
);
let mut tracker = Tracker::new(3700.0);
// Initialize the ILI9341-based LCD display. Create a black backdrop the size of
// the screen, load an image of Ferris from a RAW file, and draw it to the
// screen.
// By default, the display is in the LandscapeFlipped orientation.
let (mut display, _backlight) = sets
.display
.init(
&mut clocks,
peripherals.SERCOM7,
&mut peripherals.MCLK,
&mut sets.port,
&mut delay,
)
.unwrap();
// The display's resolution is 320x240. I'm too lazy to deal with orientation
// for something as trivial as a backdrop, so it's larger than the display in
// one dimension.
let style = PrimitiveStyleBuilder::new()
.fill_color(Rgb565::BLACK)
.build();
let backdrop = Rectangle::new(Point::new(0, 0), Point::new(320, 320)).into_styled(style);
backdrop.draw(&mut display).unwrap();
// Load the RAW image file into a renderable format. Determine the coordinate to
// center the image on the display, and draw the image there.
let image_data: ImageRawLE<Rgb565> = ImageRaw::new(
include_bytes!("../assets/ferris.raw"),
IMG_WIDTH,
IMG_HEIGHT,
);
let position = center_image(display.width(), display.height());
let image: Image<_, Rgb565> = Image::new(&image_data, position);
image.draw(&mut display).unwrap();
// Determine a baseline orientation. This doesn't really matter initially, but
// will be updated periodically.
let acceleration = lis3dh.accel_raw().unwrap();
let mut prev_orientation = tracker.update(acceleration);
loop {
// Get the current orientation of the device.
let acceleration = lis3dh.accel_raw().unwrap();
let orientation = tracker.update(acceleration);
// If the orientation hasn't changed, we have nothing left to do.
if orientation == prev_orientation {
continue;
}
// Attempt to convert the accelerometer orientation to a display orientation. If
// successful, set the display to the correct orientation and re-center the
// image.
if let Some(mode) = try_convert_orientation(orientation) {
display.set_orientation(mode).unwrap();
prev_orientation = orientation;
let position = center_image(display.width(), display.height());
let image: Image<_, Rgb565> = Image::new(&image_data, position);
backdrop.draw(&mut display).unwrap();
image.draw(&mut display).unwrap();
}
}
}
// Given the width and height of the display, return the coordinate which would
// center the image, based on its dimensions defined at the top of the file.
fn center_image(width: usize, height: usize) -> Point {
let x = (width as i32 / 2) - (IMG_WIDTH as i32 / 2);
let y = (height as i32 / 2) - (IMG_HEIGHT as i32 / 2);
Point::new(x, y)
}
// Given an accelerometer orientation, return the equivalent display
// orientation, if one exists.
fn try_convert_orientation(
orientation: accelerometer::Orientation,
) -> Option<ili9341::Orientation> {
use accelerometer::Orientation;
match orientation {
Orientation::LandscapeUp => Some(ili9341::Orientation::LandscapeFlipped),
Orientation::LandscapeDown => Some(ili9341::Orientation::Landscape),
Orientation::PortraitUp => Some(ili9341::Orientation::Portrait),
Orientation::PortraitDown => Some(ili9341::Orientation::PortraitFlipped),
_ => None,
}
}