Skip to content

Commit

Permalink
moved, refactored
Browse files Browse the repository at this point in the history
  • Loading branch information
blandger committed Feb 2, 2024
1 parent 73525b0 commit fa9687d
Show file tree
Hide file tree
Showing 19 changed files with 144 additions and 128 deletions.
15 changes: 10 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,19 @@ edition = "2021"
repository = "https://github.com/blandger/mielophone"

[workspace.dependencies]
btleplug = { version = "0.11.0", features = ["serde"] }
btleplug = { version = "0.11.5", features = ["serde"] }
#btleplug = { path = "../btleplug-blandger" }
tokio = { version = "1.28.2", features = ["full"] }
tracing = "0.1.37"
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
tokio = { version = "1.36.0", features = ["full"] }
tracing = "0.1.40"
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
async-trait = "0.1.77"
futures = "0.3.30"
tokio-stream = { version = "0.1.14", features = ["sync"] }
uuid = "1.7.0"
thiserror = "1.0.56"

color-eyre = "0.6.2"
chrono = "0.4.25"
chrono = "0.4.33"

#[build]
#rustflags = ["-C", "link-args=-gz"] #zip debug data
14 changes: 7 additions & 7 deletions brainbit/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "lib"
name = "brainbit"
version = "0.1.0"
authors.workspace = true
edition.workspace = true
Expand All @@ -8,13 +8,13 @@ description = "Library wrapper above BLE to support BrainBit device only"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
async-trait = "0.1.68"
futures = "0.3"
btleplug = { workspace = true, features = ["serde"] }

thiserror = "1.0.40"
thiserror.workspace = true
tokio = { workspace = true, features = ["rt", "sync"] }
tokio-stream = { version = "0.1.11", features = ["sync"] }
uuid = "1.3.3"
tokio-stream.workspace = true
uuid.workspace = true
tracing.workspace = true
tracing-subscriber = { workspace = true, features = ["env-filter"] }
tracing-subscriber = { workspace = true, features = ["env-filter"] }
async-trait.workspace = true
futures.workspace = true
9 changes: 9 additions & 0 deletions brainbit/src/bbit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
pub(crate) mod control;
pub mod device;
pub mod errors;
pub(crate) mod internals;
pub mod resist;
pub mod responses;
pub(crate) mod sealed;
pub mod traits;
pub mod uuids;
8 changes: 2 additions & 6 deletions brainbit/src/bbit/control.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::bbit::device::BBitResult;
use crate::bbit::eeg_uuids::WRITE_COMMAN_UUID;
use crate::bbit::uuids::WRITE_COMMAN_UUID;
use crate::{find_characteristic, Error};
use btleplug::api::{Characteristic, Peripheral as _, WriteType};
use btleplug::platform::Peripheral;
Expand Down Expand Up @@ -50,10 +50,6 @@ impl ControlPoint {
.await
.map_err(Error::BleError)
}

/* unsafe fn get_enum_as_u8_slice<T: Sized>(p: &T) -> &[u8] {
from_raw_parts((p as *const T) as *const u8, ::core::mem::size_of::<T>())
}*/
}

