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}