1use log::{debug, error, info, warn};
2
3pub const HEADSETID_AUTOCONNECT: [u8; 1] = [0xc2];
4
5#[derive(PartialEq, Eq, Debug)]
6pub enum PacketType {
7 HeadsetConnected(u16),
8 HeadsetConnectedUndefined,
9 HeadsetNotFound(u16),
10 NoHeadsetFound,
11 NotFoundUndefined,
12 HeadsetDisconnected(u16),
13 HeadsetDisconnectedUndefined,
14 RequestDenied,
15 Standby,
16 FindHeadset,
17 StandbyPacketUndefined,
18 StandbyLengthUndefined,
19 PoorSignal(u8),
20 Attention(u8),
21 Meditation(u8),
22 Blink(u8),
23 RawValue(i16),
24 AsicEeg(AsicEeg),
25 PacketUndefined(u8),
26}
27
28pub enum State {
29 NoSync,
30 FirstSync,
31 SecondSync,
32 ValidPacket,
33}
34
35#[derive(PartialEq, Eq, Debug)]
36pub struct AsicEeg {
37 pub delta: u32,
38 pub theta: u32,
39 pub low_alpha: u32,
40 pub high_alpha: u32,
41 pub low_beta: u32,
42 pub high_beta: u32,
43 pub low_gamma: u32,
44 pub mid_gamma: u32,
45}
46
47pub struct Parser {
48 state: State,
49 plength: u8,
50 payload: Vec<u8>,
51 checksum: u8,
52}
53
54impl Parser {
55 pub fn new() -> Parser {
56 Parser {
57 state: State::NoSync,
58 plength: 0,
59 payload: Vec::new(),
60 checksum: 0,
61 }
62 }
63}
64
65impl Parser {
66 pub fn parse(&mut self, data: u8) -> Option<Vec<PacketType>> {
67 match self.state {
68 State::NoSync => {
69 self.handle_nosync(data);
70 None
71 }
72 State::FirstSync => {
73 self.handle_firstsync(data);
74 None
75 }
76 State::SecondSync => {
77 self.handle_secondsync(data);
78 None
79 }
80 State::ValidPacket => self.handle_validpacket(data),
81 }
82 }
83
84 fn reset(&mut self) {
85 *self = Parser::new();
86 }
87
88 fn handle_nosync(&mut self, data: u8) {
89 if data == 0xaa {
90 self.state = State::FirstSync;
91 debug!("Standby for a valid packet");
92 }
93 }
94
95 fn handle_firstsync(&mut self, data: u8) {
96 if data == 0xaa {
97 self.state = State::SecondSync;
98 debug!("Packet synced");
99 } else {
100 self.state = State::NoSync;
101 }
102 }
103
104 fn handle_secondsync(&mut self, data: u8) {
105 if data > 0xaa {
106 self.state = State::NoSync;
107 error!("Plength larger than 170!");
108 } else if data < 0xaa {
109 self.state = State::ValidPacket;
110 self.plength = data;
111 debug!("Valid packet available, len({})", self.plength);
112 }
113 }
114
115 fn handle_validpacket(&mut self, data: u8) -> Option<Vec<PacketType>> {
116 if self.plength == 0 {
117 self.checksum = !self.checksum;
118 let re = if data != self.checksum {
119 debug!("Checksum failed");
120 None
121 } else {
122 debug!("Checksum matched, start parsing");
123 Some(self.handle_parser())
124 };
125 self.reset();
126 re
127 } else {
128 self.payload.push(data);
129 self.checksum = self.checksum.overflowing_add(data).0;
130 self.plength -= 1;
131 None
132 }
133 }
134
135 fn handle_parser(&mut self) -> Vec<PacketType> {
136 let mut n = 0;
137 let mut result: Vec<PacketType> = Vec::new();
138 while n < self.payload.len() {
139 if self.payload[n] == 0xd0 {
140 if self.payload[n + 1] == 0x02 {
142 info!(
143 "headset connected, ID {:#04x} {:#04x}",
144 self.payload[n + 2],
145 self.payload[n + 3]
146 );
147 result.push(PacketType::HeadsetConnected(
148 ((self.payload[n + 2] as u16) << 8) | (self.payload[n + 3] as u16),
149 ));
150 } else {
151 warn!("undefined packet while headset connected");
152 result.push(PacketType::HeadsetConnectedUndefined);
153 }
154
155 n += 4;
156 } else if self.payload[n] == 0xd1 {
157 if self.payload[n + 1] == 0x02 {
159 warn!(
160 "Headset {:#04x} {:#04x} not found",
161 self.payload[n + 2],
162 self.payload[n + 3]
163 );
164 result.push(PacketType::HeadsetNotFound(
165 ((self.payload[n + 2] as u16) << 8) | (self.payload[n + 3] as u16),
166 ));
167 n += 4;
168 } else if self.payload[n + 1] == 0x00 {
169 warn!("no headset could be found during Connect All.");
170 result.push(PacketType::NoHeadsetFound);
171 n += 2;
172 } else {
173 warn!("undefined packetLength while headset not found");
174 result.push(PacketType::NotFoundUndefined);
175 }
176 } else if self.payload[n] == 0xd2 {
177 if self.payload[n + 1] == 0x02 {
178 info!(
179 "disconnected from headset {:#04x} {:#04x}",
180 self.payload[n + 2],
181 self.payload[n + 3]
182 );
183 result.push(PacketType::HeadsetDisconnected(
184 ((self.payload[n + 2] as u16) << 8) | (self.payload[n + 3] as u16),
185 ));
186 } else {
187 warn!("undefined packetLength while headset disconnected");
188 result.push(PacketType::HeadsetDisconnectedUndefined);
189 }
190 n += 4;
191 } else if self.payload[n] == 0xd3 {
192 if self.payload[n + 1] == 0x00 {
193 warn!("the last command request was denied");
194 result.push(PacketType::RequestDenied);
195 } else {
196 warn!("undefined packetLength while headset disconnected");
197 result.push(PacketType::HeadsetDisconnectedUndefined);
198 }
199 n += 2;
200 } else if self.payload[n] == 0xd4 {
201 if self.payload[n + 1] == 0x01 {
202 if self.payload[n + 2] == 0x00 {
203 debug!("headset is in standby mode awaiting for a command");
204 result.push(PacketType::Standby);
205 } else if self.payload[n + 2] == 0x01 {
206 debug!("connecting to a headset");
207 result.push(PacketType::FindHeadset);
208 } else {
209 warn!("undefined packet code while standby");
210 result.push(PacketType::StandbyPacketUndefined);
211 }
212 } else {
213 warn!("undefined packet length while standby");
214 result.push(PacketType::StandbyLengthUndefined);
215 }
216 n += 3;
217 } else if self.payload[n] == 0x02 {
218 if self.payload[n + 1] == 200 {
220 warn!("the ThinkGear contacts are not touching the user's skin");
221 } else {
222 debug!("Poor signal quality {:#04x}", self.payload[n + 1]);
223 }
224 result.push(PacketType::PoorSignal(self.payload[n + 1]));
225 n += 2;
226 } else if self.payload[n] == 0x04 {
227 debug!("Attention esense {:#04x}", self.payload[n + 1]);
229 result.push(PacketType::Attention(self.payload[n + 1]));
230 n += 2;
231 } else if self.payload[n] == 0x05 {
232 debug!("Meditation esense {:#04x}", self.payload[n + 1]);
234 result.push(PacketType::Meditation(self.payload[n + 1]));
235 n += 2;
236 } else if self.payload[n] == 0x16 {
237 debug!("Blink strength {:#04x}", self.payload[n + 1]);
239 result.push(PacketType::Blink(self.payload[n + 1]));
240 n += 2;
241 } else if self.payload[n] == 0x80 {
242 let raw_val: i16 =
245 ((self.payload[n + 2] as i16) << 8) | (self.payload[n + 3] as i16);
246 debug!("Raw value {:#04x}", raw_val);
247 result.push(PacketType::RawValue(raw_val));
248 n += 4;
249 } else if self.payload[n] == 0x83 {
250 let mut eeg_vec: Vec<u32> = vec![];
254
255 for i in 0..8 {
256 let asic = ((self.payload[n + 2 + i * 3] as u32) << 16)
257 | ((self.payload[n + 3 + i * 3] as u32) << 8)
258 | (self.payload[n + 4 + i * 3] as u32);
259 eeg_vec.push(asic);
260 }
261
262 let eeg_power = AsicEeg {
263 delta: eeg_vec[0],
264 theta: eeg_vec[1],
265 low_alpha: eeg_vec[2],
266 high_alpha: eeg_vec[3],
267 low_beta: eeg_vec[4],
268 high_beta: eeg_vec[5],
269 low_gamma: eeg_vec[6],
270 mid_gamma: eeg_vec[7],
271 };
272 debug!("EEG power values = {:?}", eeg_power);
273 result.push(PacketType::AsicEeg(eeg_power));
274 n += 26;
275 } else {
276 warn!("packet code undefined {:#04x}", self.payload[n]);
277 result.push(PacketType::PacketUndefined(self.payload[n]));
278 n += 1;
279 }
280 }
281 debug!("end of packet");
282 result
283 }
284}
285
286pub fn connect_headset(
287 path: &str,
288 headset: &[u8],
289) -> Result<Box<dyn serialport::SerialPort>, &'static str> {
290 let mut port = serialport::new(path, 115_200)
291 .timeout(core::time::Duration::from_millis(1000))
292 .open()
293 .map_err(|_| "Cannot connect to dongle. Please make sure the serial number of your dongle is correct.")?;
294
295 const DISCONNECT: u8 = 0xc1;
296 const CONNECT: u8 = 0xc0;
297 let mut serial_buf: Vec<u8> = vec![0];
298
299 port.write(&[DISCONNECT])
300 .map_err(|_| "Failed to write DISCONNECT to dongle.")?;
301 port.read(serial_buf.as_mut_slice())
302 .map_err(|_| "Cannot read data from dongle.")?;
303 if headset.len() != 1 {
304 port.write(&[CONNECT])
305 .map_err(|_| "Failed to write CONNECT to dongle.")?;
306 }
307 port.write(&headset)
308 .map_err(|_| "Failed to write headset ID to dongle.")?;
309 return Ok(port);
310}
311
312#[cfg(test)]
313mod tests {
314 use super::*;
315 use pretty_assertions::assert_eq;
316
317 #[test]
318 fn test_parser() {
319 let test_vec: Vec<u8> = vec![
320 0xAA, 0xAA, 0x20, 0x02, 0x00, 0x83, 0x18, 0x00, 0x00, 0x94, 0x00, 0x00, 0x42, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x64, 0x00, 0x00, 0x4D, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x07, 0x00, 0x00, 0x05, 0x04, 0x0D, 0x05, 0x3D, 0x34, ];
357 let mut result: Vec<PacketType> = Vec::new();
358 let mut parser = Parser::new();
359 for data in test_vec {
360 if let Some(x) = parser.parse(data) {
361 result = x;
362 }
363 }
364
365 let test_asic = AsicEeg {
366 delta: 0x94,
367 theta: 0x42,
368 low_alpha: 0x0b,
369 high_alpha: 0x64,
370 low_beta: 0x4d,
371 high_beta: 0x3d,
372 low_gamma: 0x07,
373 mid_gamma: 0x05,
374 };
375
376 assert_eq!(
377 result,
378 vec![
379 PacketType::PoorSignal(0x00),
380 PacketType::AsicEeg(test_asic),
381 PacketType::Attention(0x0d),
382 PacketType::Meditation(0x3d)
383 ]
384 );
385 }
386}