#[derive(Clone, Debug, PartialEq, Eq)]
Expand Down Expand Up @@ -154,7 +150,7 @@ impl TryFrom<&[u8]> for ControlPointCommand {
#[cfg(test)]
mod tests {
use super::*;
use crate::bbit::ADS1294ChannelInput;
use crate::bbit::internals::ADS1294ChannelInput;

#[test]
fn test_resist_command_layout() {
Expand Down
32 changes: 17 additions & 15 deletions brainbit/src/bbit/device.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
use crate::bbit::control::{ControlCommandType, ControlPoint, ControlPointCommand};
use crate::bbit::eeg_uuids::{
EventType, NotifyStream, NotifyUuid, FIRMWARE_REVISION_STRING_UUID,
HARDWARE_REVISION_STRING_UUID, MODEL_NUMBER_STRING_UUID, NSS2_SERVICE_UUID,
SERIAL_NUMBER_STRING_UUID,
};
use crate::bbit::responses::{DeviceInfo, DeviceStatusData};
use crate::bbit::sealed::{Bluetooth, Configure, Connected, EventLoop, Level};
use crate::{find_characteristic, Error};
use std::collections::BTreeSet;
use std::sync::{Arc, OnceLock};
use std::time::Duration;

use crate::bbit::{ADS1294ChannelInput, ChannelType, EventHandler, MeasurementType};
use btleplug::{
api::{Central, Characteristic, Manager as _, Peripheral as _, ScanFilter},
platform::{Manager, Peripheral},
};
use futures::stream::StreamExt;
use std::collections::BTreeSet;
use std::sync::{Arc, OnceLock};
use std::time::Duration;
use tokio::sync::{mpsc, oneshot, watch};
use tracing::instrument;
use uuid::Uuid;

use crate::bbit::control::{ControlCommandType, ControlPoint, ControlPointCommand};
use crate::bbit::internals::{ADS1294ChannelInput, ChannelType, MeasurementType};
use crate::bbit::responses::{DeviceInfo, DeviceStatusData};
use crate::bbit::sealed::{Bluetooth, Configure, Connected, EventLoop, Level};
use crate::bbit::traits::EventHandler;
use crate::bbit::uuids::{
EventType, NotifyStream, NotifyUuid, FIRMWARE_REVISION_STRING_UUID,
HARDWARE_REVISION_STRING_UUID, MODEL_NUMBER_STRING_UUID, NSS2_SERVICE_UUID,
SERIAL_NUMBER_STRING_UUID,
};
use crate::{find_characteristic, Error};

pub type BBitResult<T> = Result<T, Error>;

/// Structure to contain EEG data and interval.
Expand Down Expand Up @@ -106,8 +108,8 @@ impl BBitSensor<Bluetooth> {
/// ```rust,no_run
/// # #[tokio::main]
/// # async fn main() {
/// use lib::Error;
/// use lib::bbit::device::BBitSensor;
/// use brainbit::bbit::device::BBitSensor;
/// use brainbit::bbit::errors::Error;
///
/// let mut bbit = BBitSensor::new().await.unwrap()
/// // default handling that is applied to BleSensor::block_connect
Expand Down
29 changes: 29 additions & 0 deletions brainbit/src/bbit/errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use thiserror::Error;

/// Error type for general brainbit errors and internal btleplug Ble errors
#[derive(Debug, Error)]
pub enum Error {
/// Bluetooth adapter is not found on attempt to scan it
#[error("No BLE adaptor")]
NoBleAdaptor,
/// Could not connect to a device by filter
#[error("No BLE device")]
NoDevice,
/// Device looks as it's not connected, but command was called
#[error("Not connected")]
NotConnected,
/// UUID device's characteristic is missing
#[error("Characteristic not found")]
CharacteristicNotFound,
/// EEG Data packets received from device is not parsed
#[error("Invalid '{0}'")]
InvalidData(String),
/// The command did not return a response
#[error("No command response")]
NoControlPointResponse,
/// An error occurred in the underlying BLE library.
#[error("BLE error: {0}")]
BleError(#[from] btleplug::Error),
#[error("Error generated by event handler")]
HandlerError(#[from] Box<dyn std::error::Error + Sync + Send>),
}
43 changes: 5 additions & 38 deletions brainbit/src/bbit/mod.rs → brainbit/src/bbit/internals.rs
Original file line number Diff line number Diff line change
@@ -1,40 +1,5 @@
use crate::bbit::device::{BBitResult, CommandData};
use crate::bbit::responses::DeviceStatusData;
use crate::Error;
use async_trait::async_trait;

pub(crate) mod control;
pub mod device;
pub mod eeg_uuids;
pub mod resist;
pub mod responses;
pub(crate) mod sealed;

/// Base trait for handling events coming from a BrainBit device.
#[async_trait]
pub trait EventHandler {
/// Dispatched when a internal device status update is received.
///
/// Contains the status, cmd error, battery level.
async fn device_status_update(&self, _status: DeviceStatusData) {}

/// Dispatched when an eeg data is received.
///
/// Contains information about the O1, O2, T3, T4 + interval.
async fn eeg_update(&mut self, _eeg_data: Vec<u8>) {}

/// Dispatched when measurement data is received over the PMD data UUID.
///
/// Contains data in a [`CommandData`].
async fn send_command(&self, _command_data: CommandData) {}

/// Checked at start of each event loop.
///
/// Returns [`false`] if the event loop should be terminated and close connection.
async fn should_continue(&self) -> bool {
true
}
}
use crate::bbit::device::BBitResult;
use crate::bbit::errors::Error;

/// List of measurement types you can request.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
Expand All @@ -57,6 +22,7 @@ pub enum ChannelType {
/// Channel 3, o2 (occipital lobe = o, right
O2 = 3,
}

impl ChannelType {
pub fn new(channel_number: u8) -> BBitResult<Self> {
match channel_number {
Expand All @@ -70,6 +36,7 @@ impl ChannelType {
}
}
}

impl Into<u8> for ChannelType {
fn into(self) -> u8 {
self as u8
Expand All @@ -78,7 +45,7 @@ impl Into<u8> for ChannelType {

/// Internal constants to assign for Resistance commands
#[derive(Debug, Copy, Clone)]
enum ADS1294ChannelInput {
pub enum ADS1294ChannelInput {
PowerDownGain6 = 0x00,
PowerDownGain3 = 0x91,
PowerUpGain1 = 0x48,
Expand Down
22 changes: 11 additions & 11 deletions brainbit/src/bbit/responses.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ pub struct DeviceStatusData {
/// NNS service state
pub status_nss2: Nss2Status,
// Error code. It's reset when new command is received
pub cmd_error: CommandResultError,
pub cmd_error: CommandExecutionState,
/// Battery level in percents (%) is stored by lower seven bits, 8-th bit keeps 'charging flag'
pub battery_level: u8, // 87 is a max value = 100% charge
/// Firmware version
Expand All @@ -68,7 +68,7 @@ impl Default for DeviceStatusData {
fn default() -> Self {
Self {
status_nss2: Nss2Status::Initial,
cmd_error: CommandResultError::NoError,
cmd_error: CommandExecutionState::Ok,
battery_level: 0,
firmware_version: 0,
}
Expand Down Expand Up @@ -96,7 +96,7 @@ impl TryFrom<Vec<u8>> for DeviceStatusData {
return Err("device status Vec length");
}
let status_nss2 = Nss2Status::try_from(value[0])?;
let cmd_error = CommandResultError::try_from(value[1])?;
let cmd_error = CommandExecutionState::try_from(value[1])?;
let battery_level = value[2];
let firmware_version = value[3];

Expand Down Expand Up @@ -157,22 +157,22 @@ impl Into<u8> for Nss2Status {

/// A main GATT NSS2 service sending, executing command result type
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CommandResultError {
pub enum CommandExecutionState {
/// No error after command
NoError,
Ok,
/// Command had an incorrect length
ErrorLength,
CommandLengthError,
/// Error on changing device mode, changing working mode is not possible
ErrorSwitchMode,
SwitchModeError,
}
impl TryFrom<u8> for CommandResultError {
impl TryFrom<u8> for CommandExecutionState {
type Error = &'static str;

fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0x0 => Ok(Self::NoError),
0x1 => Ok(Self::ErrorLength),
0x2 => Ok(Self::ErrorSwitchMode),
0x0 => Ok(Self::Ok),
0x1 => Ok(Self::CommandLengthError),
0x2 => Ok(Self::SwitchModeError),
_ => Err("BBit command execution result error"),
}
}
Expand Down
29 changes: 29 additions & 0 deletions brainbit/src/bbit/traits.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use crate::bbit::device::CommandData;
use crate::bbit::responses::DeviceStatusData;
use async_trait::async_trait;

/// Base trait for handling events coming from a BrainBit device.
#[async_trait]
pub trait EventHandler {
/// Dispatched when a internal device status update is received.
///
/// Contains the status, cmd error, battery level.
async fn device_status_update(&self, _status: DeviceStatusData) {}

/// Dispatched when an eeg data is received.
///
/// Contains information about the O1, O2, T3, T4 + interval.
async fn eeg_update(&mut self, _eeg_data: Vec<u8>) {}

/// Dispatched when measurement data is received over the PMD data UUID.
///
/// Contains data in a [`CommandData`].
async fn send_command(&self, _command_data: CommandData) {}

/// Checked at start of each event loop.
///
/// Returns [`false`] if the event loop should be terminated and close connection.
async fn should_continue(&self) -> bool {
true
}
}
File renamed without changes.
30 changes: 1 addition & 29 deletions brainbit/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,40 +1,12 @@
pub mod bbit;

use crate::bbit::device::BBitResult;
pub use async_trait::async_trait;
use bbit::errors::Error;
use btleplug::api::{Characteristic, Peripheral as _};
use btleplug::platform::Peripheral;
use thiserror::Error;
use uuid::Uuid;

/// Error type for general brainbit errors and internal btleplug Ble errors
#[derive(Debug, Error)]
pub enum Error {
/// Bluetooth adapter is not found on attempt to scan it
#[error("No BLE adaptor")]
NoBleAdaptor,
/// Could not connect to a device by filter
#[error("No BLE device")]
NoDevice,
/// Device looks as it's not connected, but command was called
#[error("Not connected")]
NotConnected,
/// UUID device's characteristic is missing
#[error("Characteristic not found")]
CharacteristicNotFound,
/// EEG Data packets received from device is not parsed
#[error("Invalid '{0}'")]
InvalidData(String),
/// The command did not return a response
#[error("No command response")]
NoControlPointResponse,
/// An error occurred in the underlying BLE library.
#[error("BLE error: {0}")]
BleError(#[from] btleplug::Error),
#[error("Error generated by event handler")]
HandlerError(#[from] Box<dyn std::error::Error + Sync + Send>),
}

/// Private helper to find characteristics from a [`Uuid`].
async fn find_characteristic(device: &Peripheral, uuid: Uuid) -> BBitResult<Characteristic> {
device
Expand Down
3 changes: 2 additions & 1 deletion examples/battery_level/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ description = "Subscribe on BBit device status changes including battery level"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
lib = { version = "0.1.0", path = "../../brainbit" }
brainbit = { version = "0.1.0", path = "../../brainbit" }
tokio.workspace = true
tracing.workspace = true
tracing-subscriber.workspace = true
async-trait.workspace = true

color-eyre.workspace = true
chrono.workspace = true
Loading

0 comments on commit fa9687d

Please sign in to comment.