1#[derive(Debug, Clone, Copy, PartialEq)]
6pub struct DSUFrame {
7 pub dpad_left: bool,
8 pub dpad_down: bool,
9 pub dpad_right: bool,
10 pub dpad_up: bool,
11 pub options: bool,
12 pub r3: bool,
13 pub l3: bool,
14 pub share: bool,
15 pub y: bool,
16 pub b: bool,
17 pub a: bool,
18 pub x: bool,
19 pub r1: bool,
20 pub l1: bool,
21 pub r2: bool,
22 pub l2: bool,
23 pub home: bool,
24 pub touch: bool,
25 pub left_stick_x: u8,
26 pub left_stick_y: u8,
27 pub right_stick_x: u8,
28 pub right_stick_y: u8,
29 pub analog_r2: u8,
30 pub analog_l2: u8,
31 pub raw_accel_x: f32,
32 pub raw_accel_y: f32,
33 pub raw_accel_z: f32,
34 pub raw_gyro_x: f32,
35 pub raw_gyro_y: f32,
36 pub raw_gyro_z: f32,
37 pub accel_x: f32,
38 pub accel_y: f32,
39 pub accel_z: f32,
40 pub gyro_x: f32,
41 pub gyro_y: f32,
42 pub gyro_z: f32,
43}
44
45fn write_header(buf: &mut [u8], payload_len: u16, client_id: u32) {
51 buf[0..4].copy_from_slice(b"DSUS");
52 buf[4..6].copy_from_slice(&1001u16.to_le_bytes());
53 buf[6..8].copy_from_slice(&payload_len.to_le_bytes());
54 buf[8..12].fill(0); buf[12..16].copy_from_slice(&client_id.to_le_bytes());
56}
57
58fn crc32(data: &[u8]) -> u32 {
61 let mut crc: u32 = 0xFFFFFFFF;
62 for &byte in data {
63 crc ^= byte as u32;
64 for _ in 0..8 {
65 crc = if crc & 1 != 0 {
66 (crc >> 1) ^ 0xEDB8_8320
67 } else {
68 crc >> 1
69 };
70 }
71 }
72 !crc
73}
74
75pub fn write_version_response(buf: &mut [u8], client_id: u32) {
78 write_header(buf, 2, client_id);
79 buf[16..20].copy_from_slice(&0x100000u32.to_le_bytes());
80 buf[20..22].copy_from_slice(&1001u16.to_le_bytes());
81
82 let c = crc32(&buf[..22]);
83 buf[8..12].copy_from_slice(&c.to_le_bytes());
84}
85
86pub fn write_info_response(buf: &mut [u8], slot: u8, client_id: u32, connected: bool) {
89 buf.fill(0);
90 write_header(buf, 16, client_id); buf[16..20].copy_from_slice(&0x100001u32.to_le_bytes());
92
93 buf[20] = slot;
95 if connected {
96 buf[21] = 2; buf[22] = 2; buf[23] = 1; }
100 let c = crc32(&buf[..32]);
103 buf[8..12].copy_from_slice(&c.to_le_bytes());
104}
105
106pub fn write_data_event(
108 buf: &mut [u8; 100],
109 frame: &DSUFrame,
110 packet_num: u32,
111 client_id: u32,
112 slot: u8,
113 timestamp_us: u64,
114 invert_pitch: bool,
115) {
116 buf.fill(0);
117
118 write_header(buf, 84, client_id); buf[16..20].copy_from_slice(&0x100002u32.to_le_bytes());
120
121 buf[20] = slot; buf[21] = 2; buf[22] = 2; buf[23] = 1; buf[31] = 1; buf[32..36].copy_from_slice(&packet_num.to_le_bytes());
131
132 buf[36] = get_bitmask(&[
134 (frame.dpad_left, 7),
135 (frame.dpad_down, 6),
136 (frame.dpad_right, 5),
137 (frame.dpad_up, 4),
138 (frame.options, 3),
139 (frame.r3, 2),
140 (frame.l3, 1),
141 (frame.share, 0),
142 ]);
143 buf[37] = get_bitmask(&[
144 (frame.y, 7),
145 (frame.b, 6),
146 (frame.a, 5),
147 (frame.x, 4),
148 (frame.r1, 3),
149 (frame.l1, 2),
150 (frame.r2, 1),
151 (frame.l2, 0),
152 ]);
153 buf[38] = u8::from(frame.home);
154 buf[39] = u8::from(frame.touch);
155
156 buf[40] = frame.left_stick_x;
158 buf[41] = frame.left_stick_y;
159 buf[42] = frame.right_stick_x;
160 buf[43] = frame.right_stick_y;
161
162 buf[44] = if frame.dpad_left { u8::MAX } else { 0 };
165 buf[45] = if frame.dpad_down { u8::MAX } else { 0 };
166 buf[46] = if frame.dpad_right { u8::MAX } else { 0 };
167 buf[47] = if frame.dpad_up { u8::MAX } else { 0 };
168 buf[48] = if frame.y { u8::MAX } else { 0 };
169 buf[49] = if frame.b { u8::MAX } else { 0 };
170 buf[50] = if frame.a { u8::MAX } else { 0 };
171 buf[51] = if frame.x { u8::MAX } else { 0 };
172 buf[52] = if frame.r1 { u8::MAX } else { 0 };
173 buf[53] = if frame.l1 { u8::MAX } else { 0 };
174 buf[54] = frame.analog_r2;
175 buf[55] = frame.analog_l2;
176
177 buf[68..76].copy_from_slice(×tamp_us.to_le_bytes());
181
182 let acc_x = frame.accel_x;
184 let acc_y = if invert_pitch {
185 -frame.accel_y
186 } else {
187 frame.accel_y
188 };
189 let acc_z = frame.accel_z;
190
191 buf[76..80].copy_from_slice(&acc_x.to_le_bytes());
192 buf[80..84].copy_from_slice(&acc_y.to_le_bytes());
193 buf[84..88].copy_from_slice(&acc_z.to_le_bytes());
194
195 let pitch = if invert_pitch {
197 -frame.gyro_x
198 } else {
199 frame.gyro_x
200 };
201
202 let yaw = if invert_pitch {
204 -frame.gyro_y
205 } else {
206 frame.gyro_y
207 };
208
209 let roll = frame.gyro_z;
210
211 buf[88..92].copy_from_slice(&pitch.to_le_bytes());
212 buf[92..96].copy_from_slice(&yaw.to_le_bytes());
213 buf[96..100].copy_from_slice(&roll.to_le_bytes());
214
215 let c = crc32(&buf[..100]);
216 buf[8..12].copy_from_slice(&c.to_le_bytes());
217}
218
219fn get_bitmask(bits: &[(bool, u8)]) -> u8 {
221 let mut mask = 0u8;
222 for &(on, pos) in bits {
223 if on {
224 mask |= 1u8 << pos;
225 }
226 }
227 mask
228}
229
230#[cfg(test)]
231mod tests {
232 use super::*;
233
234 #[test]
235 fn test_get_bitmask_empty() {
236 assert_eq!(get_bitmask(&[]), 0);
237 }
238
239 #[test]
240 fn test_get_bitmask_single_bit() {
241 assert_eq!(get_bitmask(&[(true, 0)]), 0b00000001);
242 assert_eq!(get_bitmask(&[(true, 7)]), 0b10000000);
243 }
244
245 #[test]
246 fn test_get_bitmask_multiple_bits() {
247 assert_eq!(get_bitmask(&[(true, 0), (true, 1), (true, 2)]), 0b00000111);
248 assert_eq!(get_bitmask(&[(true, 0), (true, 7)]), 0b10000001);
249 }
250
251 #[test]
252 fn test_write_version_response() {
253 let mut buf = [0u8; 22];
254 write_version_response(&mut buf, 0x12345678);
255
256 assert_eq!(&buf[0..4], b"DSUS");
257 assert_eq!(u16::from_le_bytes([buf[4], buf[5]]), 1001);
258 assert_eq!(u16::from_le_bytes([buf[6], buf[7]]), 2);
259 assert_eq!(
260 u32::from_le_bytes([buf[12], buf[13], buf[14], buf[15]]),
261 0x12345678
262 );
263 assert_eq!(
264 u32::from_le_bytes([buf[16], buf[17], buf[18], buf[19]]),
265 0x100000
266 );
267 assert_eq!(u16::from_le_bytes([buf[20], buf[21]]), 1001);
268 }
269
270 #[test]
271 fn test_write_info_response_connected() {
272 let mut buf = [0u8; 32];
273 write_info_response(&mut buf, 1, 0xABCD_EF01, true);
274
275 assert_eq!(&buf[0..4], b"DSUS");
276 assert_eq!(u16::from_le_bytes([buf[6], buf[7]]), 16);
277 assert_eq!(
278 u32::from_le_bytes([buf[12], buf[13], buf[14], buf[15]]),
279 0xABCD_EF01
280 );
281 assert_eq!(buf[20], 1);
282 assert_eq!(buf[21], 2);
283 assert_eq!(buf[22], 2);
284 assert_eq!(buf[23], 1);
285 }
286
287 #[test]
288 fn test_write_info_response_disconnected() {
289 let mut buf = [0u8; 32];
290 write_info_response(&mut buf, 0, 0, false);
291
292 assert_eq!(&buf[0..4], b"DSUS");
293 assert_eq!(buf[20], 0);
294 assert_eq!(buf[21], 0);
295 assert_eq!(buf[22], 0);
296 assert_eq!(buf[23], 0);
297 }
298
299 fn create_test_frame() -> DSUFrame {
300 DSUFrame {
301 dpad_left: true,
302 dpad_down: false,
303 dpad_right: true,
304 dpad_up: false,
305 options: true,
306 r3: false,
307 l3: true,
308 share: false,
309 y: true,
310 b: false,
311 a: true,
312 x: false,
313 r1: true,
314 l1: false,
315 r2: true,
316 l2: false,
317 home: true,
318 touch: false,
319 left_stick_x: 128,
320 left_stick_y: 64,
321 right_stick_x: 200,
322 right_stick_y: 50,
323 analog_r2: 200,
324 analog_l2: 100,
325 raw_accel_x: 1.0,
326 raw_accel_y: 0.5,
327 raw_accel_z: -0.5,
328 raw_gyro_x: 10.0,
329 raw_gyro_y: -5.0,
330 raw_gyro_z: 2.5,
331 accel_x: 1.0,
332 accel_y: 0.5,
333 accel_z: -0.5,
334 gyro_x: 10.0,
335 gyro_y: -5.0,
336 gyro_z: 2.5,
337 }
338 }
339
340 #[test]
341 fn test_write_data_event_basic() {
342 let mut buf = [0u8; 100];
343 let frame = create_test_frame();
344 write_data_event(&mut buf, &frame, 12345, 0xDEAD_BEEF, 0, 1_000_000, false);
345
346 assert_eq!(&buf[0..4], b"DSUS");
347 assert_eq!(u16::from_le_bytes([buf[6], buf[7]]), 84);
348 assert_eq!(
349 u32::from_le_bytes([buf[12], buf[13], buf[14], buf[15]]),
350 0xDEAD_BEEF
351 );
352 assert_eq!(buf[20], 0);
353 assert_eq!(
354 u32::from_le_bytes([buf[32], buf[33], buf[34], buf[35]]),
355 12345
356 );
357 }
358
359 #[test]
360 fn test_write_data_event_buttons() {
361 let mut buf = [0u8; 100];
362 let frame = create_test_frame();
363 write_data_event(&mut buf, &frame, 0, 0, 0, 0, false);
364
365 assert_eq!(buf[36], 0b1010_1010);
366 assert_eq!(buf[37], 0b1010_1010);
367 assert_eq!(buf[38], 1);
368 assert_eq!(buf[39], 0);
369 }
370
371 #[test]
372 fn test_write_data_event_sticks() {
373 let mut buf = [0u8; 100];
374 let frame = create_test_frame();
375 write_data_event(&mut buf, &frame, 0, 0, 0, 0, false);
376
377 assert_eq!(buf[40], 128);
378 assert_eq!(buf[41], 64);
379 assert_eq!(buf[42], 200);
380 assert_eq!(buf[43], 50);
381 }
382
383 #[test]
384 fn test_write_data_event_analog_buttons() {
385 let mut buf = [0u8; 100];
386 let frame = create_test_frame();
387 write_data_event(&mut buf, &frame, 0, 0, 0, 0, false);
388
389 assert_eq!(buf[44], 255);
390 assert_eq!(buf[45], 0);
391 assert_eq!(buf[46], 255);
392 assert_eq!(buf[47], 0);
393 assert_eq!(buf[48], 255);
394 assert_eq!(buf[49], 0);
395 assert_eq!(buf[50], 255);
396 assert_eq!(buf[51], 0);
397 assert_eq!(buf[52], 255);
398 assert_eq!(buf[53], 0);
399 assert_eq!(buf[54], 200);
400 assert_eq!(buf[55], 100);
401 }
402
403 #[test]
404 fn test_write_data_event_timestamp() {
405 let mut buf = [0u8; 100];
406 let frame = create_test_frame();
407 write_data_event(&mut buf, &frame, 0, 0, 0, 9_876_543_210, false);
408
409 assert_eq!(
410 u64::from_le_bytes(buf[68..76].try_into().unwrap()),
411 9_876_543_210
412 );
413 }
414
415 #[test]
416 fn test_write_data_event_accel_normal() {
417 let mut buf = [0u8; 100];
418 let frame = create_test_frame();
419 write_data_event(&mut buf, &frame, 0, 0, 0, 0, false);
420
421 assert_eq!(f32::from_le_bytes(buf[76..80].try_into().unwrap()), 1.0);
422 assert_eq!(f32::from_le_bytes(buf[80..84].try_into().unwrap()), 0.5);
423 assert_eq!(f32::from_le_bytes(buf[84..88].try_into().unwrap()), -0.5);
424 }
425
426 #[test]
427 fn test_write_data_event_accel_inverted() {
428 let mut buf = [0u8; 100];
429 let frame = create_test_frame();
430 write_data_event(&mut buf, &frame, 0, 0, 0, 0, true);
431
432 assert_eq!(f32::from_le_bytes(buf[76..80].try_into().unwrap()), 1.0);
433 assert_eq!(f32::from_le_bytes(buf[80..84].try_into().unwrap()), -0.5);
434 assert_eq!(f32::from_le_bytes(buf[84..88].try_into().unwrap()), -0.5);
435 }
436
437 #[test]
438 fn test_write_data_event_gyro_normal() {
439 let mut buf = [0u8; 100];
440 let frame = create_test_frame();
441 write_data_event(&mut buf, &frame, 0, 0, 0, 0, false);
442
443 assert_eq!(f32::from_le_bytes(buf[88..92].try_into().unwrap()), 10.0);
444 assert_eq!(f32::from_le_bytes(buf[92..96].try_into().unwrap()), -5.0);
445 assert_eq!(f32::from_le_bytes(buf[96..100].try_into().unwrap()), 2.5);
446 }
447
448 #[test]
449 fn test_write_data_event_gyro_inverted() {
450 let mut buf = [0u8; 100];
451 let frame = create_test_frame();
452 write_data_event(&mut buf, &frame, 0, 0, 0, 0, true);
453
454 assert_eq!(f32::from_le_bytes(buf[88..92].try_into().unwrap()), -10.0);
455 assert_eq!(f32::from_le_bytes(buf[92..96].try_into().unwrap()), 5.0);
456 assert_eq!(f32::from_le_bytes(buf[96..100].try_into().unwrap()), 2.5);
457 }
458}