1#[derive(Debug, Clone, Copy, PartialEq)]
4pub struct DSUFrame {
5 pub dpad_left: bool,
6 pub dpad_down: bool,
7 pub dpad_right: bool,
8 pub dpad_up: bool,
9 pub options: bool,
10 pub r3: bool,
11 pub l3: bool,
12 pub share: bool,
13 pub y: bool,
14 pub b: bool,
15 pub a: bool,
16 pub x: bool,
17 pub r1: bool,
18 pub l1: bool,
19 pub r2: bool,
20 pub l2: bool,
21 pub home: bool,
22 pub touch: bool,
23 pub left_stick_x: u8,
24 pub left_stick_y: u8,
25 pub right_stick_x: u8,
26 pub right_stick_y: u8,
27 pub analog_r2: u8,
28 pub analog_l2: u8,
29 pub accel_x: f32,
30 pub accel_y: f32,
31 pub accel_z: f32,
32 pub gyro_x: f32,
33 pub gyro_y: f32,
34 pub gyro_z: f32,
35}
36
37fn write_header(buf: &mut [u8], payload_len: u16, client_id: u32) {
43 buf[0..4].copy_from_slice(b"DSUS");
44 buf[4..6].copy_from_slice(&1001u16.to_le_bytes());
45 buf[6..8].copy_from_slice(&payload_len.to_le_bytes());
46 buf[8..12].fill(0); buf[12..16].copy_from_slice(&client_id.to_le_bytes());
48}
49
50fn crc32(data: &[u8]) -> u32 {
53 let mut crc: u32 = 0xFFFFFFFF;
54 for &byte in data {
55 crc ^= byte as u32;
56 for _ in 0..8 {
57 crc = if crc & 1 != 0 {
58 (crc >> 1) ^ 0xEDB8_8320
59 } else {
60 crc >> 1
61 };
62 }
63 }
64 !crc
65}
66
67pub fn write_version_response(buf: &mut [u8], client_id: u32) {
70 write_header(buf, 2, client_id);
71 buf[16..20].copy_from_slice(&0x100000u32.to_le_bytes());
72 buf[20..22].copy_from_slice(&1001u16.to_le_bytes());
73
74 let c = crc32(&buf[..22]);
75 buf[8..12].copy_from_slice(&c.to_le_bytes());
76}
77
78pub fn write_info_response(buf: &mut [u8], slot: u8, client_id: u32, connected: bool) {
81 buf.fill(0);
82 write_header(buf, 16, client_id); buf[16..20].copy_from_slice(&0x100001u32.to_le_bytes());
84
85 buf[20] = slot;
87 if connected {
88 buf[21] = 2; buf[22] = 2; buf[23] = 1; }
92 let c = crc32(&buf[..32]);
95 buf[8..12].copy_from_slice(&c.to_le_bytes());
96}
97
98pub fn write_data_event(
100 buf: &mut [u8; 100],
101 frame: &DSUFrame,
102 packet_num: u32,
103 client_id: u32,
104 slot: u8,
105 timestamp_us: u64,
106 invert_pitch: bool,
107) {
108 buf.fill(0);
109
110 write_header(buf, 84, client_id); buf[16..20].copy_from_slice(&0x100002u32.to_le_bytes());
112
113 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());
123
124 buf[36] = get_bitmask(&[
126 (frame.dpad_left, 7),
127 (frame.dpad_down, 6),
128 (frame.dpad_right, 5),
129 (frame.dpad_up, 4),
130 (frame.options, 3),
131 (frame.r3, 2),
132 (frame.l3, 1),
133 (frame.share, 0),
134 ]);
135 buf[37] = get_bitmask(&[
136 (frame.y, 7),
137 (frame.b, 6),
138 (frame.a, 5),
139 (frame.x, 4),
140 (frame.r1, 3),
141 (frame.l1, 2),
142 (frame.r2, 1),
143 (frame.l2, 0),
144 ]);
145 buf[38] = u8::from(frame.home);
146 buf[39] = u8::from(frame.touch);
147
148 buf[40] = frame.left_stick_x;
150 buf[41] = frame.left_stick_y;
151 buf[42] = frame.right_stick_x;
152 buf[43] = frame.right_stick_y;
153
154 buf[44] = if frame.dpad_left { u8::MAX } else { 0 };
157 buf[45] = if frame.dpad_down { u8::MAX } else { 0 };
158 buf[46] = if frame.dpad_right { u8::MAX } else { 0 };
159 buf[47] = if frame.dpad_up { u8::MAX } else { 0 };
160 buf[48] = if frame.y { u8::MAX } else { 0 };
161 buf[49] = if frame.b { u8::MAX } else { 0 };
162 buf[50] = if frame.a { u8::MAX } else { 0 };
163 buf[51] = if frame.x { u8::MAX } else { 0 };
164 buf[52] = if frame.r1 { u8::MAX } else { 0 };
165 buf[53] = if frame.l1 { u8::MAX } else { 0 };
166 buf[54] = frame.analog_r2;
167 buf[55] = frame.analog_l2;
168
169 buf[68..76].copy_from_slice(×tamp_us.to_le_bytes());
173
174 let acc_x = frame.accel_x;
176 let acc_y = if invert_pitch {
177 -frame.accel_y
178 } else {
179 frame.accel_y
180 };
181 let acc_z = frame.accel_z;
182
183 buf[76..80].copy_from_slice(&acc_x.to_le_bytes());
184 buf[80..84].copy_from_slice(&acc_y.to_le_bytes());
185 buf[84..88].copy_from_slice(&acc_z.to_le_bytes());
186
187 let pitch = if invert_pitch {
189 -frame.gyro_x
190 } else {
191 frame.gyro_x
192 };
193
194 let yaw = if invert_pitch {
196 -frame.gyro_y
197 } else {
198 frame.gyro_y
199 };
200
201 let roll = frame.gyro_z;
202
203 buf[88..92].copy_from_slice(&pitch.to_le_bytes());
204 buf[92..96].copy_from_slice(&yaw.to_le_bytes());
205 buf[96..100].copy_from_slice(&roll.to_le_bytes());
206
207 let c = crc32(&buf[..100]);
208 buf[8..12].copy_from_slice(&c.to_le_bytes());
209}
210
211fn get_bitmask(bits: &[(bool, u8)]) -> u8 {
213 let mut mask = 0u8;
214 for &(on, pos) in bits {
215 if on {
216 mask |= 1u8 << pos;
217 }
218 }
219 mask
220}