#[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()
}
}