1use crate::Device;
4
5#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
9#[repr(u8)]
10pub enum StickPosition {
11 Center = 0,
12 Up = 1,
13 UpRight = 2,
14 Right = 3,
15 DownRight = 4,
16 Down = 5,
17 DownLeft = 6,
18 Left = 7,
19 UpLeft = 8,
20}
21
22impl Default for StickPosition {
23 fn default() -> Self {
24 StickPosition::Center
25 }
26}
27
28impl StickPosition {
29 pub fn new() -> Self {
30 StickPosition::default()
31 }
32
33 pub fn from_u8(position: u8) -> Option<Self> {
34 match position {
35 0 => Some(StickPosition::Center),
36 1 => Some(StickPosition::Up),
37 2 => Some(StickPosition::UpRight),
38 3 => Some(StickPosition::Right),
39 4 => Some(StickPosition::DownRight),
40 5 => Some(StickPosition::Down),
41 6 => Some(StickPosition::DownLeft),
42 7 => Some(StickPosition::Left),
43 8 => Some(StickPosition::UpLeft),
44 _ => None,
45 }
46 }
47}
48
49#[derive(Debug, Default, Copy, Clone, PartialEq)]
51pub struct State {
52 pub stick_position: StickPosition,
54 pub button_1: bool,
56 pub button_2: bool,
58 pub button_back: bool,
60 pub button_menu: bool,
62 pub button_fuji: bool,
64 pub roll: u16,
67}
68
69impl State {
70
71 pub fn from_report(data: &[u8]) -> Self {
75 assert!(data.len() >= 6);
76 assert_eq!(data[0], 1);
77
78 msg_to_state(&data[1..])
79 }
80}
81
82fn msg_to_state(msg: &[u8]) -> State {
83 assert_eq!(msg.len(), 5);
84 State {
85 stick_position: StickPosition::from_u8(msg[2] >> 4).unwrap_or_default(),
86 button_1: (msg[1] & 1) == 1,
87 button_2: ((msg[1] >> 1) & 1) == 1,
88 button_back: (msg[2] & 1) == 1,
89 button_menu: ((msg[2] >> 1) & 1) == 1,
90 button_fuji: ((msg[2] >> 2) & 1) == 1,
91 roll: u16::from(msg[3]) + (u16::from(msg[4]) << 8),
92 }
93}
94
95
96pub fn process_input<D>(mut device: D) -> Result<Option<State>, D::Error>
104where
105 D: Device,
106{
107 let mut buf = [0; 6];
108 buf.fill(0);
109
110 let mut has_msg = false;
111 let mut last_amount = 0;
112 device.set_blocking(false)?;
113 let msg = loop {
114
115 let amount = device.read(&mut buf)?;
116
117 if amount == 0 && !has_msg {
118 break &buf[0..0];
120
121 } else if amount != 0 {
122 has_msg = true;
123 last_amount = amount;
124 continue;
126 }
127
128 let msg = &buf[..last_amount];
129 break msg;
130 };
131
132 if !msg.is_empty() {
133 if msg.len() != 5 {
134 eprintln!(
135 "Special report #{:02X}: {:?}",
136 buf[0],
137 msg,
138 );
139 Ok(None)
140 } else {
141 Ok(Some(msg_to_state(msg)))
142 }
143 } else {
144 Ok(None)
145 }
146}