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
143
144
145
#[cfg(feature = "linux-evdev")]
extern crate evdev;
#[macro_use]
extern crate failure;
extern crate glob;
#[cfg(feature = "poll")]
extern crate mio;
#[cfg(feature = "poll")]
mod poll;
use evdev::Device;
use failure::Error;
use glob::glob;
use std::io;
use std::os::unix::io::RawFd;
use std::time::Duration;
const SENSE_HAT_EVDEV_NAME: &[u8; 31] = b"Raspberry Pi Sense HAT Joystick";
#[derive(Debug)]
pub enum Direction {
Enter = 28,
Up = 103,
Down = 108,
Left = 105,
Right = 106,
}
impl Direction {
fn try_from(code: usize) -> Result<Self, Error> {
match code {
c if c == Direction::Enter as usize => Ok(Direction::Enter),
c if c == Direction::Up as usize => Ok(Direction::Up),
c if c == Direction::Down as usize => Ok(Direction::Down),
c if c == Direction::Left as usize => Ok(Direction::Left),
c if c == Direction::Right as usize => Ok(Direction::Right),
c => bail!("unrecognized joystick code: {}", c),
}
}
}
#[derive(Debug)]
pub enum Action {
Release = 0,
Press = 1,
Hold = 2,
}
impl Action {
fn try_from(code: usize) -> Result<Self, Error> {
match code {
c if c == Action::Press as usize => Ok(Action::Press),
c if c == Action::Release as usize => Ok(Action::Release),
c if c == Action::Hold as usize => Ok(Action::Hold),
c => bail!("unrecognized joystick action: {}", c),
}
}
}
#[derive(Debug)]
pub struct JoyStickEvent {
timestamp: Duration,
direction: Direction,
action: Action,
}
impl JoyStickEvent {
fn new(timestamp: Duration, direction: Direction, action: Action) -> Self {
JoyStickEvent {
timestamp,
direction,
action,
}
}
}
#[derive(Debug)]
pub struct JoyStick {
device: Device,
}
impl JoyStick {
pub fn open() -> Result<Self, Error> {
for entry in glob("/dev/input/event*")? {
match entry {
Ok(path) => {
let device = Device::open(&path)?;
if device.name().as_bytes() == SENSE_HAT_EVDEV_NAME {
return Ok(JoyStick { device });
}
}
Err(e) => return Err(e.into()),
}
}
bail!("No Joystick found")
}
pub fn events(&mut self) -> io::Result<Vec<JoyStickEvent>> {
let events: Vec<JoyStickEvent> = self.device
.events_no_sync()
.map_err(|e| io::Error::from(e))?
.filter(|ev| ev._type == 1)
.map(|ev| {
let secs = ev.time.tv_sec as u64;
let nsecs = ev.time.tv_usec as u32 * 1_000;
let time = Duration::new(secs, nsecs);
let direction = Direction::try_from(ev.code as usize).unwrap();
let action = Action::try_from(ev.value as usize).unwrap();
JoyStickEvent::new(time, direction, action)
})
.collect();
Ok(events)
}
pub fn fd(&self) -> RawFd {
self.device.fd()
}
}