Skip to main content

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}