Skip to main content

muse_rs/
lib.rs

1//! # muse-rs
2//!
3//! Async Rust library and terminal UI for streaming EEG data from
4//! [Interaxon Muse](https://choosemuse.com/) headsets over Bluetooth Low Energy.
5//!
6//! ## Supported hardware
7//!
8//! | Model | Firmware | EEG ch | PPG | Notes |
9//! |---|---|---|---|---|
10//! | Muse 1 (2014) | Classic | 4 | ✗ | baseline feature set |
11//! | Muse 2 | Classic | 4 + AUX | ✓ | PPG requires `enable_ppg: true` |
12//! | Muse S | Classic | 4 + AUX | ✓ | same protocol as Muse 2 |
13//! | Muse S | **Athena** | **8** | **✓** | auto-detected; PPG always included with preset `p1045` |
14//!
15//! Athena PPG data is decoded from 20-bit LE packed samples (tag lower nibble
16//! 0x4/0x5) into [`types::PpgReading`] events — 3 samples per channel
17//! (ambient, infrared, red) at 64 Hz.
18//!
19//! Firmware is detected automatically at connect time — no configuration is
20//! required.  See the [README](https://github.com/eugenehp/muse-rs#firmware-variants-classic-vs-athena)
21//! for a full protocol comparison.
22//!
23//! ## Quick start
24//!
25//! ```no_run
26//! use muse_rs::prelude::*;
27//!
28//! #[tokio::main]
29//! async fn main() -> anyhow::Result<()> {
30//!     let client = MuseClient::new(MuseClientConfig::default());
31//!     let (mut rx, handle) = client.connect().await?;
32//!     handle.start(false, false).await?;
33//!
34//!     while let Some(event) = rx.recv().await {
35//!         match event {
36//!             MuseEvent::Eeg(r) => println!("EEG ch{}: {:?}", r.electrode, r.samples),
37//!             MuseEvent::Disconnected => break,
38//!             _ => {}
39//!         }
40//!     }
41//!     Ok(())
42//! }
43//! ```
44//!
45//! ## Using as a library dependency
46//!
47//! Add to your `Cargo.toml`:
48//!
49//! ```toml
50//! [dependencies]
51//! # Full build (includes the ratatui TUI feature):
52//! muse-rs = "0.1.0"
53//!
54//! # Library only — skips ratatui / crossterm compilation:
55//! muse-rs = { version = "0.1.0", default-features = false }
56//! ```
57//!
58//! ## Module overview
59//!
60//! | Module | Purpose |
61//! |---|---|
62//! | [`prelude`] | One-line glob import of the most commonly needed types |
63//! | [`muse_client`] | BLE scanning, connecting, and the [`muse_client::MuseHandle`] command API |
64//! | [`types`] | All event and data types produced by the client |
65//! | [`protocol`] | GATT UUIDs, sampling constants, and BLE wire-format helpers |
66//! | [`parse`] | Low-level byte-to-sample decoders for EEG, IMU, PPG, and Athena packets |
67
68pub mod muse_client;
69pub mod parse;
70pub mod protocol;
71pub mod types;
72
73// ── Prelude ───────────────────────────────────────────────────────────────────
74
75/// Convenience re-exports for downstream crates.
76///
77/// A single glob import covers the entire surface area needed to scan,
78/// connect, and process events from a Muse headset:
79///
80/// ```no_run
81/// use muse_rs::prelude::*;
82///
83/// # #[tokio::main]
84/// # async fn main() -> anyhow::Result<()> {
85/// let devices = MuseClient::new(MuseClientConfig::default()).scan_all().await?;
86/// let (mut rx, handle) = MuseClient::new(MuseClientConfig::default())
87///     .connect_to(devices.into_iter().next().unwrap()).await?;
88/// handle.start(false, false).await?;
89///
90/// while let Some(ev) = rx.recv().await {
91///     if let MuseEvent::Eeg(r) = ev {
92///         println!("{:?}", r.samples);
93///     }
94/// }
95/// # Ok(())
96/// # }
97/// ```
98pub mod prelude {
99    // ── Client ────────────────────────────────────────────────────────────────
100    pub use crate::muse_client::{MuseClient, MuseClientConfig, MuseDevice, MuseHandle};
101
102    // ── Events and data types ─────────────────────────────────────────────────
103    pub use crate::types::{
104        ControlResponse, EegReading, EegSample, ImuData, MuseEvent, PpgReading, TelemetryData,
105        XyzSample,
106    };
107
108    // ── Protocol constants ────────────────────────────────────────────────────
109    pub use crate::protocol::{
110        ATHENA_PPG_CHANNELS, ATHENA_PPG_FREQUENCY, ATHENA_PPG_SAMPLES_PER_PKT,
111        EEG_CHANNEL_NAMES, EEG_FREQUENCY, EEG_SAMPLES_PER_READING, PPG_CHANNEL_NAMES,
112        PPG_FREQUENCY, PPG_SAMPLES_PER_READING,
113    };
114}