Source code for src.data_acquisition.eeg_headset.eeg_headset
from abc import ABC, abstractmethod
from logging import Logger
from pathlib import Path
from typing import Optional
from unittest.mock import MagicMock
from .errors import EEGHeadsetError
[docs]
class EEGHeadset(ABC):
[docs]
def __init__(self, *, debug: bool = False, logger: Optional[Logger] = None) -> None:
"""
:param debug: If True, the EEG device will not actually be used and no recording will be made.
"""
self._is_debug_mode = debug
self._is_running = False
self._was_disconnected = False
self._logger = logger if logger is not None else MagicMock()
[docs]
def start(self) -> None:
"""
Starts EEG data acquisition.
:raises EEGHeadsetError: If the EEG headset is already running, or if it had been disconnected.
"""
self._check_not_disconnected()
self._check_not_running()
self._is_running = True
self._log("Starting EEG headset")
if self._is_debug_mode:
return
self._start()
def _check_not_disconnected(self) -> None:
if self._was_disconnected:
raise EEGHeadsetError(
"EEG headset has been disconnected and cannot be started again."
)
def _check_not_running(self) -> None:
if self._is_running:
raise EEGHeadsetError(
"EEG headset has already been started and not stopped."
)
def _log(self, message: str) -> None:
self._logger.info(f"{self.__class__.__name__}: {message}")
@abstractmethod
def _start(self) -> None:
pass
[docs]
def stop_and_save_at_path(self, save_path: Path) -> None:
"""
Stops EEG data acquisition and saves the recording at given path.
:param save_path: Path to save the EEG recording.
:raises EEGHeadsetError: If the EEG headset is not running, or if it had been disconnected.
"""
self._check_not_disconnected()
self._check_running()
self._is_running = False
self._log(f"Stopping EEG headset and saving at path: {save_path}")
if self._is_debug_mode:
return
self._stop_and_save_at_path(save_path)
def _check_running(self) -> None:
if not self._is_running:
raise EEGHeadsetError("EEG headset has not been started.")
@abstractmethod
def _stop_and_save_at_path(self, save_path: Path) -> None:
pass
[docs]
def annotate(self, annotation: str) -> None:
"""
Makes an annotation in the EEG recording.
:param annotation: Annotation text.
:raises EEGHeadsetError: If the EEG headset is not running, or if it had been disconnected.
"""
self._check_not_disconnected()
self._check_running()
self._log(f"Adding annotation: {annotation}")
if self._is_debug_mode:
return
self._annotate(annotation)
@abstractmethod
def _annotate(self, annotation: str) -> None:
pass
[docs]
def disconnect(self) -> None:
"""
Should be called after the EEG headset is no longer needed. Some EEG devices may perform cleanup operations here. If called, the object cannot be used anymore.
:raises EEGHeadsetError: If the EEG headset has already been disconnected.
"""
self._check_not_disconnected()
self._disconnect()
def _disconnect(self) -> None:
pass