#![warn(clippy::all)]
#![allow(
clippy::float_arithmetic,
clippy::implicit_return,
clippy::needless_return,
clippy::blanket_clippy_restriction_lints,
clippy::pattern_type_mismatch
)]
#![forbid(unsafe_code)]
use core::fmt;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum DataType {
Event = 0x00,
SliceEnd = 0x02,
Version = 0x03,
Waveform = 0x80,
FrequencyBins = 0x83,
Sqi = 0x84,
ZeoTimestamp = 0x8A,
Impedance = 0x97,
BadSignal = 0x9C,
SleepStage = 0x9D,
Invalid(u8) = 0xFF,
}
impl From<u8> for DataType {
fn from(b: u8) -> DataType {
use DataType::*;
match b {
0x00 => Event,
0x02 => SliceEnd,
0x03 => Version,
0x80 => Waveform,
0x83 => FrequencyBins,
0x84 => Sqi,
0x8A => ZeoTimestamp,
0x97 => Impedance,
0x9C => BadSignal,
0x9D => SleepStage,
_ => Invalid(b),
}
}
}
impl fmt::Display for DataType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use DataType::*;
write!(
f,
"{}",
match self {
Event => "Event".into(),
SliceEnd => "SliceEnd".into(),
Version => "Version".into(),
Waveform => "Waveform".into(),
FrequencyBins => "FrequencyBins".into(),
Sqi => "Sqi".into(),
ZeoTimestamp => "ZeoTimestamp".into(),
Impedance => "Impedance".into(),
BadSignal => "BadSignal".into(),
SleepStage => "SleepStage".into(),
Invalid(b) => format!["Invalid({b})"],
}
)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum EventType {
NightStart = 0x05,
SleepOnset = 0x07,
HeadbandDocked = 0x0E,
HeadbandUnDocked = 0x0F,
AlarmOff = 0x10,
AlarmSnooze = 0x11,
AlarmPlay = 0x13,
NightEnd = 0x15,
NewHeadband = 0x24,
Invalid(u8) = 0xFF,
}
impl From<u8> for EventType {
fn from(b: u8) -> EventType {
use EventType::*;
match b {
0x05 => NightStart,
0x07 => SleepOnset,
0x0E => HeadbandDocked,
0x8F => HeadbandUnDocked,
0x10 => AlarmOff,
0x11 => AlarmSnooze,
0x13 => AlarmPlay,
0x15 => NightEnd,
0x24 => NewHeadband,
_ => Invalid(b),
}
}
}
impl fmt::Display for EventType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use EventType::*;
write!(
f,
"{}",
match self {
NightStart => "NightStart".into(),
SleepOnset => "SleepOnset".into(),
HeadbandDocked => "HeadbandDocked".into(),
HeadbandUnDocked => "HeadbandUnDocked".into(),
AlarmOff => "AlarmOff".into(),
AlarmSnooze => "AlarmSnooze".into(),
AlarmPlay => "AlarmPlay".into(),
NightEnd => "NightEnd".into(),
NewHeadband => "NewHeadband".into(),
Invalid(b) => format!["Invalid({b})"],
}
)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum FrequencyBins {
Delta = 0x00,
Theta = 0x01,
Alpha = 0x02,
BetaMid = 0x03,
BetaHigh = 0x04,
BetaLow = 0x05,
Gamma = 0x06,
Invalid(u8) = 0xFF,
}
impl FrequencyBins {
pub fn hz(&self) -> (u8, u8) {
use FrequencyBins::*;
match self {
Delta => (2, 4),
Theta => (4, 8),
Alpha => (8, 13),
BetaLow => (11, 14),
BetaMid => (13, 18),
BetaHigh => (18, 21),
Gamma => (30, 50),
Invalid(_) => (0, 0),
}
}
pub fn is_delta(&self) -> bool {
matches![self, FrequencyBins::Delta]
}
pub fn is_theta(&self) -> bool {
matches![self, FrequencyBins::Theta]
}
pub fn is_alpha(&self) -> bool {
matches![self, FrequencyBins::Alpha]
}
pub fn is_gamma(&self) -> bool {
matches![self, FrequencyBins::Gamma]
}
pub fn is_betta(&self) -> bool {
use FrequencyBins::*;
matches![self, BetaLow | BetaMid | BetaHigh]
}
}
impl From<u8> for FrequencyBins {
fn from(b: u8) -> FrequencyBins {
use FrequencyBins::*;
match b {
0x00 => Delta,
0x01 => Theta,
0x02 => Alpha,
0x03 => BetaMid,
0x04 => BetaHigh,
0x05 => BetaLow,
0x06 => Gamma,
_ => Invalid(b),
}
}
}
impl fmt::Display for FrequencyBins {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use FrequencyBins::*;
write!(
f,
"{}",
match self {
Delta => "Delta".into(),
Theta => "Theta".into(),
Alpha => "Alpha".into(),
BetaMid => "BetaMid".into(),
BetaHigh => "BetaHigh".into(),
BetaLow => "BetaLow".into(),
Gamma => "Gamma".into(),
Invalid(b) => format!["Invalid({b})"],
}
)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum SleepStages {
Undefined = 0x00,
Awake = 0x01,
Rem = 0x02,
Light = 0x03,
Deep = 0x04,
Invalid(u8) = 0xFF,
}
impl From<u8> for SleepStages {
fn from(b: u8) -> SleepStages {
use SleepStages::*;
match b {
0x00 => Undefined,
0x01 => Awake,
0x02 => Rem,
0x03 => Light,
0x04 => Deep,
_ => Invalid(b),
}
}
}
impl fmt::Display for SleepStages {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use SleepStages::*;
write!(
f,
"{}",
match self {
Undefined => "Undefined".into(),
Awake => "Awake".into(),
Rem => "Rem".into(),
Light => "Light".into(),
Deep => "Deep".into(),
Invalid(b) => format!["Invalid({b})"],
}
)
}
}
pub fn filter60hz(a: &[f64]) -> Vec<f64> {
let filter: [f64; 51] = [
0.0056, 0.0190, 0.0113, -0.0106, 0.0029, 0.0041, -0.0082, 0.0089, -0.0062, 0.0006, 0.0066,
-0.0129, 0.0157, -0.0127, 0.0035, 0.0102, -0.0244, 0.0336, -0.0323, 0.0168, 0.0136,
-0.0555, 0.1020, -0.1446, 0.1743, 0.8150, 0.1743, -0.1446, 0.1020, -0.0555, 0.0136, 0.0168,
-0.0323, 0.0336, -0.0244, 0.0102, 0.0035, -0.0127, 0.0157, -0.0129, 0.0066, 0.0006,
-0.0062, 0.0089, -0.0082, 0.0041, 0.0029, -0.0106, 0.0113, 0.0190, 0.0056,
];
let p = a.len();
let q = filter.len();
let n = p + q - 1;
let mut c = vec![0.0; n];
for k in 0..n {
let mut t = 0.0;
let lower = k.saturating_sub(q - 1);
let upper = k.min(p - 1);
for i in lower..=upper {
t += a[i] * filter[k - i];
}
c[k] = t;
}
c
}