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
//! # emotiv
//!
//! Async Rust client for streaming EEG and BCI data from
//! [Emotiv](https://www.emotiv.com/) headsets via the
//! [Cortex API](https://emotiv.gitbook.io/cortex-api/) WebSocket (JSON-RPC 2.0).
//!
//! ## Supported hardware
//!
//! | Model | EEG ch | BCI | Notes |
//! |---|---|---|---|
//! | EPOC X | 14 | ✓ | Full EEG, motion, performance metrics, mental commands |
//! | EPOC+ | 14 | ✓ | Same protocol as EPOC X |
//! | Insight | 5 | ✓ | Lightweight 5-channel headset |
//! | EPOC Flex | 32 | ✓ | Research-grade flexible cap |
//!
//! ## API credentials
//!
//! To connect to a real headset you need a **Client ID** and **Client Secret**
//! from the Emotiv developer portal:
//!
//! 1. Install and log into the [EMOTIV Launcher](https://www.emotiv.com/products/emotiv-launcher).
//! 2. Create a Cortex App at <https://www.emotiv.com/my-account/cortex-apps/>.
//! 3. Pass the credentials via [`CortexClientConfig`](client::CortexClientConfig)
//! or the `EMOTIV_CLIENT_ID` / `EMOTIV_CLIENT_SECRET` environment variables.
//!
//! On the first connection the Cortex service will prompt you to approve the app
//! inside the EMOTIV Launcher (one-time only).
//!
//! ## Quick start
//!
//! ```no_run
//! use emotiv::prelude::*;
//!
//! #[tokio::main]
//! async fn main() -> anyhow::Result<()> {
//! let config = CortexClientConfig {
//! client_id: std::env::var("EMOTIV_CLIENT_ID")
//! .expect("set EMOTIV_CLIENT_ID"),
//! client_secret: std::env::var("EMOTIV_CLIENT_SECRET")
//! .expect("set EMOTIV_CLIENT_SECRET"),
//! ..Default::default()
//! };
//! let client = CortexClient::new(config);
//! let (mut rx, handle) = client.connect().await?;
//!
//! while let Some(event) = rx.recv().await {
//! match event {
//! CortexEvent::SessionCreated(_) => {
//! handle.subscribe(&["eeg", "mot", "met", "pow"]).await?;
//! }
//! CortexEvent::Eeg(data) => {
//! println!("EEG: {:?}", &data.samples[..5.min(data.samples.len())]);
//! }
//! CortexEvent::Disconnected => break,
//! _ => {}
//! }
//! }
//! Ok(())
//! }
//! ```
//!
//! ## Simulation mode (feature = `simulate`)
//!
//! For testing without hardware or API keys, enable the `simulate` feature:
//!
//! ```toml
//! [dependencies]
//! emotiv = { version = "0.0.1", features = ["simulate"] }
//! ```
//!
//! Then use [`simulator::spawn_simulator`] to generate synthetic data
//! through the same [`CortexEvent`](types::CortexEvent) channel.
//!
//! ## Module overview
//!
//! | Module | Purpose |
//! |---|---|
//! | [`prelude`] | One-line glob import of the most commonly needed types |
//! | [`client`] | WebSocket connection, auth flow, and the [`CortexHandle`](client::CortexHandle) command API |
//! | [`types`] | All event and data types ([`CortexEvent`](types::CortexEvent), [`EegData`](types::EegData), etc.) |
//! | [`protocol`] | JSON-RPC request builders and Cortex API constants |
//! | [`simulator`] | Signal simulator for offline testing *(feature = `simulate`)* |
/// Convenience re-exports for downstream crates.
///
/// ```
/// use emotiv::prelude::*;
/// ```
///
/// This brings in [`CortexClient`](client::CortexClient),
/// [`CortexClientConfig`](client::CortexClientConfig),
/// [`CortexHandle`](client::CortexHandle), all event/data types, and the
/// stream-name constants (`STREAM_EEG`, `STREAM_MOT`, …).