1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
//! GATT UUIDs, sampling constants, and BLE wire-format helpers for IDUN Guardian earbuds.
//!
//! The Guardian uses standard Bluetooth SIG UUIDs for Device Information
//! (service `0x180A`) and Battery (characteristic `0x2A19`), plus vendor-specific
//! UUIDs for EEG/IMU data, impedance, configuration, and command channels.
//!
//! # GATT characteristic map
//!
//! | UUID suffix | Full UUID | Purpose | Direction |
//! |---|---|---|---|
//! | `fcc4` | `beffd56c-c915-48f5-930d-4c1feee0fcc4` | EEG + IMU data | Notify |
//! | `fcc8` | `beffd56c-c915-48f5-930d-4c1feee0fcc8` | Impedance data | Notify |
//! | `fcc9` | `beffd56c-c915-48f5-930d-4c1feee0fcc9` | Configuration | Write |
//! | `fcca` | `beffd56c-c915-48f5-930d-4c1feee0fcca` | Commands | Write |
//! | `2A19` | Standard BLE SIG | Battery Level | Read |
//! | `2A25` | Standard BLE SIG | Serial Number / MAC ID | Read |
//! | `2A26` | Standard BLE SIG | Firmware Revision | Read |
//! | `2A27` | Standard BLE SIG | Hardware Revision | Read |
//!
//! # Commands
//!
//! Written to the command characteristic (`fcca`):
//!
//! | Byte | ASCII | Action |
//! |---|---|---|
//! | `0x4D` | `M` | Start EEG/IMU measurement |
//! | `0x53` | `S` | Stop EEG/IMU measurement |
//! | `0x5A` | `Z` | Start impedance streaming |
//! | `0x58` | `X` | Stop impedance streaming |
//!
//! # Configuration
//!
//! Written to the configuration characteristic (`fcc9`):
//!
//! | Value | ASCII | Action |
//! |---|---|---|
//! | `0x64 0x31` | `d1` | LED on |
//! | `0x64 0x30` | `d0` | LED off |
//! | `0x6E 0x30` | `n0` | 50 Hz notch filter (Europe, Asia) |
//! | `0x6E 0x31` | `n1` | 60 Hz notch filter (Americas, Japan) |
use Uuid;
// ── Standard Bluetooth SIG UUIDs ─────────────────────────────────────────────
/// Device Information Service UUID (`0x180A`, standard BLE SIG).
pub const DEVICE_INFO_SERVICE: Uuid =
from_u128;
/// Serial Number / MAC ID characteristic (`0x2A25`, standard BLE SIG).
///
/// The Guardian stores its MAC address here as a UTF-8 string
/// (e.g. `"AA:BB:CC:DD:EE:FF"`).
pub const MAC_ID_CHARACTERISTIC: Uuid =
from_u128;
/// Firmware Revision characteristic (`0x2A26`, standard BLE SIG).
pub const FIRMWARE_VERSION_CHARACTERISTIC: Uuid =
from_u128;
/// Hardware Revision characteristic (`0x2A27`, standard BLE SIG).
pub const HARDWARE_VERSION_CHARACTERISTIC: Uuid =
from_u128;
/// Battery Level characteristic (`0x2A19`, standard BLE SIG).
///
/// Returns a single byte (0–100) representing battery state-of-charge.
pub const BATTERY_CHARACTERISTIC: Uuid =
from_u128;
// ── Vendor-specific UUIDs (IDUN Guardian) ────────────────────────────────────
//
// All vendor UUIDs share the base `beffd56c-c915-48f5-930d-4c1feee0fc__`,
// differing only in the last two bytes.
/// EEG + IMU measurement characteristic (`fcc4`, notifications).
///
/// The earbud streams raw EEG/IMU data packets on this characteristic.
/// Each notification is a binary packet:
///
/// ```text
/// byte[0] : header tag / packet type
/// byte[1] : sequence index (0–255, wraps around)
/// bytes[2..] : packed measurement samples (EEG and/or IMU)
/// ```
///
/// At 250 Hz with 20 samples per packet, notifications arrive every ~80 ms.
pub const EEG_IMU_CHARACTERISTIC: Uuid =
from_u128;
/// Impedance measurement characteristic (`fcc8`, notifications).
///
/// When impedance streaming is active, the earbud sends impedance values
/// (in ohms) as little-endian unsigned integers on this characteristic.
pub const IMPEDANCE_CHARACTERISTIC: Uuid =
from_u128;
/// Configuration characteristic (`fcc9`, write).
///
/// Used to configure LED state and notch filter frequency.
/// See [`CFG_LED_ON`], [`CFG_LED_OFF`], [`CFG_NOTCH_50HZ`], [`CFG_NOTCH_60HZ`].
pub const CONFIG_CHARACTERISTIC: Uuid =
from_u128;
/// Command characteristic (`fcca`, write).
///
/// Used to start/stop measurements.
/// See [`CMD_START_MEASUREMENT`], [`CMD_STOP_MEASUREMENT`],
/// [`CMD_START_IMPEDANCE`], [`CMD_STOP_IMPEDANCE`].
pub const COMMAND_CHARACTERISTIC: Uuid =
from_u128;
// ── Device commands ──────────────────────────────────────────────────────────
/// Command byte to start EEG/IMU measurement (`"M"` = `0x4D`).
pub const CMD_START_MEASUREMENT: & = b"M";
/// Command byte to stop EEG/IMU measurement (`"S"` = `0x53`).
pub const CMD_STOP_MEASUREMENT: & = b"S";
/// Command byte to start impedance streaming (`"Z"` = `0x5A`).
pub const CMD_START_IMPEDANCE: & = b"Z";
/// Command byte to stop impedance streaming (`"X"` = `0x58`).
pub const CMD_STOP_IMPEDANCE: & = b"X";
// ── Configuration values ─────────────────────────────────────────────────────
/// Turn the LED on (`"d1"` = `0x64 0x31`).
pub const CFG_LED_ON: & = b"d1";
/// Turn the LED off (`"d0"` = `0x64 0x30`).
pub const CFG_LED_OFF: & = b"d0";
/// Set notch filter to 50 Hz (`"n0"` — Europe, Asia, Africa, Oceania).
pub const CFG_NOTCH_50HZ: & = b"n0";
/// Set notch filter to 60 Hz (`"n1"` — Americas, Japan, South Korea, Taiwan).
pub const CFG_NOTCH_60HZ: & = b"n1";
// ── Sampling constants ───────────────────────────────────────────────────────
/// EEG sample rate in Hz (250 Hz).
pub const EEG_SAMPLE_RATE: f64 = 250.0;
/// Number of EEG samples per BLE notification packet (20).
///
/// At 250 Hz, this yields one packet every 80 ms (~12.5 packets/s).
pub const EEG_SAMPLES_PER_PACKET: usize = 20;
/// Maximum packet index before wrap-around.
///
/// The Guardian uses an 8-bit index (0–255), so this is 256.
pub const MAX_PACKET_INDEX: u16 = 256;
/// Device name prefix used to identify Guardian earbuds during BLE scanning.
///
/// Matches both `"IGEB"` (hardware v2.1a) and `"IGE-XXXXXX"` (hardware v3.0a).
pub const DEVICE_NAME_PREFIX: &str = "IGE";
// ── Channel labels ───────────────────────────────────────────────────────────
/// EEG channel name (`"EEG"`).
///
/// The Guardian uses a bipolar montage with two electrodes on a single earbud:
/// an in-ear-canal electrode (signal) and an outer-ear electrode (reference).
/// This produces one EEG channel.
pub const EEG_CHANNEL_NAME: &str = "EEG";