pad_motion/protocol/
mod.rs

1pub mod internals;
2
3use crc32fast::Hasher;
4use internals::*;
5use std::io::{Cursor, Result, Error, ErrorKind};
6use byteorder::{WriteBytesExt, LittleEndian};
7
8pub const PROTOCOL_VERSION: u16 = 1001;
9
10#[derive(Copy, Clone, Debug, PartialEq)]
11pub enum MessageSource {
12  Server,
13  Client
14}
15
16#[derive(Copy, Clone, Debug, PartialEq)]
17pub enum MessageType {
18  ProtocolVersion,
19  ConnectedControllers,
20  ControllerData
21}
22
23#[derive(Copy, Clone, Debug, PartialEq)]
24pub enum SlotState {
25  NotConnected,
26  Reserved,
27  Connected
28}
29
30impl Default for SlotState {
31  fn default() -> SlotState {
32    SlotState::NotConnected
33  }
34}
35
36#[derive(Copy, Clone, Debug, PartialEq)]
37pub enum DeviceType {
38  NotApplicable,
39  PartialGyro,
40  FullGyro
41}
42
43impl Default for DeviceType {
44  fn default() -> DeviceType {
45    DeviceType::NotApplicable
46  }
47}
48
49#[derive(Copy, Clone, Debug, PartialEq)]
50pub enum ConnectionType {
51  NotApplicable,
52  USB,
53  Bluetooth
54}
55
56impl Default for ConnectionType {
57  fn default() -> ConnectionType {
58    ConnectionType::NotApplicable
59  }
60}
61
62#[derive(Copy, Clone, Debug, PartialEq)]
63pub enum BatteryStatus {
64  NotApplicable,
65  Dying,
66  Low,
67  Medium,
68  High,
69  Full,
70  Charging,
71  Charged
72}
73
74impl Default for BatteryStatus {
75  fn default() -> BatteryStatus {
76    BatteryStatus::NotApplicable
77  }
78}
79
80#[derive(Copy, Clone, Debug, PartialEq)]
81pub enum ControllerDataRequest {
82  ReportAll,
83  SlotNumber(u8),
84  MAC(u64)
85}
86
87#[derive(Copy, Clone, Debug, PartialEq)]
88pub enum MessagePayload {
89  None,
90  ProtocolVersion(u16),
91  ConnectedControllersRequest { amount: i32, 
92                                slot_numbers: [u8; 4] },
93  ConnectedControllerResponse { controller_info: ControllerInfo },
94  ControllerDataRequest(ControllerDataRequest),
95  ControllerData { packet_number: u32,
96                   controller_info: ControllerInfo,
97                   controller_data: ControllerData }
98}
99
100#[derive(Copy, Clone, Debug, PartialEq)]
101pub struct MessageHeader {
102  pub source: MessageSource,
103  pub protocol_version: u16,
104  pub message_length: u16,
105  pub checksum: u32,
106  pub source_id: u32
107}
108
109#[derive(Copy, Clone, Debug, Default, PartialEq)]
110pub struct ControllerInfo {
111  pub slot: u8,
112  pub slot_state: SlotState,
113  pub device_type: DeviceType,
114  pub connection_type: ConnectionType,
115  pub mac_address: u64,
116  pub battery_status: BatteryStatus
117}
118
119#[derive(Copy, Clone, Debug, Default, PartialEq)]
120pub struct TouchData {
121  pub active: bool,
122  pub id: u8,
123  pub position_x: u16,
124  pub position_y: u16
125}
126
127#[derive(Copy, Clone, Debug, Default, PartialEq)]
128pub struct ControllerData {
129  pub connected: bool,
130  pub d_pad_left: bool,
131  pub d_pad_down: bool,
132  pub d_pad_right: bool,
133  pub d_pad_up: bool,
134  pub start: bool,
135  pub right_stick_button: bool,
136  pub left_stick_button: bool,
137  pub select: bool,
138  pub square: bool,
139  pub cross: bool,
140  pub circle: bool,
141  pub triangle: bool,
142  pub r1: bool,
143  pub l1: bool,
144  pub r2: bool,
145  pub l2: bool,
146  pub ps: u8,
147  pub touch: u8,
148  pub left_stick_x: u8,
149  pub left_stick_y: u8,
150  pub right_stick_x: u8,
151  pub right_stick_y: u8,
152  pub analog_d_pad_left: u8,
153  pub analog_d_pad_down: u8,
154  pub analog_d_pad_right: u8,
155  pub analog_d_pad_up: u8,
156  pub analog_square: u8,
157  pub analog_triangle: u8,
158  pub analog_cross: u8,
159  pub analog_circle: u8,
160  pub analog_r1: u8,
161  pub analog_l1: u8,
162  pub analog_r2: u8,
163  pub analog_l2: u8,
164  pub first_touch: TouchData,
165  pub second_touch: TouchData,
166  pub motion_data_timestamp: u64,
167  pub accelerometer_x: f32,
168  pub accelerometer_y: f32,
169  pub accelerometer_z: f32,
170  pub gyroscope_pitch: f32,
171  pub gyroscope_yaw: f32,
172  pub gyroscope_roll: f32,
173}
174
175#[derive(Copy, Clone, Debug, PartialEq)]
176pub struct Message {
177  pub header: MessageHeader,
178  pub message_type: MessageType,
179  pub payload: MessagePayload
180}
181
182fn compute_checksum(packet: &[u8]) -> u32 {
183  let mut packet = packet.to_vec();
184  for byte in &mut packet[8..12] {
185      *byte = 0;
186  }
187
188  let mut hasher = Hasher::new();
189  hasher.update(&packet);
190  hasher.finalize()
191}
192
193pub fn encode_message(writer: &mut Vec<u8>, message: Message) -> Result<()> {
194  encode_message_header(writer, message.header)?;
195  encode_message_type(writer, message.message_type)?;
196  encode_message_payload(writer, message.payload)?;
197
198  let length = (writer.len() - 16) as u16;
199  let mut length_bytes = vec![];
200  length_bytes.write_u16::<LittleEndian>(length)?;
201  writer[6..8].swap_with_slice(&mut length_bytes[..]);
202
203  let checksum = compute_checksum(writer);
204  let mut checksum_bytes = vec![];
205  checksum_bytes.write_u32::<LittleEndian>(checksum)?;
206  writer[8..12].swap_with_slice(&mut checksum_bytes[..]);
207
208  Ok(())
209}
210
211pub fn parse_message(message_source: MessageSource,
212                     packet: &[u8], 
213                     verify_checksum: bool) -> Result<Message> {
214  let mut reader = Cursor::new(packet);
215  let header = parse_message_header(&mut reader)?;
216
217  if header.protocol_version != PROTOCOL_VERSION {
218    return Err(Error::new(ErrorKind::InvalidData, "Unsupported protocol version"));
219  }
220
221  if packet.len() - 16 < header.message_length as usize {
222    return Err(Error::new(ErrorKind::InvalidData, "Received packet is too short"));
223  }
224
225  if verify_checksum {
226    let checksum = compute_checksum(packet);
227    if checksum != header.checksum {
228      return Err(Error::new(ErrorKind::InvalidData, "Packet has incorrect checksum"));
229    }
230  }
231
232  let message_type = parse_message_type(&mut reader)?;
233
234  let payload = parse_message_payload(&mut reader, message_source, message_type)?;
235
236  Ok(Message {
237    header,
238    message_type,
239    payload
240  })
241}