hermes_ble/types.rs
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright © 2026 Eugene Hauptmann, Frédéric Simard
3
4//! All event and data types produced by the Hermes client.
5
6/// A multi-channel EEG sample from the ADS1299 ADC.
7///
8/// Each BLE notification carries multiple sample frames. This struct
9/// represents one frame — all 8 channels sampled at the same instant.
10///
11/// Voltage values are in microvolts (µV), converted from the raw 24-bit
12/// signed ADC readings using [`crate::protocol::ads1299_to_microvolts`].
13#[derive(Debug, Clone)]
14pub struct EegSample {
15 /// Packet index (0–127) that contained this sample.
16 pub packet_index: u8,
17 /// Sample index within the packet (0-based).
18 pub sample_index: usize,
19 /// Wall-clock timestamp in milliseconds since Unix epoch.
20 pub timestamp: f64,
21 /// Voltage in µV for each of the 8 ADS1299 channels.
22 pub channels: [f64; 8],
23}
24
25/// A 3-axis inertial / magnetic measurement.
26#[derive(Debug, Clone, Copy)]
27pub struct XyzSample {
28 pub x: f32,
29 pub y: f32,
30 pub z: f32,
31}
32
33/// 9-DOF motion data from a single BLE notification.
34///
35/// The Hermes V1 packs accelerometer, gyroscope, and magnetometer readings
36/// into one characteristic notification as 9 × `i16` little-endian values.
37///
38/// Scaling factors applied:
39/// * Accelerometer: 0.061 mg/LSB → g
40/// * Gyroscope: 8.75 mdps/LSB → °/s
41/// * Magnetometer: 0.14 mgauss/LSB → gauss
42#[derive(Debug, Clone)]
43pub struct MotionData {
44 /// Wall-clock timestamp in milliseconds since Unix epoch.
45 pub timestamp: f64,
46 /// Accelerometer reading in g.
47 pub accel: XyzSample,
48 /// Gyroscope reading in degrees per second.
49 pub gyro: XyzSample,
50 /// Magnetometer reading in gauss.
51 pub mag: XyzSample,
52}
53
54/// An event notification from the device (e.g. button press).
55#[derive(Debug, Clone)]
56pub struct DeviceEvent {
57 /// Wall-clock timestamp in milliseconds since Unix epoch.
58 pub timestamp: f64,
59 /// Raw notification bytes from the event characteristic.
60 pub data: Vec<u8>,
61}
62
63/// A config response received from the EEG config characteristic.
64#[derive(Debug, Clone)]
65pub struct ConfigResponse {
66 /// Wall-clock timestamp in milliseconds since Unix epoch.
67 pub timestamp: f64,
68 /// Raw response bytes.
69 pub data: Vec<u8>,
70}
71
72/// All data events emitted by [`crate::hermes_client::HermesClient`].
73///
74/// Consumers receive these values through the `mpsc::Receiver` returned by
75/// [`crate::hermes_client::HermesClient::connect`] or
76/// [`crate::hermes_client::HermesClient::connect_to`].
77#[derive(Debug, Clone)]
78pub enum HermesEvent {
79 /// One multi-channel EEG sample (8 channels in µV).
80 ///
81 /// Multiple `Eeg` events are emitted per BLE notification (typically ~8
82 /// samples per packet at 250 Hz).
83 Eeg(EegSample),
84
85 /// A complete 9-DOF motion reading (accel + gyro + magnetometer).
86 Motion(MotionData),
87
88 /// A device event notification (e.g. button press).
89 Event(DeviceEvent),
90
91 /// A config response from the EEG configuration characteristic.
92 Config(ConfigResponse),
93
94 /// The BLE link has been established.
95 /// The inner `String` is the advertised device name (e.g. `"Hermes V1"`).
96 Connected(String),
97
98 /// The BLE link was lost (headset turned off, out of range, etc.).
99 ///
100 /// After receiving this event the channel will be closed; no further
101 /// events will arrive.
102 Disconnected,
103
104 /// One or more EEG packets were dropped (detected via packet index gap).
105 ///
106 /// The inner value is the number of missing packets.
107 PacketsDropped(usize),
108}