diff --git a/.gitignore b/.gitignore
index c40b1703..62dffb57 100644
--- a/.gitignore
+++ b/.gitignore
@@ -144,4 +144,12 @@ UserConfig.json
/John_EEG_Project/
# IDE
-.idea
\ No newline at end of file
+.idea
+
+# BAlert License
+physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/License/
+
+# BAlert runtime output
+physiolabxr/third_party/BAlert/Config/balert_command.txt
+physiolabxr/third_party/BAlert/Config/balert_status.txt
+physiolabxr/third_party/BAlert/Config/balert_impedance.json
\ No newline at end of file
diff --git a/physiolabxr/_presets/DevicePresets/BAlert.json b/physiolabxr/_presets/DevicePresets/BAlert.json
new file mode 100644
index 00000000..1bcd79e2
--- /dev/null
+++ b/physiolabxr/_presets/DevicePresets/BAlert.json
@@ -0,0 +1,10 @@
+{ "StreamName":"BAlert",
+ "NominalSamplingRate": 256,
+ "NumChan": 24,
+ "ChannelNames": [
+ "Fp1", "F7", "F8", "T4", "T6", "T5", "T3", "Fp2",
+ "O1", "P3", "Pz", "F3", "Fz", "F4", "C4", "P4",
+ "POz", "C3", "Cz", "O2", "EKG", "AUX1", "AUX2", "AUX3"
+ ],
+ "GroupInfo": [20, 21],
+ "DataType": "float32"}
\ No newline at end of file
diff --git a/physiolabxr/_ui/BAlert_Options.ui b/physiolabxr/_ui/BAlert_Options.ui
new file mode 100644
index 00000000..46f85e95
--- /dev/null
+++ b/physiolabxr/_ui/BAlert_Options.ui
@@ -0,0 +1,86 @@
+
+
+ form
+
+
+ 00640280
+
+
+ Options for B-Alert
+
+
+
+
+
+ -
+
+
+ Qt::AlignRight|Qt::AlignVCenter
+
+
+
-
+
+ Select your ABM license folder
+
+
+ -
+
+
-
+
+
+ e.g. C:\ABM\B-Alert\License
+
+
+
+ -
+
+ …
+ Browse for license folder
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+ Qt::Horizontal
+ 4020
+
+
+
+ -
+
+ Check Impedance
+ Measure electrode impedances (no streaming)
+
+
+ -
+
+ Qt::Horizontal
+ 4020
+
+
+
+
+
+
+ -
+
+
+ true
+
+ color: #c8c8c8;
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/physiolabxr/interfaces/DeviceInterface/BAlert/BAlert_Interface.py b/physiolabxr/interfaces/DeviceInterface/BAlert/BAlert_Interface.py
new file mode 100644
index 00000000..4b3b30d5
--- /dev/null
+++ b/physiolabxr/interfaces/DeviceInterface/BAlert/BAlert_Interface.py
@@ -0,0 +1,626 @@
+import os
+import time
+import platform
+import subprocess
+import threading
+import json
+import atexit
+import psutil
+from pathlib import Path
+import numpy as np
+from pylsl import resolve_byprop, StreamInlet
+from typing import Union, List, Dict, Tuple
+
+from physiolabxr.exceptions.exceptions import (
+ FailToSetupDevice,
+ CustomDeviceStartStreamError,
+ CustomDeviceStreamInterruptedError,
+ CustomDeviceNotFoundError,
+)
+
+
+from physiolabxr.interfaces.LSLInletInterface import LSLInletInterface
+
+
+class BAlert_Interface(LSLInletInterface):
+ STATUS_STARTING = 0
+ STATUS_INITIALIZING = 1
+ STATUS_DETECTING = 2
+ STATUS_MEASURING_IMPEDANCE = 3
+ STATUS_READY = 4
+ STATUS_STREAMING = 5
+ STATUS_ERROR = 6
+ STATUS_STOPPING = 7
+ STATUS_STOPPED = 8
+
+ def __init__(
+ self,
+ lsl_stream_name: str = "BAlert",
+ num_chan: int = 24,
+ nominal_srate: float = 256.0,
+ exe_path: str | None = None,
+ work_dir: str | None = None,
+ ):
+ super().__init__(lsl_stream_name=lsl_stream_name, num_chan=num_chan)
+
+ if platform.system() != "Windows":
+ raise EnvironmentError("Platform Not Supported: BAlert is only supported on Windows")
+
+ self.device_nominal_sampling_rate = nominal_srate
+ self.stream_name = lsl_stream_name
+ self.stream_type = "EEG"
+ self.inlet: StreamInlet | None = None
+ self._inlet_closed = False
+ self.device_available = False
+
+ self.proc: subprocess.Popen | None = None
+ self._reader_thread: threading.Thread | None = None
+ self._reader_stop = threading.Event()
+
+ self.exe_path = exe_path or self._guess_exe_path()
+ self.work_dir = work_dir or self._guess_work_dir()
+
+ self.status_file = os.path.join(self.work_dir, "Config", "balert_status.txt")
+ self.cmd_file = os.path.join(self.work_dir, "Config", "balert_command.txt")
+
+ self._status_watcher = None
+ self._status_watcher_stop = threading.Event()
+
+ self._stopping = False
+
+ # =================== Public API ===================
+ def _watch_status_loop(self):
+ last = None
+ seen_down_at = None
+
+ while not self._status_watcher_stop.is_set():
+ line = ""
+ try:
+ with open(self.status_file, "r", encoding="utf-8") as f:
+ line = f.read().strip()
+ except Exception:
+ pass
+
+ if line and line != last:
+ last = line
+ parts = line.split(",", 1)
+ try:
+ code = int(parts[0])
+ except Exception:
+ code = None
+ msg = parts[1] if len(parts) > 1 else ""
+ base_msg = f"[BAlert] status: {code}, {msg}"
+
+ if code == self.STATUS_ERROR and "Disconnected" in msg:
+ print(base_msg)
+ if seen_down_at is None:
+ seen_down_at = time.time()
+ continue
+
+ if code == self.STATUS_STOPPING:
+ print(base_msg)
+ if seen_down_at is None:
+ seen_down_at = time.time()
+ continue
+
+ if code == self.STATUS_STOPPED:
+ print(base_msg)
+ try:
+ self._stop_reader_thread()
+ except Exception:
+ pass
+ self.proc = None
+ self.device_available = False
+ break
+
+ print(base_msg)
+
+ if seen_down_at and (time.time() - seen_down_at > 3.0):
+ try:
+ if self.proc and self.proc.poll() is None:
+ self.proc.terminate()
+ try:
+ self.proc.wait(timeout=1.5)
+ except subprocess.TimeoutExpired:
+ self.proc.kill()
+ except Exception:
+ pass
+ break
+
+ time.sleep(0.3)
+
+ def _start_status_watcher(self):
+ self._status_watcher_stop.clear()
+ self._status_watcher = threading.Thread(target=self._watch_status_loop, daemon=True)
+ self._status_watcher.start()
+
+ def _stop_status_watcher(self) -> None:
+ try:
+ self._status_watcher_stop.set()
+ except Exception:
+ pass
+
+ @staticmethod
+ def _sync_license_to_exe_dir(exe_path: Path, user_lic_dir: Path) -> Path:
+ exts = {".key", ".exe"}
+ if user_lic_dir.is_file():
+ user_lic_dir = user_lic_dir.parent
+ dst = exe_path.parent / "License"
+ dst.mkdir(exist_ok=True)
+
+ for f in list(dst.iterdir()):
+ if f.is_file() and f.suffix.lower() in exts:
+ try:
+ f.unlink()
+ except Exception:
+ pass
+
+ for f in user_lic_dir.iterdir():
+ if f.is_file() and f.suffix.lower() in exts:
+ (dst / f.name).write_bytes(f.read_bytes())
+
+ return dst
+
+ def start_stream(self, license_dir: str | None = None, exe_path: str | None = None, **kwargs):
+ if self.proc and self.proc.poll() is None:
+ print("BAlert already running; skip start.")
+ return
+ if exe_path:
+ self.exe_path = exe_path
+
+ if not os.path.isfile(self.exe_path):
+ raise FileNotFoundError(f"BAlert.exe not found: {self.exe_path}")
+
+ self.work_dir = self._guess_work_dir()
+ self.status_file = os.path.join(self.work_dir, "Config", "balert_status.txt")
+ self.cmd_file = os.path.join(self.work_dir, "Config", "balert_command.txt")
+
+ cfg_xml = Path(self.work_dir) / "Config" / "AthenaSDK.xml"
+ if not cfg_xml.is_file():
+ raise FileNotFoundError(
+ f"AthenaSDK.xml not found under work dir: {self.work_dir}\nExpected {cfg_xml}"
+ )
+
+ env = os.environ.copy()
+
+ exe_lic = Path(self.exe_path).parent / "License"
+ if license_dir:
+ lic_dst = self._sync_license_to_exe_dir(Path(self.exe_path), Path(license_dir))
+ env["ABM_LICENSE_DIR"] = str(lic_dst)
+ else:
+ has_any = exe_lic.is_dir() and any(exe_lic.iterdir())
+ if not has_any:
+ raise FileNotFoundError("License folder not set. Please pick your ABM license folder in the UI.")
+ env["ABM_LICENSE_DIR"] = str(exe_lic)
+
+ try:
+ if os.path.exists(self.cmd_file):
+ open(self.cmd_file, "w", encoding="utf-8").close()
+ except Exception:
+ pass
+
+ try:
+ killed_any = False
+ for p in psutil.process_iter(["name"]):
+ if (p.info["name"] or "").lower() == "balert.exe":
+ p.kill()
+ killed_any = True
+ if killed_any:
+ time.sleep(1.0)
+ except Exception:
+ pass
+
+ if self._try_connect_lsl():
+ self.device_available = True
+ atexit.register(self.stop_stream)
+ return
+
+ creationflags = 0x08000000 # CREATE_NO_WINDOW
+ time.sleep(0.3)
+ self.proc = subprocess.Popen(
+ [self.exe_path],
+ cwd=self.work_dir,
+ env=env,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ text=True,
+ bufsize=1,
+ creationflags=creationflags,
+ )
+
+ self._start_reader_thread()
+ ready = self._wait_until_ready_or_lsl(timeout=90)
+
+ if not ready:
+ code, msg = self._read_status()
+ msg = (msg or "").strip()
+
+ if (code == self.STATUS_STOPPED) and ("Stopped OK" in msg):
+ self._cleanup()
+ raise CustomDeviceStartStreamError(
+ "B-Alert ESU is not connected or access was denied by the system. "
+ "Please check the USB connection, power/Bluetooth, drivers, and permissions, then try again."
+ )
+ elif code == self.STATUS_ERROR:
+ self._cleanup()
+ raise CustomDeviceStartStreamError(f"Failed to start B-Alert: {msg}")
+ else:
+ self._cleanup()
+ raise CustomDeviceStartStreamError(
+ "B-Alert did not become ready in time or no LSL stream was found. "
+ "Please verify the device connection and try again."
+ )
+
+ if not self._try_connect_lsl():
+ self._cleanup()
+ raise CustomDeviceStartStreamError(
+ "The process started, but no B-Alert LSL stream was found. "
+ "The device may not be connected, or the SDK has not started streaming."
+ )
+
+ atexit.register(self.stop_stream)
+ self._start_status_watcher()
+ self.device_available = True
+
+ def stop_stream(self, **kwargs):
+ if getattr(self, "_stopping", False) and self.proc is None and self.inlet is None:
+ return
+ self._stopping = True
+
+ self._stop_reader_thread()
+
+ if self.inlet is not None:
+ try:
+ self.inlet.close_stream()
+ except Exception:
+ pass
+ self._inlet_closed = True
+ self.inlet = None
+ self.streams = None
+
+ try:
+ if self.cmd_file:
+ with open(self.cmd_file, "w", encoding="utf-8") as f:
+ f.write("STOP")
+ except Exception:
+ pass
+
+ self._stop_status_watcher()
+
+ if self.proc and self.proc.poll() is None:
+ try:
+ self.proc.wait(timeout=2.0)
+ except subprocess.TimeoutExpired:
+ try:
+ self.proc.terminate()
+ self.proc.wait(timeout=2.0)
+ except Exception:
+ try:
+ self.proc.kill()
+ except Exception:
+ pass
+
+ self.proc = None
+ self.device_available = False
+ self._stopping = False
+
+ # ---- helper: soft fail without raising ----
+ def _cleanup(self):
+ """Internal cleanup without raising exceptions"""
+ try:
+ if self.cmd_file:
+ with open(self.cmd_file, "w", encoding="utf-8") as f:
+ f.write("STOP")
+ except Exception:
+ pass
+
+ try:
+ self._stop_reader_thread()
+ self._stop_status_watcher()
+ except Exception:
+ pass
+
+ try:
+ if self.proc and self.proc.poll() is None:
+ self.proc.terminate()
+ try:
+ self.proc.wait(timeout=1.5)
+ except subprocess.TimeoutExpired:
+ self.proc.kill()
+ except Exception:
+ pass
+
+ self.proc = None
+ self.inlet = None
+ self._inlet_closed = True
+ self.device_available = False
+
+ def _soft_fail(self, user_msg: str):
+ """Clean up and raise an exception to notify the UI"""
+ print(user_msg)
+ self._cleanup()
+ raise CustomDeviceStartStreamError(user_msg)
+
+ def get_sampling_rate(self):
+ return self.device_nominal_sampling_rate
+
+ def is_device_available(self):
+ return self.device_available
+
+ def process_frames(self):
+ if self.inlet is None or self._inlet_closed:
+ return [], [], []
+ try:
+ frames, timestamps = super().process_frames()
+ except Exception:
+ return [], [], []
+ return frames, timestamps, []
+
+ # ===== Impedance check =====
+ def check_impedance(self, timeout: float = 60.0) -> List[Dict]:
+
+ if self.proc and self.proc.poll() is None:
+ raise RuntimeError("Acquisition is running, cannot check impedance.")
+
+ try:
+ killed_any = False
+ for p in psutil.process_iter(["name"]):
+ if (p.info["name"] or "").lower() == "balert.exe":
+ p.kill()
+ killed_any = True
+ if killed_any:
+ time.sleep(0.5)
+ except Exception:
+ pass
+
+ exe = Path(self.exe_path)
+ work = Path(self.work_dir)
+ json_path = work / "Config" / "balert_impedance.json"
+ status_path = work / "Config" / "balert_status.txt"
+
+ for pth in (json_path, status_path):
+ try:
+ if pth.exists():
+ pth.unlink()
+ except Exception:
+ pass
+
+ env = os.environ.copy()
+ exe_lic = exe.parent / "License"
+ if exe_lic.is_dir() and any(exe_lic.iterdir()):
+ env["ABM_LICENSE_DIR"] = str(exe_lic)
+ elif "ABM_LICENSE_DIR" in env:
+ pass
+ else:
+ raise FileNotFoundError("No ABM license found. Please select license in Options first.")
+
+ creationflags = getattr(subprocess, "CREATE_NO_WINDOW", 0)
+
+ Payload = Union[List[Dict], str] # ok=True -> List[Dict]; ok=False -> str
+
+ def one_attempt() -> Tuple[bool, Payload]:
+ for pth in (json_path, status_path):
+ try:
+ if pth.exists():
+ pth.unlink()
+ except Exception:
+ pass
+
+ proc = subprocess.Popen(
+ [str(exe), "--impedance-only"],
+ cwd=str(work),
+ env=env,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ text=True,
+ creationflags=creationflags,
+ )
+
+ t0 = time.time()
+ last_log = ""
+ sig_line = ""
+ sig_keywords = (
+ "IsConnectionOpened=FALSE",
+ "Disconnected",
+ "No device",
+ "ACCESS_DENIED",
+ "Stopped OK",
+ )
+
+ while True:
+ rc = proc.poll()
+
+ if proc.stdout and not proc.stdout.closed:
+ try:
+ line = proc.stdout.readline()
+ if line:
+ last_log = line.rstrip()
+ if any(k in last_log for k in sig_keywords):
+ sig_line = last_log
+ except Exception:
+ pass
+
+ if json_path.exists():
+ pass
+
+ try:
+ if status_path.exists():
+ s = status_path.read_text("utf-8").strip()
+ if s:
+ parts = s.split(",", 1)
+ code = int(parts[0])
+ smsg = parts[1] if len(parts) > 1 else ""
+ if code in (6, 8) and ("Stopped OK" in smsg or "Disconnected" in smsg):
+ return False, f"disconnected::{smsg}"
+ except Exception:
+ pass
+
+ if rc is not None:
+ if sig_line:
+ return False, f"disconnected::{sig_line}"
+ elapsed = time.time() - t0
+ return False, f"early_exit::{elapsed:.2f}::{(last_log or '')}"
+
+ if time.time() - t0 > timeout:
+ try:
+ proc.kill()
+ except Exception:
+ pass
+ return False, f"Timeout. Last log: {last_log or 'none'}"
+
+ time.sleep(0.08)
+
+ ok, payload = one_attempt()
+ if ok:
+ return payload # type: ignore[return-value]
+
+ if isinstance(payload, str) and payload.startswith("early_exit::"):
+ try:
+ elapsed = float(payload.split("::", 2)[1])
+ except Exception:
+ elapsed = 0.0
+ if elapsed < 1.8:
+ time.sleep(0.6)
+ ok2, payload2 = one_attempt()
+ if ok2:
+ return payload2 # type: ignore[return-value]
+ payload = payload2
+
+ last = payload.split("::", 2)[-1] if isinstance(payload, str) else ""
+ raise RuntimeError(
+ "B-Alert exited before producing impedance results."
+ )
+
+ raise RuntimeError(f"Impedance failed: {payload}")
+
+ # =================== Internals ===================
+ def _guess_exe_path(self) -> str:
+ here = Path(__file__).resolve().parent
+ candidates = [
+ here / "x64" / "Release" / "BAlert.exe",
+ ]
+ for p in candidates:
+ if p.is_file():
+ return str(p)
+ raise FileNotFoundError(
+ "BAlert.exe not found in:\n" + "\n".join(str(p) for p in candidates)
+ )
+
+ def _guess_work_dir(self) -> str:
+ here = Path(__file__).resolve().parent
+ tried = []
+ for anc in [here] + list(here.parents):
+ if anc.name.lower() == "physiolabxr":
+ base = anc / "third_party" / "BAlert"
+ cfg = base / "Config" / "AthenaSDK.xml"
+ tried.append(str(cfg))
+ if cfg.is_file():
+ return str(base)
+ raise FileNotFoundError(
+ "AthenaSDK.xml not found. Looked for:\n" + "\n".join(tried)
+ )
+
+ def _read_status(self):
+ try:
+ with open(self.status_file, "r", encoding="utf-8") as f:
+ line = f.read().strip()
+ if not line:
+ return None, ""
+ parts = line.split(",", 1)
+ code = int(parts[0])
+ msg = parts[1] if len(parts) > 1 else ""
+ return code, msg
+ except Exception:
+ return None, ""
+
+ def _wait_until_ready_or_lsl(self, timeout=90) -> bool:
+ t0 = time.time()
+ last_msg = ""
+ while time.time() - t0 < timeout:
+ if self._has_lsl_stream():
+ return True
+ code, msg = self._read_status()
+ if msg and msg != last_msg:
+ last_msg = msg
+ print(f"[BAlert] status: {code}, {msg}")
+ if code in (self.STATUS_READY, self.STATUS_STREAMING):
+ return True
+ if code in (self.STATUS_ERROR, self.STATUS_STOPPED):
+ return False
+ time.sleep(0.2)
+ return False
+
+ def _has_lsl_stream(self) -> bool:
+ try:
+ streams = resolve_byprop("name", self.stream_name, timeout=0.3)
+ if streams:
+ return True
+ eeg_streams = resolve_byprop("type", "EEG", timeout=0.3)
+ return any(s.name() == self.stream_name for s in eeg_streams)
+ except Exception:
+ return False
+
+ def _try_connect_lsl(self) -> bool:
+ streams = resolve_byprop("name", self.stream_name, timeout=2.0)
+ if not streams:
+ eeg_streams = resolve_byprop("type", "EEG", timeout=2.0)
+ streams = [s for s in eeg_streams if s.name() == self.stream_name]
+
+ print("LSL streams found:",
+ [(s.name(), s.type(), s.channel_count(), s.nominal_srate()) for s in streams])
+
+ if not streams:
+ return False
+
+ info = streams[0]
+ n_ch = info.channel_count()
+ if n_ch != self.lsl_num_chan:
+ raise RuntimeError(f"channels mismatch: preset {self.lsl_num_chan} vs stream {n_ch}")
+
+ self.inlet = StreamInlet(info, max_buflen=60, recover=False)
+ self._inlet_closed = False
+ self.streams = streams
+ return True
+
+ # ---------- stdout reader ----------
+ def _reader_loop(self):
+ if not self.proc or not self.proc.stdout:
+ return
+ while not self._reader_stop.is_set():
+ line = self.proc.stdout.readline()
+ if not line:
+ break
+ try:
+ print("[BAlert.exe]", line.rstrip())
+ except Exception:
+ pass
+
+ def _start_reader_thread(self):
+ self._reader_stop.clear()
+ if self.proc and self.proc.stdout:
+ self._reader_thread = threading.Thread(target=self._reader_loop, daemon=True)
+ self._reader_thread.start()
+
+ def _stop_reader_thread(self):
+ self._reader_stop.set()
+ t = self._reader_thread
+ self._reader_thread = None
+ if t and t.is_alive():
+ try:
+ t.join(timeout=1.0)
+ except Exception:
+ pass
+
+
+if __name__ == "__main__":
+ dev = BAlert_Interface(lsl_stream_name="BAlert", num_chan=24, nominal_srate=256.0)
+ lic = os.environ.get("ABM_LICENSE_DIR", None)
+ dev.start_stream(license_dir=lic)
+ try:
+ for _ in range(200):
+ frames, timestamps, _ = dev.process_frames()
+ if len(timestamps):
+ print("shape:", np.array(frames).shape, "n_ts:", len(timestamps))
+ time.sleep(0.05)
+ finally:
+ dev.stop_stream()
\ No newline at end of file
diff --git a/physiolabxr/interfaces/DeviceInterface/BAlert/BAlert_Options.py b/physiolabxr/interfaces/DeviceInterface/BAlert/BAlert_Options.py
new file mode 100644
index 00000000..dcd1f562
--- /dev/null
+++ b/physiolabxr/interfaces/DeviceInterface/BAlert/BAlert_Options.py
@@ -0,0 +1,634 @@
+from __future__ import annotations
+import os
+import json
+import psutil
+import time
+import subprocess
+from pathlib import Path
+from typing import List
+
+import numpy as np
+from PyQt6 import QtWidgets, QtCore
+from PyQt6.QtWidgets import QHeaderView
+from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg as FigureCanvas
+import matplotlib.pyplot as plt
+from matplotlib.patches import Ellipse
+
+try:
+ import mne
+except Exception:
+ mne = None
+
+from physiolabxr.ui.BaseDeviceOptions import BaseDeviceOptions
+from physiolabxr.configs.configs import AppConfigs
+
+# ----------------- constants -----------------
+ORDER = [
+ "Fp1", "F7", "F8", "T4", "T6", "T5", "T3", "Fp2",
+ "O1", "P3", "Pz", "F3", "Fz", "F4", "C4", "P4",
+ "POz", "C3", "Cz", "O2"
+]
+_NAME_TO_MNE = {"T3": "T7", "T4": "T8", "T5": "P7", "T6": "P8", "POz": "Oz"}
+
+WINDOW_MIN_W, WINDOW_MIN_H = 1000, 860
+HEAD_R = 1.05
+PLOT_PAD = 0.22
+NOSE_APEX_H = 0.16
+NOSE_BASE_IN = 0.03
+NOSE_HALF = 0.085
+NOSE_LINE_W = 2.0
+EAR_A = 0.09
+EAR_B = 0.15
+EAR_LINE_W = 2.0
+MARGIN = 0.85
+
+# ----------------- helpers -----------------
+def _kill_existing_balert(timeout: float = 1.5):
+ try:
+ killed = False
+ for p in psutil.process_iter(['name']):
+ if (p.info.get('name') or '').lower() == 'balert.exe':
+ p.kill()
+ killed = True
+ if killed:
+ time.sleep(timeout)
+ except Exception:
+ pass
+
+def _sync_license_to_exe_dir(exe: Path, user_lic_dir: Path) -> Path:
+ exts = {".key", ".exe"}
+ if user_lic_dir.is_file():
+ user_lic_dir = user_lic_dir.parent
+
+ dst = exe.parent / "License"
+ dst.mkdir(exist_ok=True)
+
+ try:
+ if user_lic_dir.resolve() == dst.resolve():
+ return dst
+ except Exception:
+ pass
+
+ for f in list(dst.iterdir()):
+ if f.is_file() and f.suffix.lower() in exts:
+ try:
+ f.unlink()
+ except Exception:
+ pass
+
+ for f in user_lic_dir.iterdir():
+ if f.is_file() and f.suffix.lower() in exts:
+ (dst / f.name).write_bytes(f.read_bytes())
+
+ return dst
+
+def build_pos_from_mne(order: list[str]) -> dict[str, tuple[float, float]]:
+ ch_pos = {}
+ if mne is not None:
+ try:
+ montage = mne.channels.make_standard_montage("standard_1020")
+ ch_pos = montage.get_positions().get("ch_pos", {}) or {}
+ except Exception:
+ ch_pos = {}
+
+ names_mne = [_NAME_TO_MNE.get(ch, ch) for ch in order]
+ xyz_list, keep_names = [], []
+ for raw_name, mne_name in zip(order, names_mne):
+ if mne_name in ch_pos:
+ v = np.asarray(ch_pos[mne_name], dtype=float)
+ nrm = np.linalg.norm(v)
+ if nrm > 0:
+ v = v / nrm
+ xyz_list.append(v)
+ keep_names.append(raw_name)
+
+ if not xyz_list:
+ import math
+ r = HEAD_R * 0.75
+ n = max(len(order), 1)
+ return {ch: (r * math.cos(2*np.pi*i/n), r * math.sin(2*np.pi*i/n))
+ for i, ch in enumerate(order)}
+
+ xyz = np.vstack(xyz_list)
+ x, y, z = xyz[:, 0], xyz[:, 1], xyz[:, 2]
+ theta = np.arctan2(y, x)
+ colat = np.arccos(np.clip(z, -1.0, 1.0))
+ colat_max = np.percentile(colat, 98) or (np.pi/2)
+ if colat_max <= 0:
+ colat_max = np.pi / 2
+ r = (colat / colat_max) * (MARGIN * HEAD_R)
+ px = r * np.cos(theta)
+ py = r * np.sin(theta)
+
+ out = {name: (float(ix), float(iy)) for name, ix, iy in zip(keep_names, px, py)}
+
+ R_clip = HEAD_R * 0.98
+ for k, (ix, iy) in list(out.items()):
+ rad = (ix*ix + iy*iy) ** 0.5
+ if rad > R_clip and rad > 0:
+ s = R_clip / rad
+ out[k] = (ix * s, iy * s)
+
+ middle_flat = {"T3", "C3", "Cz", "C4", "T4"}
+ last_arc = {"O1", "POz", "O2"}
+
+ MID_UP = 0.06 * HEAD_R
+ ys_mid = [out[n][1] for n in middle_flat if n in out]
+ if ys_mid:
+ y_flat = float(np.mean(ys_mid)) + MID_UP
+ for n in middle_flat:
+ if n in out:
+ x0, _ = out[n]
+ out[n] = (x0, y_flat)
+
+ xs_last = [abs(out[n][0]) for n in last_arc if n in out]
+ if xs_last:
+ x_max = max(xs_last) or 1.0
+ y_base = float(np.mean([out[n][1] for n in last_arc if n in out]))
+ AMP = 0.08 * HEAD_R
+ POWER = 1.5
+ for n in last_arc:
+ if n in out:
+ x0, _ = out[n]
+ k = 1.0 - (abs(x0) / x_max) ** POWER
+ new_y = y_base + AMP * k
+ out[n] = (x0, new_y - 0.1 * HEAD_R)
+
+ return out
+
+POS: dict[str, tuple[float, float]] = build_pos_from_mne(ORDER)
+
+def color_for_value(v: float, ok: bool, th_g: float = 40.0, th_y: float = 80.0):
+ if v == 99999:
+ return (0.6, 0.6, 0.6)
+ if v < th_g:
+ return (0.2, 0.8, 0.2)
+ if v < th_y:
+ return (1.0, 0.85, 0.2)
+ return (1.0, 0.3, 0.3)
+
+def _balert_exe_path() -> Path:
+ here = Path(__file__).parent
+ cands = [here / "x64" / "Release" / "BAlert.exe"]
+ for p in cands:
+ if p.is_file():
+ return p
+ return cands[0]
+
+def _guess_work_dir_like_interface() -> Path:
+ here = Path(__file__).resolve().parent
+ for anc in [here] + list(here.parents):
+ if anc.name.lower() == "physiolabxr":
+ base = anc / "third_party" / "BAlert"
+ if (base / "Config" / "AthenaSDK.xml").is_file():
+ return base
+ raise FileNotFoundError("AthenaSDK.xml not found under physiolabxr/third_party/BAlert")
+
+# ----------------- worker -----------------
+class _ImpWorker(QtCore.QThread):
+ finished_items = QtCore.pyqtSignal(list)
+ failed = QtCore.pyqtSignal(str)
+
+ def __init__(self, exe: Path, license_dir: str, work_dir: Path,
+ timeout: float = 60.0, parent=None):
+ super().__init__(parent)
+ self.exe = exe
+ self.license_dir = license_dir
+ self.work_dir = work_dir
+ self.timeout = timeout
+ self.status_path = self.work_dir / "Config" / "balert_status.txt"
+ self.json_path = self.work_dir / "Config" / "balert_impedance.json"
+ self.before_mtime = self.json_path.stat().st_mtime if self.json_path.exists() else 0.0
+
+ def run(self):
+ try:
+ if not self.exe.exists():
+ self.failed.emit(f"Cannot find BAlert.exe at: {self.exe}")
+ return
+ if not self.license_dir or not Path(self.license_dir).exists():
+ self.failed.emit("Invalid license folder.")
+ return
+
+ def one_attempt() -> tuple[bool, str]:
+ for p in (self.json_path, self.status_path):
+ try:
+ if p.exists():
+ p.unlink()
+ except Exception:
+ pass
+
+ env = os.environ.copy()
+ env["ABM_LICENSE_DIR"] = self.license_dir
+
+ flags = 0
+ if hasattr(subprocess, "CREATE_NO_WINDOW"):
+ flags |= subprocess.CREATE_NO_WINDOW
+
+ time.sleep(0.3)
+
+ proc = subprocess.Popen(
+ [str(self.exe), "--impedance-only"],
+ cwd=str(self.work_dir),
+ env=env,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ text=True,
+ creationflags=flags,
+ )
+
+ t0 = time.time()
+ last_log = ""
+ disconnected_hit = False
+ disconnect_markers = (
+ "IsConnectionOpened=FALSE",
+ "Disconnected",
+ "No device",
+ "Stopped OK",
+ "STATUS_STOPPED",
+ )
+
+ while True:
+ rc = proc.poll()
+
+ if proc.stdout and not proc.stdout.closed:
+ try:
+ line = proc.stdout.readline()
+ if line:
+ line = line.rstrip()
+ last_log = line
+ if any(m in line for m in disconnect_markers):
+ disconnected_hit = True
+ except Exception:
+ pass
+
+ if self.json_path.exists():
+ try:
+ data = json.loads(self.json_path.read_text("utf-8"))
+ items = []
+ for it in data.get("impedances", []):
+ name = it.get("name", "")
+ val = float(it.get("value", 99999))
+ ok = bool(it.get("ok", (val != 99999 and val < 40.0)))
+ items.append({"name": name, "value": val, "ok": ok})
+ self.finished_items.emit(items)
+ return True, ""
+ except Exception as e:
+ last_log = f"JSON parse error: {e}"
+
+ try:
+ if self.status_path.exists():
+ s = self.status_path.read_text("utf-8").strip()
+ if s:
+ code = int(s.split(",", 1)[0])
+ msg = s.split(",", 1)[1] if "," in s else ""
+ # SDK ERROR
+ if code == 6:
+ return False, (msg or "SDK error")
+ if code == 8:
+ if "Impedance done" in msg and not self.json_path.exists():
+ time.sleep(0.3)
+ if self.json_path.exists():
+ continue
+ return False, "Impedance finished but no result file produced."
+ return False, "disconnected::status_stopped"
+ except Exception:
+ pass
+
+ if rc is not None:
+ elapsed = time.time() - t0
+ prefix = "disconnected" if disconnected_hit else "early_exit"
+ return False, f"{prefix}::{elapsed:.2f}::{last_log or 'no-log'}"
+
+ if time.time() - t0 > self.timeout:
+ try:
+ proc.kill()
+ except Exception:
+ pass
+ return False, f"Timeout. Last log: {last_log or 'none'}"
+
+ time.sleep(0.08)
+
+ def _clean_log(s: str) -> str:
+ if not s:
+ return s
+ noisy = ("bin_dir=", "cfg_dir=", "lic_dir=", "license_dir=")
+ return "" if any(k in s for k in noisy) else s
+
+ ok, msg = one_attempt()
+
+ if not ok and isinstance(msg, str) and msg.startswith("disconnected::"):
+ self.failed.emit(
+ "B-Alert ESU is not connected or access was denied. "
+ "Please check USB/power/Bluetooth, drivers, and permissions."
+ )
+ return
+
+ if not ok and isinstance(msg, str) and msg.startswith("early_exit::"):
+ parts = msg.split("::", 2)
+ try:
+ elapsed = float(parts[1])
+ except Exception:
+ elapsed = 0.0
+ last_log = parts[2] if len(parts) > 2 else ""
+
+ if elapsed < 2.5:
+ time.sleep(1.0)
+ ok2, msg2 = one_attempt()
+ if ok2:
+ return
+ if isinstance(msg2, str) and msg2.startswith("early_exit::"):
+ self.failed.emit("Please wait a few seconds and try again.")
+ return
+ msg = msg2 or msg
+ last_log = (msg.split("::", 2)[-1]
+ if isinstance(msg, str) and "::" in msg else last_log)
+
+ clean = _clean_log(last_log)
+ if clean:
+ self.failed.emit(f"Failed to measure impedance. Details: {clean}")
+ else:
+ self.failed.emit("Failed to measure impedance. The SDK exited before producing results.")
+ return
+
+ if not ok:
+ clean = _clean_log(str(msg))
+ self.failed.emit(clean or "Failed to measure impedance.")
+ return
+
+ return
+
+ except Exception as e:
+ self.failed.emit(str(e))
+
+# ----------------- table & canvas -----------------
+class ImpTable(QtWidgets.QTableWidget):
+ def __init__(self, parent=None):
+ super().__init__(0, 3, parent)
+ self.setHorizontalHeaderLabels(["Channel", "Value (kΩ)", ""])
+ self.verticalHeader().setVisible(False)
+ self.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers)
+ self.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows)
+ self.setSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred,
+ QtWidgets.QSizePolicy.Policy.Expanding)
+
+ hdr = self.horizontalHeader()
+ hdr.setStretchLastSection(False)
+ hdr.setSectionResizeMode(0, QHeaderView.ResizeMode.Stretch)
+ hdr.setSectionResizeMode(1, QHeaderView.ResizeMode.Stretch)
+ hdr.setSectionResizeMode(2, QHeaderView.ResizeMode.Fixed)
+ self.setColumnWidth(2, 18)
+ self.verticalHeader().setDefaultSectionSize(22)
+
+ def _make_swatch(self, rgb):
+ r, g, b = [int(x * 255) for x in rgb]
+ box = QtWidgets.QLabel()
+ box.setFixedSize(16, 16)
+ box.setStyleSheet(
+ f"background-color: rgb({r},{g},{b});"
+ f"border: 1px solid #333; border-radius: 3px;"
+ )
+ wrapper = QtWidgets.QWidget()
+ lay = QtWidgets.QHBoxLayout(wrapper)
+ lay.setContentsMargins(0, 0, 0, 0)
+ lay.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
+ lay.addWidget(box)
+ return wrapper
+
+ def update_rows(self, items: List[dict]):
+ self.setRowCount(0)
+ rank = {name: i for i, name in enumerate(ORDER)}
+ items = sorted(items, key=lambda x: rank.get(x.get("name", ""), 999))
+ for it in items:
+ n = it.get("name", "")
+ v = float(it.get("value", 99999))
+ ok = bool(it.get("ok", False))
+ row = self.rowCount()
+ self.insertRow(row)
+ self.setItem(row, 0, QtWidgets.QTableWidgetItem(n))
+ self.setItem(row, 1, QtWidgets.QTableWidgetItem("NA" if v == 99999 else f"{int(v)}"))
+ self.setCellWidget(row, 2, self._make_swatch(color_for_value(v, ok)))
+ self.resizeColumnsToContents()
+
+class TopoCanvas(FigureCanvas):
+ def __init__(self):
+ fig, ax = plt.subplots(figsize=(4.8, 4.8))
+ super().__init__(fig)
+ self.ax = ax
+ self._draw_base()
+
+ def _draw_base(self):
+ ax = self.ax
+ ax.clear()
+ gray = (0.5, 0.5, 0.5)
+ R = HEAD_R
+
+ head = plt.Circle((0.0, 0.0), R, fill=False, linewidth=2.0, color=gray)
+ ax.add_patch(head)
+
+ apex_y = R + NOSE_APEX_H * R
+ base_y = R + 0.005 * R
+ base_dx = NOSE_HALF * R
+ nose = plt.Polygon(
+ [(0.0, apex_y), (-base_dx, base_y), (base_dx, base_y)],
+ closed=True, fill=False, linewidth=NOSE_LINE_W, color=gray
+ )
+ ax.add_patch(nose)
+
+ ear_w = 2 * EAR_A * R
+ ear_h = 2 * EAR_B * R
+ left_center_x = -R - EAR_A * R
+ right_center_x = R + EAR_A * R
+ left_ear = Ellipse((left_center_x, 0.0), width=ear_w, height=ear_h,
+ angle=0, fill=False, linewidth=EAR_LINE_W, edgecolor=gray)
+ right_ear = Ellipse((right_center_x, 0.0), width=ear_w, height=ear_h,
+ angle=0, fill=False, linewidth=EAR_LINE_W, edgecolor=gray)
+ ax.add_patch(left_ear)
+ ax.add_patch(right_ear)
+
+ pad = PLOT_PAD * R
+ ax.set_xlim(-R - pad, R + pad)
+ ax.set_ylim(-R - pad, R + pad)
+ ax.set_aspect("equal", adjustable="box")
+ ax.axis("off")
+
+ def update_impedance(self, items: list[dict]):
+ self._draw_base()
+ xs, ys, cols = [], [], []
+ for it in items:
+ n = it.get("name", "")
+ if n not in POS:
+ continue
+ x, y = POS[n]
+ v = float(it.get("value", 99999))
+ ok = bool(it.get("ok", False))
+ cols.append(color_for_value(v, ok))
+ xs.append(x)
+ ys.append(y)
+ label = f"{n}\n{'NA' if v == 99999 else int(v)}"
+ self.ax.text(x, y, label, ha="center", va="center", fontsize=8, zorder=3)
+ self.ax.scatter(xs, ys, s=480, c=cols, edgecolors="k", linewidths=1, zorder=2)
+ self.draw_idle()
+
+# ----------------- options window -----------------
+class BAlert_Options(BaseDeviceOptions):
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+
+ self.setMinimumSize(WINDOW_MIN_W, WINDOW_MIN_H)
+ self.resize(WINDOW_MIN_W, WINDOW_MIN_H)
+
+ self.license_browse_btn.clicked.connect(self._on_browse_license) # type: ignore[attr-defined]
+
+ self.check_impedance_btn.clicked.connect(self._on_check_impedance) # type: ignore[attr-defined]
+
+ self.license_sync_label = QtWidgets.QLabel(
+ "License will be synced when you click 'Sync License' or start streaming."
+ )
+ self.license_sync_label.setWordWrap(True)
+ self.license_sync_label.setStyleSheet("color:#9aa0a6;")
+
+ self.status_label = QtWidgets.QLabel("")
+ self.table = ImpTable(self)
+ self.canvas = TopoCanvas()
+
+ self.canvas.setMinimumSize(460, 460)
+ self.canvas.setSizePolicy(
+ QtWidgets.QSizePolicy.Policy.Expanding,
+ QtWidgets.QSizePolicy.Policy.Expanding,
+ )
+
+ hbox = QtWidgets.QHBoxLayout()
+ hbox.addWidget(self.table)
+ hbox.addWidget(self.canvas, 1)
+ hbox.setStretch(0, 0)
+ hbox.setStretch(1, 1)
+
+ root_layout = self.layout() or QtWidgets.QVBoxLayout(self)
+ if self.layout() is None:
+ self.setLayout(root_layout)
+ self._place_license_hint_above_check_button(root_layout)
+
+ root_layout.addWidget(self.status_label)
+ root_layout.addLayout(hbox)
+
+ if getattr(AppConfigs(), "balert_license_dir", None):
+ self.license_dir_lineedit.setText(AppConfigs().balert_license_dir) # type: ignore[attr-defined]
+
+ empty = [{"name": ch, "value": 99999, "ok": False} for ch in ORDER]
+ self.table.update_rows(empty)
+ self.canvas.update_impedance(empty)
+
+ self._worker: _ImpWorker | None = None
+
+ def _place_license_hint_above_check_button(self, root_layout: QtWidgets.QVBoxLayout):
+ row = None
+ parent_w = self.check_impedance_btn.parentWidget() # type: ignore[attr-defined]
+ if parent_w is not None and isinstance(parent_w.layout(), QtWidgets.QHBoxLayout):
+ row = parent_w.layout()
+ if row is not None:
+ for i in range(root_layout.count()):
+ it = root_layout.itemAt(i)
+ if it and it.layout() is row:
+ root_layout.insertWidget(i, self.license_sync_label)
+ return
+ root_layout.insertWidget(0, self.license_sync_label)
+
+ # ----- license hint -----
+ def _show_license_selected(self, _path: str):
+ self.license_sync_label.setText("License folder selected.")
+ self.license_sync_label.setStyleSheet("color:#9aa0a6;")
+
+ def _show_license_synced(self):
+ self.license_sync_label.setText("License synced successfully.")
+ self.license_sync_label.setStyleSheet("color:#2e7d32; font-weight:600;")
+
+ def _show_license_sync_failed(self, reason: str | None = None):
+ msg = "License sync failed."
+ if reason:
+ msg += f" {reason}"
+ self.license_sync_label.setText(msg)
+ self.license_sync_label.setStyleSheet("color:#c62828; font-weight:600;")
+
+ # ----- select license -----
+ def _on_browse_license(self):
+ saved_dir = getattr(AppConfigs(), "balert_license_dir", "")
+ default_dir = saved_dir if saved_dir else str(Path.home())
+ path = QtWidgets.QFileDialog.getExistingDirectory(
+ self, "Select License Folder",
+ self.license_dir_lineedit.text() or default_dir # type: ignore[attr-defined]
+ )
+ if path:
+ self.license_dir_lineedit.setText(path) # type: ignore[attr-defined]
+ try:
+ AppConfigs().balert_license_dir = path
+ except Exception:
+ pass
+ self._show_license_selected(path)
+
+ # ----- Check Impedance -----
+ def _on_check_impedance(self):
+ exe = _balert_exe_path()
+ if not exe.exists():
+ QtWidgets.QMessageBox.critical(self, "Check Impedance", f"Cannot find BAlert.exe:\n{exe}")
+ return
+
+ license_dir = (self.license_dir_lineedit.text() or "").strip() # type: ignore[attr-defined]
+ if not license_dir or not Path(license_dir).exists():
+ QtWidgets.QMessageBox.critical(self, "Check Impedance", "Please select a valid License folder.")
+ return
+
+ _kill_existing_balert(timeout=1.0)
+ try:
+ lic_dst = _sync_license_to_exe_dir(exe, Path(license_dir))
+ except Exception as e:
+ self._show_license_sync_failed("Please reselect the folder.")
+ QtWidgets.QMessageBox.critical(self, "Check Impedance", f"License sync failed:\n{e}")
+ return
+ QtCore.QThread.msleep(350)
+ self._show_license_synced()
+
+ try:
+ AppConfigs().balert_license_dir = license_dir
+ except Exception:
+ pass
+
+ self.check_btn_set_enabled(False)
+
+ wd = _guess_work_dir_like_interface()
+ self._worker = _ImpWorker(exe=exe, license_dir=str(lic_dst), work_dir=wd, timeout=60.0)
+ self._worker.finished_items.connect(self._apply_impedance)
+ self._worker.failed.connect(self._impedance_failed)
+ self._worker.finished.connect(lambda: self.check_btn_set_enabled(True))
+ self._worker.start()
+
+ def check_btn_set_enabled(self, enabled: bool):
+ try:
+ self.check_impedance_btn.setEnabled(enabled) # type: ignore[attr-defined]
+ self.check_impedance_btn.setText("Check Impedance" if enabled else "Checking…")
+ except Exception:
+ pass
+
+ # ----- impedance result -----
+ def _apply_impedance(self, items: list):
+ self.table.update_rows(items)
+ self.canvas.update_impedance(items)
+ eeg_items = [it for it in items if it.get("name") != "Ref"]
+ need_fix = [
+ it for it in eeg_items
+ if float(it.get("value", 99999)) == 99999
+ or float(it.get("value", 99999)) >= 40.0
+ ]
+ total = 20
+ self.status_label.setText("OK" if not need_fix else f"{len(need_fix)}/{total} channel(s) need fix")
+
+ def _impedance_failed(self, msg: str):
+ self.status_label.setText(f"Failed: {msg}")
+ if "license" in msg.lower():
+ self._show_license_sync_failed()
+ QtWidgets.QMessageBox.critical(self, "Check Impedance", msg)
+
+ # ----------
+ def start_stream_args(self) -> dict:
+ license_dir = (self.license_dir_lineedit.text() or "").strip() # type: ignore[attr-defined]
+ exe = _balert_exe_path()
+ return {"license_dir": license_dir, "exe_path": str(exe)}
\ No newline at end of file
diff --git a/physiolabxr/interfaces/DeviceInterface/BAlert/BAlert_Process.py b/physiolabxr/interfaces/DeviceInterface/BAlert/BAlert_Process.py
new file mode 100644
index 00000000..3261ba83
--- /dev/null
+++ b/physiolabxr/interfaces/DeviceInterface/BAlert/BAlert_Process.py
@@ -0,0 +1,125 @@
+from __future__ import annotations
+import os
+import time
+import subprocess
+from pathlib import Path
+from typing import Optional
+from .BAlert_Options import _guess_work_dir_like_interface
+from .BAlert_Options import _sync_license_to_exe_dir
+
+
+def _exe_path() -> Path:
+ from .BAlert_Options import _balert_exe_path
+ return _balert_exe_path()
+
+
+class BAlertProcess:
+ """Helper to launch/stop BAlert.exe and talk via status/command files."""
+ def __init__(self, license_dir: Optional[str] = None,
+ exe_path: Optional[str | Path] = None):
+ self.exe: Path = Path(exe_path) if exe_path else _exe_path()
+
+ self.license_dir = license_dir or os.environ.get("ABM_LICENSE_DIR") or ""
+ self.proc: subprocess.Popen | None = None
+
+ self.work_dir: Path = _guess_work_dir_like_interface()
+
+ self.cfg_dir: Path = self.work_dir / "Config"
+ self.status_file = self.cfg_dir / "balert_status.txt"
+ self.command_file = self.cfg_dir / "balert_command.txt"
+
+ # ---------------- lifecycle ----------------
+
+ def start(self, mode: str = "run", capture_output: bool = False) -> None:
+ if not self.exe.exists():
+ raise FileNotFoundError(f"BAlert.exe not found at {self.exe}")
+
+ env = os.environ.copy()
+
+ exe_lic = self.exe.parent / "License"
+ if self.license_dir:
+ lic_dst = _sync_license_to_exe_dir(self.exe, Path(self.license_dir))
+ env["ABM_LICENSE_DIR"] = str(lic_dst)
+ else:
+ if exe_lic.exists() and any(exe_lic.iterdir()):
+ env["ABM_LICENSE_DIR"] = str(exe_lic)
+ else:
+ raise FileNotFoundError(
+ "No ABM license found. Please select a license folder in Options."
+ )
+
+ try:
+ self.command_file.write_text("", encoding="utf-8")
+ except Exception:
+ pass
+
+ args = [str(self.exe)]
+ if mode == "ping":
+ args.append("--version")
+ elif mode == "impedance":
+ args.append("--impedance-only")
+
+ flags = 0
+ if hasattr(subprocess, "CREATE_NO_WINDOW"):
+ flags |= subprocess.CREATE_NO_WINDOW
+
+ stdout = subprocess.PIPE if capture_output else None
+ self.proc = subprocess.Popen(
+ args,
+ cwd=str(self.work_dir),
+ env=env,
+ creationflags=flags,
+ stdout=stdout,
+ stderr=subprocess.STDOUT if capture_output else None,
+ text=bool(capture_output),
+ bufsize=1 if capture_output else -1,
+ )
+
+ def stop(self, graceful_timeout: float = 10.0) -> None:
+
+ if not self.proc:
+ return
+
+ try:
+ self.command_file.write_text("STOP", encoding="utf-8")
+ except Exception:
+ pass
+
+ if self.proc.poll() is None:
+ try:
+ self.proc.wait(timeout=graceful_timeout)
+ except subprocess.TimeoutExpired:
+ try:
+ self.proc.kill()
+ except Exception:
+ pass
+
+ self.proc = None
+
+ # ---------------- helpers ----------------
+
+ def is_running(self) -> bool:
+ return self.proc is not None and self.proc.poll() is None
+
+ def read_status(self) -> tuple[Optional[int], str]:
+ try:
+ line = self.status_file.read_text(encoding="utf-8").strip()
+ if not line:
+ return None, ""
+ parts = line.split(",", 1)
+ code = int(parts[0])
+ msg = parts[1] if len(parts) > 1 else ""
+ return code, msg
+ except Exception:
+ return None, ""
+
+ def wait_until_ready(self, timeout: float = 90.0) -> None:
+ t0 = time.time()
+ while time.time() - t0 < timeout:
+ code, _ = self.read_status()
+ if code in (4, 5): # STATUS_READY / STATUS_STREAMING
+ return
+ if code in (6, 8): # STATUS_ERROR / STATUS_STOPPED
+ raise RuntimeError("BAlert reported error/stop")
+ time.sleep(0.2)
+ raise TimeoutError("BAlert not ready in time")
\ No newline at end of file
diff --git a/physiolabxr/interfaces/DeviceInterface/BAlert/README.md b/physiolabxr/interfaces/DeviceInterface/BAlert/README.md
new file mode 100644
index 00000000..1aaf5b87
--- /dev/null
+++ b/physiolabxr/interfaces/DeviceInterface/BAlert/README.md
@@ -0,0 +1,30 @@
+# Building BAlert Executables
+
+This guide provides instructions on building the `BAlert.exe`executables in Visual Studio.
+
+## Prerequisites
+- **Visual Studio**: Installed with the C++ Desktop development workload.
+- **LSL(liblsl)**: Add `include`/`lib`, link `lsl.lib`, and put `lsl.dll` next to the exe in `x64/Release` (or add `bin` to `PATH`).
+- **ABM SDK64**: Add headers/libs, link `BAlert64.lib` and `ABM_ThirdPartyCommunication64.lib`, and place required ABM DLLs by the exe.
+- **ABM License folder** : Place the provided `License` folder under `x64/Release`.
+
+## Build the Executables
+
+1. **Open Solution in Visual Studio**
+ - Open `BAlert.sln` in Visual Studio.
+
+2. **Set the Startup Project**
+ - In Solution Explorer, right-click on `BAlert` and select **Set as Startup Project**.
+
+3. **Build BAlert.exe**
+ - Go to the top menu and select **Build → Build Solution** or press **Ctrl+Shift+B**.
+
+4. **Locate the Executables**
+ - After successful builds, BAlert.exe will be located in `x64/Release` folder.
+
+## Troubleshooting
+- Ensure that all dependencies are properly linked.
+- Ensure that License folder is cloned properly.
+- Verify that the correct build configuration (`Release`) is selected.
+
+You’re all set! The executables are now ready to use.
\ No newline at end of file
diff --git a/physiolabxr/interfaces/DeviceInterface/BAlert/__init__.py b/physiolabxr/interfaces/DeviceInterface/BAlert/__init__.py
new file mode 100644
index 00000000..891eed3a
--- /dev/null
+++ b/physiolabxr/interfaces/DeviceInterface/BAlert/__init__.py
@@ -0,0 +1,2 @@
+from .BAlert_Interface import BAlert_Interface
+from .BAlert_Options import BAlert_Options
\ No newline at end of file
diff --git a/physiolabxr/interfaces/DeviceInterface/BAlert/native/BAlert.cpp b/physiolabxr/interfaces/DeviceInterface/BAlert/native/BAlert.cpp
new file mode 100644
index 00000000..a55e7785
--- /dev/null
+++ b/physiolabxr/interfaces/DeviceInterface/BAlert/native/BAlert.cpp
@@ -0,0 +1,422 @@
+// BAlert.cpp — ABM B-Alert RAW -> LSL (portable build + PhysioLabXR communication)
+// Build: x64 / Release
+// Link: BAlert64.lib, ABM_ThirdPartyCommunication64.lib, lsl.lib
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "AbmSdkInclude.h"
+#pragma comment(lib, "BAlert64.lib")
+#pragma comment(lib, "ABM_ThirdPartyCommunication64.lib")
+
+#include
+#pragma comment(lib, "lsl.lib")
+
+#if __has_include()
+#include
+namespace fs = std::filesystem;
+#else
+#include
+namespace fs = std::experimental::filesystem;
+#endif
+
+// ---------------- CONSTANTS ----------------
+static const int kDetectTimeoutSec = 20;
+static const int kRetries = 3;
+static const int kSampleRateHz = 256;
+static const BOOL kAllowOldFW = TRUE;
+static const BOOL kAllowNoStrip = FALSE;
+
+static const char* kStatusFile = "balert_status.txt";
+static const char* kCommandFile = "balert_command.txt";
+
+// ---------------- GLOBALS ----------------
+static std::wstring g_cfgDir, g_binDir, g_licDir;
+static std::atomic g_doneImpedance{ false };
+static std::atomic g_stop{ false };
+static std::atomic g_ready{ false };
+
+// ---------------- PhysioLabXR ----------------
+enum Status {
+ STATUS_STARTING = 0,
+ STATUS_INITIALIZING,
+ STATUS_DETECTING,
+ STATUS_MEASURING_IMPEDANCE,
+ STATUS_READY,
+ STATUS_STREAMING,
+ STATUS_ERROR,
+ STATUS_STOPPING,
+ STATUS_STOPPED
+};
+
+static void write_status(Status st, const std::string& msg = std::string()) {
+ std::ofstream f(kStatusFile, std::ios::trunc);
+ if (!f.good()) return;
+ f << static_cast(st);
+ if (!msg.empty()) f << "," << msg;
+ f.close();
+}
+
+static bool take_stop_command() {
+ std::ifstream f(kCommandFile);
+ if (!f.good()) return false;
+ std::string cmd;
+ std::getline(f, cmd);
+ f.close();
+ if (cmd == "STOP" || cmd == "stop") {
+ std::ofstream c(kCommandFile, std::ios::trunc);
+ c.close();
+ return true;
+ }
+ return false;
+}
+
+// ---------------- small helpers ----------------
+static BOOL WINAPI ConsoleHandler(DWORD type) {
+ if (type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT ||
+ type == CTRL_CLOSE_EVENT || type == CTRL_LOGOFF_EVENT ||
+ type == CTRL_SHUTDOWN_EVENT) {
+ g_stop = true;
+ write_status(STATUS_STOPPING, "Console interrupt");
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static std::wstring exe_dir() {
+ wchar_t buf[MAX_PATH]{ 0 };
+ GetModuleFileNameW(nullptr, buf, MAX_PATH);
+ std::wstring p(buf);
+ size_t pos = p.find_last_of(L"\\/");
+ return (pos == std::wstring::npos) ? L"." : p.substr(0, pos);
+}
+
+static std::wstring join2(const std::wstring& a, const std::wstring& b) {
+ if (a.empty()) return b;
+ return (a.back() == L'\\' || a.back() == L'/') ? (a + b) : (a + L"\\" + b);
+}
+
+static void set_env_w(const wchar_t* name, const std::wstring& val) {
+ SetEnvironmentVariableW(name, val.c_str());
+}
+
+static bool detect_paths() {
+ write_status(STATUS_STARTING, "Detecting paths");
+
+ const std::wstring ed = exe_dir();
+
+ std::vector bases = {
+ join2(ed, L"third_party\\BAlert"),
+ join2(ed, L"third_party\\balert"),
+ join2(join2(ed, L".."), L"third_party\\BAlert"),
+ join2(join2(ed, L".."), L"third_party\\balert"),
+ join2(join2(join2(ed, L".."), L".."), L"third_party\\BAlert"),
+ join2(join2(join2(ed, L".."), L".."), L"third_party\\balert"),
+ ed // fallback
+ };
+
+ for (auto& base : bases) {
+ const std::wstring cfg = join2(base, L"Config\\");
+ const std::wstring bin = join2(base, L"SDK64\\bin\\");
+ const std::wstring lic = join2(base, L"License\\");
+ std::wcout << L"[BAlert] Try base: " << base << L"\n";
+
+ if (fs::exists(cfg) && fs::exists(bin) && fs::exists(join2(cfg, L"AthenaSDK.xml"))) {
+ g_cfgDir = cfg; g_binDir = bin; g_licDir = lic;
+ std::wcout << L"[BAlert] Use bundled ABM: cfg=" << g_cfgDir
+ << L" bin=" << g_binDir << L" lic=" << g_licDir << L"\n";
+ return true;
+ }
+ }
+
+ const std::wstring inst = L"C:\\ABM\\B-Alert";
+ const std::wstring cfg = join2(inst, L"Config\\");
+ const std::wstring bin = join2(inst, L"SDK64\\bin\\");
+ const std::wstring lic = join2(inst, L"License\\");
+ if (fs::exists(cfg) && fs::exists(bin) && fs::exists(join2(cfg, L"AthenaSDK.xml"))) {
+ g_cfgDir = cfg; g_binDir = bin; g_licDir = lic;
+ std::wcout << L"[BAlert] Use installed ABM: cfg=" << g_cfgDir
+ << L" bin=" << g_binDir << L" lic=" << g_licDir << L"\n";
+ return true;
+ }
+ return false;
+}
+
+static void apply_runtime_or_throw() {
+ if (!detect_paths()) {
+ write_status(STATUS_ERROR, "B-Alert files not found");
+ throw std::runtime_error("B-Alert installation not found");
+ }
+
+ SetDllDirectoryW(g_binDir.c_str());
+
+ set_env_w(L"ABM_LICENSE_DIR", g_licDir);
+
+ if (!SetCurrentDirectoryW(g_cfgDir.c_str())) {
+ write_status(STATUS_ERROR, "SetCurrentDirectory failed");
+ throw std::runtime_error("SetCurrentDirectory failed");
+ }
+
+ if (SetConfigPath(const_cast(g_cfgDir.c_str())) == 0) {
+ write_status(STATUS_ERROR, "SetConfigPath failed");
+ throw std::runtime_error("SetConfigPath failed");
+ }
+
+ std::wcout << L"[BAlert] exe_dir=" << exe_dir() << L"\n";
+ std::wcout << L"[BAlert] cfg_dir=" << g_cfgDir << L"\n";
+ std::wcout << L"[BAlert] bin_dir=" << g_binDir << L"\n";
+ std::wcout << L"[BAlert] lic_dir=" << g_licDir << L"\n";
+}
+
+// ---------------- ABM helpers ----------------
+static void CallbackImpedance(ELECTRODE* pEl, int& nCount) {
+ for (int i = 0; i < nCount; ++i)
+ std::wcout << L"[BAlert] Impedance " << pEl[i].chName
+ << L" = " << pEl[i].fImpedanceValue << L"\n";
+ g_doneImpedance = true;
+}
+
+static std::wstring devtype_to_string(int id) {
+ switch (id) {
+ case ABM_DEVICE_X24Flex_10_20: return L"X24Flex_10_20";
+ case ABM_DEVICE_X24Flex_10_20_LM: return L"X24Flex_10_20_LM";
+ case ABM_DEVICE_X24LE_10_20_LM: return L"X24LE_10_20_LM";
+ case ABM_DEVICE_X24Flex_10_20_LM_Red: return L"X24Flex_10_20_LM_Red";
+ case ABM_DEVICE_X24LE_10_20_LM_Red: return L"X24LE_10_20_LM_Red";
+ case ABM_DEVICE_X10Flex_Standard: return L"X10Flex_Standard";
+ case ABM_DEVICE_X24Flex_Reduced: return L"X24Flex_Reduced";
+ case ABM_DEVICE_X10Flex_10_20_LM_Red: return L"X10Flex_10_20_LM_Red";
+ default: return L"Unknown(" + std::to_wstring(id) + L")";
+ }
+}
+
+static void print_connection_state() {
+ BOOL opened = IsConnectionOpened();
+ auto* esu = GetESUPortInfo();
+ std::wcout << L"[ABM] IsConnectionOpened=" << (opened ? L"TRUE" : L"FALSE") << L"\n";
+ if (esu)
+ std::wcout << L"[ABM] ESU: type=" << esu->nESU_TYPE
+ << L" wired=" << (esu->bWired ? L"TRUE" : L"FALSE") << L"\n";
+}
+
+static _DEVICE_INFO* detect_device() {
+ write_status(STATUS_DETECTING, "Detecting device");
+
+ CloseCurrentConnection();
+ std::this_thread::sleep_for(std::chrono::milliseconds(200));
+
+ for (int a = 1; a <= kRetries; ++a) {
+ if (g_stop.load() || take_stop_command()) {
+ write_status(STATUS_STOPPING, "Stop during detect");
+ return nullptr;
+ }
+ int strip = -1, err = -1;
+ _DEVICE_INFO* dev = GetDeviceInfo(kDetectTimeoutSec, strip, err);
+ if (dev) {
+ std::wcout << L"[BAlert] Device: " << dev->chDeviceName
+ << L", channels=" << dev->nNumberOfChannel
+ << L", handle=" << dev->nDeviceHandle << L"\n";
+ return dev;
+ }
+ std::wcout << L"[BAlert] Detect attempt " << a << L"/" << kRetries
+ << L" failed (strip=" << strip << L", err=" << err << L")\n";
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+ }
+ write_status(STATUS_ERROR, "No device detected");
+ return nullptr;
+}
+
+static int try_init_raw(_DEVICE_INFO* dev) {
+ if (!dev) return -1;
+
+ const bool is24 = (dev->nNumberOfChannel >= 24);
+ std::vector ids = is24
+ ? std::vector{6, 9, 10, 11, 12}
+ : std::vector{ 7,8,13 };
+
+ const int handles[] = { 0, -1 };
+ for (int id : ids) {
+ for (int h : handles) {
+ if (g_stop.load() || take_stop_command()) {
+ write_status(STATUS_STOPPING, "Stop during init");
+ return -1;
+ }
+ int rc = InitSessionForCurrentConnection(id, ABM_SESSION_RAW, h, FALSE);
+ std::wcout << L"[BAlert] Init RAW: id=" << id << L" ("
+ << devtype_to_string(id) << L") handle=" << h
+ << L" rc=" << rc << L"\n";
+ if (rc == 1) return id;
+
+ rc = InitSessionForCurrentConnection(id, ABM_SESSION_RAW, h, TRUE);
+ std::wcout << L"[BAlert] Init RAW(EBS=TRUE): id=" << id << L" ("
+ << devtype_to_string(id) << L") handle=" << h
+ << L" rc=" << rc << L"\n";
+ if (rc == 1) return id;
+ }
+ }
+ return -1;
+}
+
+static bool measure_impedances() {
+ write_status(STATUS_MEASURING_IMPEDANCE, "Measuring impedances");
+
+ if (MeasureImpedances(CallbackImpedance) != IMP_STARTED_OK) {
+ write_status(STATUS_ERROR, "MeasureImpedances failed to start");
+ return false;
+ }
+ while (!g_doneImpedance.load()) {
+ if (g_stop.load() || take_stop_command()) {
+ write_status(STATUS_STOPPING, "Stop during impedance");
+ return false;
+ }
+ std::this_thread::sleep_for(std::chrono::milliseconds(50));
+ }
+ return true;
+}
+
+static std::unique_ptr make_outlet(int nRawCh, int device_id) {
+ _CHANNELMAP_INFO cmap{}; bool haveMap = (GetChannelMapInfo(cmap) != 0);
+
+ lsl::stream_info info("BAlert", "EEG", nRawCh, kSampleRateHz,
+ lsl::cf_float32, "BAlert_RAW_" + std::to_string(device_id));
+
+ auto acq = info.desc().append_child("acquisition");
+ acq.append_child_value("manufacturer", "Advanced Brain Monitoring");
+ acq.append_child_value("model", "B-Alert X-Series");
+
+ // device_type: wide->narrow
+ std::wstring w = devtype_to_string(device_id);
+ size_t n = w.size() + 1;
+ std::vector tmp(n, 0);
+ size_t outc = 0;
+ wcstombs_s(&outc, tmp.data(), n, w.c_str(), n - 1);
+ acq.append_child_value("device_type", tmp.data());
+
+ auto chs = info.desc().append_child("channels");
+ for (int i = 0; i < nRawCh; ++i) {
+ auto c = chs.append_child("channel");
+ if (haveMap) c.append_child_value("label", cmap.stEEGChannels.cChName[i]);
+ else {
+ std::string lab = "EEG" + std::to_string(i + 1);
+ c.append_child_value("label", lab.c_str());
+ }
+ c.append_child_value("unit", "microvolts");
+ c.append_child_value("type", "EEG");
+ }
+
+ std::wcout << L"[BAlert] LSL outlet ready: ch=" << nRawCh
+ << L" srate=" << kSampleRateHz << L"\n";
+
+ return std::make_unique(info);
+}
+
+static void stream_loop(lsl::stream_outlet& outlet, int nRawCh) {
+ write_status(STATUS_READY, "Ready to stream");
+ g_ready = true;
+
+ std::wcout << L"[BAlert] StartAcquisition...\n";
+ int rc = StartAcquisition();
+ if (rc != 1) {
+ write_status(STATUS_ERROR, "StartAcquisition failed");
+ throw std::runtime_error("StartAcquisition failed");
+ }
+
+ write_status(STATUS_STREAMING, "Streaming");
+ std::wcout << L"[BAlert] Streaming... (write STOP in balert_command.txt to stop)\n";
+
+ auto t0 = std::chrono::steady_clock::now();
+ long long pushed = 0;
+
+ while (!g_stop.load() && !take_stop_command()) {
+ int nRecv = 0;
+ float* buf = GetRawData(nRecv);
+ if (buf && nRecv > 0) {
+ for (int i = 0; i < nRecv; ++i)
+ outlet.push_sample(&buf[i * nRawCh]);
+ pushed += nRecv;
+ }
+ else {
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
+ }
+
+ if (pushed && (std::chrono::steady_clock::now() - t0 > std::chrono::seconds(5))) {
+ double dt = std::chrono::duration(std::chrono::steady_clock::now() - t0).count();
+ std::wcout << L"[BAlert] " << pushed << L" samples, ~"
+ << std::fixed << std::setprecision(1) << (pushed / dt) << L" Hz\n";
+ t0 = std::chrono::steady_clock::now();
+ pushed = 0;
+ }
+ }
+
+ write_status(STATUS_STOPPING, "Stopping");
+ std::wcout << L"[BAlert] Stopping...\n";
+ StopAcquisition();
+ CloseCurrentConnection();
+}
+
+// ---------------- MAIN ----------------
+int wmain() {
+ SetConsoleCtrlHandler(ConsoleHandler, TRUE);
+
+ try {
+ apply_runtime_or_throw();
+
+ SetClassicFlexOldFwAllowed(kAllowOldFW);
+ SetNoStripAllowed(kAllowNoStrip);
+
+ write_status(STATUS_INITIALIZING, "Initializing SDK");
+ print_connection_state();
+
+ _DEVICE_INFO* dev = detect_device();
+ if (!dev) return 1;
+
+ int device_id = try_init_raw(dev);
+ if (device_id < 0) {
+ write_status(STATUS_ERROR, "Init RAW failed");
+ return 1;
+ }
+
+ if (!measure_impedances()) return 1;
+
+ device_id = try_init_raw(dev);
+ if (device_id < 0) {
+ write_status(STATUS_ERROR, "Re-init RAW failed");
+ return 1;
+ }
+
+ int nRaw = 0, nDecon = 0, nPSD = 0, nRawPSD = 0, nQual = 0;
+ GetPacketChannelNmbInfo(nRaw, nDecon, nPSD, nRawPSD, nQual);
+ if (nRaw <= 0) nRaw = dev->nNumberOfChannel;
+ std::wcout << L"[BAlert] Channels: RAW=" << nRaw
+ << L" Decon=" << nDecon << L" PSD=" << nPSD << L"\n";
+
+ auto outlet = make_outlet(nRaw, device_id);
+ stream_loop(*outlet, nRaw);
+ }
+ catch (const std::exception& e) {
+ std::wcerr << L"[BAlert] EXCEPTION: " << e.what() << L"\n";
+ write_status(STATUS_ERROR, e.what());
+ try { StopAcquisition(); CloseCurrentConnection(); }
+ catch (...) {}
+ return 1;
+ }
+ catch (...) {
+ std::wcerr << L"[BAlert] UNKNOWN EXCEPTION\n";
+ write_status(STATUS_ERROR, "Unknown exception");
+ try { StopAcquisition(); CloseCurrentConnection(); }
+ catch (...) {}
+ return 1;
+ }
+
+ write_status(STATUS_STOPPED, "Stopped OK");
+ std::wcout << L"[BAlert] Done.\n";
+ return 0;
+}
\ No newline at end of file
diff --git a/physiolabxr/interfaces/DeviceInterface/BAlert/native/BAlert.sln b/physiolabxr/interfaces/DeviceInterface/BAlert/native/BAlert.sln
new file mode 100644
index 00000000..0c5613fc
--- /dev/null
+++ b/physiolabxr/interfaces/DeviceInterface/BAlert/native/BAlert.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.7.34031.279
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BAlert", "BAlert\BAlert.vcxproj", "{D549B186-FC4F-446C-8A0A-983B4C4DD458}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {D549B186-FC4F-446C-8A0A-983B4C4DD458}.Debug|x64.ActiveCfg = Debug|x64
+ {D549B186-FC4F-446C-8A0A-983B4C4DD458}.Debug|x64.Build.0 = Debug|x64
+ {D549B186-FC4F-446C-8A0A-983B4C4DD458}.Debug|x86.ActiveCfg = Debug|Win32
+ {D549B186-FC4F-446C-8A0A-983B4C4DD458}.Debug|x86.Build.0 = Debug|Win32
+ {D549B186-FC4F-446C-8A0A-983B4C4DD458}.Release|x64.ActiveCfg = Release|x64
+ {D549B186-FC4F-446C-8A0A-983B4C4DD458}.Release|x64.Build.0 = Release|x64
+ {D549B186-FC4F-446C-8A0A-983B4C4DD458}.Release|x86.ActiveCfg = Release|Win32
+ {D549B186-FC4F-446C-8A0A-983B4C4DD458}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {C4A854BC-1C92-4DF4-AA2F-0192E9AF50F0}
+ EndGlobalSection
+EndGlobal
diff --git a/physiolabxr/interfaces/DeviceInterface/BAlert/native/BAlert.vcxproj b/physiolabxr/interfaces/DeviceInterface/BAlert/native/BAlert.vcxproj
new file mode 100644
index 00000000..671ac219
--- /dev/null
+++ b/physiolabxr/interfaces/DeviceInterface/BAlert/native/BAlert.vcxproj
@@ -0,0 +1,144 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 17.0
+ Win32Proj
+ {d549b186-fc4f-446c-8a0a-983b4c4dd458}
+ BAlert
+ 10.0
+
+
+
+ Application
+ true
+ v143
+ Unicode
+
+
+ Application
+ false
+ v143
+ true
+ Unicode
+
+
+ Application
+ true
+ v143
+ Unicode
+
+
+ Application
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ C:\ABM\B-Alert\SDK64\include;C:\LSL\liblsl-1.16.2-Win_amd64\include;C:\Users\LabUser\source\repos\BAlert;$(IncludePath)
+ C:\ABM\B-Alert\SDK64\lib;C:\LSL\liblsl-1.16.2-Win_amd64\lib;$(LibraryPath)
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ $(ProjectDir);C:\ABM\B-Alert\SDK64\include;C:\LSL\liblsl-1.16.2-Win_amd64\include;C:\Users\LabUser\source\repos\BAlert;C:\ABM\B-Alert\SDK64\include\lsl
+ true
+ stdcpp17
+
+
+ Console
+ true
+ true
+ true
+ C:\ABM\B-Alert\SDK64\lib;C:\LSL\liblsl-1.16.2-Win_amd64\lib;C:\ABM\B-Alert\SDK64\lib\64
+ BAlert64.lib;ABM_ThirdPartyCommunication64.lib;64\lsl.lib;ABM_Athena64.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/physiolabxr/interfaces/DeviceInterface/BAlert/native/BAlert.vcxproj.filters b/physiolabxr/interfaces/DeviceInterface/BAlert/native/BAlert.vcxproj.filters
new file mode 100644
index 00000000..60160b35
--- /dev/null
+++ b/physiolabxr/interfaces/DeviceInterface/BAlert/native/BAlert.vcxproj.filters
@@ -0,0 +1,22 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/physiolabxr/interfaces/DeviceInterface/BAlert/native/BAlert.vcxproj.user b/physiolabxr/interfaces/DeviceInterface/BAlert/native/BAlert.vcxproj.user
new file mode 100644
index 00000000..06658334
--- /dev/null
+++ b/physiolabxr/interfaces/DeviceInterface/BAlert/native/BAlert.vcxproj.user
@@ -0,0 +1,7 @@
+
+
+
+ $(OutDir)
+ WindowsLocalDebugger
+
+
\ No newline at end of file
diff --git a/physiolabxr/interfaces/DeviceInterface/BAlert/native/wchar_t.h b/physiolabxr/interfaces/DeviceInterface/BAlert/native/wchar_t.h
new file mode 100644
index 00000000..2e9f878d
--- /dev/null
+++ b/physiolabxr/interfaces/DeviceInterface/BAlert/native/wchar_t.h
@@ -0,0 +1,2 @@
+#pragma once
+#include
\ No newline at end of file
diff --git a/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/ABM_Athena64.dll b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/ABM_Athena64.dll
new file mode 100644
index 00000000..f6800ae1
Binary files /dev/null and b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/ABM_Athena64.dll differ
diff --git a/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/ABM_Datastreaming64.dll b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/ABM_Datastreaming64.dll
new file mode 100644
index 00000000..58a467b3
Binary files /dev/null and b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/ABM_Datastreaming64.dll differ
diff --git a/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/ABM_PlayEbs64.dll b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/ABM_PlayEbs64.dll
new file mode 100644
index 00000000..d6ae3f15
Binary files /dev/null and b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/ABM_PlayEbs64.dll differ
diff --git a/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/ABM_ThirdPartyCommunication64.dll b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/ABM_ThirdPartyCommunication64.dll
new file mode 100644
index 00000000..ef71f40c
Binary files /dev/null and b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/ABM_ThirdPartyCommunication64.dll differ
diff --git a/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/BAlert.exe b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/BAlert.exe
new file mode 100644
index 00000000..87bc52f3
Binary files /dev/null and b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/BAlert.exe differ
diff --git a/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/BAlert.pdb b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/BAlert.pdb
new file mode 100644
index 00000000..83228cb5
Binary files /dev/null and b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/BAlert.pdb differ
diff --git a/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/BAlert64.dll b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/BAlert64.dll
new file mode 100644
index 00000000..b7766d19
Binary files /dev/null and b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/BAlert64.dll differ
diff --git a/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/BAlert_Classification64.dll b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/BAlert_Classification64.dll
new file mode 100644
index 00000000..052eb2bf
Binary files /dev/null and b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/BAlert_Classification64.dll differ
diff --git a/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/BAlert_EventHandling64.dll b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/BAlert_EventHandling64.dll
new file mode 100644
index 00000000..9f8496f3
Binary files /dev/null and b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/BAlert_EventHandling64.dll differ
diff --git a/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/BAlert_HRAnalysis64.dll b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/BAlert_HRAnalysis64.dll
new file mode 100644
index 00000000..1b80c030
Binary files /dev/null and b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/BAlert_HRAnalysis64.dll differ
diff --git a/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/BAlert_PSD64.dll b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/BAlert_PSD64.dll
new file mode 100644
index 00000000..d97f6ffd
Binary files /dev/null and b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/BAlert_PSD64.dll differ
diff --git a/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/BAlert_Performance64.dll b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/BAlert_Performance64.dll
new file mode 100644
index 00000000..4f47d9ad
Binary files /dev/null and b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/BAlert_Performance64.dll differ
diff --git a/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/BAlert_Report64.dll b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/BAlert_Report64.dll
new file mode 100644
index 00000000..103e0ec3
Binary files /dev/null and b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/BAlert_Report64.dll differ
diff --git a/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/BAlert_SignalHandling64.dll b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/BAlert_SignalHandling64.dll
new file mode 100644
index 00000000..5df20b6b
Binary files /dev/null and b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/BAlert_SignalHandling64.dll differ
diff --git a/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/Balert_DataFiltering64.dll b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/Balert_DataFiltering64.dll
new file mode 100644
index 00000000..2643ecc5
Binary files /dev/null and b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/Balert_DataFiltering64.dll differ
diff --git a/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/Balert_DefFile64.dll b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/Balert_DefFile64.dll
new file mode 100644
index 00000000..b692ceaf
Binary files /dev/null and b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/Balert_DefFile64.dll differ
diff --git a/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/SiUSBXp.dll b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/SiUSBXp.dll
new file mode 100644
index 00000000..3ee1e79a
Binary files /dev/null and b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/SiUSBXp.dll differ
diff --git a/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/ftd2xx64.dll b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/ftd2xx64.dll
new file mode 100644
index 00000000..7e63fa92
Binary files /dev/null and b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/ftd2xx64.dll differ
diff --git a/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/lsl.dll b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/lsl.dll
new file mode 100644
index 00000000..cef9a597
Binary files /dev/null and b/physiolabxr/interfaces/DeviceInterface/BAlert/x64/Release/lsl.dll differ
diff --git a/physiolabxr/third_party/BAlert/Config/AthenaSDK.xml b/physiolabxr/third_party/BAlert/Config/AthenaSDK.xml
new file mode 100644
index 00000000..cae39ec2
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/Config/AthenaSDK.xml
@@ -0,0 +1,207 @@
+
+
+ 00.07.00.00
+
+
+ 1
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+ 1
+
+
+ 1
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 0
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 10
+
+
+ 0
+
+
+ 1
+
+
+ 0
+
+
+
+
+ 10000
+
+
+ 60000
+
+
+ 0
+
+
+
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ 0.3
+ 0
+ 1
+ 1
+
+
+
+ 0
+
+
+ 0
+
+
+ 1
+
+
+
+
+ 1
+
+
+
+ 1
+
+
+ 1200000
+
+
+
+
+ ThetaTotal_3_7
+
+
+
+
+ AlphaTotal_8_13
+
+
+
+
+ Beta_13_30
+
+
+
+
+ Gamma_25_40
+
+
+
+
+
diff --git a/physiolabxr/third_party/BAlert/Config/BAlertArtifacts.xml b/physiolabxr/third_party/BAlert/Config/BAlertArtifacts.xml
new file mode 100644
index 00000000..972fbc45
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/Config/BAlertArtifacts.xml
@@ -0,0 +1,18 @@
+
+
+ 00.00.00.00
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
diff --git a/physiolabxr/third_party/BAlert/Config/BAlertFilters.xml b/physiolabxr/third_party/BAlert/Config/BAlertFilters.xml
new file mode 100644
index 00000000..7c949706
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/Config/BAlertFilters.xml
@@ -0,0 +1,30 @@
+
+
+ 00.01.00.00
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 0
+
+
+ 0
+
+
+ 1
+
+
+
diff --git a/physiolabxr/third_party/BAlert/Config/BAlertHeartRate.xml b/physiolabxr/third_party/BAlert/Config/BAlertHeartRate.xml
new file mode 100644
index 00000000..07116787
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/Config/BAlertHeartRate.xml
@@ -0,0 +1,27 @@
+
+
+ 00.00.00.00
+
+
+ 0.300000
+
+
+ 0
+
+
+ 1
+
+
+ 5
+
+
+ 10
+
+
+ 15
+
+
+ 20
+
+
+
diff --git a/physiolabxr/third_party/BAlert/Config/BAlertPerf.xml b/physiolabxr/third_party/BAlert/Config/BAlertPerf.xml
new file mode 100644
index 00000000..d801a822
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/Config/BAlertPerf.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ 139
+
+
+ 258
+
+
+ 316
+
+
+ 376
+
+
+
+ 1000
+
+
diff --git a/physiolabxr/third_party/BAlert/Config/BenchmarkPopulation.txt b/physiolabxr/third_party/BAlert/Config/BenchmarkPopulation.txt
new file mode 100644
index 00000000..33759dfa
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/Config/BenchmarkPopulation.txt
@@ -0,0 +1,3 @@
+Population 3C-VT,GOOD,0.776 ± 1.010,4.235 ± 4.723,16.360 ± 6.432,78.627 ± 7.385,300,300,0.222 ± 0.712,0.545 ± 1.488,0.008 ± 0.012,0.055 ± 0.055,0.216 ± 0.055,0.707 ± 0.222,96.090 ± 4.012,0.614 ± 0.077,N/A
+Population V-PVT,GOOD,0.719 ± 1.186,6.056 ± 4.773,74.287 ± 6.969,18.936 ± 7.411,300,300,0.493 ± 1.829,0.661 ±2.303,0.009 ± 0.014,0.079 ± 0.057,0.688 ± 0.122,0.209 ± 0.076,N/A ,N/A ,1.81 ± 2.094
+Population A-PVT,GOOD,0.441 ± 1.019,84.868 ± 6.256,7.673 ± 5.456,7.0174 ± 5.6209,300,300,0.125 ± 0.220,0.253 ±0.777,0.005 ± 0.011,0.822 ± 0.157,0.093 ± 0.071,0.066 ± 0.064,N/A ,N/A ,1.311 ± 4.382
diff --git a/physiolabxr/third_party/BAlert/Config/ClassificationSettings.xml b/physiolabxr/third_party/BAlert/Config/ClassificationSettings.xml
new file mode 100644
index 00000000..1ef355ad
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/Config/ClassificationSettings.xml
@@ -0,0 +1,208 @@
+
+
+ 00.00.00.00
+
+
+ 0.9
+
+
+ 0.1
+
+
+ 0.6
+
+
+ 0.3
+
+
+
+
+ hz14fzpo
+
+
+ hz25fzpo
+
+
+ hz27fzpo
+
+
+ hz30fzpo
+
+
+ hz36fzpo
+
+
+ hz38fzpo
+
+
+ hz40fzpo
+
+
+ hz4czpo
+
+
+ hz5czpo
+
+
+ hz6czpo
+
+
+ hz10czpo
+
+
+ hz28czpo
+
+
+ hz32czpo
+
+
+ hz33czpo
+
+
+ hz35czpo
+
+
+ r8czpo
+
+
+ r9czpo
+
+
+ r11czpo
+
+
+ r12czpo
+
+
+ r14czpo
+
+
+ r16czpo
+
+
+ r26czpo
+
+
+ r35czpo
+
+
+ r40czpo
+
+
+
+
+ hz1c3c4
+
+
+ hz15c3c4
+
+
+ hz31c3c4
+
+
+ hz26czpo
+
+
+ hz36czpo
+
+
+ hz37czpo
+
+
+ hz6f3cz
+
+
+ hz7f3cz
+
+
+ hz10f3cz
+
+
+ hz16f3cz
+
+
+ hz28f3cz
+
+
+ hz1fzc3
+
+
+ hz6fzc3
+
+
+ hz8fzc3
+
+
+ hz13fzc3
+
+
+ hz15fzc3
+
+
+ hz4fzpo
+
+
+ hz10fzpo
+
+
+ hz16fzpo
+
+
+ hz28fzpo
+
+
+ hz40fzpo
+
+
+ PROB3
+
+
+ PROB7
+
+
+ PROB8
+
+
+ r8c3c4
+
+
+ r15c3c4
+
+
+ r16c3c4
+
+
+ r16czpo
+
+
+ r32czpo
+
+
+ r34czpo
+
+
+ r38czpo
+
+
+ r40czpo
+
+
+ r12f3cz
+
+
+ r20f3cz
+
+
+ r17fzc3
+
+
+ r30fzc3
+
+
+ r33fzpo
+
+
+ r35fzpo
+
+
+
diff --git a/physiolabxr/third_party/BAlert/Config/DeviceTypeConfiguration.xml b/physiolabxr/third_party/BAlert/Config/DeviceTypeConfiguration.xml
new file mode 100644
index 00000000..35286f8d
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/Config/DeviceTypeConfiguration.xml
@@ -0,0 +1,2033 @@
+
+05.02.00.00
+
+
+ 7
+ X24Flex X10 Standard
+ 10
+
+
+ ECG
+ 1
+ 0
+ 0
+ 0
+ 0
+
+
+ POz
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ Fz
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ Cz
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ C3
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ C4
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ F3
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ F4
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ P3
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ P4
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+ Ref
+ 0
+ 5
+ 2
+ -1
+
+
+ POz
+ 1
+ 1
+ 1
+ 0
+
+
+ Fz
+ 2
+ 3
+ 2
+ 0
+
+
+ Cz
+ 3
+ 5
+ 3
+ 0
+
+
+ C3
+ 4
+ 7
+ 4
+ 0
+
+
+ C4
+ 5
+ 9
+ 5
+ 0
+
+
+ F3
+ 6
+ 11
+ 6
+ 0
+
+
+ F4
+ 7
+ 129
+ 7
+ 0
+
+
+ P3
+ 8
+ 131
+ 8
+ 0
+
+
+ P4
+ 9
+ 133
+ 9
+ 0
+
+
+
+ 0
+ 0
+ 0
+ 1
+ 0
+ 0
+
+
+
+ 4150
+ 3550
+
+
+ 8
+ 2048
+
+
+
+ 1
+ 1
+ 1
+
+
+
+ 6
+ X24t 10 20
+ 24
+
+
+ Fp1
+ 0
+ 1
+ 1
+ 1
+ 1
+
+
+ F7
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ F8
+ 2
+ 1
+ 1
+ 1
+ 1
+
+
+ T4
+ 3
+ 1
+ 1
+ 1
+ 1
+
+
+ T6
+ 4
+ 1
+ 1
+ 1
+ 1
+
+
+ T5
+ 5
+ 1
+ 1
+ 1
+ 1
+
+
+ T3
+ 6
+ 1
+ 1
+ 1
+ 1
+
+
+ Fp2
+ 7
+ 1
+ 1
+ 1
+ 1
+
+
+ O1
+ 8
+ 1
+ 1
+ 1
+ 1
+
+
+ P3
+ 9
+ 1
+ 1
+ 1
+ 1
+
+
+ Pz
+ 10
+ 1
+ 1
+ 1
+ 1
+
+
+ F3
+ 11
+ 1
+ 1
+ 1
+ 1
+
+
+ Fz
+ 12
+ 1
+ 1
+ 1
+ 1
+
+
+ F4
+ 13
+ 1
+ 1
+ 1
+ 1
+
+
+ C4
+ 14
+ 1
+ 1
+ 1
+ 1
+
+
+ P4
+ 15
+ 1
+ 1
+ 1
+ 1
+
+
+ POz
+ 16
+ 1
+ 1
+ 1
+ 1
+
+
+ C3
+ 17
+ 1
+ 1
+ 1
+ 1
+
+
+ Cz
+ 18
+ 1
+ 1
+ 1
+ 1
+
+
+ O2
+ 19
+ 1
+ 1
+ 1
+ 1
+
+
+ ECG
+ 20
+ 1
+ 0
+ 0
+ 0
+
+
+ AUX1
+ 21
+ 1
+ 0
+ 0
+ 0
+
+
+ AUX2
+ 22
+ 1
+ 0
+ 0
+ 0
+
+
+ AUX3
+ 23
+ 1
+ 0
+ 0
+ 0
+
+
+
+
+ Ref
+ 0
+ 135
+ 12
+ -1
+
+
+ Fp1
+ 1
+ 1
+ 0
+ 0
+
+
+ F7
+ 2
+ 2
+ 1
+ 0
+
+
+ F8
+ 3
+ 3
+ 2
+ 0
+
+
+ T4
+ 4
+ 4
+ 3
+ 0
+
+
+ T6
+ 5
+ 5
+ 4
+ 0
+
+
+ T5
+ 6
+ 6
+ 5
+ 0
+
+
+ T3
+ 7
+ 7
+ 6
+ 0
+
+
+ Fp2
+ 8
+ 8
+ 7
+ 0
+
+
+ O1
+ 9
+ 9
+ 8
+ 0
+
+
+ P3
+ 10
+ 10
+ 9
+ 0
+
+
+ Pz
+ 11
+ 11
+ 10
+ 0
+
+
+ F3
+ 12
+ 12
+ 11
+ 0
+
+
+ Fz
+ 13
+ 129
+ 12
+ 0
+
+
+ F4
+ 14
+ 130
+ 13
+ 0
+
+
+ C4
+ 15
+ 131
+ 14
+ 0
+
+
+ P4
+ 16
+ 132
+ 15
+ 0
+
+
+ POz
+ 17
+ 133
+ 16
+ 0
+
+
+ C3
+ 18
+ 134
+ 17
+ 0
+
+
+ Cz
+ 19
+ 135
+ 18
+ 0
+
+
+ O2
+ 20
+ 136
+ 19
+ 0
+
+
+
+ 0
+ 0
+ 0
+ 0
+ 20
+ 0
+
+
+
+ 4150
+ 3550
+
+
+ 8
+ 2048
+
+
+
+ 1
+ 1
+ 1
+
+
+
+ 8
+ X24Flex Reduced
+ 10
+
+
+ ECG
+ 1
+ 0
+ 0
+ 0
+ 0
+
+
+
+
+ POz
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ Fz
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ Cz
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ C3
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ C4
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ F3
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ F4
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ P3
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ P4
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+ Ref
+ 0
+ 5
+ 2
+ -1
+
+
+ POz
+ 1
+ 1
+ 1
+ 0
+
+
+ Fz
+ 2
+ 3
+ 2
+ 0
+
+
+ Cz
+ 3
+ 5
+ 3
+ 0
+
+
+ C3
+ 4
+ 7
+ 4
+ 0
+
+
+ C4
+ 5
+ 9
+ 5
+ 0
+
+
+ F3
+ 6
+ 11
+ 6
+ 0
+
+
+ F4
+ 7
+ 129
+ 7
+ 0
+
+
+ P3
+ 8
+ 131
+ 8
+ 0
+
+
+ P4
+ 9
+ 133
+ 9
+ 0
+
+
+
+ 0
+ 0
+ 0
+ 1
+ 0
+ 0
+
+
+
+ 4150
+ 3550
+
+
+ 8
+ 2048
+
+
+
+ 1
+ 1
+ 1
+
+
+
+ 9
+ X24t 10-20 LM
+ 24
+
+
+ Fp1
+ 0
+ 1
+ 1
+ 1
+ 1
+
+
+ F7
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ F8
+ 2
+ 1
+ 1
+ 1
+ 1
+
+
+ T4
+ 3
+ 1
+ 1
+ 1
+ 1
+
+
+ T6
+ 4
+ 1
+ 1
+ 1
+ 1
+
+
+ T5
+ 5
+ 1
+ 1
+ 1
+ 1
+
+
+ T3
+ 6
+ 1
+ 1
+ 1
+ 1
+
+
+ Fp2
+ 7
+ 1
+ 1
+ 1
+ 1
+
+
+ O1
+ 8
+ 1
+ 1
+ 1
+ 1
+
+
+ P3
+ 9
+ 1
+ 1
+ 1
+ 1
+
+
+ Pz
+ 10
+ 1
+ 1
+ 1
+ 1
+
+
+ F3
+ 11
+ 1
+ 1
+ 1
+ 1
+
+
+ Fz
+ 12
+ 1
+ 1
+ 1
+ 1
+
+
+ F4
+ 13
+ 1
+ 1
+ 1
+ 1
+
+
+ C4
+ 14
+ 1
+ 1
+ 1
+ 1
+
+
+ P4
+ 15
+ 1
+ 1
+ 1
+ 1
+
+
+ POz
+ 16
+ 1
+ 1
+ 1
+ 1
+
+
+ C3
+ 17
+ 1
+ 1
+ 1
+ 1
+
+
+ Cz
+ 18
+ 1
+ 1
+ 1
+ 1
+
+
+ O2
+ 19
+ 1
+ 1
+ 1
+ 1
+
+
+ ECG
+ 20
+ 1
+ 0
+ 0
+ 0
+
+
+ AUX1
+ 21
+ 1
+ 0
+ 0
+ 0
+
+
+ AUX2
+ 22
+ 1
+ 0
+ 0
+ 0
+
+
+ AUX3
+ 23
+ 1
+ 0
+ 0
+ 0
+
+
+
+
+ Ref
+ 0
+ 135
+ 12
+ -1
+
+
+ Fp1
+ 1
+ 1
+ 0
+ 0
+
+
+ F7
+ 2
+ 2
+ 1
+ 0
+
+
+ F8
+ 3
+ 3
+ 2
+ 0
+
+
+ T4
+ 4
+ 4
+ 3
+ 0
+
+
+ T6
+ 5
+ 5
+ 4
+ 0
+
+
+ T5
+ 6
+ 6
+ 5
+ 0
+
+
+ T3
+ 7
+ 7
+ 6
+ 0
+
+
+ Fp2
+ 8
+ 8
+ 7
+ 0
+
+
+ O1
+ 9
+ 9
+ 8
+ 0
+
+
+ P3
+ 10
+ 10
+ 9
+ 0
+
+
+ Pz
+ 11
+ 11
+ 10
+ 0
+
+
+ F3
+ 12
+ 12
+ 11
+ 0
+
+
+ Fz
+ 13
+ 129
+ 12
+ 0
+
+
+ F4
+ 14
+ 130
+ 13
+ 0
+
+
+ C4
+ 15
+ 131
+ 14
+ 0
+
+
+ P4
+ 16
+ 132
+ 15
+ 0
+
+
+ POz
+ 17
+ 133
+ 16
+ 0
+
+
+ C3
+ 18
+ 134
+ 17
+ 0
+
+
+ Cz
+ 19
+ 135
+ 18
+ 0
+
+
+ O2
+ 20
+ 136
+ 19
+ 0
+
+
+
+ 0
+ 0
+ 0
+ 0
+ 20
+ 0
+
+
+
+ 4150
+ 3550
+
+
+ 8
+ 2048
+
+
+
+ 1
+ 1
+ 1
+
+
+
+ 10
+ X24LE 10-20 LM
+ 24
+
+
+ Fp1
+ 0
+ 1
+ 1
+ 1
+ 1
+
+
+ F7
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ F8
+ 2
+ 1
+ 1
+ 1
+ 1
+
+
+ T4
+ 3
+ 1
+ 1
+ 1
+ 1
+
+
+ T6
+ 4
+ 1
+ 1
+ 1
+ 1
+
+
+ T5
+ 5
+ 1
+ 1
+ 1
+ 1
+
+
+ T3
+ 6
+ 1
+ 1
+ 1
+ 1
+
+
+ Fp2
+ 7
+ 1
+ 1
+ 1
+ 1
+
+
+ O1
+ 8
+ 1
+ 1
+ 1
+ 1
+
+
+ P3
+ 9
+ 1
+ 1
+ 1
+ 1
+
+
+ Pz
+ 10
+ 1
+ 1
+ 1
+ 1
+
+
+ F3
+ 11
+ 1
+ 1
+ 1
+ 1
+
+
+ Fz
+ 12
+ 1
+ 1
+ 1
+ 1
+
+
+ F4
+ 13
+ 1
+ 1
+ 1
+ 1
+
+
+ C4
+ 14
+ 1
+ 1
+ 1
+ 1
+
+
+ P4
+ 15
+ 1
+ 1
+ 1
+ 1
+
+
+ POz
+ 16
+ 1
+ 1
+ 1
+ 1
+
+
+ C3
+ 17
+ 1
+ 1
+ 1
+ 1
+
+
+ Cz
+ 18
+ 1
+ 1
+ 1
+ 1
+
+
+ O2
+ 19
+ 1
+ 1
+ 1
+ 1
+
+
+ ECG
+ 20
+ 1
+ 0
+ 0
+ 0
+
+
+ AUX1
+ 21
+ 1
+ 0
+ 0
+ 0
+
+
+ AUX2
+ 22
+ 1
+ 0
+ 0
+ 0
+
+
+ AUX3
+ 23
+ 1
+ 0
+ 0
+ 0
+
+
+
+
+ Ref
+ 0
+ 135
+ 12
+ -1
+
+
+ Fp1
+ 1
+ 1
+ 0
+ 0
+
+
+ F7
+ 2
+ 2
+ 1
+ 0
+
+
+ F8
+ 3
+ 3
+ 2
+ 0
+
+
+ T4
+ 4
+ 4
+ 3
+ 0
+
+
+ T6
+ 5
+ 5
+ 4
+ 0
+
+
+ T5
+ 6
+ 6
+ 5
+ 0
+
+
+ T3
+ 7
+ 7
+ 6
+ 0
+
+
+ Fp2
+ 8
+ 8
+ 7
+ 0
+
+
+ O1
+ 9
+ 9
+ 8
+ 0
+
+
+ P3
+ 10
+ 10
+ 9
+ 0
+
+
+ Pz
+ 11
+ 11
+ 10
+ 0
+
+
+ F3
+ 12
+ 12
+ 11
+ 0
+
+
+ Fz
+ 13
+ 129
+ 12
+ 0
+
+
+ F4
+ 14
+ 130
+ 13
+ 0
+
+
+ C4
+ 15
+ 131
+ 14
+ 0
+
+
+ P4
+ 16
+ 132
+ 15
+ 0
+
+
+ POz
+ 17
+ 133
+ 16
+ 0
+
+
+ C3
+ 18
+ 134
+ 17
+ 0
+
+
+ Cz
+ 19
+ 135
+ 18
+ 0
+
+
+ O2
+ 20
+ 136
+ 19
+ 0
+
+
+
+ 0
+ 0
+ 0
+ 0
+ 20
+ 0
+
+
+
+ 4150
+ 3550
+
+
+ 8
+ 2048
+
+
+
+ 1
+ 1
+ 1
+
+
+
+ 11
+ X24Flex LM Reduced
+ 10
+
+
+ ECG
+ 1
+ 0
+ 0
+ 0
+ 0
+
+
+ POz
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ Fz
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ Cz
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ C3
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ C4
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ F3
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ F4
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ P3
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ P4
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+ Ref
+ 0
+ 5
+ 2
+ -1
+
+
+ POz
+ 1
+ 1
+ 1
+ 0
+
+
+ Fz
+ 2
+ 3
+ 2
+ 0
+
+
+ Cz
+ 3
+ 5
+ 3
+ 0
+
+
+ C3
+ 4
+ 7
+ 4
+ 0
+
+
+ C4
+ 5
+ 9
+ 5
+ 0
+
+
+ F3
+ 6
+ 11
+ 6
+ 0
+
+
+ F4
+ 7
+ 129
+ 7
+ 0
+
+
+ P3
+ 8
+ 131
+ 8
+ 0
+
+
+ P4
+ 9
+ 133
+ 9
+ 0
+
+
+
+ 0
+ 0
+ 0
+ 1
+ 0
+ 0
+
+
+
+ 4150
+ 3550
+
+
+ 8
+ 2048
+
+
+
+ 1
+ 1
+ 1
+
+
+
+
+ 12
+ X24LE LM Reduced
+ 10
+
+
+ ECG
+ 1
+ 0
+ 0
+ 0
+ 0
+
+
+ POz
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ Fz
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ Cz
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ C3
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ C4
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ F3
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ F4
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ P3
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ P4
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+ Ref
+ 0
+ 5
+ 2
+ -1
+
+
+ POz
+ 1
+ 1
+ 1
+ 0
+
+
+ Fz
+ 2
+ 3
+ 2
+ 0
+
+
+ Cz
+ 3
+ 5
+ 3
+ 0
+
+
+ C3
+ 4
+ 7
+ 4
+ 0
+
+
+ C4
+ 5
+ 9
+ 5
+ 0
+
+
+ F3
+ 6
+ 11
+ 6
+ 0
+
+
+ F4
+ 7
+ 129
+ 7
+ 0
+
+
+ P3
+ 8
+ 131
+ 8
+ 0
+
+
+ P4
+ 9
+ 133
+ 9
+ 0
+
+
+
+ 0
+ 0
+ 0
+ 1
+ 0
+ 0
+
+
+
+ 4150
+ 3550
+
+
+ 8
+ 2048
+
+
+
+ 1
+ 1
+ 1
+
+
+
+
+ 13
+ X10Flex LM Reduced
+ 10
+
+
+ ECG
+ 1
+ 0
+ 0
+ 0
+ 0
+
+
+ POz
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ Fz
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ Cz
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ C3
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ C4
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ F3
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ F4
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ P3
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+ P4
+ 1
+ 1
+ 1
+ 1
+ 1
+
+
+
+
+ Ref
+ 0
+ 5
+ 2
+ -1
+
+
+ POz
+ 1
+ 1
+ 1
+ 0
+
+
+ Fz
+ 2
+ 3
+ 2
+ 0
+
+
+ Cz
+ 3
+ 5
+ 3
+ 0
+
+
+ C3
+ 4
+ 7
+ 4
+ 0
+
+
+ C4
+ 5
+ 9
+ 5
+ 0
+
+
+ F3
+ 6
+ 11
+ 6
+ 0
+
+
+ F4
+ 7
+ 129
+ 7
+ 0
+
+
+ P3
+ 8
+ 131
+ 8
+ 0
+
+
+ P4
+ 9
+ 133
+ 9
+ 0
+
+
+
+ 0
+ 0
+ 0
+ 1
+ 0
+ 0
+
+
+
+ 4150
+ 3550
+
+
+ 8
+ 2048
+
+
+
+ 1
+ 1
+ 1
+
+
+
+
+
diff --git a/physiolabxr/third_party/BAlert/Config/PSDSettings.xml b/physiolabxr/third_party/BAlert/Config/PSDSettings.xml
new file mode 100644
index 00000000..2813f4d7
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/Config/PSDSettings.xml
@@ -0,0 +1,340 @@
+
+
+ 01.00.00.00
+
+
+ 0
+
+
+ 3
+
+
+ 4
+
+
+ 5
+
+
+ 9
+
+
+
+
+ 35
+
+
+ 38
+
+
+ 39
+
+
+ 40
+
+
+ 2.419900
+
+
+ 2.419900
+
+
+ 2.169900
+
+
+ 2.169900
+
+
+ 2
+
+
+ 6
+
+
+
+
+ 70
+
+
+ 128
+
+
+ 23.933350
+
+
+ 23.933350
+
+
+
+
+ 12
+
+
+ Delta_1_3
+
+ 1
+
+
+ 3
+
+
+ 0
+
+
+
+ ThetaSlow_3_5
+
+ 3
+
+
+ 5
+
+
+ 0
+
+
+
+ ThetaFast_5_7
+
+ 5
+
+
+ 7
+
+
+ 0
+
+
+
+ ThetaTotal_3_7
+
+ 3
+
+
+ 7
+
+
+ 0
+
+
+
+ AlphaSlow_8_10
+
+ 8
+
+
+ 10
+
+
+ 0
+
+
+
+ AlphaFast_10_13
+
+ 10
+
+
+ 13
+
+
+ 0
+
+
+
+ AlphaTotal_8_13
+
+ 8
+
+
+ 13
+
+
+ 0
+
+
+
+ Beta_13_30
+
+ 13
+
+
+ 30
+
+
+ 0
+
+
+
+ Gamma_25_40
+
+ 25
+
+
+ 40
+
+
+ 0
+
+
+
+ FastGamma_40_59
+
+ 40
+
+
+ 59
+
+
+ 0
+
+
+
+
+ AffectiveClassifierGammaBand
+
+
+ 31
+
+
+ 40
+
+
+ 1
+
+
+
+
+ AffectiveClassifierSigmaBand
+
+
+ 12
+
+
+ 15
+
+
+ 1
+
+
+
+
+
+ 9
+
+
+
+ Frontal
+
+
+ Fz,F1,F2,F3,F4,F7,F8
+
+
+
+
+
+
+
+ Central
+
+
+ Cz,C1,C2,C3,C4
+
+
+
+
+
+
+
+ Parietal
+
+
+ POz,Pz,P1,P2,P3,P4
+
+
+
+
+
+
+
+ Occipital
+
+
+ Oz,O1,O2
+
+
+
+
+
+
+
+ Temporal Left
+
+
+ T3,T5
+
+
+
+
+
+
+
+ Left
+
+
+ F3,C3,P3,F1,C1,P1,O1,T3,T5,F7
+
+
+
+
+
+
+
+ Midline
+
+
+ Fz,Cz,POz,Pz,Oz,CPz
+
+
+
+
+
+
+
+ Right
+
+
+ F4,C4,P4,F2,C2,P2,O2,T4,T6,F8
+
+
+
+
+
+
+
+ Temporal Right
+
+
+ T4,T6
+
+
+
+
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ 0
+
+
+
diff --git a/physiolabxr/third_party/BAlert/Config/Priorg.txt b/physiolabxr/third_party/BAlert/Config/Priorg.txt
new file mode 100644
index 00000000..4f962c64
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/Config/Priorg.txt
@@ -0,0 +1,2 @@
+1_2143_16 2_2143_16 1_4143_16 2_4143_16
+0.411637 0.588363 0.432555 0.567445
diff --git a/physiolabxr/third_party/BAlert/Config/ReportVars.txt b/physiolabxr/third_party/BAlert/Config/ReportVars.txt
new file mode 100644
index 00000000..ef830645
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/Config/ReportVars.txt
@@ -0,0 +1,17 @@
+HR HeartRate
+Delta PSDBandwidths_ByChannel
+ThetaTotal PSDBandwidths_ByChannel
+AlphaTotal PSDBandwidths_ByChannel
+Beta PSDBandwidths_ByChannel
+Gamma PSDBandwidths_ByChannel
+Delta PSDBandwidths_Overall
+ThetaTotal PSDBandwidths_Overall
+AlphaTotal PSDBandwidths_Overall
+Beta PSDBandwidths_Overall
+Gamma PSDBandwidths_Overall
+Sleep Onset Classify
+Distraction Classify
+Low Engagement Classify
+High Engagement Classify
+Drowsy Classify
+Workload Classify
\ No newline at end of file
diff --git a/physiolabxr/third_party/BAlert/Config/SignalsMapingConf.xml b/physiolabxr/third_party/BAlert/Config/SignalsMapingConf.xml
new file mode 100644
index 00000000..037a7063
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/Config/SignalsMapingConf.xml
@@ -0,0 +1,1442 @@
+
+
+
+ X24_FLEX_10_20
+ 4800
+ 0
+ 24
+ 200
+ 20
+ 50
+ 50
+
+
+ Fp1
+ 23
+ 0
+ 1
+ 0
+ 1
+ 0
+ 0
+ 1
+
+
+ F7
+ 22
+ 1
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ F8
+ 21
+ 2
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ T4
+ 20
+ 3
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ T6
+ 19
+ 4
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ T5
+ 18
+ 5
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ T3
+ 17
+ 6
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ Fp2
+ 16
+ 7
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ O1
+ 15
+ 8
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ P3
+ 14
+ 9
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ Pz
+ 13
+ 10
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ F3
+ 12
+ 11
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ Fz
+ 11
+ 12
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ F4
+ 10
+ 13
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ C4
+ 9
+ 14
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ P4
+ 8
+ 15
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ POz
+ 7
+ 16
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ C3
+ 6
+ 17
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ Cz
+ 5
+ 18
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ O2
+ 4
+ 19
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ ECG
+ 0
+ 20
+ 1
+ 0
+ 0
+ 1
+ 0
+ 0
+
+
+ OPT1
+ 3
+ 21
+ 1
+ 0
+ 0
+ 0
+ 1
+ 0
+
+
+ OPT2
+ 2
+ 22
+ 1
+ 0
+ 0
+ 0
+ 1
+ 0
+
+
+ OPT3
+ 1
+ 23
+ 1
+ 0
+ 0
+ 0
+ 1
+ 0
+
+
+
+
+ X24Flex_X10_Standard
+ 10
+ 4800
+ 0
+ 200
+ 10
+ 30
+ 150
+
+
+ ECG
+ 0
+ 0
+ 1
+ 0
+ 0
+ 1
+ 0
+ 0
+
+
+ POz
+ 9
+ 1
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ Fz
+ 8
+ 2
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ Cz
+ 7
+ 3
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ C3
+ 6
+ 4
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ C4
+ 5
+ 5
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ F3
+ 4
+ 6
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ F4
+ 3
+ 7
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ P3
+ 2
+ 8
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ P4
+ 1
+ 9
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+
+
+ X24Flex_Reduced
+ 10
+ 4800
+ 0
+ 200
+ 10
+ 200
+ 1000
+
+
+ ECG
+ 1
+ 0
+ 0
+ 0
+ 0
+ 1
+ 0
+ 0
+
+
+ POz
+ 1
+ 1
+ 9
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ Fz
+ 1
+ 2
+ 8
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ Cz
+ 1
+ 7
+ 3
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ C3
+ 0
+ 4
+ 6
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ C4
+ 0
+ 5
+ 5
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ F3
+ 0
+ 6
+ 4
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ F4
+ 0
+ 7
+ 3
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ P3
+ 0
+ 8
+ 2
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ P4
+ 0
+ 9
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+
+
+ X24_FLEX_10_20_LM
+ 4800
+ 0
+ 24
+ 200
+ 10
+ 30
+ 150
+
+
+ Fp1
+ 23
+ 0
+ 1
+ 0
+ 1
+ 0
+ 0
+ 1
+
+
+ F7
+ 22
+ 1
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ F8
+ 21
+ 2
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ T4
+ 20
+ 3
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ T6
+ 19
+ 4
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ T5
+ 18
+ 5
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ T3
+ 17
+ 6
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ Fp2
+ 16
+ 7
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ O1
+ 15
+ 8
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ P3
+ 14
+ 9
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ Pz
+ 13
+ 10
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ F3
+ 12
+ 11
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ Fz
+ 11
+ 12
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ F4
+ 10
+ 13
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ C4
+ 9
+ 14
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ P4
+ 8
+ 15
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ POz
+ 7
+ 16
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ C3
+ 6
+ 17
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ Cz
+ 5
+ 18
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ O2
+ 4
+ 19
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ ECG
+ 0
+ 20
+ 1
+ 0
+ 0
+ 1
+ 0
+ 0
+
+
+ OPT1
+ 3
+ 21
+ 0
+ 0
+ 0
+ 0
+ 1
+ 0
+
+
+ OPT2
+ 2
+ 22
+ 0
+ 0
+ 0
+ 0
+ 1
+ 0
+
+
+ OPT3
+ 1
+ 23
+ 0
+ 0
+ 0
+ 0
+ 1
+ 0
+
+
+
+
+
+ X24_FLEX_LE_10_20_LM
+ 4800
+ 0
+ 24
+ 200
+ 10
+ 30
+ 150
+
+
+ Fp1
+ 23
+ 0
+ 1
+ 0
+ 1
+ 0
+ 0
+ 1
+
+
+ F7
+ 22
+ 1
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ F8
+ 21
+ 2
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ T4
+ 20
+ 3
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ T6
+ 19
+ 4
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ T5
+ 18
+ 5
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ T3
+ 17
+ 6
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ Fp2
+ 16
+ 7
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ O1
+ 15
+ 8
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ P3
+ 14
+ 9
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ Pz
+ 13
+ 10
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ F3
+ 12
+ 11
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ Fz
+ 11
+ 12
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ F4
+ 10
+ 13
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ C4
+ 9
+ 14
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ P4
+ 8
+ 15
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ POz
+ 7
+ 16
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ C3
+ 6
+ 17
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ Cz
+ 5
+ 18
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ O2
+ 4
+ 19
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ ECG
+ 0
+ 20
+ 1
+ 0
+ 0
+ 1
+ 0
+ 0
+
+
+ OPT1
+ 3
+ 21
+ 0
+ 0
+ 0
+ 0
+ 1
+ 0
+
+
+ OPT2
+ 2
+ 22
+ 0
+ 0
+ 0
+ 0
+ 1
+ 0
+
+
+ OPT3
+ 1
+ 23
+ 0
+ 0
+ 0
+ 0
+ 1
+ 0
+
+
+
+
+ X24_FLEX_10_20_LM_RED
+ 10
+ 4800
+ 0
+ 200
+ 10
+ 30
+ 150
+
+
+ ECG
+ 0
+ 0
+ 1
+ 0
+ 0
+ 1
+ 0
+ 0
+
+
+ POz
+ 9
+ 1
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ Fz
+ 8
+ 2
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ Cz
+ 7
+ 3
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ C3
+ 6
+ 4
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ C4
+ 5
+ 5
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ F3
+ 4
+ 6
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ F4
+ 3
+ 7
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ P3
+ 2
+ 8
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ P4
+ 1
+ 9
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+
+
+ X24_LE_10_20_LM_RED
+ 10
+ 4800
+ 0
+ 200
+ 10
+ 30
+ 150
+
+
+ ECG
+ 0
+ 0
+ 1
+ 0
+ 0
+ 1
+ 0
+ 0
+
+
+ POz
+ 9
+ 1
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ Fz
+ 8
+ 2
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ Cz
+ 7
+ 3
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ C3
+ 6
+ 4
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ C4
+ 5
+ 5
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ F3
+ 4
+ 6
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ F4
+ 3
+ 7
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ P3
+ 2
+ 8
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ P4
+ 1
+ 9
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+
+
+ X10_FLEX_10_20_LM_RED
+ 10
+ 4800
+ 0
+ 200
+ 10
+ 30
+ 150
+
+
+ ECG
+ 0
+ 0
+ 1
+ 0
+ 0
+ 1
+ 0
+ 0
+
+
+ POz
+ 9
+ 1
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ Fz
+ 8
+ 2
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ Cz
+ 7
+ 3
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ C3
+ 6
+ 4
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ C4
+ 5
+ 5
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ F3
+ 4
+ 6
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ F4
+ 3
+ 7
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ P3
+ 2
+ 8
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+ P4
+ 1
+ 9
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+
+
+
+
\ No newline at end of file
diff --git a/physiolabxr/third_party/BAlert/Config/WorkloadInvPcov2143_Model16.txt b/physiolabxr/third_party/BAlert/Config/WorkloadInvPcov2143_Model16.txt
new file mode 100644
index 00000000..7fbd7319
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/Config/WorkloadInvPcov2143_Model16.txt
@@ -0,0 +1,39 @@
+C3C4HZ01 C3C4HZ15 C3C4HZ31 CZPOHZ26 CZPOHZ36 CZPOHZ37 F3CZHZ06 F3CZHZ07 F3CZHZ10 F3CZHZ16 F3CZHZ28 FZC3HZ01 FZC3HZ06 FZC3HZ08 FZC3HZ13 FZC3HZ15 FZPOHZ04 FZPOHZ10 FZPOHZ16 FZPOHZ28 FZPOHZ40 PROB3 PROB7 PROB8 rC34Hz08 rC34Hz15 rC34Hz16 rCPOHz16 rCPOHz32 rCPOHz34 rCPOHz38 rCPOHz40 rF3CHz12 rF3CHz20 rFC3Hz17 rFC3Hz30 rFPOHz33 rFPOHz35
+7.453896293967380E+00 -1.758009906608890E+00 -6.713082116225490E-02 2.542984897733820E-01 -3.668388368223250E-02 -1.164557990829600E-01 -5.912308201958460E-01 -3.658421776801700E-01 -8.594873088755300E-02 1.151788000487210E-01 1.650293778305650E-01 -2.229644391378890E+00 -9.005030912987640E-02 1.314462345489750E-01 4.590033376065890E-02 3.311066694427450E-01 -1.604287365881910E+00 7.664159315801440E-01 -6.353257528521510E-01 1.071933664704240E-01 4.060145218589850E-01 -2.286080178974780E-01 -2.484815281129750E-01 4.464661217619150E-01 2.719696806960470E-01 -1.736572733292770E+00 -2.656424162997360E-01 -7.531538737729820E-01 -5.281715874479010E-02 -1.707377778453930E-01 -4.158394956781790E-01 2.191795397739620E-01 -4.055812044563780E-01 -3.136193793280010E-01 -4.107369782634470E-01 4.709190000778780E-01 3.777887658546190E-02 3.846156114832800E-01
+-1.758009906608890E+00 4.404238887085530E+01 -4.096478640738940E+00 -2.747822207083460E+00 -6.414558936599950E-01 -2.242017379319230E+00 -1.143254734027500E+00 -2.178722053461490E+00 -3.810281539413580E+00 -2.421258569838730E+00 -2.017642730269850E+00 8.001756724045830E-01 -3.122229094113900E-01 -4.872916274448830E+00 -4.306572878772680E+00 -6.622496747992840E+00 -9.404338638242720E-01 -1.288798199921490E+00 1.532983412909350E+00 -5.548153454601370E-01 -1.737658041224500E-01 3.341783622300300E+00 3.473333383021510E+00 2.991648904358780E+00 -3.811243215532650E+00 3.791419551098890E+01 -4.143809495654090E+00 2.139073911877750E+00 8.331582499982570E-02 1.902636016635250E-01 -2.469623542490920E+00 -1.114677884656900E+00 1.421467349014310E+00 6.938880059855710E-01 2.526842637036580E+00 -2.596744065543810E+00 1.678039033894730E+00 -9.747758836214100E-01
+-6.713082116225490E-02 -4.096478640738940E+00 9.555346740938520E+00 2.540399127597830E-01 -6.204863617300770E-01 -7.530821088656730E-02 -2.231414220740880E-01 -1.618203196180540E-01 -9.658465346141850E-02 -3.794236684275310E-01 -7.123543014054940E-01 -1.044572899920580E-01 -8.977374875441990E-01 -3.603502359911150E-01 -3.203785040546530E-01 -5.176543463067810E-01 -8.768157728961610E-01 -3.040193367236130E-02 -9.735351563642370E-02 6.959294061385550E-02 -2.276229727386990E-01 -2.741646927049610E-01 -2.573869178602390E-01 -5.036864791551920E-01 -4.841353493065140E-01 -3.992187660423230E+00 5.430856646955860E-01 -5.577577777726830E-01 6.739966987677280E-01 9.369866964602600E-01 6.001492766343150E-02 1.851178355187250E-01 -2.038143487833570E-01 2.828203076028580E-01 2.217075730766880E-01 4.026338683480700E+00 1.124618522802900E-02 -2.986600643652140E-01
+2.542984897733820E-01 -2.747822207083460E+00 2.540399127597830E-01 1.002931291171860E+01 -3.679255715048760E-01 -1.200201292917490E+00 -1.862868116569210E-03 7.297223289698040E-02 -3.348834692941500E-01 -3.271901860516540E-01 -1.762992780726690E+00 2.977710733139120E-01 8.176170667591690E-02 2.352970104074040E-01 -5.743654603270270E-01 -5.068307174614830E-03 -4.893435483335830E-01 -4.805793048984610E-02 -1.685843216612680E+00 -1.516105139979790E+00 -1.229423316756190E+00 6.752645578177910E-01 2.805188377336590E-01 7.246971678284650E-01 1.146307813187970E-01 -2.046567158099190E+00 6.419835907774250E-01 -7.899571303227550E-01 5.015172551667290E-01 -6.624300463722670E-01 4.958137878655220E-02 -3.830670245927210E-01 4.582272033051990E-01 3.117907304238260E-01 3.624788661804230E-01 2.343788441178570E-02 9.166670190309110E-01 2.226854806925090E-01
+-3.668388368223270E-02 -6.414558936599920E-01 -6.204863617300780E-01 -3.679255715048760E-01 1.776879495912630E+01 -1.084706908511960E+01 1.552764490167970E-01 -9.749062418454740E-01 -1.599441144768350E-01 -2.375732973228440E-02 -1.664977866971450E-01 1.986753860019350E-01 -8.140310669746730E-01 2.109064542045370E-01 -1.147318928969150E-01 2.114977517076090E-01 -2.391970702268330E-01 -1.234701900413640E+00 -1.451462408927470E+00 -5.399461992647070E-01 -1.343672172919700E+00 7.989997039431390E-02 5.502940076542530E-01 1.561928507408560E-01 4.674415671829890E-02 -5.373907969127730E-01 -1.669719736619420E-01 -9.041417015610330E-01 3.477181133714290E-01 -3.264840210399390E-01 -2.762370120228710E+00 8.597237682725660E-01 9.063845586740860E-01 7.993793153589640E-03 5.128176329726150E-02 -3.650067090848470E-01 -4.846646240449950E-01 6.144601962491460E+00
+-1.164557990829600E-01 -2.242017379319230E+00 -7.530821088656990E-02 -1.200201292917490E+00 -1.084706908511950E+01 2.063649746542650E+01 -3.037010612287530E-01 3.413038591192930E-01 1.446201140152340E-01 3.018375917813800E-01 3.085737171654090E-02 -2.240163173832830E-01 1.397841062344890E-02 -4.100669802084140E-01 3.891769324927670E-01 7.015495182284000E-01 -3.908413522137600E-01 -1.242335370561630E+00 -2.470533530554480E+00 -6.707930998174740E-01 -2.550821968363710E+00 1.277655157634650E+00 9.679493528692510E-01 7.868013507327040E-01 5.198500897827630E-02 -1.808844147453920E+00 9.139788454456940E-02 -1.655032401329160E+00 -4.306541050265110E-01 2.342256798776470E-01 9.240872828155830E+00 -2.275678455005260E+00 -5.900463670923850E-01 6.052729009320800E-01 -3.393652576321590E-01 7.705355064674870E-02 1.091384244580790E+00 -2.094429348544660E+00
+-5.912308201958450E-01 -1.143254734027500E+00 -2.231414220740880E-01 -1.862868116569440E-03 1.552764490167980E-01 -3.037010612287540E-01 1.407956896609500E+01 -7.701506208046940E+00 -3.310506900489020E-02 -4.053880733434450E-01 -5.370014941255260E-01 -5.675310179429160E-01 -1.668372378899060E+00 2.472470790871600E-01 3.719389570802150E-01 -1.689861365279820E-01 -1.195625152537260E+00 6.376970539199320E-01 -1.369897381132540E-01 3.943108933798600E-01 1.464398764485050E-01 5.882681481398040E-02 4.572454081541570E-01 9.364631555099970E-01 -4.955851568442570E-01 -1.693627118932470E+00 -6.414515973798280E-01 3.442281688673890E-02 3.112282745192760E-01 6.728662498117640E-02 2.767210126759970E-02 -5.964122132587400E-01 -1.026602721047320E+00 -1.047548474405930E+00 1.712347711184320E-01 1.478144814342250E-01 -8.431178137560190E-02 -1.096584719439690E-01
+-3.658421776801700E-01 -2.178722053461490E+00 -1.618203196180540E-01 7.297223289698050E-02 -9.749062418454740E-01 3.413038591192940E-01 -7.701506208046930E+00 1.520986466071090E+01 -4.066248813084080E-01 -5.100043092262040E-01 -9.989049160502320E-04 2.824310133039390E-01 -6.541780630481620E-01 -1.221242936982950E+00 1.712458142776340E-01 -1.188697594000580E-01 -5.290311240745420E-02 3.216860539442620E-01 -8.416426684217520E-01 3.606273498617120E-01 -3.749849892788810E-01 -1.242515515837930E+00 -1.421982406376740E+00 -1.306761895992360E+00 1.594967669839320E+00 -2.020598329564320E+00 1.864684390261740E-01 4.271905330616760E-03 -1.018369242184750E-02 4.672324841146750E-01 -8.164415165215480E-02 -4.326701831915450E-01 -7.409740123475910E-01 -5.355098917477730E-01 4.467535964355860E-02 2.560454255718560E-01 2.665359543300010E-02 -5.141155945186080E-01
+-8.594873088755320E-02 -3.810281539413580E+00 -9.658465346141850E-02 -3.348834692941510E-01 -1.599441144768340E-01 1.446201140152350E-01 -3.310506900488990E-02 -4.066248813084090E-01 1.001768782719290E+01 -4.776261460490210E-01 -5.987934465222340E-01 2.505222217409790E-01 8.767029961198980E-02 -8.984573619501450E-01 -2.207185743418030E-01 -2.785583352222280E-01 1.058479088936500E-01 -3.627652485957040E+00 2.041572530490490E-01 -3.724814690741790E-01 -1.800684284012400E-01 -3.895393876419750E-01 -2.630171562313880E-01 8.932478124430440E-01 2.319475966778360E-01 -3.785681059226650E+00 -4.037312946643990E-02 -7.674832236501940E-02 3.808444128406940E-01 3.749367055519830E-01 5.185834587633070E-01 -3.077719040395510E-01 -4.965330048419370E-01 -1.297556577308630E+00 -1.078441672224300E-01 1.759501279514550E-01 -4.606378970089620E-01 -6.935083730263860E-01
+1.151788000487200E-01 -2.421258569838730E+00 -3.794236684275300E-01 -3.271901860516530E-01 -2.375732973228330E-02 3.018375917813770E-01 -4.053880733434440E-01 -5.100043092262040E-01 -4.776261460490200E-01 1.065479043908550E+01 -1.411299395958460E+00 -4.495143137640910E-01 -5.091424042216820E-02 -4.711194407111660E-01 -3.889503126224270E-01 -8.993233061771090E-02 2.927965128491260E-01 5.944760019895620E-01 -4.315391144329750E+00 5.061497881336720E-01 -6.910098366247680E-01 -6.425269013848080E-01 -5.312470363702930E-01 -6.232961401297960E-01 2.849309300469410E-01 -2.220128200269050E+00 2.210939915388060E+00 -1.975778737731760E+00 2.160644726914670E-01 2.918540734563900E-01 -6.171760784902120E-02 -6.723984411480450E-01 -6.994619970776920E-01 1.141348514518230E+00 4.992975930332810E-01 5.757019909729260E-01 -1.855583017998080E-01 2.568989904328860E-01
+1.650293778305640E-01 -2.017642730269860E+00 -7.123543014054930E-01 -1.762992780726690E+00 -1.664977866971440E-01 3.085737171654080E-02 -5.370014941255250E-01 -9.989049160503690E-04 -5.987934465222340E-01 -1.411299395958450E+00 7.509514047157030E+00 -6.100404533888680E-01 1.812060477486150E-01 -1.822319674797430E-01 -8.436044779477580E-04 -4.534291571018580E-01 1.031441674686580E-01 -1.014006451670380E-01 1.301021724262900E-01 -1.799258782874260E+00 -3.823287658833220E-01 -7.358140000150750E-01 -5.745188542563720E-01 -4.448349871313760E-01 -8.510549139313620E-01 -2.248493137817960E+00 2.601997839614820E-01 2.838860823599280E-01 5.539161651104950E-01 1.445776186970540E-01 -6.597742043598190E-01 -7.049575125477450E-01 -8.448028276474620E-01 7.299771805173530E-01 3.806607827085020E-02 1.041637795341470E+00 9.571407515730330E-02 6.590478091702260E-02
+-2.229644391378890E+00 8.001756724045830E-01 -1.044572899920580E-01 2.977710733139120E-01 1.986753860019350E-01 -2.240163173832830E-01 -5.675310179429160E-01 2.824310133039390E-01 2.505222217409790E-01 -4.495143137640910E-01 -6.100404533888680E-01 1.072976714677330E+01 -6.994059293725070E-01 -1.623739078443420E-01 -6.882205928679780E-02 -1.562925371076910E-01 -3.596698065231650E-01 -4.578309748035650E-01 3.772624801310050E-01 2.375515255703010E-01 -4.650496568422180E-01 1.141529401098050E+00 1.168671072572890E+00 1.469478226946190E+00 1.091857964016700E-01 8.284584965423180E-01 5.873005541821750E-02 4.362842784970770E-01 -1.997799365446680E-01 -6.477941723225880E-01 -1.647696189108730E-01 -5.182152009417750E-01 4.129743965864220E-01 -2.829867974603650E-01 -1.366802814803670E-01 -3.235382971212230E-01 6.356418459723930E-01 1.584134764963710E-01
+-9.005030912987650E-02 -3.122229094113920E-01 -8.977374875441990E-01 8.176170667591720E-02 -8.140310669746740E-01 1.397841062345020E-02 -1.668372378899060E+00 -6.541780630481610E-01 8.767029961199010E-02 -5.091424042216780E-02 1.812060477486150E-01 -6.994059293725080E-01 8.774296019940350E+00 -1.231558464248080E+00 -1.443140758877510E-01 -4.758024340852540E-01 -8.955745996146400E-01 5.617976307236280E-01 -1.084109203583480E+00 1.444849083731160E-01 2.289371968726210E-01 4.165042801737370E+00 3.816443275556410E+00 4.712960918262520E+00 5.172840987896010E-01 -1.468907715268240E-01 3.109474019545750E-01 -1.008066664195460E+00 2.992706589581350E-01 7.975950490652570E-01 3.668897530793690E-01 5.244209879906390E-01 1.354228176013290E-01 1.382908217116880E-01 -2.160917671703560E+00 -2.095859111665860E+00 -1.085438486449370E+00 -1.110686382069420E+00
+1.314462345489740E-01 -4.872916274448820E+00 -3.603502359911140E-01 2.352970104074040E-01 2.109064542045370E-01 -4.100669802084150E-01 2.472470790871610E-01 -1.221242936982950E+00 -8.984573619501470E-01 -4.711194407111650E-01 -1.822319674797440E-01 -1.623739078443410E-01 -1.231558464248080E+00 1.102060284013960E+01 2.752482324514760E-01 -4.671592783884290E-01 1.102115392595190E-01 -1.638409498480450E-01 -3.472735572838270E-01 -3.004601417807730E-02 -1.111051132555020E-01 -9.593251035054650E-01 -7.061290288609490E-01 -9.788279766933860E-01 4.277429361610600E+00 -5.144087175864800E+00 5.537703972805620E-01 -5.457539703385880E-01 -2.265194364542660E-01 -1.659853014014970E-01 -8.028809463034410E-04 -1.857534321945320E-01 2.117804866468740E-01 6.271520580426520E-01 -6.056143015163950E-01 -1.332030741964930E+00 -1.865444317544580E-02 2.069477492768980E-01
+4.590033376065870E-02 -4.306572878772670E+00 -3.203785040546530E-01 -5.743654603270280E-01 -1.147318928969140E-01 3.891769324927660E-01 3.719389570802160E-01 1.712458142776330E-01 -2.207185743418040E-01 -3.889503126224270E-01 -8.436044779485200E-04 -6.882205928679760E-02 -1.443140758877510E-01 2.752482324514760E-01 8.210452036587140E+00 -2.044596367620550E+00 3.745084360634800E-01 3.051861266885060E-01 -7.441659018715660E-01 -2.456693921384140E-01 5.242741232424730E-02 -1.118707388323070E+00 -1.139705856593730E+00 -1.297202084164900E+00 -1.017313186962930E+00 -3.977987812635230E+00 -4.711305285443520E-02 -1.493364738817930E-01 -9.161550785758460E-04 -4.327349688167100E-01 -3.361578903958340E-02 -3.046557093117660E-01 2.112138557371590E+00 -4.625522201862700E-01 -7.335577238784500E-01 -1.131409848013840E+00 3.350927408113320E-02 -2.045601856855800E-01
+3.311066694427450E-01 -6.622496747992850E+00 -5.176543463067800E-01 -5.068307174614190E-03 2.114977517076090E-01 7.015495182284000E-01 -1.689861365279810E-01 -1.188697594000580E-01 -2.785583352222270E-01 -8.993233061770780E-02 -4.534291571018580E-01 -1.562925371076910E-01 -4.758024340852540E-01 -4.671592783884280E-01 -2.044596367620550E+00 1.286599327236490E+01 4.533823328410520E-01 4.592072995680390E-01 -3.163833767129960E+00 3.310101077416120E-01 5.835772664022930E-02 -6.062182447467790E-01 -3.104954503720610E-01 -4.296678801427310E-01 -3.599076549965440E-02 -1.518403461033590E+00 8.236361541029800E-01 -1.549210631934390E+00 -1.203817756401520E-01 3.597275561876480E-01 4.935423677516680E-01 2.217843024083920E-01 2.543294624028760E-02 5.940742721336350E-01 7.625234096575820E-01 -8.179318294093040E-02 -6.225365059917490E-01 3.617091670893440E-01
+-1.604287365881910E+00 -9.404338638242730E-01 -8.768157728961600E-01 -4.893435483335820E-01 -2.391970702268320E-01 -3.908413522137600E-01 -1.195625152537260E+00 -5.290311240745350E-02 1.058479088936500E-01 2.927965128491250E-01 1.031441674686580E-01 -3.596698065231650E-01 -8.955745996146400E-01 1.102115392595200E-01 3.745084360634800E-01 4.533823328410510E-01 1.063091891574980E+01 1.499513358021360E+00 -8.612708131108310E-01 1.904570262376000E-01 -4.240524387045980E-01 1.864987418890770E+00 2.191353191238130E+00 2.102207434580560E+00 2.921491281227610E-01 -1.284531613810790E+00 1.416593083164610E-01 -1.950842439436790E+00 2.454392737963350E-01 3.237877722498930E-01 -4.189424859896320E-01 -4.571528467217450E-01 -1.140470835305840E+00 -2.444577667124950E-01 -3.895768927502010E-01 -4.361552504662620E-01 -5.830316778042410E-01 -6.686259835422600E-01
+7.664159315801440E-01 -1.288798199921490E+00 -3.040193367236160E-02 -4.805793048984600E-02 -1.234701900413640E+00 -1.242335370561630E+00 6.376970539199320E-01 3.216860539442610E-01 -3.627652485957040E+00 5.944760019895620E-01 -1.014006451670370E-01 -4.578309748035650E-01 5.617976307236280E-01 -1.638409498480450E-01 3.051861266885070E-01 4.592072995680390E-01 1.499513358021360E+00 1.116839541640270E+01 -4.029110656130100E+00 -1.758957782508790E-01 -2.384377555605530E+00 -4.227917094005250E+00 -3.986845526758720E+00 -5.747347135079820E+00 9.276091069771590E-01 -2.040314487405930E+00 6.974652741720310E-02 -5.298690147229300E+00 -9.001571504214560E-01 2.238770024422590E-01 -1.606941187558940E+00 -2.967997507910470E+00 -4.938407871254320E-02 1.568591993351400E-01 -9.265754959482480E-01 -7.174310132518250E-01 -1.118620668508050E+00 -1.863228418129370E+00
+-6.353257528521500E-01 1.532983412909350E+00 -9.735351563642440E-02 -1.685843216612680E+00 -1.451462408927470E+00 -2.470533530554480E+00 -1.369897381132540E-01 -8.416426684217510E-01 2.041572530490510E-01 -4.315391144329760E+00 1.301021724262880E-01 3.772624801310040E-01 -1.084109203583480E+00 -3.472735572838270E-01 -7.441659018715670E-01 -3.163833767129950E+00 -8.612708131108320E-01 -4.029110656130100E+00 2.800386937991150E+01 -1.505432734955790E+00 -4.654109581406470E+00 3.250891407902750E+00 2.305566651417570E+00 1.991136693067760E+00 -3.612531857329680E-01 1.194460516447280E+00 -9.807688035526060E-01 2.039052097687100E+01 -5.881416989971870E-01 -3.754056754485360E-01 -2.940820401090260E+00 -4.001165228751070E+00 2.555491557610760E-01 -3.524560281031700E-01 1.764337908673600E+00 -1.633623681132330E-02 -2.467433232515120E-01 -1.202547346427650E+00
+1.071933664704240E-01 -5.548153454601370E-01 6.959294061385580E-02 -1.516105139979790E+00 -5.399461992647050E-01 -6.707930998174740E-01 3.943108933798610E-01 3.606273498617120E-01 -3.724814690741790E-01 5.061497881336730E-01 -1.799258782874260E+00 2.375515255703010E-01 1.444849083731160E-01 -3.004601417807700E-02 -2.456693921384140E-01 3.310101077416130E-01 1.904570262376000E-01 -1.758957782508790E-01 -1.505432734955790E+00 1.100446929822930E+01 -1.590466743903970E+00 7.595011020195500E-01 3.702304536734840E-01 5.789286483351150E-01 -4.135196905655300E-01 -2.611455263691670E-02 -9.302457885552050E-02 -4.211877359473630E-01 4.871486173010480E-01 5.957896967658810E-01 4.882501502491120E-01 -3.157158535011300E-01 8.467819632605560E-01 -1.908674178269550E-01 -3.868300099676960E-01 9.577116821381410E-02 -2.132673100099330E-01 -5.699425320088190E-02
+4.060145218589850E-01 -1.737658041224500E-01 -2.276229727386990E-01 -1.229423316756190E+00 -1.343672172919700E+00 -2.550821968363710E+00 1.464398764485060E-01 -3.749849892788810E-01 -1.800684284012400E-01 -6.910098366247670E-01 -3.823287658833210E-01 -4.650496568422180E-01 2.289371968726210E-01 -1.111051132555010E-01 5.242741232424790E-02 5.835772664022810E-02 -4.240524387045990E-01 -2.384377555605530E+00 -4.654109581406470E+00 -1.590466743903970E+00 2.069198491556150E+01 2.308529548336300E+00 1.376961187334890E+00 1.946928740232110E+00 -9.003733536453800E-01 -5.391274194512210E-01 6.165413006174100E-01 -4.392223807036810E+00 -3.366337049935870E-01 -7.346615433238180E-01 -9.598439331586990E-01 1.496632895233190E+01 -2.038642998952230E-01 3.743815620495370E-01 -8.879862858809090E-01 -1.043493024101730E-01 2.017065420955200E-01 -9.293830641027910E-02
+-2.286080178974770E-01 3.341783622300310E+00 -2.741646927049630E-01 6.752645578177900E-01 7.989997039431230E-02 1.277655157634650E+00 5.882681481397700E-02 -1.242515515837930E+00 -3.895393876419730E-01 -6.425269013848100E-01 -7.358140000150750E-01 1.141529401098060E+00 4.165042801737360E+00 -9.593251035054670E-01 -1.118707388323080E+00 -6.062182447467810E-01 1.864987418890770E+00 -4.227917094005260E+00 3.250891407902770E+00 7.595011020195490E-01 2.308529548336300E+00 1.566964501045850E+02 1.522394239812740E+02 1.532172085029510E+02 -9.989546923306680E-01 5.712430690801150E+00 -2.179120043376960E+00 4.652952428394070E+00 -6.036143321092750E-01 -7.248535916008600E-01 8.532228050824240E-01 8.107291688472620E-01 3.817135337794210E-01 4.749702916886230E-01 1.380492039347560E+00 3.241896648781020E+00 3.280795450017210E+00 -3.879206818963590E-01
+-2.484815281129740E-01 3.473333383021510E+00 -2.573869178602420E-01 2.805188377336660E-01 5.502940076542510E-01 9.679493528692480E-01 4.572454081541520E-01 -1.421982406376740E+00 -2.630171562313880E-01 -5.312470363702930E-01 -5.745188542563740E-01 1.168671072572890E+00 3.816443275556410E+00 -7.061290288609520E-01 -1.139705856593730E+00 -3.104954503720640E-01 2.191353191238130E+00 -3.986845526758720E+00 2.305566651417580E+00 3.702304536734870E-01 1.376961187334890E+00 1.522394239812740E+02 1.570482733172510E+02 1.527503950114240E+02 -1.071924338351910E+00 5.700181415978270E+00 -1.895378266863650E+00 3.391338014396320E+00 -9.880167327063010E-01 -6.746744443092280E-01 5.072795821934180E-01 -1.883881924469570E-01 7.996198067286440E-01 7.819369264639820E-01 1.756332000301930E+00 2.821348124026000E+00 3.577078324980200E+00 1.971652301886840E-01
+4.464661217619140E-01 2.991648904358790E+00 -5.036864791551970E-01 7.246971678284740E-01 1.561928507408530E-01 7.868013507327040E-01 9.364631555099880E-01 -1.306761895992350E+00 8.932478124430390E-01 -6.232961401297960E-01 -4.448349871313790E-01 1.469478226946190E+00 4.712960918262520E+00 -9.788279766933900E-01 -1.297202084164900E+00 -4.296678801427360E-01 2.102207434580560E+00 -5.747347135079820E+00 1.991136693067780E+00 5.789286483351210E-01 1.946928740232120E+00 1.532172085029510E+02 1.527503950114240E+02 1.719337977084320E+02 -1.503512927369960E+00 4.705597406974120E+00 -1.751865835399570E+00 2.264065639911590E+00 -1.215998456917500E+00 -5.284661397847160E-01 4.659158073317330E-01 5.413250691144810E-01 -3.102140771679990E-02 8.448874338445840E-01 2.491330531302740E+00 2.650268092387980E+00 3.093242776326530E+00 4.996301856694280E-01
+2.719696806960470E-01 -3.811243215532650E+00 -4.841353493065130E-01 1.146307813187970E-01 4.674415671829960E-02 5.198500897827620E-02 -4.955851568442550E-01 1.594967669839320E+00 2.319475966778350E-01 2.849309300469410E-01 -8.510549139313620E-01 1.091857964016700E-01 5.172840987896010E-01 4.277429361610600E+00 -1.017313186962930E+00 -3.599076549965440E-02 2.921491281227610E-01 9.276091069771600E-01 -3.612531857329700E-01 -4.135196905655290E-01 -9.003733536453800E-01 -9.989546923306690E-01 -1.071924338351920E+00 -1.503512927369960E+00 1.136519516317230E+01 -3.823511920321880E+00 2.924318208246960E-01 -1.428198244227570E+00 -1.672156363468240E-01 -4.238958150776010E-02 1.916303262742960E-01 -5.389017069447830E-01 6.605413878575110E-01 5.205748695907970E-01 -3.993912771735480E-01 1.654422285434200E-03 -2.566040488722460E-01 8.537117516829250E-01
+-1.736572733292770E+00 3.791419551098890E+01 -3.992187660423230E+00 -2.046567158099190E+00 -5.373907969127760E-01 -1.808844147453920E+00 -1.693627118932480E+00 -2.020598329564310E+00 -3.785681059226650E+00 -2.220128200269060E+00 -2.248493137817950E+00 8.284584965423180E-01 -1.468907715268210E-01 -5.144087175864800E+00 -3.977987812635230E+00 -1.518403461033580E+00 -1.284531613810790E+00 -2.040314487405940E+00 1.194460516447280E+00 -2.611455263691740E-02 -5.391274194512220E-01 5.712430690801140E+00 5.700181415978260E+00 4.705597406974110E+00 -3.823511920321880E+00 4.824969341193610E+01 -1.140434916107800E+01 1.747246546901690E+00 6.994647303177140E-01 2.010896285241110E-01 -1.985286604542480E+00 -1.073811588971370E+00 1.774783700324310E+00 3.270993952207010E-01 2.885877920861660E+00 -2.965409359661890E+00 1.196152600747970E+00 -8.690559525541570E-01
+-2.656424162997370E-01 -4.143809495654090E+00 5.430856646955860E-01 6.419835907774260E-01 -1.669719736619410E-01 9.139788454456900E-02 -6.414515973798270E-01 1.864684390261740E-01 -4.037312946644100E-02 2.210939915388060E+00 2.601997839614810E-01 5.873005541821760E-02 3.109474019545740E-01 5.537703972805640E-01 -4.711305285443390E-02 8.236361541029780E-01 1.416593083164610E-01 6.974652741720370E-02 -9.807688035526090E-01 -9.302457885552030E-02 6.165413006174110E-01 -2.179120043376970E+00 -1.895378266863660E+00 -1.751865835399570E+00 2.924318208246970E-01 -1.140434916107800E+01 1.534627710327290E+01 -1.493139325051330E+00 -1.886340099861120E-02 6.189171387275560E-01 1.150292652316530E-01 3.110420369104450E-01 3.657116058553790E-01 -4.624721003479700E-01 -3.341488231209780E+00 6.752777234484890E-01 -2.985042915483870E-01 -4.735407732171750E-01
+-7.531538737729820E-01 2.139073911877750E+00 -5.577577777726840E-01 -7.899571303227560E-01 -9.041417015610360E-01 -1.655032401329160E+00 3.442281688673850E-02 4.271905330618520E-03 -7.674832236501880E-02 -1.975778737731760E+00 2.838860823599260E-01 4.362842784970760E-01 -1.008066664195460E+00 -5.457539703385880E-01 -1.493364738817940E-01 -1.549210631934390E+00 -1.950842439436790E+00 -5.298690147229300E+00 2.039052097687100E+01 -4.211877359473610E-01 -4.392223807036810E+00 4.652952428394050E+00 3.391338014396300E+00 2.264065639911570E+00 -1.428198244227570E+00 1.747246546901690E+00 -1.493139325051320E+00 2.560900250028320E+01 -8.686799377176160E-01 -6.312831245612560E-01 -2.452196155391350E+00 -3.360167371657770E+00 7.552789064148700E-01 -9.555950850876040E-01 -2.685694972944800E-01 1.008760374506820E-01 -5.267628432710890E-02 -9.094078377365720E-01
+-5.281715874479010E-02 8.331582499982440E-02 6.739966987677270E-01 5.015172551667300E-01 3.477181133714280E-01 -4.306541050265090E-01 3.112282745192760E-01 -1.018369242184730E-02 3.808444128406940E-01 2.160644726914670E-01 5.539161651104950E-01 -1.997799365446680E-01 2.992706589581340E-01 -2.265194364542650E-01 -9.161550785751970E-04 -1.203817756401520E-01 2.454392737963350E-01 -9.001571504214560E-01 -5.881416989971850E-01 4.871486173010470E-01 -3.366337049935890E-01 -6.036143321092750E-01 -9.880167327063020E-01 -1.215998456917500E+00 -1.672156363468240E-01 6.994647303177120E-01 -1.886340099860960E-02 -8.686799377176140E-01 1.172569754641520E+01 -4.754850285892090E-01 -1.252969285355830E+00 -1.495702645406280E+00 -7.332747845010660E-02 -7.206089092077520E-02 1.883427851621630E-01 -1.208774266478270E-01 -4.838292335701310E+00 -4.907443848985540E-01
+-1.707377778453930E-01 1.902636016635250E-01 9.369866964602590E-01 -6.624300463722670E-01 -3.264840210399370E-01 2.342256798776460E-01 6.728662498117570E-02 4.672324841146750E-01 3.749367055519840E-01 2.918540734563890E-01 1.445776186970540E-01 -6.477941723225880E-01 7.975950490652580E-01 -1.659853014014960E-01 -4.327349688167090E-01 3.597275561876480E-01 3.237877722498940E-01 2.238770024422590E-01 -3.754056754485400E-01 5.957896967658810E-01 -7.346615433238160E-01 -7.248535916008570E-01 -6.746744443092250E-01 -5.284661397847120E-01 -4.238958150775950E-02 2.010896285241120E-01 6.189171387275580E-01 -6.312831245612600E-01 -4.754850285892060E-01 1.380551269645640E+01 -1.566816095343070E+00 -2.216631942907930E+00 -2.510334737994160E-01 -4.262049827494040E-01 2.444096057957700E-01 3.443219565401690E-01 -4.913667499430050E+00 -4.903598608594540E+00
+-4.158394956781790E-01 -2.469623542490920E+00 6.001492766343180E-02 4.958137878655200E-02 -2.762370120228710E+00 9.240872828155820E+00 2.767210126760120E-02 -8.164415165215600E-02 5.185834587633030E-01 -6.171760784901970E-02 -6.597742043598180E-01 -1.647696189108730E-01 3.668897530793670E-01 -8.028809463031700E-04 -3.361578903958260E-02 4.935423677516680E-01 -4.189424859896320E-01 -1.606941187558930E+00 -2.940820401090260E+00 4.882501502491120E-01 -9.598439331587000E-01 8.532228050824250E-01 5.072795821934180E-01 4.659158073317310E-01 1.916303262742960E-01 -1.985286604542480E+00 1.150292652316530E-01 -2.452196155391350E+00 -1.252969285355830E+00 -1.566816095343070E+00 1.514497305572260E+01 -3.931217866831620E+00 1.627722832875200E-01 -1.539241904073430E-01 -4.628911869636480E-01 -6.616167100339770E-02 -7.387345653857450E-02 -1.631830523882750E+00
+2.191795397739610E-01 -1.114677884656900E+00 1.851178355187260E-01 -3.830670245927220E-01 8.597237682725640E-01 -2.275678455005260E+00 -5.964122132587400E-01 -4.326701831915440E-01 -3.077719040395510E-01 -6.723984411480450E-01 -7.049575125477450E-01 -5.182152009417760E-01 5.244209879906400E-01 -1.857534321945310E-01 -3.046557093117660E-01 2.217843024083910E-01 -4.571528467217450E-01 -2.967997507910470E+00 -4.001165228751070E+00 -3.157158535011310E-01 1.496632895233190E+01 8.107291688472580E-01 -1.883881924469620E-01 5.413250691144760E-01 -5.389017069447830E-01 -1.073811588971370E+00 3.110420369104430E-01 -3.360167371657770E+00 -1.495702645406280E+00 -2.216631942907930E+00 -3.931217866831630E+00 2.166126713604600E+01 3.961856677902050E-01 4.699559198801130E-01 -5.176845734338780E-01 -6.638308140120200E-03 -1.934196136045320E-01 -4.849163754922510E-01
+-4.055812044563780E-01 1.421467349014310E+00 -2.038143487833570E-01 4.582272033051990E-01 9.063845586740860E-01 -5.900463670923870E-01 -1.026602721047320E+00 -7.409740123475910E-01 -4.965330048419380E-01 -6.994619970776920E-01 -8.448028276474620E-01 4.129743965864220E-01 1.354228176013290E-01 2.117804866468720E-01 2.112138557371590E+00 2.543294624028760E-02 -1.140470835305840E+00 -4.938407871254380E-02 2.555491557610770E-01 8.467819632605560E-01 -2.038642998952220E-01 3.817135337794230E-01 7.996198067286460E-01 -3.102140771679820E-02 6.605413878575100E-01 1.774783700324310E+00 3.657116058553780E-01 7.552789064148720E-01 -7.332747845010710E-02 -2.510334737994170E-01 1.627722832875180E-01 3.961856677902060E-01 1.147783734204210E+01 1.050139009308990E+00 1.742115233097560E-01 3.297220538788040E-01 2.680397647317700E-01 6.054964228172990E-01
+-3.136193793280010E-01 6.938880059855700E-01 2.828203076028580E-01 3.117907304238250E-01 7.993793153588590E-03 6.052729009320810E-01 -1.047548474405930E+00 -5.355098917477730E-01 -1.297556577308630E+00 1.141348514518230E+00 7.299771805173530E-01 -2.829867974603650E-01 1.382908217116880E-01 6.271520580426520E-01 -4.625522201862700E-01 5.940742721336350E-01 -2.444577667124940E-01 1.568591993351410E-01 -3.524560281031700E-01 -1.908674178269560E-01 3.743815620495380E-01 4.749702916886250E-01 7.819369264639840E-01 8.448874338445860E-01 5.205748695907970E-01 3.270993952207000E-01 -4.624721003479700E-01 -9.555950850876040E-01 -7.206089092077530E-02 -4.262049827494030E-01 -1.539241904073430E-01 4.699559198801130E-01 1.050139009308990E+00 1.036246696564370E+01 -1.108611877111870E+00 -2.029676860627810E-01 -2.527245068600210E-01 4.068698936475800E-01
+-4.107369782634460E-01 2.526842637036580E+00 2.217075730766880E-01 3.624788661804230E-01 5.128176329726070E-02 -3.393652576321580E-01 1.712347711184320E-01 4.467535964355870E-02 -1.078441672224300E-01 4.992975930332800E-01 3.806607827085080E-02 -1.366802814803670E-01 -2.160917671703560E+00 -6.056143015163950E-01 -7.335577238784500E-01 7.625234096575820E-01 -3.895768927502010E-01 -9.265754959482490E-01 1.764337908673610E+00 -3.868300099676970E-01 -8.879862858809110E-01 1.380492039347560E+00 1.756332000301930E+00 2.491330531302740E+00 -3.993912771735480E-01 2.885877920861660E+00 -3.341488231209780E+00 -2.685694972944780E-01 1.883427851621640E-01 2.444096057957720E-01 -4.628911869636480E-01 -5.176845734338800E-01 1.742115233097560E-01 -1.108611877111870E+00 1.157919067489790E+01 -9.659281263614200E-01 -1.797214485742480E-01 -1.145531702357840E-01
+4.709190000778770E-01 -2.596744065543810E+00 4.026338683480700E+00 2.343788441178570E-02 -3.650067090848460E-01 7.705355064674740E-02 1.478144814342250E-01 2.560454255718570E-01 1.759501279514560E-01 5.757019909729250E-01 1.041637795341470E+00 -3.235382971212220E-01 -2.095859111665860E+00 -1.332030741964930E+00 -1.131409848013840E+00 -8.179318294093160E-02 -4.361552504662620E-01 -7.174310132518260E-01 -1.633623681132170E-02 9.577116821381410E-02 -1.043493024101730E-01 3.241896648781020E+00 2.821348124026000E+00 2.650268092387980E+00 1.654422285433120E-03 -2.965409359661880E+00 6.752777234484890E-01 1.008760374506830E-01 -1.208774266478270E-01 3.443219565401700E-01 -6.616167100339940E-02 -6.638308140118840E-03 3.297220538788040E-01 -2.029676860627810E-01 -9.659281263614200E-01 1.076097629668680E+01 -5.404115051787520E-01 -8.476454080497210E-01
+3.777887658546180E-02 1.678039033894730E+00 1.124618522802980E-02 9.166670190309110E-01 -4.846646240449960E-01 1.091384244580790E+00 -8.431178137560140E-02 2.665359543300010E-02 -4.606378970089610E-01 -1.855583017998080E-01 9.571407515730310E-02 6.356418459723930E-01 -1.085438486449370E+00 -1.865444317544670E-02 3.350927408113180E-02 -6.225365059917480E-01 -5.830316778042410E-01 -1.118620668508050E+00 -2.467433232515090E-01 -2.132673100099320E-01 2.017065420955160E-01 3.280795450017210E+00 3.577078324980200E+00 3.093242776326520E+00 -2.566040488722460E-01 1.196152600747970E+00 -2.985042915483890E-01 -5.267628432710670E-02 -4.838292335701310E+00 -4.913667499430050E+00 -7.387345653857700E-02 -1.934196136045350E-01 2.680397647317700E-01 -2.527245068600200E-01 -1.797214485742460E-01 -5.404115051787520E-01 1.466774659176510E+01 -5.089790012894510E-01
+3.846156114832800E-01 -9.747758836214090E-01 -2.986600643652150E-01 2.226854806925100E-01 6.144601962491460E+00 -2.094429348544660E+00 -1.096584719439690E-01 -5.141155945186080E-01 -6.935083730263890E-01 2.568989904328870E-01 6.590478091702250E-02 1.584134764963710E-01 -1.110686382069420E+00 2.069477492768980E-01 -2.045601856855800E-01 3.617091670893430E-01 -6.686259835422610E-01 -1.863228418129370E+00 -1.202547346427650E+00 -5.699425320088360E-02 -9.293830641027260E-02 -3.879206818963540E-01 1.971652301886880E-01 4.996301856694330E-01 8.537117516829240E-01 -8.690559525541560E-01 -4.735407732171760E-01 -9.094078377365720E-01 -4.907443848985560E-01 -4.903598608594550E+00 -1.631830523882750E+00 -4.849163754922430E-01 6.054964228172980E-01 4.068698936475820E-01 -1.145531702357840E-01 -8.476454080497210E-01 -5.089790012894470E-01 1.494235160377770E+01
diff --git a/physiolabxr/third_party/BAlert/Config/WorkloadInvPcov413_Model16.txt b/physiolabxr/third_party/BAlert/Config/WorkloadInvPcov413_Model16.txt
new file mode 100644
index 00000000..c57a6276
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/Config/WorkloadInvPcov413_Model16.txt
@@ -0,0 +1,39 @@
+C3C4HZ01 C3C4HZ15 C3C4HZ31 CZPOHZ26 CZPOHZ36 CZPOHZ37 F3CZHZ06 F3CZHZ07 F3CZHZ10 F3CZHZ16 F3CZHZ28 FZC3HZ01 FZC3HZ06 FZC3HZ08 FZC3HZ13 FZC3HZ15 FZPOHZ04 FZPOHZ10 FZPOHZ16 FZPOHZ28 FZPOHZ40 PROB3 PROB7 PROB8 rC34Hz08 rC34Hz15 rC34Hz16 rCPOHz16 rCPOHz32 rCPOHz34 rCPOHz38 rCPOHz40 rF3CHz12 rF3CHz20 rFC3Hz17 rFC3Hz30 rFPOHz33 rFPOHz35
+7.924083063996580E+00 -1.549777272378120E+00 -1.540751345637490E-01 4.989781174726350E-01 2.932588191269970E-01 9.966857660139110E-02 -7.781585505158930E-01 -4.361795399789910E-01 -3.387094404351670E-01 -3.644255958003110E-03 8.287852787154400E-02 -2.392987219311010E+00 -1.409892224547110E-01 1.556058027356000E-01 2.633583412498810E-01 2.190522021405010E-01 -1.572498307150910E+00 4.340050775088350E-01 -4.093856706336820E-01 2.827204711067730E-01 1.996725414550090E-01 -4.831530055915900E-01 -4.834433847104120E-01 6.718422541410790E-02 2.279877549384000E-01 -1.675025991353550E+00 -1.598102616232780E-01 -5.801249588860760E-01 1.103412138706330E-01 -2.483480587594980E-01 -4.414020849025470E-01 4.532754926026280E-02 -2.504720397052160E-01 -4.319345678051290E-01 -2.633604569023170E-01 2.522004758842550E-01 4.486111028181430E-01 7.339143043876790E-01
+-1.549777272378120E+00 4.501763553861430E+01 -3.732695634636530E+00 -2.346906404964480E+00 -4.215079037265140E-01 -2.241512878421550E+00 -1.016680113865870E+00 -2.768273856420710E+00 -4.174020115160900E+00 -2.684222813198110E+00 -2.350327888710520E+00 3.116412583935020E-01 -8.177176028952470E-01 -3.853742310836550E+00 -5.299266315170780E+00 -7.181793256984310E+00 -8.351935341345120E-01 -7.737259566115870E-01 1.388102416079850E+00 5.222549137498580E-02 -5.180946997261990E-02 1.088083626342760E+00 9.149247525090310E-01 8.834767789927270E-01 -2.905203223264720E+00 3.886010892160600E+01 -3.719763607563050E+00 1.867353782530330E+00 5.181415486816440E-01 -1.640230226584410E-02 -1.972885411678590E+00 -7.979544056705830E-01 1.348618892559920E+00 7.730751136959500E-01 2.404912425788220E+00 -2.925047906267790E+00 1.226152842993550E+00 -1.127181236203480E+00
+-1.540751345637490E-01 -3.732695634636530E+00 9.471911040453390E+00 -5.246712369902980E-02 -5.130569966770110E-01 2.103853846042900E-02 -1.915313543722050E-01 -1.294099297731550E-01 -3.220025725645860E-01 -3.708708625257270E-01 -6.366641784922280E-01 -6.054487296824320E-02 -8.547746481944440E-01 -4.447454139122040E-01 -2.359083649162190E-01 -7.000485411860400E-01 -5.259253944814660E-01 -2.747311246927440E-01 1.270615024353780E-01 2.283190065501510E-01 -8.632107124082050E-02 -3.628389816750690E-02 7.636155045934590E-03 -1.224825983329040E-01 -1.630698729979410E-01 -3.846690005551700E+00 4.017422901587650E-01 -2.634959921603790E-01 6.866736774983060E-01 7.604927285017380E-01 4.446050217930010E-01 2.209855378531850E-01 -3.955152824052120E-01 2.082165342655330E-01 -1.875527293674560E-02 3.742476565198040E+00 3.125316230636900E-01 -1.248397220906990E-01
+4.989781174726350E-01 -2.346906404964490E+00 -5.246712369903070E-02 1.010484004907620E+01 -4.884874288521080E-01 -8.174534337668260E-01 -1.861138767712320E-02 -1.239313666373670E-01 -6.567669325367950E-02 -2.087454360196760E-01 -1.893526262932430E+00 -7.076783583082740E-02 1.534149863223680E-01 2.144866005794990E-01 -4.294751954164930E-01 -1.212193641489130E-01 -2.088393362246950E-01 -6.974560549975850E-03 -1.911680509503020E+00 -1.657352214148940E+00 -1.030098441156070E+00 9.229327244353060E-01 6.674878718762200E-01 8.017637615937930E-01 -6.122606677335220E-02 -1.918308155671810E+00 6.433430970523770E-01 -1.002685509069760E+00 -3.551372472095600E-02 -4.497148954430160E-02 2.184391076091050E-01 -3.378271142429790E-01 4.391554527009540E-01 4.932458372727370E-01 1.000407578652350E-01 -1.456694841225820E-01 4.122082335163840E-01 4.147918803823840E-01
+2.932588191269960E-01 -4.215079037265090E-01 -5.130569966770130E-01 -4.884874288521100E-01 1.805973049653820E+01 -1.089061943817520E+01 -1.596033815472510E-01 -6.042969559181100E-01 -7.605462058364000E-02 -3.525838042148650E-01 -7.133971959323880E-02 2.397926940986700E-01 -7.365356108610170E-01 6.327820004118450E-02 -1.350423759107590E-02 2.813396191303570E-01 -6.763292644162630E-01 -8.257574645304430E-01 -1.962573324221000E+00 -5.837513769385180E-01 -1.534922300392410E+00 1.380571982449250E-01 5.474347330263800E-01 -1.459881189837730E-01 -3.261010196841940E-02 -4.467099962080160E-02 -4.327603409514990E-01 -1.465506626098620E+00 1.667142060883280E-01 -5.778843637938560E-01 -2.753052600592200E+00 6.553423696512670E-01 2.963252020152210E-01 -1.190878347574590E-01 -4.434237090659250E-01 -7.676571902904700E-02 -1.907921106490000E-01 6.693665586026470E+00
+9.966857660139110E-02 -2.241512878421560E+00 2.103853846043130E-02 -8.174534337668260E-01 -1.089061943817520E+01 1.975629049404880E+01 -4.153334265178210E-01 1.416026083480380E-01 -2.681867286858810E-02 3.504580526927620E-01 7.013275059432220E-02 -7.670514779752640E-02 1.375257399333300E-01 -1.898691518415360E-01 3.666928310147240E-01 4.627878089094040E-01 -3.543476745945540E-01 -1.129450348391550E+00 -2.275773718783610E+00 -5.955375777391940E-01 -2.601779840040400E+00 1.419311381191140E+00 9.868869187762190E-01 1.289964104695210E+00 9.258463157195030E-03 -2.359909305487700E+00 5.858929351868490E-01 -1.748170578049400E+00 3.057220379264820E-01 3.680336920401880E-01 8.714687073589370E+00 -2.316602698976740E+00 -2.138554535109950E-01 1.863181906236130E-01 -1.231898469620070E-01 4.301885011390230E-01 6.325138915313870E-01 -2.185886781653180E+00
+-7.781585505158940E-01 -1.016680113865870E+00 -1.915313543722050E-01 -1.861138767712360E-02 -1.596033815472510E-01 -4.153334265178210E-01 1.328799709420940E+01 -6.531956605084710E+00 -2.415984094836400E-03 -6.670222770872120E-01 -7.969235825966820E-02 -1.822529493759070E-01 -1.490768141864170E+00 -8.031172325854800E-02 5.893887501220100E-01 -3.979337251601020E-01 -1.193125397604670E+00 6.286194789852330E-01 -1.554092001256290E-01 5.795835727375570E-01 5.681705639307240E-02 1.010087229589890E-02 1.665929973796570E-01 1.008788461643760E+00 -8.460744398275110E-01 -1.505235881219410E+00 -8.123220316616990E-01 -1.169121102902000E-01 8.177519752726310E-01 -4.164985703403100E-02 -3.259693141736390E-01 -4.399967243758930E-01 -1.207131314094700E+00 -9.370861032191930E-01 4.314182470051680E-01 5.286569805821850E-02 -2.836605923237170E-01 -2.263045367663230E-01
+-4.361795399789900E-01 -2.768273856420710E+00 -1.294099297731550E-01 -1.239313666373660E-01 -6.042969559181100E-01 1.416026083480380E-01 -6.531956605084710E+00 1.368684491563110E+01 -4.036887083028480E-01 -1.788254694034800E-01 -1.584144562385930E-01 3.573113332871650E-01 -5.851940692037570E-01 -1.159212922195250E+00 -2.187017569621620E-02 1.120967912192440E-01 1.016745953073220E-01 8.241025910695610E-02 -9.014293324507310E-01 1.458714067551160E-01 -2.122369271223100E-01 -1.413227718943390E+00 -1.404375736070080E+00 -9.464553252301980E-01 2.016174229017940E+00 -2.502085804318730E+00 2.477789019962990E-02 -4.428929526304030E-01 -2.064755439701130E-01 6.193772052503520E-01 -1.925778401583070E-01 -2.184256330870080E-01 -1.082616606731710E+00 -4.330732065890680E-01 1.448311846842700E-01 3.985263433237560E-01 1.608567727483520E-01 -5.257497760171910E-01
+-3.387094404351670E-01 -4.174020115160900E+00 -3.220025725645860E-01 -6.567669325368020E-02 -7.605462058363950E-02 -2.681867286858790E-02 -2.415984094836700E-03 -4.036887083028480E-01 1.014480307463260E+01 -2.244022963895280E-01 -4.209936185810680E-01 1.640312964392220E-01 3.969175411052810E-01 -1.078147612290280E+00 -1.547967292383420E-01 -1.146584208804710E-01 2.494442360164120E-01 -3.516516517522720E+00 1.063768781733960E-02 -4.509812806870110E-01 -4.049503291823210E-01 8.472091255541020E-01 1.122270221596980E+00 1.624541269752160E+00 1.889379027500890E-01 -4.082369067131240E+00 1.557962928206280E-01 -1.458096908495320E-01 4.479111549300410E-02 3.171494185050850E-01 5.908892561179580E-01 -5.820488790753000E-01 -3.858072138494290E-01 -1.272254170198080E+00 1.407204148487220E-01 2.134973760153650E-01 -3.609225875596760E-01 -7.807321285164010E-01
+-3.644255958003050E-03 -2.684222813198120E+00 -3.708708625257250E-01 -2.087454360196760E-01 -3.525838042148640E-01 3.504580526927610E-01 -6.670222770872120E-01 -1.788254694034790E-01 -2.244022963895270E-01 1.055168533991620E+01 -1.673529077144800E+00 -6.099717838370960E-01 8.504854078772830E-02 -8.529629141732450E-01 -3.875414495810220E-01 -2.264659782646040E-01 2.824617358515850E-01 4.673023105674040E-01 -3.969773411395300E+00 5.787969653567830E-01 -4.453627713830810E-01 -7.061717291275610E-01 -5.277985116726240E-01 -3.884808745753710E-01 9.109233429231120E-02 -1.856766966566490E+00 1.870626459905020E+00 -1.759340868669510E+00 1.498591777742770E-01 6.057745132915250E-01 -7.879509626238390E-02 -5.682506984486170E-01 -8.805367626519790E-01 1.124850996653980E+00 2.705203129451210E-01 7.991063400693890E-01 3.314780580344910E-02 -1.623372536668230E-01
+8.287852787154390E-02 -2.350327888710520E+00 -6.366641784922290E-01 -1.893526262932430E+00 -7.133971959323830E-02 7.013275059432310E-02 -7.969235825966810E-02 -1.584144562385920E-01 -4.209936185810680E-01 -1.673529077144800E+00 7.167381073696760E+00 -1.120688542093470E-01 4.397662203600730E-02 -2.145978105406410E-01 4.149045521861650E-01 -2.582348662546360E-01 7.567623094696150E-02 5.648197715162630E-02 1.741025017818250E-01 -1.969702835124590E+00 -6.596222045837150E-01 -8.114192456882850E-01 -7.625604123794770E-01 -4.315858305645890E-01 -9.417598705501710E-01 -2.390793479857570E+00 -4.410479840497560E-02 4.795385950337270E-01 4.159064988895650E-01 -3.149160660478340E-01 -5.059537538899340E-01 -1.059046365306170E+00 -8.518898902685510E-01 7.338797305819120E-01 4.046420694833960E-01 7.341197562970420E-01 2.347401218322860E-01 -5.270705003756470E-02
+-2.392987219311010E+00 3.116412583935030E-01 -6.054487296824330E-02 -7.076783583082720E-02 2.397926940986700E-01 -7.670514779752590E-02 -1.822529493759080E-01 3.573113332871650E-01 1.640312964392230E-01 -6.099717838370960E-01 -1.120688542093470E-01 1.100152999465490E+01 -8.438698126177900E-01 -3.583823479189560E-01 -4.929677867342820E-02 1.050182361622340E-02 -2.644097314279800E-01 -7.570366070957140E-02 -6.111337365441780E-02 -5.091984181390920E-02 -4.591165338845740E-01 2.703925227323520E+00 2.708846144310440E+00 3.079580173792880E+00 1.083552783589730E-01 5.079744443259210E-01 -3.413850154204550E-01 -3.080340461291040E-01 -5.539070532331270E-02 -1.402330008861590E-01 5.651532942569570E-02 -7.349478325874210E-01 2.758544556232860E-01 -3.805661441951690E-01 -2.656855516816500E-01 2.888780299485050E-01 1.607742705512700E-01 -9.641416473598090E-02
+-1.409892224547110E-01 -8.177176028952480E-01 -8.547746481944450E-01 1.534149863223680E-01 -7.365356108610170E-01 1.375257399333300E-01 -1.490768141864170E+00 -5.851940692037560E-01 3.969175411052820E-01 8.504854078772780E-02 4.397662203600700E-02 -8.438698126177900E-01 9.011875312241000E+00 -1.212182152128610E+00 -8.363393317524840E-02 -1.672448951422380E-01 -9.725182880234660E-01 4.514354093382650E-01 -1.138419308358660E+00 2.495018720617940E-01 -6.322288573417250E-02 5.937571347732970E+00 5.550009517929930E+00 6.624971452835470E+00 4.825083154839060E-01 -9.156064781686330E-01 4.069453102411540E-01 -8.637093671713540E-01 1.857507090345350E-01 1.021406941669380E+00 1.698383765303970E-01 8.880461614742180E-02 1.527491365036050E-01 2.763273513938840E-01 -1.682626339522440E+00 -1.838886057743620E+00 -1.194303450532860E+00 -9.956913042216250E-01
+1.556058027356000E-01 -3.853742310836540E+00 -4.447454139122060E-01 2.144866005794980E-01 6.327820004118540E-02 -1.898691518415370E-01 -8.031172325854760E-02 -1.159212922195250E+00 -1.078147612290280E+00 -8.529629141732450E-01 -2.145978105406410E-01 -3.583823479189560E-01 -1.212182152128610E+00 1.109121445563010E+01 2.019354164786250E-01 -5.309671342940200E-01 -1.771069817717020E-01 -5.125218862010730E-01 -1.664058788560910E-01 3.190323786906980E-01 -1.461909701531860E-01 -1.285451890972540E+00 -1.097756490265170E+00 -1.900772228248810E+00 3.912430737286430E+00 -4.168080480849970E+00 1.929898882762160E-01 -9.585688475196250E-02 4.535673178420190E-01 -3.913732444921810E-02 -2.076310102154320E-01 9.268577717543990E-02 1.804029656129400E-01 5.679482242826450E-01 -6.099771442484620E-01 -1.615205625079670E+00 -4.081876409977380E-01 1.873683794582880E-03
+2.633583412498810E-01 -5.299266315170780E+00 -2.359083649162190E-01 -4.294751954164940E-01 -1.350423759107460E-02 3.666928310147230E-01 5.893887501220100E-01 -2.187017569621610E-02 -1.547967292383420E-01 -3.875414495810220E-01 4.149045521861650E-01 -4.929677867342840E-02 -8.363393317524810E-02 2.019354164786260E-01 8.406869887122580E+00 -1.995268682756180E+00 1.046622827583670E-01 2.521460662611550E-01 -1.024216857877030E+00 -1.956639090386630E-01 -3.574776408032410E-01 -4.534872988424510E-01 -5.923258330495750E-01 -6.069046842750860E-01 -1.166577972038940E+00 -5.456418387538200E+00 1.587934574657040E-01 -3.870532054196680E-01 3.184864567098800E-01 -1.624366758744580E-01 -1.292162344321150E-01 -8.446966520947910E-01 2.262730552057410E+00 -2.574164474825760E-01 -6.866891039313360E-01 -9.385865291844710E-01 -8.792664425089270E-02 -6.588318891980450E-02
+2.190522021405010E-01 -7.181793256984310E+00 -7.000485411860410E-01 -1.212193641489140E-01 2.813396191303570E-01 4.627878089094050E-01 -3.979337251601020E-01 1.120967912192440E-01 -1.146584208804710E-01 -2.264659782646020E-01 -2.582348662546370E-01 1.050182361622340E-02 -1.672448951422380E-01 -5.309671342940200E-01 -1.995268682756180E+00 1.321149836462940E+01 2.527696561197300E-01 4.736900747810430E-01 -2.554932404407840E+00 -2.604728060735560E-01 3.203669795429190E-01 2.160004017561060E-01 6.848417327576340E-01 2.563823498641560E-01 -4.972033663039220E-02 -1.713689804468840E+00 5.929416313095780E-01 -1.207265869109470E+00 -1.537896542359230E-01 9.399194780762190E-02 3.036611042147900E-01 3.590932299281390E-01 -5.128132642083670E-03 5.228325389199210E-01 8.434438222013820E-01 -3.604499357630380E-02 -5.248919553932240E-01 2.538443038041310E-01
+-1.572498307150910E+00 -8.351935341345120E-01 -5.259253944814660E-01 -2.088393362246950E-01 -6.763292644162620E-01 -3.543476745945540E-01 -1.193125397604670E+00 1.016745953073210E-01 2.494442360164130E-01 2.824617358515860E-01 7.567623094696140E-02 -2.644097314279790E-01 -9.725182880234670E-01 -1.771069817717020E-01 1.046622827583670E-01 2.527696561197300E-01 1.057080510926390E+01 1.543026521882810E+00 -6.928995644666510E-01 1.740676521883330E-02 -6.223259038269350E-01 1.943775592261560E+00 2.613747963695510E+00 2.686355944532560E+00 -6.824841944477060E-02 -1.170927688738950E+00 2.947187479700100E-01 -1.977588570934470E+00 2.584922693884690E-01 3.056170775715140E-01 -1.273305599174680E-01 -8.390183471638610E-01 -1.113951138403260E+00 -3.567608896565080E-01 -3.998091264748030E-01 -8.311235769869400E-02 -6.013109720301280E-01 -9.994143915536590E-01
+4.340050775088350E-01 -7.737259566115870E-01 -2.747311246927440E-01 -6.974560549976210E-03 -8.257574645304430E-01 -1.129450348391550E+00 6.286194789852330E-01 8.241025910695520E-02 -3.516516517522720E+00 4.673023105674040E-01 5.648197715162600E-02 -7.570366070957110E-02 4.514354093382660E-01 -5.125218862010730E-01 2.521460662611550E-01 4.736900747810440E-01 1.543026521882810E+00 1.080364377640540E+01 -3.734936997405200E+00 -1.717478321222310E-01 -2.786113059557990E+00 -4.257547759902220E+00 -4.347462914732790E+00 -5.972947340905360E+00 7.409093642731330E-01 -1.189247288797870E+00 -2.488130326455740E-02 -5.197227869150390E+00 -6.818962499194730E-01 1.835215194288260E-02 -1.824795037753250E+00 -3.276828811623430E+00 -1.388731593817380E-01 1.669065495696510E-01 -8.644674743887650E-01 -6.959302272713070E-01 -9.009579611985630E-01 -1.442544121641960E+00
+-4.093856706336830E-01 1.388102416079860E+00 1.270615024353770E-01 -1.911680509503020E+00 -1.962573324221000E+00 -2.275773718783610E+00 -1.554092001256280E-01 -9.014293324507320E-01 1.063768781733810E-02 -3.969773411395300E+00 1.741025017818250E-01 -6.111337365441780E-02 -1.138419308358660E+00 -1.664058788560900E-01 -1.024216857877020E+00 -2.554932404407830E+00 -6.928995644666500E-01 -3.734936997405200E+00 2.783842953801380E+01 -1.381537732116400E+00 -4.772607328298290E+00 1.709593455196120E+00 7.495138863069620E-01 1.698396810753990E-01 -1.953026663711210E-01 9.040188251360940E-01 -4.099780163044790E-01 2.102750841802790E+01 -1.097079489881990E+00 -6.399335875186920E-01 -2.117355193398060E+00 -3.847659921957570E+00 2.497687870565020E-01 -5.952382690895900E-01 1.490522909277880E+00 -2.286879321363550E-01 -3.100307273249000E-01 -1.585442760842500E+00
+2.827204711067730E-01 5.222549137498660E-02 2.283190065501510E-01 -1.657352214148940E+00 -5.837513769385190E-01 -5.955375777391940E-01 5.795835727375570E-01 1.458714067551160E-01 -4.509812806870120E-01 5.787969653567840E-01 -1.969702835124590E+00 -5.091984181390940E-02 2.495018720617940E-01 3.190323786906990E-01 -1.956639090386640E-01 -2.604728060735570E-01 1.740676521883340E-02 -1.717478321222310E-01 -1.381537732116400E+00 1.144097253902490E+01 -1.493471676058980E+00 1.924300505731910E-01 1.009440196314990E-01 6.516496737901590E-01 -3.957934611362910E-01 2.124362782199990E-01 8.455665715643630E-02 -6.903108098337180E-01 9.616290657682060E-01 4.590205220234730E-01 5.009419973301110E-01 -7.585237411021410E-01 9.095784195867750E-01 -1.537198430286760E-01 -5.015729410632650E-01 -8.510116939079010E-02 2.095821149679940E-02 -1.527434548310370E-02
+1.996725414550100E-01 -5.180946997262080E-02 -8.632107124081970E-02 -1.030098441156070E+00 -1.534922300392410E+00 -2.601779840040410E+00 5.681705639307310E-02 -2.122369271223080E-01 -4.049503291823250E-01 -4.453627713830820E-01 -6.596222045837150E-01 -4.591165338845740E-01 -6.322288573417350E-02 -1.461909701531860E-01 -3.574776408032420E-01 3.203669795429180E-01 -6.223259038269350E-01 -2.786113059557990E+00 -4.772607328298290E+00 -1.493471676058980E+00 2.136311441326850E+01 2.337201437833010E+00 1.395426800136920E+00 1.911073293243290E+00 -8.797503307901990E-01 2.302703306471820E-01 7.773184615502970E-01 -4.025673408660840E+00 -1.087739812318040E+00 -9.837270679440340E-01 -1.184199236340800E+00 1.637800070869260E+01 -1.561316273941350E-01 4.623037706278880E-01 -8.551693085637690E-01 -1.082447350383040E-01 4.995700744715990E-01 -1.095638623519610E-01
+-4.831530055915840E-01 1.088083626342750E+00 -3.628389816750780E-02 9.229327244353130E-01 1.380571982449250E-01 1.419311381191150E+00 1.010087229589850E-02 -1.413227718943390E+00 8.472091255540990E-01 -7.061717291275650E-01 -8.114192456882870E-01 2.703925227323520E+00 5.937571347732970E+00 -1.285451890972540E+00 -4.534872988424430E-01 2.160004017561060E-01 1.943775592261550E+00 -4.257547759902230E+00 1.709593455196130E+00 1.924300505731890E-01 2.337201437833010E+00 2.071487672104410E+02 2.024827172991490E+02 2.041454647098820E+02 -1.217517921565520E+00 4.393970663363150E+00 -3.303557778236600E+00 2.290707904886980E+00 -5.067793819764990E-01 3.255565847380860E-01 1.716405410856650E+00 -6.606918409295620E-01 -1.840327718429430E-01 -3.545045554873540E-01 2.882849158710560E+00 3.690681583891900E+00 2.849215412025390E+00 -1.523572657236130E-01
+-4.834433847104040E-01 9.149247525090170E-01 7.636155045934650E-03 6.674878718762230E-01 5.474347330263790E-01 9.868869187762320E-01 1.665929973796590E-01 -1.404375736070080E+00 1.122270221596990E+00 -5.277985116726280E-01 -7.625604123794780E-01 2.708846144310440E+00 5.550009517929930E+00 -1.097756490265160E+00 -5.923258330495690E-01 6.848417327576340E-01 2.613747963695500E+00 -4.347462914732800E+00 7.495138863069680E-01 1.009440196314970E-01 1.395426800136910E+00 2.024827172991490E+02 2.072410899160970E+02 2.037737882564770E+02 -1.138594880334760E+00 4.375210737800210E+00 -3.278341560249700E+00 1.035701984324280E+00 -1.102569167912740E+00 3.977518883272070E-01 1.288564545790850E+00 -1.574425652765170E+00 3.737131985134710E-02 -1.950593271871360E-01 3.345231161749250E+00 3.218783351832160E+00 3.108455977609470E+00 3.975427727639200E-01
+6.718422541411260E-02 8.834767789927110E-01 -1.224825983329020E-01 8.017637615937960E-01 -1.459881189837730E-01 1.289964104695220E+00 1.008788461643760E+00 -9.464553252301980E-01 1.624541269752160E+00 -3.884808745753740E-01 -4.315858305645900E-01 3.079580173792880E+00 6.624971452835470E+00 -1.900772228248810E+00 -6.069046842750810E-01 2.563823498641570E-01 2.686355944532560E+00 -5.972947340905370E+00 1.698396810754060E-01 6.516496737901570E-01 1.911073293243290E+00 2.041454647098820E+02 2.037737882564770E+02 2.252784799739530E+02 -1.680659615680960E+00 3.492435494768870E+00 -3.019646731652640E+00 4.399675373052340E-02 -1.321304146246860E+00 1.986278524778660E-01 1.508533681360290E+00 -9.716030784135750E-01 -6.044208468061620E-01 -1.853227475483330E-02 4.020514022916620E+00 3.155685405489600E+00 3.018739138698050E+00 3.581331345278560E-01
+2.279877549384000E-01 -2.905203223264720E+00 -1.630698729979420E-01 -6.122606677335230E-02 -3.261010196841930E-02 9.258463157194380E-03 -8.460744398275110E-01 2.016174229017940E+00 1.889379027500890E-01 9.109233429231110E-02 -9.417598705501710E-01 1.083552783589730E-01 4.825083154839070E-01 3.912430737286430E+00 -1.166577972038940E+00 -4.972033663039280E-02 -6.824841944477040E-02 7.409093642731340E-01 -1.953026663711220E-01 -3.957934611362910E-01 -8.797503307902000E-01 -1.217517921565520E+00 -1.138594880334760E+00 -1.680659615680970E+00 1.133080214247450E+01 -2.728171103988300E+00 -1.841138294885920E-02 -9.539993182329360E-01 -2.482839624001010E-01 2.859933470467400E-01 -1.081788501756430E-01 -4.951533340257070E-01 7.560091320043810E-01 4.090404212503550E-01 -3.496400214222230E-01 1.260112417870510E-01 1.443070608888070E-01 5.197829743536820E-01
+-1.675025991353550E+00 3.886010892160600E+01 -3.846690005551690E+00 -1.918308155671810E+00 -4.467099962080840E-02 -2.359909305487690E+00 -1.505235881219410E+00 -2.502085804318730E+00 -4.082369067131240E+00 -1.856766966566480E+00 -2.390793479857570E+00 5.079744443259200E-01 -9.156064781686330E-01 -4.168080480849970E+00 -5.456418387538200E+00 -1.713689804468840E+00 -1.170927688738950E+00 -1.189247288797870E+00 9.040188251360910E-01 2.124362782200000E-01 2.302703306471810E-01 4.393970663363170E+00 4.375210737800220E+00 3.492435494768880E+00 -2.728171103988300E+00 4.929888174537010E+01 -1.105010125668070E+01 1.310627285747560E+00 8.932590007298270E-01 2.075297662254560E-01 -1.572808522380160E+00 -6.177705453433410E-01 1.429643692728990E+00 8.508835246991910E-01 3.072991222627490E+00 -2.966552108963910E+00 1.113287002965650E+00 -1.156206516318550E+00
+-1.598102616232780E-01 -3.719763607563050E+00 4.017422901587640E-01 6.433430970523770E-01 -4.327603409514960E-01 5.858929351868480E-01 -8.123220316616990E-01 2.477789019963040E-02 1.557962928206280E-01 1.870626459905020E+00 -4.410479840497620E-02 -3.413850154204560E-01 4.069453102411540E-01 1.929898882762160E-01 1.587934574657030E-01 5.929416313095780E-01 2.947187479700100E-01 -2.488130326455850E-02 -4.099780163044810E-01 8.455665715643610E-02 7.773184615502980E-01 -3.303557778236600E+00 -3.278341560249700E+00 -3.019646731652640E+00 -1.841138294885910E-02 -1.105010125668070E+01 1.513482163462030E+01 -1.000955131415330E+00 -1.750300361294910E-01 2.753525259912550E-01 1.437643052148290E-01 5.521042889363740E-01 2.977840548546550E-01 -7.415079344023860E-01 -3.704597206648910E+00 5.168740152626560E-01 -1.624279765641520E-02 -2.067916252984050E-01
+-5.801249588860770E-01 1.867353782530340E+00 -2.634959921603800E-01 -1.002685509069760E+00 -1.465506626098620E+00 -1.748170578049400E+00 -1.169121102902000E-01 -4.428929526304040E-01 -1.458096908495330E-01 -1.759340868669510E+00 4.795385950337270E-01 -3.080340461291050E-01 -8.637093671713550E-01 -9.585688475196220E-02 -3.870532054196670E-01 -1.207265869109470E+00 -1.977588570934480E+00 -5.197227869150400E+00 2.102750841802790E+01 -6.903108098337180E-01 -4.025673408660850E+00 2.290707904886970E+00 1.035701984324280E+00 4.399675373051530E-02 -9.539993182329360E-01 1.310627285747570E+00 -1.000955131415330E+00 2.710734345214520E+01 -1.366252169925590E+00 -8.018998141799480E-01 -2.009438426428000E+00 -2.877419496727010E+00 8.146422589866500E-01 -1.081265626670750E+00 -5.728546511383850E-01 -2.976142962247170E-01 -3.210853191839550E-01 -1.018655994332640E+00
+1.103412138706320E-01 5.181415486816450E-01 6.866736774983050E-01 -3.551372472095680E-02 1.667142060883290E-01 3.057220379264830E-01 8.177519752726300E-01 -2.064755439701130E-01 4.479111549300420E-02 1.498591777742770E-01 4.159064988895650E-01 -5.539070532331280E-02 1.857507090345350E-01 4.535673178420190E-01 3.184864567098800E-01 -1.537896542359230E-01 2.584922693884690E-01 -6.818962499194720E-01 -1.097079489881990E+00 9.616290657682060E-01 -1.087739812318040E+00 -5.067793819765140E-01 -1.102569167912750E+00 -1.321304146246880E+00 -2.482839624001010E-01 8.932590007298280E-01 -1.750300361294920E-01 -1.366252169925590E+00 1.254165602414190E+01 4.567346134528670E-02 -1.116001090929540E+00 -2.344928351302880E+00 -1.812287386612870E-01 1.768687919681020E-01 1.729804778814150E-01 -2.444198790223890E-01 -5.026070577656260E+00 -9.518635423501920E-01
+-2.483480587594980E-01 -1.640230226584440E-02 7.604927285017380E-01 -4.497148954430120E-02 -5.778843637938570E-01 3.680336920401860E-01 -4.164985703403090E-02 6.193772052503510E-01 3.171494185050850E-01 6.057745132915260E-01 -3.149160660478340E-01 -1.402330008861580E-01 1.021406941669380E+00 -3.913732444921810E-02 -1.624366758744580E-01 9.399194780762200E-02 3.056170775715140E-01 1.835215194288060E-02 -6.399335875186940E-01 4.590205220234720E-01 -9.837270679440290E-01 3.255565847380990E-01 3.977518883272210E-01 1.986278524778780E-01 2.859933470467400E-01 2.075297662254560E-01 2.753525259912550E-01 -8.018998141799490E-01 4.567346134528830E-02 1.427279201312540E+01 -1.816825891986300E+00 -2.508622845825160E+00 -5.752869569174940E-01 -4.545638074981940E-01 5.597885163424080E-01 5.000767910427870E-02 -5.055730515773560E+00 -5.182273351017430E+00
+-4.414020849025470E-01 -1.972885411678590E+00 4.446050217930010E-01 2.184391076091050E-01 -2.753052600592200E+00 8.714687073589370E+00 -3.259693141736380E-01 -1.925778401583080E-01 5.908892561179580E-01 -7.879509626238410E-02 -5.059537538899350E-01 5.651532942569520E-02 1.698383765303980E-01 -2.076310102154310E-01 -1.292162344321160E-01 3.036611042147900E-01 -1.273305599174680E-01 -1.824795037753260E+00 -2.117355193398060E+00 5.009419973301110E-01 -1.184199236340790E+00 1.716405410856630E+00 1.288564545790830E+00 1.508533681360270E+00 -1.081788501756430E-01 -1.572808522380170E+00 1.437643052148300E-01 -2.009438426428000E+00 -1.116001090929540E+00 -1.816825891986300E+00 1.494394270283300E+01 -3.976313513297810E+00 7.391285046884720E-01 -3.848945814886800E-01 -1.191396659476600E-01 2.621105422734220E-01 1.671157416281660E-01 -1.415249597831570E+00
+4.532754926026330E-02 -7.979544056705800E-01 2.209855378531850E-01 -3.378271142429770E-01 6.553423696512720E-01 -2.316602698976740E+00 -4.399967243758930E-01 -2.184256330870070E-01 -5.820488790753030E-01 -5.682506984486180E-01 -1.059046365306170E+00 -7.349478325874200E-01 8.880461614742050E-02 9.268577717544000E-02 -8.446966520947920E-01 3.590932299281380E-01 -8.390183471638610E-01 -3.276828811623430E+00 -3.847659921957570E+00 -7.585237411021420E-01 1.637800070869260E+01 -6.606918409295510E-01 -1.574425652765160E+00 -9.716030784135650E-01 -4.951533340257060E-01 -6.177705453433380E-01 5.521042889363720E-01 -2.877419496727010E+00 -2.344928351302880E+00 -2.508622845825160E+00 -3.976313513297810E+00 2.340885042083250E+01 4.264930874146620E-01 3.924837579286450E-01 -5.677097596252390E-01 -9.084425988176250E-02 -8.978911257137560E-02 -3.933846231119140E-01
+-2.504720397052160E-01 1.348618892559920E+00 -3.955152824052120E-01 4.391554527009540E-01 2.963252020152210E-01 -2.138554535109950E-01 -1.207131314094700E+00 -1.082616606731710E+00 -3.858072138494290E-01 -8.805367626519790E-01 -8.518898902685520E-01 2.758544556232860E-01 1.527491365036050E-01 1.804029656129410E-01 2.262730552057410E+00 -5.128132642082960E-03 -1.113951138403260E+00 -1.388731593817390E-01 2.497687870565000E-01 9.095784195867760E-01 -1.561316273941340E-01 -1.840327718429430E-01 3.737131985134710E-02 -6.044208468061620E-01 7.560091320043810E-01 1.429643692728990E+00 2.977840548546550E-01 8.146422589866480E-01 -1.812287386612870E-01 -5.752869569174950E-01 7.391285046884730E-01 4.264930874146630E-01 1.146137303134090E+01 7.382773066565070E-01 -1.688176082615730E-01 5.917280448573190E-01 3.284522491837170E-01 4.761446258298690E-01
+-4.319345678051290E-01 7.730751136959480E-01 2.082165342655340E-01 4.932458372727360E-01 -1.190878347574590E-01 1.863181906236140E-01 -9.370861032191930E-01 -4.330732065890680E-01 -1.272254170198080E+00 1.124850996653980E+00 7.338797305819110E-01 -3.805661441951690E-01 2.763273513938840E-01 5.679482242826450E-01 -2.574164474825760E-01 5.228325389199220E-01 -3.567608896565080E-01 1.669065495696510E-01 -5.952382690895900E-01 -1.537198430286750E-01 4.623037706278880E-01 -3.545045554873540E-01 -1.950593271871360E-01 -1.853227475483310E-02 4.090404212503550E-01 8.508835246991890E-01 -7.415079344023860E-01 -1.081265626670750E+00 1.768687919681010E-01 -4.545638074981950E-01 -3.848945814886790E-01 3.924837579286450E-01 7.382773066565060E-01 1.022991002863750E+01 -1.064813751223740E+00 -5.630504252135930E-01 -3.866677439269620E-01 8.255659807478700E-02
+-2.633604569023170E-01 2.404912425788210E+00 -1.875527293674550E-02 1.000407578652350E-01 -4.434237090659260E-01 -1.231898469620060E-01 4.314182470051690E-01 1.448311846842700E-01 1.407204148487220E-01 2.705203129451210E-01 4.046420694833970E-01 -2.656855516816500E-01 -1.682626339522440E+00 -6.099771442484610E-01 -6.866891039313350E-01 8.434438222013830E-01 -3.998091264748030E-01 -8.644674743887650E-01 1.490522909277880E+00 -5.015729410632650E-01 -8.551693085637690E-01 2.882849158710570E+00 3.345231161749250E+00 4.020514022916630E+00 -3.496400214222220E-01 3.072991222627490E+00 -3.704597206648910E+00 -5.728546511383830E-01 1.729804778814150E-01 5.597885163424090E-01 -1.191396659476600E-01 -5.677097596252410E-01 -1.688176082615720E-01 -1.064813751223740E+00 1.107239145629130E+01 -7.712791254781920E-01 -3.109950682595010E-01 -9.078350489698230E-01
+2.522004758842550E-01 -2.925047906267790E+00 3.742476565198040E+00 -1.456694841225820E-01 -7.676571902904570E-02 4.301885011390220E-01 5.286569805821940E-02 3.985263433237560E-01 2.134973760153630E-01 7.991063400693880E-01 7.341197562970420E-01 2.888780299485050E-01 -1.838886057743620E+00 -1.615205625079670E+00 -9.385865291844710E-01 -3.604499357630370E-02 -8.311235769869400E-02 -6.959302272713060E-01 -2.286879321363550E-01 -8.510116939079030E-02 -1.082447350383040E-01 3.690681583891910E+00 3.218783351832160E+00 3.155685405489600E+00 1.260112417870510E-01 -2.966552108963910E+00 5.168740152626570E-01 -2.976142962247170E-01 -2.444198790223880E-01 5.000767910427900E-02 2.621105422734230E-01 -9.084425988176210E-02 5.917280448573190E-01 -5.630504252135930E-01 -7.712791254781920E-01 1.007041382725310E+01 -6.944447338668820E-03 -3.385935648791810E-01
+4.486111028181440E-01 1.226152842993550E+00 3.125316230636930E-01 4.122082335163850E-01 -1.907921106490020E-01 6.325138915313910E-01 -2.836605923237160E-01 1.608567727483520E-01 -3.609225875596750E-01 3.314780580344970E-02 2.347401218322860E-01 1.607742705512700E-01 -1.194303450532860E+00 -4.081876409977390E-01 -8.792664425089200E-02 -5.248919553932240E-01 -6.013109720301280E-01 -9.009579611985610E-01 -3.100307273249010E-01 2.095821149680040E-02 4.995700744715940E-01 2.849215412025390E+00 3.108455977609470E+00 3.018739138698060E+00 1.443070608888060E-01 1.113287002965640E+00 -1.624279765641410E-02 -3.210853191839570E-01 -5.026070577656260E+00 -5.055730515773560E+00 1.671157416281690E-01 -8.978911257138130E-02 3.284522491837170E-01 -3.866677439269630E-01 -3.109950682595010E-01 -6.944447338666030E-03 1.409921726772640E+01 -2.072992053514810E-01
+7.339143043876800E-01 -1.127181236203480E+00 -1.248397220906990E-01 4.147918803823840E-01 6.693665586026480E+00 -2.185886781653180E+00 -2.263045367663230E-01 -5.257497760171900E-01 -7.807321285164020E-01 -1.623372536668240E-01 -5.270705003756470E-02 -9.641416473598110E-02 -9.956913042216250E-01 1.873683794582530E-03 -6.588318891980450E-02 2.538443038041310E-01 -9.994143915536590E-01 -1.442544121641960E+00 -1.585442760842500E+00 -1.527434548310350E-02 -1.095638623519660E-01 -1.523572657236220E-01 3.975427727639110E-01 3.581331345278470E-01 5.197829743536830E-01 -1.156206516318540E+00 -2.067916252984060E-01 -1.018655994332640E+00 -9.518635423501950E-01 -5.182273351017430E+00 -1.415249597831570E+00 -3.933846231119170E-01 4.761446258298690E-01 8.255659807478600E-02 -9.078350489698230E-01 -3.385935648791810E-01 -2.072992053514770E-01 1.537845788745180E+01
diff --git a/physiolabxr/third_party/BAlert/Config/WorkloadMean2143_Model16.txt b/physiolabxr/third_party/BAlert/Config/WorkloadMean2143_Model16.txt
new file mode 100644
index 00000000..1ccd9a2e
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/Config/WorkloadMean2143_Model16.txt
@@ -0,0 +1,3 @@
+C3C4HZ01 C3C4HZ15 C3C4HZ31 CZPOHZ26 CZPOHZ36 CZPOHZ37 F3CZHZ06 F3CZHZ07 F3CZHZ10 F3CZHZ16 F3CZHZ28 FZC3HZ01 FZC3HZ06 FZC3HZ08 FZC3HZ13 FZC3HZ15 FZPOHZ04 FZPOHZ10 FZPOHZ16 FZPOHZ28 FZPOHZ40 PROB3 PROB7 PROB8 rC34Hz08 rC34Hz15 rC34Hz16 rCPOHz16 rCPOHz32 rCPOHz34 rCPOHz38 rCPOHz40 rF3CHz12 rF3CHz20 rFC3Hz17 rFC3Hz30 rFPOHz33 rFPOHz35
+9.394458296751540E-01 1.765834679543460E+00 1.146015452151010E+00 1.353340035118520E+00 7.193158033362600E-01 6.853040386303770E-01 1.912973309920980E+00 1.916483494293240E+00 2.069664793678670E+00 1.544336172080770E+00 1.321683757682180E+00 9.472302019315190E-01 1.907114837576820E+00 1.921033362598770E+00 1.720412379280070E+00 1.545418173836700E+00 2.323684811237930E+00 2.675626075504830E+00 2.028122036874450E+00 1.373542054433710E+00 7.267283582089550E-01 5.164640035118530E-01 3.674632133450390E-01 1.096399473222120E-01 1.465027229752970E+00 1.672123191122600E+00 1.688576483484320E+00 1.724774999136550E+00 2.581809064105820E+00 2.726804586493880E+00 2.923955332762540E+00 3.041793260769560E+00 1.449457033484310E+00 1.800792942176140E+00 1.748078471518590E+00 2.291079086092780E+00 2.681377992403640E+00 2.818429265450170E+00
+8.712844594594590E-01 1.608565909090910E+00 1.148675245700250E+00 1.288384336609340E+00 8.565603808353810E-01 8.134495085995090E-01 1.900318304668300E+00 1.877421130221130E+00 1.922641891891890E+00 1.453792567567570E+00 1.239231756756760E+00 8.948758599508600E-01 1.954351597051600E+00 1.877231449631450E+00 1.640464250614250E+00 1.442805036855040E+00 2.293258169533170E+00 2.518046130221130E+00 1.915349140049140E+00 1.420727149877150E+00 8.707978501228500E-01 4.718939189189190E-01 4.282038083538080E-01 8.945110565110580E-02 1.492413072626570E+00 1.758175419063920E+00 1.771456377294880E+00 1.754603775154680E+00 2.408275765326670E+00 2.517307583508490E+00 2.687678283754190E+00 2.776040384491290E+00 1.504453829055240E+00 1.844305610382020E+00 1.827237994177530E+00 2.256099480664020E+00 2.516250187053810E+00 2.620269597373220E+00
\ No newline at end of file
diff --git a/physiolabxr/third_party/BAlert/Config/WorkloadMean413_Model16.txt b/physiolabxr/third_party/BAlert/Config/WorkloadMean413_Model16.txt
new file mode 100644
index 00000000..396d88a4
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/Config/WorkloadMean413_Model16.txt
@@ -0,0 +1,3 @@
+C3C4HZ01 C3C4HZ15 C3C4HZ31 CZPOHZ26 CZPOHZ36 CZPOHZ37 F3CZHZ06 F3CZHZ07 F3CZHZ10 F3CZHZ16 F3CZHZ28 FZC3HZ01 FZC3HZ06 FZC3HZ08 FZC3HZ13 FZC3HZ15 FZPOHZ04 FZPOHZ10 FZPOHZ16 FZPOHZ28 FZPOHZ40 PROB3 PROB7 PROB8 rC34Hz08 rC34Hz15 rC34Hz16 rCPOHz16 rCPOHz32 rCPOHz34 rCPOHz38 rCPOHz40 rF3CHz12 rF3CHz20 rFC3Hz17 rFC3Hz30 rFPOHz33 rFPOHz35
+9.633850120870270E-01 1.728424254633360E+00 1.158994439967770E+00 1.369445366639810E+00 7.889602739726030E-01 7.391008863819500E-01 1.889563658340050E+00 1.909489685737310E+00 2.069745608380340E+00 1.536535858178890E+00 1.316974536663980E+00 9.399132957292510E-01 1.881854955680900E+00 1.897101692183720E+00 1.719869460112810E+00 1.527487832393230E+00 2.293004109589040E+00 2.637379290894440E+00 1.993065753424660E+00 1.432155922643030E+00 8.473507655116840E-01 5.046130539887190E-01 3.961736502820310E-01 9.640467365028220E-02 1.438804972446370E+00 1.680433094928240E+00 1.703770564710670E+00 1.742039810532460E+00 2.538302743650920E+00 2.664311849210950E+00 2.852979133658970E+00 2.903415717059460E+00 1.467459318896960E+00 1.845986635577060E+00 1.756950167377190E+00 2.289244365604430E+00 2.655243296657920E+00 2.743180363539470E+00
+8.712844594594590E-01 1.608565909090910E+00 1.148675245700250E+00 1.288384336609340E+00 8.565603808353810E-01 8.134495085995090E-01 1.900318304668300E+00 1.877421130221130E+00 1.922641891891890E+00 1.453792567567570E+00 1.239231756756760E+00 8.948758599508600E-01 1.954351597051600E+00 1.877231449631450E+00 1.640464250614250E+00 1.442805036855040E+00 2.293258169533170E+00 2.518046130221130E+00 1.915349140049140E+00 1.420727149877150E+00 8.707978501228500E-01 4.718939189189190E-01 4.282038083538080E-01 8.945110565110540E-02 1.492413072626570E+00 1.758175419063920E+00 1.771456377294880E+00 1.754603775154680E+00 2.408275765326670E+00 2.517307583508490E+00 2.687678283754190E+00 2.776040384491290E+00 1.504453829055240E+00 1.844305610382020E+00 1.827237994177530E+00 2.256099480664020E+00 2.516250187053810E+00 2.620269597373220E+00
diff --git a/physiolabxr/third_party/BAlert/Config/X10 Standard.ced b/physiolabxr/third_party/BAlert/Config/X10 Standard.ced
new file mode 100644
index 00000000..c755eb4b
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/Config/X10 Standard.ced
@@ -0,0 +1,11 @@
+channum label theta radius x y z sph_theta sph_phi sph_radius
+1 EKG 162.074 0.514988889 -80.78401377 -26.1330144 -4.001084542 -162.074 -2.698 85 21 []
+2 POz 180 0.379944444 -79.02553886 -9.68E-15 31.30438001 -180 21.61 85 18 []
+3 Fz 0 0.253377778 60.73848095 0 59.46290383 0 44.392 85 5 []
+4 Cz 0 0 5.20E-15 0 85 0 90 85 10 []
+5 C3 -90 0.266688889 3.87E-15 63.17128071 56.87169149 90 41.996 85 9 []
+6 C4 90 0.266666667 3.87E-15 -63.16731017 56.87610154 -90 42 85 11 []
+7 F3 -39.947 0.344594444 57.55106339 48.20042732 39.86971167 39.947 27.973 85 4 []
+8 F4 39.897 0.3445 57.58402611 -48.14259647 39.89198344 -39.897 27.99 85 6 []
+9 P3 -140.053 0.344594444 -57.55106339 48.20042732 39.86971167 140.053 27.973 85 14 []
+10 P4 140.103 0.3445 -57.58402611 -48.14259647 39.89198344 -140.103 27.99 85 16 []
diff --git a/physiolabxr/third_party/BAlert/Config/X24 10-20.ced b/physiolabxr/third_party/BAlert/Config/X24 10-20.ced
new file mode 100644
index 00000000..d5e85c56
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/Config/X24 10-20.ced
@@ -0,0 +1,22 @@
+channum label theta radius x y z sph_theta sph_phi sph_radius
+1 Fp1 -17.926 0.514988889 80.78401377 26.1330144 -4.001084542 17.926 -2.698 85
+2 F7 -53.913 0.528083333 49.87137795 68.42333503 -7.48951836 53.913 -5.055 85
+3 F8 53.867 0.528066667 49.92652681 -68.3835903 -7.48508507 -53.867 -5.052 85
+4 T4 90 0.533183333 5.18E-15 -84.53853864 -8.845082514 -90 -5.973 85
+5 T6 126.133 0.528066667 -49.92652681 -68.3835903 -7.48508507 -126.133 -5.052 85
+6 T5 -126.087 0.528083333 -49.87137795 68.42333503 -7.48951836 126.087 -5.055 85
+7 T3 -90 0.533183333 5.18E-15 84.53853864 -8.845082514 90 -5.973 85
+8 Fp2 17.926 0.514988889 80.78401377 -26.1330144 -4.001084542 -17.926 -2.698 85
+9 O1 -162.074 0.514988889 -80.78401377 26.1330144 -4.001084542 162.074 -2.698 85
+10 P3 -140.053 0.344594444 -57.55106339 48.20042732 39.86971167 140.053 27.973 85
+11 Pz 180 0.253377778 -60.73848095 -7.44E-15 59.46290383 -180 44.392 85
+12 F3 -39.947 0.344594444 57.55106339 48.20042732 39.86971167 39.947 27.973 85
+13 Fz 0 0.253377778 60.73848095 0 59.46290383 0 44.392 85
+14 F4 39.897 0.3445 57.58402611 -48.14259647 39.89198344 -39.897 27.99 85
+15 C4 90 0.266666667 3.87E-15 -63.16731017 56.87610154 -90 42 85
+16 P4 140.103 0.3445 -57.58402611 -48.14259647 39.89198344 -140.103 27.99 85
+17 POz 180 0.379944444 -79.02553886 -9.68E-15 31.30438001 -180 21.61 85
+18 C3 -90 0.266688889 3.87E-15 63.17128071 56.87169149 90 41.996 85
+19 Cz 0 0 5.20E-15 0 85 0 90 85
+20 O2 162.074 0.514988889 -80.78401377 -26.1330144 -4.001084542 -162.074 -2.698 85
+21 EKG 162.074 0.514988889 -80.78401377 -26.1330144 -4.001084542 -162.074 -2.698 85
\ No newline at end of file
diff --git a/physiolabxr/third_party/BAlert/SDK64/bin/ABM_Athena64.dll b/physiolabxr/third_party/BAlert/SDK64/bin/ABM_Athena64.dll
new file mode 100644
index 00000000..f6800ae1
Binary files /dev/null and b/physiolabxr/third_party/BAlert/SDK64/bin/ABM_Athena64.dll differ
diff --git a/physiolabxr/third_party/BAlert/SDK64/bin/ABM_Datastreaming64.dll b/physiolabxr/third_party/BAlert/SDK64/bin/ABM_Datastreaming64.dll
new file mode 100644
index 00000000..58a467b3
Binary files /dev/null and b/physiolabxr/third_party/BAlert/SDK64/bin/ABM_Datastreaming64.dll differ
diff --git a/physiolabxr/third_party/BAlert/SDK64/bin/ABM_PlayEbs64.dll b/physiolabxr/third_party/BAlert/SDK64/bin/ABM_PlayEbs64.dll
new file mode 100644
index 00000000..d6ae3f15
Binary files /dev/null and b/physiolabxr/third_party/BAlert/SDK64/bin/ABM_PlayEbs64.dll differ
diff --git a/physiolabxr/third_party/BAlert/SDK64/bin/ABM_ThirdPartyCommunication64.dll b/physiolabxr/third_party/BAlert/SDK64/bin/ABM_ThirdPartyCommunication64.dll
new file mode 100644
index 00000000..ef71f40c
Binary files /dev/null and b/physiolabxr/third_party/BAlert/SDK64/bin/ABM_ThirdPartyCommunication64.dll differ
diff --git a/physiolabxr/third_party/BAlert/SDK64/bin/BAlert64.dll b/physiolabxr/third_party/BAlert/SDK64/bin/BAlert64.dll
new file mode 100644
index 00000000..b7766d19
Binary files /dev/null and b/physiolabxr/third_party/BAlert/SDK64/bin/BAlert64.dll differ
diff --git a/physiolabxr/third_party/BAlert/SDK64/bin/BAlert_Classification64.dll b/physiolabxr/third_party/BAlert/SDK64/bin/BAlert_Classification64.dll
new file mode 100644
index 00000000..052eb2bf
Binary files /dev/null and b/physiolabxr/third_party/BAlert/SDK64/bin/BAlert_Classification64.dll differ
diff --git a/physiolabxr/third_party/BAlert/SDK64/bin/BAlert_EventHandling64.dll b/physiolabxr/third_party/BAlert/SDK64/bin/BAlert_EventHandling64.dll
new file mode 100644
index 00000000..9f8496f3
Binary files /dev/null and b/physiolabxr/third_party/BAlert/SDK64/bin/BAlert_EventHandling64.dll differ
diff --git a/physiolabxr/third_party/BAlert/SDK64/bin/BAlert_HRAnalysis64.dll b/physiolabxr/third_party/BAlert/SDK64/bin/BAlert_HRAnalysis64.dll
new file mode 100644
index 00000000..1b80c030
Binary files /dev/null and b/physiolabxr/third_party/BAlert/SDK64/bin/BAlert_HRAnalysis64.dll differ
diff --git a/physiolabxr/third_party/BAlert/SDK64/bin/BAlert_PSD64.dll b/physiolabxr/third_party/BAlert/SDK64/bin/BAlert_PSD64.dll
new file mode 100644
index 00000000..d97f6ffd
Binary files /dev/null and b/physiolabxr/third_party/BAlert/SDK64/bin/BAlert_PSD64.dll differ
diff --git a/physiolabxr/third_party/BAlert/SDK64/bin/BAlert_Performance64.dll b/physiolabxr/third_party/BAlert/SDK64/bin/BAlert_Performance64.dll
new file mode 100644
index 00000000..4f47d9ad
Binary files /dev/null and b/physiolabxr/third_party/BAlert/SDK64/bin/BAlert_Performance64.dll differ
diff --git a/physiolabxr/third_party/BAlert/SDK64/bin/BAlert_Report64.dll b/physiolabxr/third_party/BAlert/SDK64/bin/BAlert_Report64.dll
new file mode 100644
index 00000000..103e0ec3
Binary files /dev/null and b/physiolabxr/third_party/BAlert/SDK64/bin/BAlert_Report64.dll differ
diff --git a/physiolabxr/third_party/BAlert/SDK64/bin/BAlert_SignalHandling64.dll b/physiolabxr/third_party/BAlert/SDK64/bin/BAlert_SignalHandling64.dll
new file mode 100644
index 00000000..5df20b6b
Binary files /dev/null and b/physiolabxr/third_party/BAlert/SDK64/bin/BAlert_SignalHandling64.dll differ
diff --git a/physiolabxr/third_party/BAlert/SDK64/bin/Balert_DataFiltering64.dll b/physiolabxr/third_party/BAlert/SDK64/bin/Balert_DataFiltering64.dll
new file mode 100644
index 00000000..2643ecc5
Binary files /dev/null and b/physiolabxr/third_party/BAlert/SDK64/bin/Balert_DataFiltering64.dll differ
diff --git a/physiolabxr/third_party/BAlert/SDK64/bin/Balert_DefFile64.dll b/physiolabxr/third_party/BAlert/SDK64/bin/Balert_DefFile64.dll
new file mode 100644
index 00000000..b692ceaf
Binary files /dev/null and b/physiolabxr/third_party/BAlert/SDK64/bin/Balert_DefFile64.dll differ
diff --git a/physiolabxr/third_party/BAlert/SDK64/bin/SiUSBXp.dll b/physiolabxr/third_party/BAlert/SDK64/bin/SiUSBXp.dll
new file mode 100644
index 00000000..3ee1e79a
Binary files /dev/null and b/physiolabxr/third_party/BAlert/SDK64/bin/SiUSBXp.dll differ
diff --git a/physiolabxr/third_party/BAlert/SDK64/bin/ftd2xx64.dll b/physiolabxr/third_party/BAlert/SDK64/bin/ftd2xx64.dll
new file mode 100644
index 00000000..7e63fa92
Binary files /dev/null and b/physiolabxr/third_party/BAlert/SDK64/bin/ftd2xx64.dll differ
diff --git a/physiolabxr/third_party/BAlert/SDK64/bin/lsl.dll b/physiolabxr/third_party/BAlert/SDK64/bin/lsl.dll
new file mode 100644
index 00000000..cef9a597
Binary files /dev/null and b/physiolabxr/third_party/BAlert/SDK64/bin/lsl.dll differ
diff --git a/physiolabxr/third_party/BAlert/SDK64/include/AbmSdkInclude.h b/physiolabxr/third_party/BAlert/SDK64/include/AbmSdkInclude.h
new file mode 100644
index 00000000..a9f5100f
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/SDK64/include/AbmSdkInclude.h
@@ -0,0 +1,7 @@
+#include "Athena.h"
+#include "EegAcqDefine.h"
+#include "ErrorCode.h"
+#include "PlayEbs.h"
+#include "TypeDef.h"
+#include "TypeDefDataTypes.h"
+
diff --git a/physiolabxr/third_party/BAlert/SDK64/include/Athena.h b/physiolabxr/third_party/BAlert/SDK64/include/Athena.h
new file mode 100644
index 00000000..6cabf518
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/SDK64/include/Athena.h
@@ -0,0 +1,232 @@
+// The following ifdef block is the standard way of creating macros which make exporting
+// from a DLL simpler. All files within this DLL are compiled with the FFFFFF_EXPORTS
+// symbol defined on the command line. this symbol should not be defined on any project
+// that uses this DLL. This way any other project whose source files include this file see
+// FFFFFF_API functions as being imported from a DLL, whereas this DLL sees symbols
+// defined with this macro as being exported.
+#ifdef ATHENA_EXPORTS
+#define ATHENA_API __declspec(dllexport)
+#else
+#define ATHENA_API __declspec(dllimport)
+#endif
+
+#include "TypeDef.h"
+
+ATHENA_API int __stdcall StartAcquisition();
+ATHENA_API int __stdcall CloseCurrentConnection();
+
+
+ATHENA_API int __stdcall StopAcquisition();
+
+ATHENA_API int __stdcall InitSessionForCurrentConnection(int DeviceType,int SessionType,int nSelectedDeviceHandle, BOOL bPlayEBS );
+ATHENA_API int __stdcall InitSessionForCurrentConnectionWithHRV(int DeviceType, int SessionType, int nSelectedDeviceHandle, BOOL bPlayEBS, BOOL bHRVAnalysisInSession);
+
+
+ATHENA_API _BRAIN_STATE* __stdcall GetBrainState(int& );
+
+ATHENA_API float* __stdcall GetRawData(int&);
+
+ATHENA_API float* __stdcall GetDeconData(int& );
+
+ATHENA_API float* __stdcall GetQualityChannelData(int& );
+
+ATHENA_API float* __stdcall GetPSDData(int& );
+
+
+
+
+
+ATHENA_API float* __stdcall GetMovementData(int& );
+
+ATHENA_API float* __stdcall GetPSDDataraw(int& );
+
+ATHENA_API float* __stdcall GetBandOverallPSDData(int& nCountPackages, int& nPackageSize);
+
+ATHENA_API float* __stdcall GetBandOverallPSDRawData(int& nCountPackages, int& nPackageSize);
+
+ATHENA_API float* __stdcall GetPSDBandwidthData(int& nCountPackages, int& nPackageSize);
+
+ATHENA_API float* __stdcall GetPSDBandwidthRawData(int& nCountPackages, int& nPackageSize);
+
+ATHENA_API int __stdcall GetPSDCountBands(int& nCountBandwidths, int& nCountBandwidthsOverall );
+
+ATHENA_API int __stdcall InitZScoreData( wchar_t* sZScoreSourceList );
+
+ATHENA_API int __stdcall ResetZScoreData( wchar_t* sNewZScoreSourceList );
+
+ATHENA_API int __stdcall ReleaseZScoreData();
+
+ATHENA_API float* __stdcall GetZScoreData(int& nCountPackages, int& nPackageSize);
+
+ATHENA_API _ESU_PORT_INFO* __stdcall GetESUPortInfo();
+
+ATHENA_API int __stdcall SaveESUPortInfo(_ESU_PORT_INFO* pESUPortInfo);
+
+ATHENA_API int __stdcall TechnicalMonitoring(void (__stdcall *pFunc)(CHANNEL_INFO*, int&), int nSeconds, _DEVICE_INFO* pDeviceInfo = NULL);
+
+
+
+
+
+ATHENA_API unsigned char* __stdcall GetThirdPartyData(int& );
+
+ATHENA_API unsigned char* __stdcall GetTimeStampsStreamData(int nType);
+
+ATHENA_API int __stdcall SetArtifactsCallbackFuncs(void (__stdcall *pFuncEB)(int epstart, int offstart, float shour, float sminute, float ssecond, float smili , int epend, int offend, float ehour, float eminute, float esecond, float emili),
+ void (__stdcall *pFuncExc)(int indexch,int epstart, int offstart, float shour, float sminute, float ssecond, float smili, int epend, int offend, float ehour, float eminute, float esecond, float emili),
+ void (__stdcall *pFuncSat)(int indexch,int epstart, int offstart, float shour, float sminute, float ssecond, float smili, int epend, int offend, float ehour, float eminute, float esecond, float emili),
+ void (__stdcall *pFuncSpk)(int indexch, int epstart, int offstart, float shour, float sminute, float ssecond, float smili, int epend, int offend, float ehour, float eminute, float esecond, float emili),
+ void (__stdcall *pFuncEMG)(int indexch,int epstart, int offstart, float shour, float sminute, float ssecond, float smili, int epend, int offend, float ehour, float eminute, float esecond, float emili));
+
+ATHENA_API int __stdcall RegisterCallbackOnError(void (__stdcall *pFunc)(int));
+
+ATHENA_API int __stdcall RegisterCallbackOnStatusInfo(void (__stdcall *pFunc)(_STATUS_INFO*));
+
+ATHENA_API int __stdcall RegisterCallbackOnThirdParty(void (__stdcall *pFunc)(const unsigned char*,int));
+
+ATHENA_API int __stdcall RegisterCallbackDataArrived(void (__stdcall *pFunc)(int));
+
+ATHENA_API int __stdcall RegisterCallbackMissedBlocks(void (__stdcall *pFunc)(int, int));
+
+ATHENA_API int __stdcall RegisterCallbackDeviceDetectionInfo(void (__stdcall *pFunc)(wchar_t*, int));
+
+ATHENA_API int __stdcall StopTechnicalMonitoring();
+
+ATHENA_API float* __stdcall GetEKGData(int& );
+
+
+
+
+
+
+
+ATHENA_API int __stdcall SetMarker(int epoch, int offset, int val);
+
+ATHENA_API int __stdcall SetMarkerWithComment(int epoch, int offset, int val, wchar_t* comment);
+
+ATHENA_API int __stdcall GetFirmwareVer(_BALERT_FIRMWARE_VERSION &stFWVer);
+
+//play ebs mode functions
+
+ATHENA_API BOOL __stdcall PlayInEbsModeDataAll(float* pEegData, int nSamples, WORD* pOpticalData, int nOpticalSamples, int* nTiltData, int nTiltSamples,
+ WORD* pOpticalRawData, int nOpticalRawSamples );
+
+
+ATHENA_API _EXTERN_CALC_TABLE_NAME* __stdcall GetMapCalcChannels( int& nSize );
+
+ATHENA_API void __stdcall StopPlayEbsData();
+
+
+ATHENA_API float* __stdcall GetQualityChannelData(int& nCount);
+
+
+
+ATHENA_API int __stdcall GetCurrentSDKMode();
+ATHENA_API int __stdcall GetMissedBlocks();
+
+ATHENA_API int __stdcall InitiatePlaybackSession( _SESSION_INFO* pSessionInfo, int nDeviceType, _DEVICE_INFO* pDeviceInfo, int nHardwareDeviceType, BOOL bTilt, BOOL bHRVAnalysis);
+
+ATHENA_API float* __stdcall GetRawRawData(int&);
+
+ATHENA_API float* __stdcall GetFilteredData(int&);
+
+ATHENA_API float* __stdcall GetTiltRawData(int& nCount);
+
+ATHENA_API float* __stdcall GetTiltAnglesData(int& nCount);
+
+ATHENA_API int __stdcall SetDefinitionFile(wchar_t* pDefinitionFile);
+
+ATHENA_API int __stdcall SetDestinationFile(wchar_t* pDestinationFile);
+
+
+
+
+
+ATHENA_API int __stdcall GetBatteryLevel(float &fBatteryLevel, int &nBatteryPercentage);
+
+ATHENA_API int __stdcall GetPacketChannelNmbInfo(int& nRawPacketChannelsNmb, int& nDeconPacketChannelsNmb, int& nPSDPacketChannelsNmb, int& nRawPSDPacketChannelNmb, int& nQualityPacketChannelNmb);
+
+ATHENA_API int __stdcall GetChannelMapInfo( _CHANNELMAP_INFO & stChannelMapInfo);
+
+ATHENA_API int __stdcall GetEEGChannelsInfo( _EEGCHANNELS_INFO & stEEGChannelsInfo);
+
+ATHENA_API int __stdcall GetTimestampType();
+
+ATHENA_API int __stdcall SetConfigPath( wchar_t* pConfigPath );
+
+ATHENA_API int __stdcall GetThirdPartyTimestamp(int &label, int &millisESU, _SYSTEMTIME &st);
+
+ATHENA_API float* __stdcall GetCurrentQualityData(int& nCount);
+
+ATHENA_API float* __stdcall GetClassQualityData(int& nCount);
+
+ATHENA_API int __stdcall GetBandsDescription(wchar_t** pszBands, int& count);
+
+ATHENA_API int __stdcall InitiatePESession(int nDeviceType, int sessionType, wchar_t* chDefFile, BOOL bTilt);
+
+ATHENA_API void __stdcall FreeBuffer( void* ptrBuffer);
+
+ATHENA_API int __stdcall MeasureImpedances(void(__stdcall* pFunc)(ELECTRODE* pEl, int& nCount));
+
+ATHENA_API int __stdcall GetOverallBandsDescription(wchar_t** pszBands, int& count);
+
+ATHENA_API void __stdcall InitOCEANAcquisition(BOOL bStartOCEAN);
+
+ATHENA_API int __stdcall GetEdfId( char** pszEdfId );
+
+ATHENA_API void __stdcall SetSwPackageVersion( wchar_t* pszVersion );
+
+ATHENA_API int __stdcall GetDestinationFile( wchar_t** pszDestinationFile );
+
+ATHENA_API int __stdcall InitSessionStream(int nDeviceType,int nSessionType,int nSelectedDeviceHandle, BOOL bPlayEBS);
+
+ATHENA_API int __stdcall StartAcquisitionStream( char* pchIPAddress );
+
+ATHENA_API int __stdcall StopAcquisitionStream();
+
+ATHENA_API int __stdcall SetMBCallbackFuncs(void (__stdcall *pFuncMB)(int epstart, int offstart, float shour, float sminute, float ssecond, float smili , int epend, int offend, float ehour, float eminute, float esecond, float emili));
+
+
+
+ATHENA_API int __stdcall SetPeriodicImpedanceMonitor(int nPeriodeMinutes);
+
+ATHENA_API int __stdcall SetPeriodicImpMBCallbackFuncs(void (__stdcall *pFuncMB)(int epstart, int offstart, float shour, float sminute, float ssecond, float smili , int epend, int offend, float ehour, float eminute, float esecond, float emili));
+
+ATHENA_API BOOL __stdcall CheckImpedancesPerRequest();
+
+ATHENA_API void __stdcall SetImpPerRequestCallbackFuncs(void (__stdcall *pFunc)(int bImpedanceStatus));
+
+ATHENA_API void __stdcall GetEDFDestinationFile( wchar_t** pszDestinationFile );
+
+
+
+ATHENA_API _DEVICE_INFO_DETAILS* __stdcall GetDeviceInfoDetails( int& nErrorCode, int& nStripCode );
+
+ATHENA_API int __stdcall CheckForLongMB(BOOL& bLongMBHappened);
+ATHENA_API void __stdcall FreeNonArrayBuffer( void* ptrBuffer);
+
+ATHENA_API _DEVICE_INFO* __stdcall GetDeviceInfo(int nRetry /*default 20*/, int& nStripCode, int& nErrorCode);
+ATHENA_API BOOL __stdcall IsConnectionOpened();
+ATHENA_API int __stdcall GetDetectedDevicePath( wchar_t** pszDevicePath );
+
+
+
+ATHENA_API _ESU_PORT_INFO* __stdcall GetESUPortInfoForCurrentConnection();
+
+ATHENA_API void __stdcall SetNoStripAllowed(BOOL bNoStripAllowed);
+ATHENA_API void __stdcall SetClassicFlexOldFwAllowed(BOOL bOldClassicFwAllowed);
+
+ATHENA_API BOOL __stdcall GetESUSerialNumber(wchar_t** esuSerialNum);
+ATHENA_API BOOL __stdcall GetDeviceSerialNumber(wchar_t** deviceSerialNum);
+
+ATHENA_API int __stdcall GetMachineGuidBegin(wchar_t** ptchMachineGuidBegin);
+ATHENA_API int __stdcall PingFlexBattery();
+ATHENA_API int __stdcall GetReceiverInfo();
+ATHENA_API int __stdcall StartLSLReceiver(BOOL bStartOCEANReceiver, BOOL bStartReceiver);
+ATHENA_API int __stdcall InvokeResynchingProcedure();
+ATHENA_API void __stdcall SetSignalCheckDestinationFile( bool bSet );
+
+ATHENA_API void __stdcall SetEEGLSLSettings(_LSLSTREAMING_INFO* info);
+ATHENA_API void __stdcall EnableHRVAnalysis(BOOL bEnableHRV);
+
+ATHENA_API void __stdcall SetTeaming(wchar_t* teamingID);
diff --git a/physiolabxr/third_party/BAlert/SDK64/include/BMS/BMS.h b/physiolabxr/third_party/BAlert/SDK64/include/BMS/BMS.h
new file mode 100644
index 00000000..890e5aeb
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/SDK64/include/BMS/BMS.h
@@ -0,0 +1,253 @@
+#ifdef BMS_EXPORTS
+#define BMS_API __declspec(dllexport)
+#else
+#define BMS_API __declspec(dllimport)
+#endif
+
+#include "typedef.h"
+#include ".\BMS_Comm\BMS_Comm.h"
+#include "SDKFlexDefinitions.h"
+
+// Desc: This function returns information on Balert device, it is optional and may be called at any time.
+// It is advisable to call this function at the beginning of a session to ensure that the device is active and connected successfully.
+// Parameters: &deviceInfo - OUTPUT - _BALERT_DEVICE_INFO_BMS struct holding information on device
+// nDeviceType - INPUT - a type of Balert device (X4-BAlert = 4, X10-Standard=10, X24-qEEG=24, X24-stERP=241)
+// Return Value: Connection status (1 = Device & ESU connected and working fine , 0=no device, -1= wrong device model selected, -2 = ESU or device not configured properly)
+BMS_API int __stdcall BAlertGetDeviceInfo(_BALERT_DEVICE_INFO_BMS &deviceInfo, int nDeviceType);
+
+
+
+// Desc: This function sets destination file, if not called prior to start of the acquisition, then no output file will be created
+// Current date and time is being appended to the filename and two files will be created (Signals.EDF and Events.EDF) for every session
+// This function may be called multiple times while data acquisition and impedance checking are not active and each time
+// a new set of EDF+ files will be created with a unique name appended with the current date and time.
+// Parameters: pDestinationFilePath - INPUT - full path of destination file (e.g. C:\\ABM\\EEG\\Data)
+// nSubjNum - INPUT - a session information parameter
+// nGroup - INPUT - a session information parameter
+// nSessIter - INPUT - a session information parameter
+// nTaskType - INPUT - a session information parameter
+// nTaskIter - INPUT - a session information parameter
+// nDevice type: INPUT - a type of Balert device (X4-BAlert = 4, X10-Standard=10, X24-qEEG=24, X24-stERP=241)
+// Return Value: status - Success (1)/ Failed (0)
+BMS_API int __stdcall BAlertSetDestinationFile( WCHAR* pDestinationFilePath, int nSubjNum, int nGroup, int nSessIter, int nTaskType, int nTaskIter, int nDeviceType, bool bSecurityMode );
+
+// Desc: This function starts impedance measurement - it opens the communication port if the port is not already opened.
+// Parameters: pFunc - INPUT - a callback function - reports each channel separately - the impedance associated with both the electrodes of that channel are returned.
+// channels - INPUT - a channel selection mask - integer value (4 bytes) coded as bits - each bit for one channel (0xFFFFFFFF is reserved to indicate all channels)
+// (for e.g to check impedance of channel 2, the user should enter 0x00000002, to check channels 2 & 3 enter 0x00000006)
+// nDeviceType - INPUT - a type of Balert device (X4-BAlert = 4, X10-Standard=10, X24-qEEG=24, X24-stERP=241)
+// Return Value: status (success=1/failed=0)
+BMS_API int __stdcall BAlertCheckImpedances(void (__stdcall *pFunc)(_BALERT_IMPEDANCE_RESULT*, int&), int channels, int nDeviceType);
+
+// Desc: This function starts data Acquisition - it opens the communication port if the port is not already opened.
+// Parameters: None
+// Return Value: status - (success (1) /failed (0)).
+BMS_API int __stdcall BAlertStartAcquisition();
+
+// Desc: This function ends the session and closes all active files.
+// Parameters: None
+// Return Value: status - (success (1) /failed (0)).
+BMS_API int __stdcall BAlertStopAcquisition();
+
+
+// Desc: Stops impedance measurement in progress.
+// Parameters: none
+// Return Value: (success=1/failed=0).
+BMS_API int __stdcall BAlertStopImpedance(BOOL bCanceled);
+
+// Desc: This function is blocking, it blocks till a number of samples equal to nBlockSize is available from each EEG channel.
+// It flushes the internal buffer the very first time this function is called and resets the samplecounter
+// Parameters: fbuffer - OUTPUT - a pointer to buffer holding data
+// The return buffer has structure which depends on device used. It can be one of the folowing:
+// _BALERT_DATA_X10_PACKET, _BALERT_DATA_X10_PACKET or _BALERT_DATA_X24_PACKET.
+// The total size of the return buffer will be fixed and equal to nBlockSize * sizeof (_BALERT_DATA_XYZ_PACKET)
+// nBlockSize - INPUT - a number of samples to wait for
+// Return Value: status (success-1/failed-0)
+BMS_API int __stdcall BAlertWaitForData(float* fBuffer, int nBlockSize);
+
+// Desc: This function is NON-blocking and returns all the data available in the internal buffer at that moment of call.
+// The return buffer has structure which depends on device used. It can be one of the folowing:
+// _BALERT_DATA_X10_PACKET, _BALERT_DATA_X10_PACKET or _BALERT_DATA_X24_PACKET.
+// Parameters: &nCount - OUTPUT - number of samples returned per channel.
+// Return Value: pointer to the buffer holding data - The size of the return buffer is equal to nCount * sizeof (_BALERT_DATA_XYZ_PACKET)
+BMS_API float* __stdcall BAlertGetData(int &nCount);
+
+
+// Desc: This function is NON-blocking and returns all the MIC data available in the internal buffer at that moment of call.
+// (works only for X4 devices with extended protocol)
+// Parameters: &nCount - OUTPUT - number of samples returned per channel.
+// Return Value: pointer to the buffer holding data
+BMS_API float* __stdcall BAlertGetMicData(int &nCount);
+
+// Desc: This function is NON-blocking and returns all the Raw Optical data available in the internal buffer at that moment of call.
+// (works only for X4 devices with extended protocol)
+// Parameters: &nCount - OUTPUT - number of samples returned per channel.
+// Return Value: pointer to the buffer holding data
+BMS_API float* __stdcall BAlertGetRawOpticalData(int &nCount);
+
+// Desc: This function is NON-blocking and returns all the Optical data available in the internal buffer at that moment of call.
+// (works only for X4 devices with extended protocol)
+// Parameters: &nCount - OUTPUT - number of samples returned per channel.
+// Return Value: pointer to the buffer holding data
+BMS_API float* __stdcall BAlertGetOpticalData(int &nCount);
+
+// Desc: The function is non-blocking and returns all the available events in the event buffer.
+// Parameters: nCount - OUTPUT - number of event packets in the event buffer.
+// Return Value: Event Buffer - has a structure like in _BALERT_DATA_EVENT and can be explicitly casted to a pointer to it
+// Size of the buffer is nCount*sizeof ( _BALERT_DATA_EVENT)
+BMS_API BYTE* __stdcall BAlertGetEvents(int &nCount);
+
+
+// Desc: This function enables calling applications to send events to the dll which will then be timestamped,
+// stored in the internal buffer and in EDF file (if available), and made accessible through BAlertGetEvents function.
+// Events MUST be US-ASCII encoded, non-ASCII characters out of the limits will be dropped and will not be stored.
+// Parameters: pBuffer - INPUT - Char buffer pointer holding text
+// nEventSize - INPUT - buffer size in bytes
+// Return Value: Status - (1=event timestamped and stored, 0=failed).
+BMS_API int __stdcall BAlertSetEvents(WCHAR* pBuffer, int nEventSize, WORD nHour, WORD nMinute, WORD nSecond, WORD nMiliSec );
+
+// Desc: Get firmware version from either headset or dongle or esu device
+// Parameters: - INPUT - nType - headset=1, dongle=2, esu=3
+// - OUTPUT - pcVersion - char[50], return version as xx.xx.xx
+// Retrun Value: on success return 1, if failed return -1
+BMS_API int __stdcall BAlertGetFirmwareVer(int nType, WCHAR* pcVersion);
+
+
+// Desc: Disconnect device
+// Parameters:
+// Return Value: on success return 1, if failed return -1
+BMS_API int __stdcall BAlertCloseSession();
+
+BMS_API int __stdcall BAlertSetCallbackOnNewSample(DWORD dwDAUHandle, PABMOnNewSample pOnNewSample, void* p);
+BMS_API int __stdcall BAlertSetCallbackOnNewRawSample(DWORD dwDAUHandle, PABMOnNewRawSample pOnNewRawSample, void* p);
+BMS_API int __stdcall BAlertSetCallbackOnNewTimestamp(DWORD dwDAUHandle, PABMOnNewTimestamp pOnNewSample, void* p);
+BMS_API int __stdcall BAlertSetCallbackOnNewTilt(DWORD dwDAUHandle, PABMOnNewTilt pOnNewTilt, void* p);
+BMS_API int __stdcall BAlertSetCallbackOnNewRawSample(DWORD dwDAUHandle, PABMOnNewRawSample pOnNewSample, void* p);
+BMS_API int __stdcall BAlertSetCallbackOnNewThirdPartyData(DWORD dwDAUHandle, PABMOnNewThirdPartyData pOnNewThirdPartyData, void* p);
+BMS_API int __stdcall BAlertSetCallbackOnNewSlowChannels(DWORD dwDAUHandle, PABMOnNewSlowChannels pOnNewSlowChannels, void* p);
+BMS_API int __stdcall BAlertSetCallbackOnNewIRed(DWORD dwDAUHandle, PABMOnNewIRed pOnNewIRed, void* p);
+BMS_API int __stdcall BAlertSetCallbackOnNewProbeData(DWORD dwDAUHandle, PABMOnNewProbeData pOnNewProbeData, void* p);
+BMS_API int __stdcall BAlertSetCallbackOnNewMic(DWORD dwDAUHandle, PABMOnNewMicData pOnNewMic, void* p);
+BMS_API int __stdcall BAlertSetCallbackOnNewIRedRaw(DWORD dwDAUHandle, PABMOnNewIRedRawData pOnNewIRedRaw, void* p);
+BMS_API int __stdcall BAlertSetCallbackOnNewTechnicalChannel(DWORD dwDAUHandle, PABMOnNewTechnicalChannel pOnNewTechnicalChannel, void* p);
+
+
+BMS_API int __stdcall BAlertGetDeviceSerialNum(WCHAR** serialNum);
+BMS_API int __stdcall BAlertGetDAUInfo(TABMDAUInfo* info);
+BMS_API int __stdcall BAlertGetESUInfo(TABMESUInfo* info);
+
+BMS_API int __stdcall BAlertGetRawSample(DWORD dwDAUHandle, TABMRawSampleInfo* pRawSampleInfo, DWORD dwCount, DWORD* dwActualCount);
+BMS_API int __stdcall BAlertGetSample2(DWORD dwDAUHandle, TABMSampleInfo* pRawSampleInfo, DWORD dwCount, DWORD* dwActualCount);
+BMS_API float* __stdcall BAlertGetSample(DWORD dwDAUHandle, DWORD dwCount, DWORD* dwActualCount);
+
+BMS_API bool __stdcall BAlertImpedanceMeasurementStart(DWORD dwDAUHandle);
+BMS_API bool __stdcall BAlertImpedanceMeasurementStop(DWORD dwDAUHandle);
+BMS_API bool __stdcall BAlertImpedanceMeasurementSetChannel(DWORD dwDAUHandle, bool bHighCurrent, int channelIndex);
+BMS_API bool __stdcall BAlertSendBytesToDAU(DWORD dwDAUHandle,unsigned char* pBytes, int nBytes, int nRetry, int nPause);
+
+BMS_API int __stdcall BAlertDisconnect();
+BMS_API int __stdcall BAlertDisconnectLight(int);
+BMS_API int __stdcall BAlertConnectLight();
+
+BMS_API void __stdcall BAlertSetProcessMissedBlock(BOOL flag);
+
+BMS_API void __stdcall BAlertSetWriteOutputs(BOOL flag);
+
+BMS_API void __stdcall BAlertWriteFlexImpedanceResults( char* pchElectrodes, char* pchImpResults, int nCountElectrodes, int* nRawImpValues );
+
+
+BMS_API int __stdcall BAlertStop();
+BMS_API int __stdcall BAlertStopLight();
+BMS_API void __stdcall BAlertGetEDFFileNames( WCHAR** pchSignalFileName, WCHAR** pchEventsFileName);
+
+//used to set init battery state
+BMS_API int __stdcall BAlertGetBatteryPercentage(float fBattery);
+
+
+//used to set init fill device info usually for battery state
+BMS_API int __stdcall BAlertFillDeviceInfo(_BALERT_DEVICE_INFO_BMS &deviceInfo);
+
+BMS_API void __stdcall BAlertFreeBuffer( void* ptrBuffer);
+
+//flex related api
+BMS_API int __stdcall BAlertFlexGetSensorConfigurationBase(int&);
+
+BMS_API int __stdcall BAlertFlexMeasureImpedances( int nSensorConfig, int** naImpedances );
+
+BMS_API int __stdcall BAlertFlexUSBSynch(RECEIVER_INFO& esu, DEVICE_INFO& dev);
+
+BMS_API int __stdcall BAlertGetFlexDeviceInfoViaUSB( FLEX_DEVICE_INFO& XDev );
+
+BMS_API int __stdcall BAlertFlexUploadFirmware(WCHAR* fwFile);
+
+BMS_API int __stdcall BAlertGetFlexDeviceModel(int& nDeviceModel, int&, float&);
+
+BMS_API int __stdcall BAlertGetFlexBatteryEstimate();
+
+//BMS_API int __stdcall BAlertGetFlexBatteryEstimateForCurrentConnection();
+
+//New ST receiver(dongle) firmware upload
+BMS_API int __stdcall BAlertUpgradeFirmwareReceiverST(WCHAR* fwFile, int );
+BMS_API int __stdcall BAlertUpgradeFirmwareReceiverLE(WCHAR* fwFile);
+
+BMS_API DWORD __stdcall BAlertEnumDevices(DWORD dwConnectionHandle, PABMEnumESUsProc pEnumESUsProc, PABMEnumDAUsProc pEnumDAUsProc, TABMPortInfoEx* p);
+BMS_API DWORD __stdcall BAlertConnect();
+BMS_API DWORD __stdcall BAlertDisconnectConnectionHandle(DWORD dwHandle);
+BMS_API DWORD __stdcall BAlertEnumConnections(PABMEnumConnectionsProc pEnumConnectionsProc, void* p);
+BMS_API DWORD __stdcall BAlertGetESUInfoForConnection(DWORD dwConnectionHandle, bool bReadFromMemory, TABMESUInfo* pESUInfo);
+BMS_API DWORD __stdcall BAlertESUEditSettingsEnd(DWORD dwESUHandle, bool bSaveChanges);
+BMS_API DWORD __stdcall BAlertESUSetBTPortSettings(DWORD dwESUHandle, TABMESUBTPortSettings* pBTPortSettings, BYTE bPortIndex);
+BMS_API DWORD __stdcall BAlertESUSetPARPortSettings(DWORD dwESUHandle, TABMESUPARPortSettings* pPARPortSettings);
+BMS_API DWORD __stdcall BAlertESUEditSettingsBegin(DWORD dwESUHandle);
+BMS_API DWORD __stdcall BAlertESUSetSERPortSettings(DWORD dwESUHandle, TABMESUSERPortSettings* pSERPortSettings, BYTE bPortIndex);
+BMS_API DWORD __stdcall BAlertEnumPorts(PABMEnumPortsProc pEnumPortsProc, TABMPortInfoEx* p);
+BMS_API DWORD __stdcall BAlertBTSynchWithDevice(WCHAR* btNum);
+BMS_API DWORD __stdcall BAlertSearchBTDevices(WCHAR* deviceNames,WCHAR* btNum, int* nDeviceNameLength,int& nNumOfDevices);
+BMS_API DWORD __stdcall BAlertSearchBTDevicesForCurrentConnection(WCHAR* deviceNames,WCHAR* btNum, int* nDeviceNameLength,int& nNumOfDevices);
+BMS_API DWORD __stdcall BAlertSetConfigPath(WCHAR* configPath);
+BMS_API DWORD __stdcall BAlertUploadFWToXSeriesHeadset(WCHAR* tchFirmwareName);
+BMS_API DWORD __stdcall BAlertUploadFWToOldReciever(WCHAR* tchFirmwareName);
+BMS_API DWORD __stdcall BAlertEnumDevicesNoDetails(DWORD dwConnectionHandle, PABMEnumESUsProc pEnumESUsProc, PABMEnumDAUsProc pEnumDAUsProc, TABMPortInfoEx* p);
+BMS_API DWORD __stdcall BAlertEnumDevicesESUDetails(DWORD dwConnectionHandle, PABMEnumESUsProc pEnumESUsProc, PABMEnumDAUsProc pEnumDAUsProc, TABMPortInfoEx* p);
+
+BMS_API int __stdcall BAlertIsDeviceUSB( BOOL& bUSBDevice );
+
+BMS_API int __stdcall BAlertConfigureFlexAudio(int nAudioOn);
+
+BMS_API DWORD __stdcall BAlertEnumDevicesKeepConnection(DWORD dwConnectionHandle, PABMEnumESUsProc pEnumESUsProc, PABMEnumDAUsProc pEnumDAUsProc, TABMPortInfoEx* p);
+
+BMS_API int __stdcall BAlertGetFlexDeviceModelForCurrentConnection(int& nDeviceModel, int&, float&);
+BMS_API int __stdcall BAlertGetFlexDeviceModelForCurrentConnectionStrip( int& nDeviceModel, int& nDetectedStripCode, float& nPercentageEstimate );
+BMS_API int __stdcall BAlertStartAcquisitionForCurrentConnection();
+BMS_API int __stdcall BAlertCloseCurrentConnection();
+BMS_API DWORD __stdcall BAlertEnumDevicesESUDetailsForCurrentConnection(DWORD dwConnectionHandle, PABMEnumESUsProc pEnumESUsProc, PABMEnumDAUsProc pEnumDAUsProc, TABMPortInfoEx* p);
+BMS_API int __stdcall BAlertFlexMeasureImpedancesForCurrentConnection( int nSensorConfig, int** naImpedances );
+BMS_API int __stdcall BAlertGetConnectedDevicePath(WCHAR* chDevicePath);
+
+BMS_API int __stdcall BAlertMakeConnection(WCHAR*);
+BMS_API int __stdcall BAlertConnectToPort( WCHAR* chDevicePath );
+
+BMS_API DWORD __stdcall BAlertGetPotentialThirdPartyPorts(int** pPortNumbers,int& nNumOfPorts);
+
+BMS_API int __stdcall BAlertGetBatteryPercOldDevices();
+
+BMS_API void __stdcall BAlertSetNoStripAllowed(BOOL bNoStripAllowed);
+
+BMS_API int __stdcall BAlertSendTPartyTest( int nSerialPort, int nDataLength, unsigned char* pucData );
+BMS_API int __stdcall BAlertGetThirdPartyPort( int& nThirdPartyPort );
+BMS_API int __stdcall BAlertGetThirdPartyPorts( int& nThirdPartyPorts, int** thirdPartyPorts);
+
+BMS_API BOOL __stdcall BAlertOpenLogFile();
+BMS_API void __stdcall BAlertSetDetailedLog(bool);
+BMS_API int __stdcall BAlertPingFlexBattery();
+BMS_API int __stdcall BAlertPreserveUSC();
+BMS_API int __stdcall BAlertGetSTDongleBTInfo(byte& bBTInfo);
+BMS_API int __stdcall BAlertGetLastUSCPair(DWORD& dwUSC, DWORD& dwCounter);
+BMS_API int __stdcall BAlertSendPCSync( int nComPort );
+
+
+BMS_API int __stdcall BAlertStartAcquisitionForCurrentConnectionLight();
+
+BMS_API void __stdcall BAlertSetLEHeadset(BOOL bLEDevice);
+
+BMS_API int __stdcall BAlertCheckLEDongleDriver();
\ No newline at end of file
diff --git a/physiolabxr/third_party/BAlert/SDK64/include/BMS/BMS_Comm/BMS_Comm.h b/physiolabxr/third_party/BAlert/SDK64/include/BMS/BMS_Comm/BMS_Comm.h
new file mode 100644
index 00000000..dcac0e9c
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/SDK64/include/BMS/BMS_Comm/BMS_Comm.h
@@ -0,0 +1,406 @@
+
+#include "CommLibDefs.h"
+
+
+//---------------------------------------------------------------------------
+
+/*!
+\brief Enumerates all ports supported by library
+\param pEnumPortsProc Pointer to an application-defined callback function. For more information, see PABMEnumPortsProc.
+\param p Pointer to an application-defined value to be passed to the callback function.
+\return Returns number of supported ports found.
+\remark No remarks.
+*/
+DWORD BmsCommLibEnumPorts(PABMEnumPortsProc pEnumPortsProc, TABMPortInfoEx* p);
+
+//---------------------------------------------------------------------------
+
+/*!
+\brief Connects to a communication port with specified device instance ID
+*/
+DWORD BmsCommLibConnect(WCHAR* pDeviceInstanceID);
+DWORD BmsCommLibConnectToExisting();
+
+/*!
+\brief Terminates connection with specified handle
+*/
+bool BmsCommLibDisconnect(DWORD dwConnectionHandle);
+bool BmsCommLibClosePort(DWORD dwConnectionHandle);
+bool BmsCommLibReopenPort(DWORD dwConnectionHandle);
+
+
+//---------------------------------------------------------------------------
+
+/*!
+\brief Enumerates all established connections
+*/
+DWORD BmsCommLibEnumConnections(PABMEnumConnectionsProc pEnumConnectionsProc, void* p);
+
+//---------------------------------------------------------------------------
+
+/*!
+\brief Gets information about connection with specified handle
+*/
+bool BmsCommLibGetConnectionInfo(DWORD dwConnectionHandle, TABMConnectionInfo* pConnectionInfo);
+
+//---------------------------------------------------------------------------
+
+/*!
+\brief Enumerates all ABM devices available on a connection with specified handle
+*/
+DWORD BmsCommLibEnumDevices(DWORD dwConnectionHandle, PABMEnumESUsProc pEnumESUsProc, PABMEnumDAUsProc pEnumDAUsProc, TABMPortInfoEx* p, bool, bool);
+
+DWORD BmsCommLibEnumDevicesKeepConnection(DWORD dwConnectionHandle, PABMEnumESUsProc pEnumESUsProc, PABMEnumDAUsProc pEnumDAUsProc, TABMPortInfoEx* p, bool, bool);
+
+//---------------------------------------------------------------------------
+
+/*!
+\brief Begins editing settings of external synchronization unit with specified handle
+*/
+bool BmsCommLibESUEditSettingsBegin(DWORD dwESUHandle);
+
+/*!
+\brief Ends editing settings of external synchronization unit with specified handle
+*/
+bool BmsCommLibESUEditSettingsEnd(DWORD dwESUHandle, bool bSaveChanges);
+
+/*!
+\brief Sets serial number of external synchronization unit with specified handle
+*/
+bool BmsCommLibESUSetSerialNumber(DWORD dwESUHandle, WCHAR SerialNumber[10]);
+
+/*!
+\brief Sets Bluetooth port settings of external synchronization unit with specified handle
+*/
+bool BmsCommLibESUSetBTPortSettings(DWORD dwESUHandle, TABMESUBTPortSettings* pBTPortSettings, BYTE bPortIndex);
+
+/*!
+\brief Sets serial port settings of external synchronization unit with specified handle
+*/
+bool BmsCommLibESUSetSERPortSettings(DWORD dwESUHandle, TABMESUSERPortSettings* pSERPortSettings, BYTE bPortIndex);
+
+/*!
+\brief Sets parallel port settings of external synchronization unit with specified handle
+*/
+bool BmsCommLibESUSetPARPortSettings(DWORD dwESUHandle, TABMESUPARPortSettings* pPARPortSettings);
+
+/*!
+\brief Sets debug byte of external synchronization unit with specified handle
+*/
+bool BmsCommLibESUSetDebugByte(DWORD dwESUHandle, BYTE bDebugByte);
+
+/*!
+\brief Automatically configure external synchronization unit for proper data transfer from data acquisition unit
+*/
+bool BmsCommLibESUAutoConfiguration(DWORD dwESUHandle, TABMDAUInfo* pDAUInfo);
+
+//---------------------------------------------------------------------------
+bool BmsCommLibPrepareForThirdPartyCheck(DWORD dwESUHandle);
+
+bool BmsCommLibGetThirdPartyCheckStatus(DWORD dwESUHandle);
+
+/*!
+\brief Gets information about external synchronization unit on a connection with specified handle
+*/
+bool BmsCommLibGetESUInfo(DWORD dwConnectionHandle, bool bReadFromMemory, TABMESUInfo* pESUInfo);
+
+//---------------------------------------------------------------------------
+
+/*!
+\brief Begins editing settings of data acquisition unit with specified handle
+*/
+bool BmsCommLibDAUEditSettingsBegin(DWORD dwDAUHandle);
+
+/*!
+\brief Ends editing settings of data acquisition unit with specified handle
+*/
+bool BmsCommLibDAUEditSettingsEnd(DWORD dwDAUHandle, bool bSaveChanges);
+
+/*!
+\brief Sets serial number of data acquisition unit with specified handle
+*/
+bool BmsCommLibDAUSetSerialNumber(DWORD dwDAUHandle, WCHAR SerialNumber[10]);
+
+/*!
+\brief Sets number of channels of data acquisition unit with specified handle
+*/
+bool BmsCommLibDAUSetNumberOfChannels(DWORD dwDAUHandle, BYTE bNumberOfChannels);
+
+/*!
+\brief Sets sample size in bytes of data acquisition unit with specified handle.
+*/
+bool BmsCommLibDAUSetSampleSizeInBytes(DWORD dwDAUHandle, BYTE bSampleSizeInBytes);
+
+/*!
+\brief Sets ECG channel number of data acquisition unit with specified handle.
+*/
+bool BmsCommLibDAUSetECGChannel(DWORD dwDAUHandle, BYTE bECGChannel);
+
+// /* !
+// \brief DAU configuration function, do not use (internal use only)
+// */
+// bool CommLibDAUSetCutOffFrequency(DWORD dwDAUHandle, WORD wCutOffFrequency);
+// /* !
+// \brief DAU configuration function, do not use (internal use only)
+// */
+// bool CommLibDAUSetReconfigurableChannelGains(DWORD dwDAUHandle, TABMReconfigurableChannelGains* pReconfigurableChannelGains);
+/*!
+\brief Sets tilt transmision of data acquisition unit with specified handle
+*/
+bool BmsCommLibDAUSetTiltTransmitted(DWORD dwDAUHandle, bool bTiltTransmited);
+
+/*!
+\brief Sets BDA number for data acquisition unit with specified handle to connect to
+*/
+bool BmsCommLibDAUSetBDA(DWORD dwDAUHandle, WCHAR BDA[13]);
+
+/*!
+\brief Sets gain calibration data for data acquisition unit with specified handle
+*/
+bool BmsCommLibDAUSetGainCalibrationData(DWORD dwDAUHandle, TABMGainCalibrationData* pGainCalibrationData);
+
+/*!
+\brief Sets impedance calibration data for data acquisition unit with specified handle
+*/
+bool BmsCommLibDAUSetImpedanceCalibrationData(DWORD dwDAUHandle, TABMImpedanceCalibrationData* pImpedanceCalibrationData);
+
+/*!
+\brief Sets channel pin mapping data for data acquisition unit with specified handle
+*/
+bool BmsCommLibDAUSetChannelsPinMappingData(DWORD dwDAUHandle, TABMChannelsPinMappingData* pChannelsPinMappingData);
+
+/*!
+\brief Sets EEG DC offset for data acquisition unit with specified handle
+*/
+bool BmsCommLibDAUSetEEGDCOffsetData(DWORD dwDAUHandle, TABMEEGDCOffsetData* pEEGDCOffsetData);
+
+//---------------------------------------------------------------------------
+
+/*!
+\brief Gets information about data acquisition unit with specified handle
+*/
+bool BmsCommLibGetDAUInfo(DWORD dwDAUHandle, bool bReadFromMemory, TABMDAUInfo* pDAUInfo);
+
+//---------------------------------------------------------------------------
+
+/*!
+\brief Sets working mode of a data acquisition unit with specified handle
+*/
+bool BmsCommLibSetWorkingMode(DWORD dwDAUHandle, WORD wNewWorkingMode, WORD* wActualWorkingMode);
+
+/*!
+\brief Sets acquisition data block type on a data acquisition unit with specified handle
+*/
+bool BmsCommLibSetAcquisitionDataBlockType(DWORD dwDAUHandle, DWORD dwNewDataBlockType, DWORD* dwActualDataBlockType);
+
+/*!
+\brief Sets real time clock
+*/
+bool BmsCommLibSetRealTimeClock(DWORD dwDAUHandle, BYTE bYear, BYTE bMonth, BYTE bDay, BYTE bHours, BYTE bMinutes, BYTE bSeconds);
+
+//---------------------------------------------------------------------------
+
+/*!
+\brief Stops data acquisition on a data acquisition unit with specified handle
+*/
+bool BmsCommLibStopAcquisition(DWORD dwDAUHandle);
+
+bool BmsCommLibPingStartAcquisition(DWORD dwDAUHandle, bool bSaveToSDCard);
+
+/*!
+\brief Starts data acquisition on a data acquisition unit with specified handle
+*/
+bool BmsCommLibStartAcquisition(DWORD dwDAUHandle, bool bSaveToSDCard);
+
+//---------------------------------------------------------------------------
+
+/*!
+\brief Sends bytes to a data acquisition unit with specified handle without waiting for responce
+*/
+bool BmsCommLibSendBytesToDAU(DWORD dwDAUHandle,unsigned char* pBytes, int nBytes, int nRetry, int nPause);
+
+
+//---------------------------------------------------------------------------
+
+/*!
+\brief Sets application-defined callback function used for unbuffered output of raw samples from data acquisition unit with specified handle
+*/
+bool BmsCommLibSetCallbackOnNewRawSample(DWORD dwDAUHandle, PABMOnNewRawSample pOnNewRawSample, void* p);
+
+/*!
+\brief Sets application-defined callback function used for unbuffered output of samples from data acquisition unit with specified handle
+*/
+bool BmsCommLibSetCallbackOnNewSample(DWORD dwDAUHandle, PABMOnNewSample pOnNewSample, void* p);
+
+/*!
+\brief Sets application-defined callback function used for unbuffered output of accelerometer data from data acquisition unit with specified handle
+*/
+bool BmsCommLibSetCallbackOnNewTilt(DWORD dwDAUHandle, PABMOnNewTilt pOnNewTilt, void* p);
+
+/*!
+\brief Sets application-defined callback function used for unbuffered output of optical channel data from data acquisition unit with specified handle
+*/
+bool BmsCommLibSetCallbackOnNewIRed(DWORD dwDAUHandle, PABMOnNewIRed pOnNewIRed, void* p);
+
+/*!
+\brief Sets application-defined callback function used for unbuffered output of optical channel data from data acquisition unit with specified handle
+*/
+bool BmsCommLibSetCallbackOnNewRed(DWORD dwDAUHandle, PABMOnNewRed pOnNewRed, void* p);
+
+/*!
+\brief Sets application-defined callback function used for unbuffered output of mic data from data acquisition unit with specified handle
+*/
+bool BmsCommLibSetCallbackOnNewMic(DWORD dwDAUHandle, PABMOnNewMicData pOnNewMic, void* p);
+
+/*!
+\brief Sets application-defined callback function used for unbuffered output of mic data from data acquisition unit with specified handle
+*/
+bool BmsCommLibSetCallbackOnNewIRedRaw(DWORD dwDAUHandle, PABMOnNewIRedRawData pOnNewIRedRaw, void* p);
+
+/*!
+\brief Sets application-defined callback function used for unbuffered output of mic data from data acquisition unit with specified handle
+*/
+bool BmsCommLibSetCallbackOnNewTechnicalChannel(DWORD dwDAUHandle, PABMOnNewTechnicalChannel pOnNewTechnicalChannelData, void* p);
+
+
+/*!
+\brief Sets application-defined callback function used for real time notification about new data acquired from slow channels from data acquisition unit with specified handle
+*/
+bool BmsCommLibSetCallbackOnNewSlowChannels(DWORD dwDAUHandle, PABMOnNewSlowChannels pOnNewSlowChannels, void* p);
+
+/*!
+\brief Sets application-defined callback function used for unbuffered output of timestamps from data acquisition unit with specified handle
+*/
+bool BmsCommLibSetCallbackOnNewTimestamp(DWORD dwDAUHandle, PABMOnNewTimestamp pOnNewTimestamp, void* p);
+
+/*!
+\brief Sets application-defined callback function used for unbuffered output of third party data from connection where DAU with specified handle is connected
+*/
+bool BmsCommLibSetCallbackOnNewThirdPartyData(DWORD dwDAUHandle, PABMOnNewThirdPartyData pOnNewThirdPartyData, void* p);
+
+/*!
+\brief Sets application-defined callback function used for unbuffered output of miscellaneous data from data acquisition unit with specified handle
+*/
+bool BmsCommLibSetCallbackOnNewProbeData(DWORD dwDAUHandle, PABMOnNewProbeData pOnNewProbeData, void* p);
+
+//---------------------------------------------------------------------------
+
+/*!
+\brief Gets number of raw samples pending in buffered output from data acquisition unit with specified handle
+*/
+DWORD BmsCommLibGetRawSamplePending(DWORD dwDAUHandle);
+
+/*!
+\brief Gets number of samples pending in buffered output from data acquisition unit with specified handle
+*/
+DWORD BmsCommLibGetSamplePending(DWORD dwDAUHandle);
+
+/*!
+\brief Gets number of accelerometer data pending in buffered output from data acquisition unit with specified handle
+*/
+DWORD BmsCommLibGetTiltPending(DWORD dwDAUHandle);
+
+/*!
+\brief Gets number of optical channel data pending in buffered output from data acquisition unit with specified handle
+*/
+DWORD BmsCommLibGetIRedPending(DWORD dwDAUHandle);
+
+/*!
+\brief Gets number of red pending in buffered output from data acquisition unit with specified handle
+*/
+DWORD BmsCommLibGetRedPending(DWORD dwDAUHandle);
+
+/*!
+\brief Gets number of mic pending in buffered output from data acquisition unit with specified handle
+*/
+DWORD BmsCommLibGetMicPending(DWORD dwDAUHandle);
+
+/*!
+\brief Gets number of timestamps pending in buffered output from data acquisition unit with specified handle
+*/
+DWORD BmsCommLibGetTimestampPending(DWORD dwDAUHandle);
+
+/*!
+\brief Gets number of third party data bytes pending in buffered output from data acquisition unit with specified handle
+*/
+DWORD BmsCommLibGetThirdPartyDataPending(DWORD dwDAUHandle);
+
+/*!
+\brief Gets number of misc data pending in buffered output from data acquisition unit with specified handle
+*/
+DWORD BmsCommLibGetProbeDataPending(DWORD dwDAUHandle);
+
+//---------------------------------------------------------------------------
+
+/*!
+\brief Reads samples pending in buffered output from data acquisition unit with specified handle
+*/
+bool BmsCommLibGetRawSample(DWORD dwDAUHandle, TABMRawSampleInfo* pRawSampleInfo, DWORD dwCount, DWORD* dwActualCount);
+
+/*!
+\brief Reads raw samples pending in buffered output from data acquisition unit with specified handle
+*/
+bool BmsCommLibGetSample(DWORD dwDAUHandle, TABMSampleInfo* pSampleInfo, DWORD dwCount, DWORD* dwActualCount);
+
+/*!
+\brief Reads accelerometer data pending in buffered output from data acquisition unit with specified handle
+*/
+bool BmsCommLibGetTilt(DWORD dwDAUHandle, TABMTiltInfo* pTiltInfo, DWORD dwCount, DWORD* dwActualCount);
+
+/*!
+\brief Reads optical channel data pending in buffered output from data acquisition unit with specified handle
+*/
+bool BmsCommLibGetIRed(DWORD dwDAUHandle, TABMIRedInfo* pIRedInfo, DWORD dwCount, DWORD* dwActualCount);
+
+/*!
+\brief Reads optical channel data pending in buffered output from data acquisition unit with specified handle
+*/
+bool BmsCommLibGetRed(DWORD dwDAUHandle, TABMRedInfo* pRedInfo, DWORD dwCount, DWORD* dwActualCount);
+
+/*!
+\brief Reads mic data pending in buffered output from data acquisition unit with specified handle
+*/
+bool BmsCommLibGetMic(DWORD dwDAUHandle, TABMMicInfo* pMicInfo, DWORD dwCount, DWORD* dwActualCount);
+
+
+/*!
+\brief Reads IRedRaw data pending in buffered output from data acquisition unit with specified handle
+*/
+bool BmsCommLibGetIRedRaw(DWORD dwDAUHandle, TABMIRedRawInfo* pIRedRawInfo, DWORD dwCount, DWORD* dwActualCount);
+
+/*!
+\brief Reads Technical Channel data pending in buffered output from data acquisition unit with specified handle
+*/
+bool BmsCommLibGetTechnicalChannel(DWORD dwDAUHandle, TABMTechnicalChannelInfo* pTechnicalChannelInfo, DWORD dwCount, DWORD* dwActualCount);
+
+/*!
+\brief Reads data acquired from slow channels from data acquisition unit with specified handle
+*/
+bool BmsCommLibGetSlowChannels(DWORD dwDAUHandle, TABMSlowChannelsInfo* pSlowChannelsInfo);
+
+/*!
+\brief Reads timestamps pending in buffered output from data acquisition unit with specified handle
+*/
+bool BmsCommLibGetTimestamp(DWORD dwDAUHandle, TABMTimestampInfo* pTimestampInfo, DWORD dwCount, DWORD* dwActualCount);
+
+/*!
+\brief Reads third party data pending in buffered output from data acquisition unit with specified handle
+*/
+bool BmsCommLibGetThirdPartyData(DWORD dwDAUHandle, BYTE* pBuffer, DWORD dwCount, DWORD* dwActualCount);
+
+/*!
+\brief Reads probe data pending in buffered output from data acquisition unit with specified handle
+*/
+bool BmsCommLibGetProbeData(DWORD dwDAUHandle, TABMProbeDataInfo* pProbeDataInfo, DWORD dwCount, DWORD* dwActualCount);
+
+//---------------------------------------------------------------------------
+
+
+
+bool BmsCommLibSetCallbackOnNewTechnicalChannel(DWORD dwDAUHandle, PABMOnNewTechnicalChannel pOnNewTechnicalCh, void* p);
+
+bool BmsCommLibConnectToPort(WCHAR* chDevicepath);
+
+
+bool BmsCommLibESUQuickQuery(DWORD dwESUHandle, BYTE& bBTInfo, BYTE& bAUXInfo);
+bool BmsCommLibPreserveUSC(DWORD dwDAUHandle);
\ No newline at end of file
diff --git a/physiolabxr/third_party/BAlert/SDK64/include/BMS/BMS_Comm/CommLibDefs.h b/physiolabxr/third_party/BAlert/SDK64/include/BMS/BMS_Comm/CommLibDefs.h
new file mode 100644
index 00000000..7f418420
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/SDK64/include/BMS/BMS_Comm/CommLibDefs.h
@@ -0,0 +1,637 @@
+#pragma once
+
+#ifndef _COMMLIBDEFS_H
+#define _COMMLIBDEFS_H
+
+#include
+#include
+
+//---------------------------------------------------------------------------
+
+#define ABM_MAX_DAU_HARDWARE_CHANNELS 24
+
+//---------------------------------------------------------------------------
+
+/*!
+\brief CommLib error codes
+*/
+typedef enum
+{
+ ABM_COMMLIB_ERR_NO_ERROR = 0x00000000,
+ ABM_COMMLIB_ERR_APPLICATION_ERR_BASE = 0x10000000, /* Check SetLastError MSDN reference for more info */
+ ABM_COMMLIB_ERR_NOT_IMPLEMENTED = 0x10000010,
+ ABM_COMMLIB_ERR_NOT_SUPPORTED = 0x10000020,
+
+ ABM_COMMLIB_ERR_INVALID_PARAMETER = 0x10000100,
+
+ ABM_COMMLIB_ERR_INVALID_PORTINFO = 0x10000110,
+ ABM_COMMLIB_ERR_INVALID_CONNECTION_HANDLE = 0x10000120,
+
+ ABM_COMMLIB_ERR_INVALID_ESU_HANDLE = 0x10000140,
+
+ ABM_COMMLIB_ERR_INVALID_DAU_HANDLE = 0x10000140,
+
+ ABM_COMMLIB_ERR_NOT_SUPPORTED_BY_PROTOCOL = 0x10000420,
+ ABM_COMMLIB_ERR_INVALID_DEVICE_STATE = 0x10000430,
+ ABM_COMMLIB_ERR_INVALID_COMMAND_PARAMETER = 0x10000440,
+ ABM_COMMLIB_ERR_COMMAND_RESPONSE_TIMEOUT = 0x10000450
+} TABMCommLibError; /* SetLastError/GetLastError */
+
+//---------------------------------------------------------------------------
+
+/*!
+\brief Supported port types
+*/
+typedef enum
+{
+ ABM_PORT_TYPE_UNKNOWN = 0x00,
+ ABM_PORT_TYPE_SERIAL = 0x01,
+ ABM_PORT_TYPE_USBEXPRESS = 0x02
+} TABMPortType;
+
+/*!
+\brief Information about port used for connecting to ABM devices
+*/
+typedef struct
+{
+ WCHAR FriendlyName[MAX_PATH];
+ WCHAR DeviceInstanceID[MAX_PATH];
+ TABMPortType PortType;
+
+} TABMPortInfo;
+
+/*!
+\brief Extended information about port used for communication with ABM devices (internal use only)
+*/
+typedef struct
+{
+ TABMPortInfo PortInfo;
+ WCHAR DevicePath[MAX_PATH];
+} TABMPortInfoEx;
+
+/*!
+\brief Port statistics (internal use only)
+*/
+typedef struct
+{
+ DWORD TotalBytesRX;
+ DWORD TotalBytesTX;
+} TABMPortStat;
+
+//---------------------------------------------------------------------------
+
+/*!
+\brief Information about connection to port used for communication with ABM devices
+*/
+typedef struct
+{
+ DWORD Handle;
+ TABMPortInfo PortInfo;
+} TABMConnectionInfo;
+
+//---------------------------------------------------------------------------
+
+/*!
+\brief Information about BlueTooth device detected by ESU during searching mode
+*/
+typedef struct
+{
+ WCHAR BDA[13];
+ WCHAR FriendlyName[33];
+} TABMBTDeviceInfo;
+
+//---------------------------------------------------------------------------
+
+/*!
+\brief Supported external synchronization unit types
+*/
+typedef enum
+{
+ ABM_ESU_TYPE_UNKNOWN = 0x00,
+ ABM_ESU_TYPE_DONGLE = 0x01,
+ ABM_ESU_TYPE_SINGLE_CHANNEL = 0x02,
+ ABM_ESU_TYPE_MULTI_CHANNEL = 0x03,
+ ABM_ESU_TYPE_SMART_DONGLE = 0x04,
+ ABM_ESU_TYPE_SMART_MULTI_CHANNEL = 0x05,
+ ABM_ESU_TYPE_BL654_LE_DONGLE = 0x06
+} TABMESUType;
+
+#define IsESUSingleChannel(X) ((X == ABM_ESU_TYPE_DONGLE) || (X == ABM_ESU_TYPE_SMART_DONGLE) || (X == ABM_ESU_TYPE_SINGLE_CHANNEL) || (X == ABM_ESU_TYPE_BL654_LE_DONGLE))
+#define IsADongle(X) ((X == ABM_ESU_TYPE_DONGLE) || (X == ABM_ESU_TYPE_SMART_DONGLE) || (X == ABM_ESU_TYPE_BL654_LE_DONGLE))
+
+/*!
+\brief Possible states of external synchronization unit
+*/
+typedef enum
+{
+ ABM_ESU_STATE_UNKNOWN = 0x00,
+ ABM_ESU_STATE_NOT_INITIALIZED = 0x01,
+ ABM_ESU_STATE_READY = 0x02,
+ ABM_ESU_STATE_ENUMERATING_BT_DEVICES = 0x03,
+ ABM_ESU_STATE_MEMORY_EDITING = 0x04
+} TABMESUState;
+
+/*!
+\brief ESU Bluetooth port settings
+*/
+typedef struct
+{
+ BYTE BDA[13];
+ BYTE ModuleType;
+ BYTE BoardType;
+ BYTE Delay;
+ bool TimestampProcessing;
+} TABMESUBTPortSettings;
+
+/*!
+\brief ESU serial port settings
+*/
+typedef struct
+{
+ BYTE Protocol;
+ BYTE Delay;
+} TABMESUSERPortSettings;
+
+/*!
+\brief ESU parallel port settings
+*/
+typedef struct
+{
+ BYTE Protocol;
+ BYTE Delay;
+} TABMESUPARPortSettings;
+
+/*!
+\brief Information about external synchronization unit
+*/
+typedef struct
+{
+ DWORD Handle;
+ TABMConnectionInfo ConnectionInfo;
+ bool Initialized;
+ BYTE ProtocolVersion;
+
+ TABMESUType ESUType;
+
+ WCHAR FirmwareVersion[5];
+ WCHAR SerialNumber[10];
+
+ WCHAR FriendlyName[33];
+
+ TABMESUBTPortSettings BTPortSettings[2];
+ TABMESUSERPortSettings SERPortSettings[4];
+ TABMESUPARPortSettings PARPortSettings;
+
+ BYTE Debug;
+} TABMESUInfo;
+
+//---------------------------------------------------------------------------
+
+/*!
+\brief Supported data acquisition unit types
+*/
+typedef enum
+{
+ ABM_DAU_TYPE_UNKNOWN = 0x00,
+ ABM_DAU_TYPE_06CH_16BIT = 0x01,
+ ABM_DAU_TYPE_04CH_16BIT_TILT_IRED = 0x01,
+ ABM_DAU_TYPE_06CH_24BIT = 0x02,
+ ABM_DAU_TYPE_09CH_24BIT = 0x03,
+ ABM_DAU_TYPE_04CH_24BIT = 0x04,
+ ABM_DAU_TYPE_10CH_16BIT_TILT = 0x05,
+ ABM_DAU_TYPE_04CH_16BIT_TILT = 0x06,
+ ABM_DAU_TYPE_10CH_16BIT = 0x07,
+ ABM_DAU_TYPE_10CH_24BIT = 0x08,
+ ABM_DAU_TYPE_10CH_24BIT_TILT = 0x09,
+ ABM_DAU_TYPE_24CH_16BIT = 0x0A,
+ ABM_DAU_TYPE_24CH_16BIT_TILT = 0x0B
+} TABMDAUType;
+
+/*!
+\brief Possible states of data acquisition unit
+*/
+typedef enum
+{
+ ABM_DAU_STATE_UNKNOWN = 0x00,
+ ABM_DAU_STATE_NOT_INITIALIZED = 0x01,
+ ABM_DAU_STATE_READY = 0x02,
+ ABM_DAU_STATE_MEMORY_EDITING = 0x03,
+ ABM_DAU_STATE_ACQUISITION = 0x04,
+ ABM_DAU_STATE_IMPEDANCE = 0x05,
+ ABM_DAU_STATE_TECHNICAL_MONITORING = 0x06
+} TABMDAUState;
+
+/*!
+\brief Possible working submodes of data acquisition unit
+*/
+typedef enum
+{
+ ABM_WORKING_SUBMODE_UNKNOWN = 0x0000,
+ ABM_WORKING_SUBMODE_STARTUP_INIT = 0x0111,
+ ABM_WORKING_SUBMODE_STARTUP_BTINIT = 0x0112,
+ ABM_WORKING_SUBMODE_STARTUP_BTHOSTINIT = 0x0113,
+ ABM_WORKING_SUBMODE_STARTUP_BTHOSTWAIT = 0x0114,
+ ABM_WORKING_SUBMODE_STARTUP_BTSLAVEINIT = 0x0115,
+ ABM_WORKING_SUBMODE_STARTUP_BTSLAVEWAIT = 0x0116,
+ ABM_WORKING_SUBMODE_BOOTSTRAP_INIT = 0x0221,
+ ABM_WORKING_SUBMODE_BOOTSTRAP_SDUPLOAD = 0x0222,
+ ABM_WORKING_SUBMODE_BOOTSTRAP_BTUPLOAD = 0x0223,
+ ABM_WORKING_SUBMODE_INIT_MANAGEMENT = 0x0331,
+ ABM_WORKING_SUBMODE_INIT_STUDY = 0x0332,
+
+ ABM_WORKING_SUBMODE_ACQUISITION_BT_SD = 0x0441,
+ ABM_WORKING_SUBMODE_ACQUISITION_BT = 0x0442,
+ ABM_WORKING_SUBMODE_ACQUISITION_SD = 0x0443,
+ ABM_WORKING_SUBMODE_ACQUISITION_SHUTDOWN = 0x0444,
+ ABM_WORKING_SUBMODE_ACQUISITION_ERROR = 0x0445,
+ ABM_WORKING_SUBMODE_ACQUISITION_TIMEOUT = 0x0446,
+ ABM_WORKING_SUBMODE_ACQUISITION_VOLTAGE = 0x0447,
+ ABM_WORKING_SUBMODE_COMMUNICATION_ACTIVE = 0x0551,
+ ABM_WORKING_SUBMODE_ERROR_HW = 0x0EE1,
+ ABM_WORKING_SUBMODE_ERROR_BATTLOW = 0x0EE2,
+ ABM_WORKING_SUBMODE_ERROR_BATTERR = 0x0EE3,
+ ABM_WORKING_SUBMODE_LOWPOWER_OFF = 0x0FF1,
+ ABM_WORKING_SUBMODE_LOWPOWER_TIMEOUT = 0x0FF2
+} TABMDAUWorkingSubmode;
+
+/* !
+\brief Reconfigurable channel gains settings of data acquisition unit
+*/
+//typedef BYTE TABMReconfigurableChannelGains[4];
+
+/*!
+\brief Gain calibration settings of data acquisition unit
+*/
+typedef short TABMGainCalibrationData[ABM_MAX_DAU_HARDWARE_CHANNELS];
+
+/*!
+\brief Impedance calibration settings of data acquisition unit
+*/
+typedef short TABMImpedanceCalibrationData[ABM_MAX_DAU_HARDWARE_CHANNELS];
+
+/*!
+\brief Channels pin mapping settings of data acquisition unit
+*/
+typedef BYTE TABMChannelsPinMappingData[2 * ABM_MAX_DAU_HARDWARE_CHANNELS];
+
+/*!
+\brief DC offset settings of data acquisition unit
+*/
+typedef short TABMEEGDCOffsetData[ABM_MAX_DAU_HARDWARE_CHANNELS];
+
+/*!
+\brief Information about data acquisition unit
+*/
+typedef struct
+{
+ DWORD Handle;
+ TABMConnectionInfo ConnectionInfo;
+ bool Initialized;
+ BYTE ProtocolVersion;
+
+ WCHAR SerialNumberHost[17];
+ WCHAR HardwareVersionHost[5];
+ WCHAR FirmwareVersionHost[12];
+
+ WCHAR SerialNumberHostSys[17];
+ WCHAR ReleaseHostSys[9];
+
+ WCHAR SerialNumberAcq[17];
+ WCHAR HardwareVersionAcq[5];
+ WCHAR FirmwareVersionAcq[12];
+
+ WCHAR SerialNumberAcqSys[17];
+ WCHAR ReleaseAcqSys[9];
+
+ WCHAR SerialNumberAdc[17];
+ WCHAR HardwareVersionAdc[5];
+
+ short TxOffset;
+ short RxOffset;
+ bool TiltTransmitted;
+ bool CalibrationMemoryPresent;
+ bool CalibrationMemoryInitialized;
+ WCHAR BDA[13];
+
+ WORD HeadsetImpedancePinConfiguration;
+
+ /* 4x16, 4x24, 9x16, 9x24, 10x16, 10x24, 24x16 */
+ WORD SamplingRate; /* 128, 256, 512, ... */
+ BYTE NumberOfChannels; /* 4, 9, 10, 24 */
+ bool IRedChannelPresent;
+ bool ExtendedX4Packet;
+ bool MICChannelPresent;
+ bool IRedRawChannelPresent;
+ bool TCChannelsPresent;
+ BYTE SampleSizeInBytes; /* 2, 3 */
+ BYTE SampleBlocksPerPacket; /* 1 for 24ch, 2 for all other */
+ BYTE SampleBlockSizeInBytes; /* NumberOfChannels * SampleSizeInBytes */
+ BYTE AcquisitionDataSizeInBytes; /* SampleBlocksPerPacket * SampleBlockSizeInBytes */
+ BYTE AccelerometerDataSizeInBytes; /* 0, 6 */
+ BYTE AcquisitionPacketSizeInBytes; /* 5 + AcquisitionDataSizeInBytes + AccelerometerDataSizeInBytes */
+ bool ECGChannelPresent;
+ BYTE ECGChannelNumber;
+
+ WCHAR FriendlyName[33];
+
+ TABMGainCalibrationData GainCalibrationData;
+ TABMImpedanceCalibrationData ImpedanceCalibrationData;
+ TABMChannelsPinMappingData ChannelsPinMappingData;
+ TABMEEGDCOffsetData EEGDCOffsetData;
+
+ float GainCoefficients[24];
+} TABMDAUInfo;
+
+//---------------------------------------------------------------------------
+
+/*!
+\brief Information about data acquisition unit
+*/
+typedef struct
+{
+ DWORD DAUHandle;
+
+ BYTE BlockType;
+ BYTE ByteOrder;
+
+ BYTE ProtocolStatus; // ?
+
+ BYTE Unused01;
+
+ WORD WorkingSubMode;
+
+ WORD SamplingRate; /* 128, 256, 512, ... */
+
+ BYTE NumberOfChannels; /* 4, 9, 10, 24 */
+ bool IRedChannelPresent;
+ bool RedChannelPresent;
+ bool MicChannelPresent;
+ bool ECGChannelPresent;
+ BYTE ECGChannelNumber;
+
+ BYTE SampleSizeInBytes; /* 2, 3 */
+ BYTE SampleBlocksPerPacket; /* 1 for 4ch and 24ch, 2 for all other */
+ BYTE SampleBlockSizeInBytes; /* NumberOfChannels * SampleSizeInBytes */
+ BYTE AcquisitionDataSizeInBytes; /* SampleBlocksPerPacket * SampleBlockSizeInBytes */
+ BYTE AccelerometerDataSizeInBytes; /* 0, 6 */
+ BYTE AcquisitionPacketSizeInBytes; /* 5 + AcquisitionDataSizeInBytes + AccelerometerDataSizeInBytes */
+
+//#pragma message (__LOCATION__ "TABMAcquisitionDataInfo: Define this structure!!!\n")
+} TABMAcquisitionDataInfo;
+
+/*!
+\brief One 16-bit raw sample for one channel
+*/
+typedef struct
+{
+ BYTE Low;
+ BYTE High;
+} TABMSample16;
+
+/*!\brief One 24-bit raw sample for one channel
+*/
+typedef struct
+{
+ BYTE High;
+ BYTE Mid;
+ BYTE Low;
+} TABMSample24;
+
+/*!
+\brief Set of raw samples for all channels
+*/
+typedef struct
+{
+ WORD Counter;
+ union
+ {
+ BYTE Bytes[72]; /* Size of this array is a size of largest array in bytes */
+ TABMSample16 Samples16[ABM_MAX_DAU_HARDWARE_CHANNELS];
+ TABMSample24 Samples24[ABM_MAX_DAU_HARDWARE_CHANNELS];
+ };
+} TABMRawSampleInfo; /* NOTE - Holds bytes for ONE sample only */
+
+/*!
+\brief Set of integer samples for all channels (internal use only)
+*/
+typedef struct
+{
+ WORD Counter;
+ int Samples[ABM_MAX_DAU_HARDWARE_CHANNELS];
+} TABMSampleIntegersInfo;
+
+/*!
+\brief Set of float samples for all channels
+*/
+typedef struct
+{
+ WORD Counter;
+ float Samples[ABM_MAX_DAU_HARDWARE_CHANNELS];
+} TABMSampleInfo;
+
+/*!
+\brief Accelerometer data
+*/
+typedef struct
+{
+ WORD Counter;
+ short X;
+ short Y;
+ short Z;
+} TABMTiltInfo;
+
+/*!
+\brief Optical channel data
+*/
+typedef struct
+{
+ WORD Counter;
+ WORD IRed;
+} TABMIRedInfo;
+
+/*!
+\brief Optical channel data
+*/
+typedef struct
+{
+ WORD Counter;
+ WORD Red;
+} TABMRedInfo;
+
+/*!
+\brief Mic data
+*/
+typedef struct
+{
+ WORD Counter;
+ WORD Mic;
+} TABMMicInfo;
+
+/*!
+\brief Data acquired from slow channels
+*/
+typedef struct
+{
+ WORD PassCounter;
+ WORD BatteryVoltageWORD;
+ float BatteryVoltage;
+ WORD VCCWORD;
+ float VCC;
+ WORD TemperatureHostWORD;
+ float TemperatureHost;
+ WORD TemperatureAcqWORD;
+ float TemperatureAcq;
+ BYTE ImpedanceLevelAndChannel;
+ WORD RfSerialNumber;
+ DWORD Timestamp;
+ BYTE CustomMarkA;
+ BYTE CustomMarkB;
+ BYTE CustomMarkC;
+ BYTE CustomMarkD;
+ BYTE OnLineImpStatus;
+ BYTE OnLineImpValues[24];
+ WORD TechEvent;
+} TABMSlowChannelsInfo;
+
+/*!
+\brief Timestamp acquired from external synchronization unit
+*/
+typedef struct
+{
+//#ifdef LONG_COUNTER
+ int Counter;
+//#else
+// WORD Counter;
+//#endif
+ DWORD Timestamp;
+} TABMTimestampInfo;
+
+/*!
+\brief Miscellaneous data acquired
+*/
+typedef struct
+{
+ WORD Counter;
+ WORD Haptic;
+} TABMProbeDataInfo;
+
+
+/*!
+\brief IRedRAw data acquired
+*/
+typedef struct
+{
+ WORD Counter;
+ WORD IRedRaw;
+} TABMIRedRawInfo;
+
+
+/*!
+\brief Technical channel data acquired
+*/
+typedef struct
+{
+ WORD Counter;
+ BYTE BatteryVoltage;
+ BYTE ImpedanceR1R2;
+ BYTE ImpedanceR3R4;
+ BYTE AlarmAlert;
+} TABMTechnicalChannelInfo;
+
+
+//---------------------------------------------------------------------------
+
+/*!
+\brief Pointer to application-defined callback function used for enumerating supported ports available on system
+*/
+typedef bool (__stdcall *PABMEnumPortsProc)(const TABMPortInfoEx*, void*, bool bReadDeviceDetails, bool bReadESUDetails);
+
+/*!
+\brief Pointer to application-defined callback function used for enumerating established connections
+*/
+typedef bool (__stdcall *PABMEnumConnectionsProc)(const TABMConnectionInfo*, void*);
+
+/*!
+\brief Pointer to application-defined callback function used for enumerating BlueTooth devices in range
+*/
+typedef bool (__stdcall *PABMEnumBTDevicesProc)(const TABMBTDeviceInfo*, void*);
+
+/*!
+\brief Pointer to application-defined callback function used for enumerating available external synchronization units
+*/
+typedef bool (__stdcall *PABMEnumESUsProc)(const TABMESUInfo*, void*);
+
+/*!
+\brief Pointer to application-defined callback function used for enumerating available data acquisition units
+*/
+typedef bool (__stdcall *PABMEnumDAUsProc)(const TABMDAUInfo*, void*);
+
+//---------------------------------------------------------------------------
+
+/*!
+\brief Pointer to application-defined callback function used for unbuffered output of raw samples
+*/
+typedef void (__stdcall *PABMOnNewRawSample)(const TABMRawSampleInfo*, void*);
+
+/*!
+\brief Pointer to application-defined callback function used for unbuffered output of samples
+*/
+typedef void (__stdcall *PABMOnNewSample)(const TABMSampleInfo*, void*);
+
+/*!
+\brief Pointer to application-defined callback function used for unbuffered output of accelerometer data
+*/
+typedef void (__stdcall *PABMOnNewTilt)(const TABMTiltInfo*, void*);
+
+/*!
+\brief Pointer to application-defined callback function used for unbuffered output of optical channel data
+*/
+typedef void (__stdcall *PABMOnNewIRed)(const TABMIRedInfo*, void*);
+
+/*!
+\brief Pointer to application-defined callback function used for unbuffered output of optical channel data
+*/
+typedef void (__stdcall *PABMOnNewRed)(const TABMRedInfo*, void*);
+
+
+/*!
+\brief Pointer to application-defined callback function used for real time notification about new data acquired from slow channels
+*/
+typedef void (__stdcall *PABMOnNewSlowChannels)(const TABMSlowChannelsInfo*, void*);
+
+/*!
+\brief Pointer to application-defined callback function used for unbuffered output of timestamps
+*/
+typedef void (__stdcall *PABMOnNewTimestamp)(const TABMTimestampInfo*, void*);
+
+/*!
+\brief Pointer to application-defined callback function used for unbuffered output of third party data
+*/
+typedef void (__stdcall *PABMOnNewThirdPartyData)(const BYTE*, const DWORD, void*);
+
+/*!
+\brief Pointer to application-defined callback function used for unbuffered output of probe data
+*/
+typedef void (__stdcall *PABMOnNewProbeData)(const TABMProbeDataInfo*, void*);
+
+/*!
+\brief Pointer to application-defined callback function used for unbuffered output of MIC data
+*/
+typedef void (__stdcall *PABMOnNewMicData)(const TABMMicInfo*, void*);
+
+/*!
+\brief Pointer to application-defined callback function used for unbuffered output of IRedRaw data
+*/
+typedef void (__stdcall *PABMOnNewIRedRawData)(const TABMIRedRawInfo*, void*);
+
+/*!
+\brief Pointer to application-defined callback function used for unbuffered output of Technical Channel data
+*/
+typedef void (__stdcall *PABMOnNewTechnicalChannel)(const TABMTechnicalChannelInfo*, void*);
+
+
+
+//---------------------------------------------------------------------------
+
+
+#endif
diff --git a/physiolabxr/third_party/BAlert/SDK64/include/BMS/FleXProtocol_DLLErrors.h b/physiolabxr/third_party/BAlert/SDK64/include/BMS/FleXProtocol_DLLErrors.h
new file mode 100644
index 00000000..39462a0b
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/SDK64/include/BMS/FleXProtocol_DLLErrors.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#define SUCCESS 1
+
+#define NOT_FIND_CONNECTED_ESUDONGLE -101
+#define NOT_IDENTIFY_ESUDONGLE -102
+#define NOT_ATTACHED_DEVICE_TO_USB -103
+#define NOT_ACCESSIBLE_DEVICE -104
+#define NOT_UPDATED_SYSTEM_FILE -105
+#define NOT_OPENED_PORT -106
+#define NOT_IMPEDANCE_MEASURED -107
+#define FAILED_TO_SET_SENSOR_CONFIG -108
+#define FAILED_TO_GET_SENSOR_CONFIG -109
+
+#define COULD_NOT_DOWNLOAD_RAW_FILE -201
+#define COULD_NOT_CONVERT_RAW_FILE -202
+
+#define COULD_NOT_UPLOAD_FW_FILE -300
+#define WRONG_FW_FILE -301
+#define WRONG_STRIP -302
+#define COULD_NOT_READ_FW_FILE -303
+#define WRONG_DEVICE -304
+#define NO_STRIP -305
+
+#define NOT_VALID_STRING_PATH -1001 //general errors
+#define WRONG_SEQUENCY_OF_COMMAND -1002
+
+
diff --git a/physiolabxr/third_party/BAlert/SDK64/include/BMS/SDKFlexDefinitions.h b/physiolabxr/third_party/BAlert/SDK64/include/BMS/SDKFlexDefinitions.h
new file mode 100644
index 00000000..39d1a0e5
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/SDK64/include/BMS/SDKFlexDefinitions.h
@@ -0,0 +1,164 @@
+#pragma once
+
+#include
+#define MAX_NUM_CHANNELS 24
+#define MAX_NUM_ELECTRODE 24
+
+struct DEVICE_INFO
+{
+public:
+ DEVICE_INFO()
+ {
+ memset(chDeviceName,0,256 * sizeof(char));
+ memset(ucSerial1, 0, 17 * sizeof(char));
+
+ memset(ucBtSerialNum, 0, 13 * sizeof(char));
+ memset(ucFirmwareVersion, 0, 12 * sizeof(char));
+ memset(ucHardwareVersion, 0, 5 * sizeof(char));
+ memset(ucESUFirmwareVersion, 0, 5 * sizeof(char));
+
+ memset(chDeviceInstanceID, 0, MAX_PATH * sizeof(char));
+
+ nCommPort = -1;
+ nECGPos = -1;
+ nNumberOfChannel = -1;
+ nBytesPerSample = -1;
+ bTilt = FALSE;
+ bHasESU = FALSE;
+ bMultiChESU = FALSE;
+ }
+
+ char chDeviceName[256];//device's name
+ int nCommPort; //comm port
+ int nECGPos; //ecg position
+ int nNumberOfChannel; //number of channel
+ int nESUType; //type of connecting device
+ int nTymestampType; // type of timestamp
+ int nDeviceHandle; // handle to identify device
+ char chDeviceInstanceID[MAX_PATH];
+ int nBytesPerSample;
+ BOOL bTilt;
+ BOOL bHasESU;
+ BOOL bMultiChESU;
+ char ucSerial1[17];
+
+ char ucBtSerialNum[13];
+ char ucFirmwareVersion[12];
+ char ucHardwareVersion[5];
+ char ucESUFirmwareVersion[5];
+
+ int nChannelsConfigurationAdc[MAX_NUM_CHANNELS * 2];
+ int nDCoffsetAdc[MAX_NUM_CHANNELS];
+
+ int nImpedanceOffsetAdc[MAX_NUM_CHANNELS];
+ int nImpedanceConstAdc[MAX_NUM_ELECTRODE];
+};
+
+struct RECEIVER_INFO
+{
+ RECEIVER_INFO()
+ {
+ nHeadsetTypeOnBT1 = -1;
+ nHeadsetTypeOnBT2 = -1;
+ nBTModule1Type = -1;
+ nBTModule2Type = -1;
+ nThirdPartyDataTypeSerial1 = -1;
+ nThirdPartyDataTypeSerial2 = -1;
+ nThirdPartyDataTypeSerial3 = -1;
+ nThirdPartyDataTypeSerial4 = -1;
+ nThirdPartyDataTypeParalel = -1;
+ fHeadset1Delay = 0;
+ fHeadset2Delay = 0;
+ fSerialPort1Delay = 0;
+ fSerialPort2Delay = 0;
+ fSerialPort3Delay = 0;
+ fSerialPort4Delay = 0;
+ fParalelPortDelay = 0;
+ bProcessTimeStamp = FALSE;
+ bMultiChEsu = FALSE;
+
+ memset(ucESUSerialNum,0,10 * sizeof(unsigned char));
+ memset(ucDebugMask, 0, 9 * sizeof(unsigned char));
+ memset(ucBTSerialNum1, 0, 13 * sizeof(unsigned char));
+ memset(ucBTSerialNum2, 0, 13 * sizeof(unsigned char));
+ memset(ucESUFirmwareVersion, 0, 5 * sizeof(unsigned char));
+ }
+
+ int nHeadsetTypeOnBT1;
+ int nHeadsetTypeOnBT2;
+ int nBTModule1Type;
+ int nBTModule2Type;
+ int nThirdPartyDataTypeSerial1;
+ int nThirdPartyDataTypeSerial2;
+ int nThirdPartyDataTypeSerial3;
+ int nThirdPartyDataTypeSerial4;
+ int nThirdPartyDataTypeParalel;
+ float fHeadset1Delay;
+ float fHeadset2Delay;
+ float fSerialPort1Delay;
+ float fSerialPort2Delay;
+ float fSerialPort3Delay;
+ float fSerialPort4Delay;
+ float fParalelPortDelay;
+ BOOL bProcessTimeStamp;
+ unsigned char ucESUSerialNum[10];
+ unsigned char ucBTSerialNum1[13];
+ unsigned char ucBTSerialNum2[13];
+ unsigned char ucDebugMask[9];
+ unsigned char ucESUFirmwareVersion[5];
+ unsigned char ucESUName[30];
+ BOOL bMultiChEsu;
+};
+
+
+
+
+
+struct FLEX_DEVICE_INFO
+{
+ FLEX_DEVICE_INFO()
+ {
+ nXDeviceName = 0;
+ nXDeviceModel = 0;
+ nSensorConfiguration = 0;
+ strDeviceSN = "";
+ strFirmwareVersion = "";
+ strHardwareRevision= "";
+ nACQType = 0;
+ nRecordingMode = 0;
+ nAuxChannel = 0;
+ nAudioOn = 0;
+ }
+ int nXDeviceName;
+ int nXDeviceModel;
+ int nSensorConfiguration;
+ CString strDeviceSN;
+ CString strFirmwareVersion;
+ CString strHardwareRevision;
+ int nACQType;
+ int nRecordingMode;
+ int nAuxChannel;
+ int nAudioOn;
+};
+
+typedef struct TD_SDK_EXPORTED_PARAMS
+{
+ BOOL bCreateSyncFile;
+ BOOL bCopyRawFile;
+ BOOL bCopySystemDatFile;
+ BOOL bConvertWholeRaw;
+ WCHAR tchSDCardDownloadPath[MAX_PATH];
+}_SDK_EXPORTED_PARAMS;
+
+typedef struct _CBStudyInfo
+{
+ SYSTEMTIME stStartTime;
+ SYSTEMTIME stEndTime;
+ int nSessionIndexStart;
+ int nSessionIndexEnd;
+ int nDuration; // in minutes
+ WCHAR strGuid[MAX_PATH];
+ bool bInclude;
+ bool bDownloaded;
+} CBStudyInfo;
+
diff --git a/physiolabxr/third_party/BAlert/SDK64/include/BMS/typedef.h b/physiolabxr/third_party/BAlert/SDK64/include/BMS/typedef.h
new file mode 100644
index 00000000..fb1673ef
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/SDK64/include/BMS/typedef.h
@@ -0,0 +1,255 @@
+#pragma once
+
+// consts
+#define BALERT_MAX_NUM_CHANNELS 24
+#define BALERT_MAX_CH_NAME 20
+#define BALERT_MAX_EVENT_DATA_SIZE 1024
+#define ABM_DATA_X4_CHANNELS 4
+#define ABM_DATA_X24_CHANNELS 24
+#define ABM_DATA_X10_CHANNELS 10
+#define MAX_NUM_ELECTRODE 24
+#define MAX_LENGTH_CHANNEL_NAME 20
+#define MAX_NUM_EEGCHANNELS 24
+
+typedef struct TD_ELECTRODES_INFO_BMS{
+ int nNumElectrodes;
+ int nStabilization;
+ int nAgregationsSamples;
+ int nCurrentType;
+ char cElName[MAX_NUM_ELECTRODE][MAX_LENGTH_CHANNEL_NAME];//[in]the name of electrode max 20 characters
+ int nElCommand[MAX_NUM_ELECTRODE];// Impedance command to be sent for this electrode to be measured
+ int nElChannel[MAX_NUM_ELECTRODE];// EEG channel to be used when measuring electrode
+ int nElReferentialElectrode[MAX_NUM_ELECTRODE];// Electrode to be used when substracting ref el. (-1 for none)
+}_ELECTRODES_INFO_BMS;
+
+typedef struct TD_EEGCHANNELS_INFO_BMS{
+ char cChName[MAX_NUM_EEGCHANNELS][MAX_LENGTH_CHANNEL_NAME];//[in]the name of channels max 20 characters
+ BOOL bChUsed[MAX_NUM_EEGCHANNELS];// whether channel is used or not
+ BOOL bChUsedInQualityData[MAX_NUM_EEGCHANNELS];// whether channel is used or not for quality
+ BOOL bChCanBeDecontaminated[MAX_NUM_EEGCHANNELS];
+ BOOL bIsChEEG[MAX_NUM_EEGCHANNELS];
+ BOOL nFirstElectrode[MAX_NUM_EEGCHANNELS];
+ BOOL nSecondElectrode[MAX_NUM_EEGCHANNELS];
+}_EEGCHANNELS_INFO_BMS;
+
+typedef struct TD_AUXDATA_INFO_BMS{
+ BOOL bIred;
+ BOOL bRed;
+ BOOL bTilt;
+ int nEcgIndex;
+ BOOL bMic;
+ BOOL bHaptic;
+}_AUXDATA_INFO_BMS;
+
+typedef struct TD_HARDWARE_INFO_BMS{
+ int nBatteryMax; //millivolts
+ int nBatteryMin; //millivolts
+ int nTiltLinearTransformA;
+ int nTiltLinearTransformB;
+}_HARDWARE_INFO_BMS;
+
+
+typedef struct TD_SESSIONTYPES_INFO_BMS{
+ BOOL bDecon; //whether decontamination is supported or not
+ BOOL bBalert;//whether b-alert classification is supported or not
+ BOOL bWorkload; //whether workload calculation is supported or not
+}_SESSIONTYPES_INFO_BMS;
+
+typedef struct TD_CHANNELMAP_INFO_BMS{
+ int nDeviceTypeCode;
+ int nSize;
+ _EEGCHANNELS_INFO_BMS stEEGChannels;
+ _ELECTRODES_INFO_BMS stElectrodes;
+ _AUXDATA_INFO_BMS stAuxData;
+ _HARDWARE_INFO_BMS stHardwareInfo;
+ _SESSIONTYPES_INFO_BMS stSessionTypes;
+}_CHANNELMAP_INFO_BMS;
+
+typedef struct TD_BMS_SETTINGS{
+ bool bNewImpedanceMeasuring;
+ bool bCreateMBStat;
+}_BMS_SETTINGS;
+
+typedef struct __TD_DEVICE_INFO_BMS{
+ int nConnectionStatus; //port opened
+ int nNumberOfChannels; //number of channel
+ char chChannelMap[BALERT_MAX_NUM_CHANNELS*BALERT_MAX_CH_NAME]; // Ch(N)-ChName - comma separated
+ int nBatteryPercentage;
+ char chDeviceName[256];//device's name
+ int nESU_TYPE;
+ int nHEADSET_TYPE; //old 1, flex 8 - 2, flex x24t 3
+}_BALERT_DEVICE_INFO_BMS;
+
+typedef struct _DATA_HEADER_BMS{
+ float Counter;
+ float ESUtimestamp;
+ float hour;
+ float minute;
+ float second;
+ float millisecond;
+ float packetSize;
+}_BALERT_DATA_HEADER_BMS;
+
+typedef struct _EVENT_HEADER_BMS{
+ float Counter;
+ float EEGSampleCounter;
+ float ESUtimestamp;
+ float hour;
+ float minute;
+ float second;
+ float millisecond;
+ float packetSize;
+}_BALERT_EVENT_HEADER_BMS;
+
+typedef struct TD_DATA_X4_DATA_BMS{
+ _BALERT_DATA_HEADER_BMS header;
+ float samples[ABM_DATA_X4_CHANNELS];
+ float tiltX;
+ float tiltY;
+ float tiltZ;
+}_BALERT_DATA_X4_PACKET_BMS;
+
+typedef struct TD_DATA_X10_DATA{
+ _BALERT_DATA_HEADER_BMS header;
+ float samples[ABM_DATA_X10_CHANNELS];
+ float tiltX;
+ float tiltY;
+ float tiltZ;
+}_BALERT_DATA_X10_PACKET;
+
+typedef struct TD_DATA_X24_DATA{
+ _BALERT_DATA_HEADER_BMS header;
+ float samples[ABM_DATA_X24_CHANNELS];
+ float tiltX;
+ float tiltY;
+ float tiltZ;
+}_BALERT_DATA_X24_PACKET;
+
+typedef struct TD_DATA_MIC_DATA{
+ _BALERT_DATA_HEADER_BMS header;
+ float micValue;
+}_BALERT_DATA_MIC_PACKET;
+
+typedef struct TD_DATA_RAW_OPTICAL_DATA{
+ _BALERT_DATA_HEADER_BMS header;
+ float opticalRawValue;
+}_BALERT_DATA_RAW_OPTICAL_PACKET;
+
+typedef struct TD_DATA_OPTICAL_DATA{
+ _BALERT_DATA_HEADER_BMS header;
+ float opticalValue;
+}_BALERT_DATA_OPTICAL_PACKET;
+
+
+typedef struct TD_DATA_EVENT{
+ _BALERT_EVENT_HEADER_BMS header;
+ char data[BALERT_MAX_EVENT_DATA_SIZE];
+}_BALERT_DATA_EVENT;
+
+typedef struct TD_IMPEDANCE_RESULT{
+ int channelNumber;
+ char channelName[BALERT_MAX_CH_NAME];
+ int firstElectrodeImpedanceStatus;
+ char firstElectrodeName[BALERT_MAX_CH_NAME];
+ float firstElectrodeValue;
+ int secondElectrodeImpedanceStatus;
+ char secondElectrodeName[BALERT_MAX_CH_NAME];
+ float secondElectrodeValue;
+}_BALERT_IMPEDANCE_RESULT;
+
+typedef struct TD_BMS_RETURN_VALUE{
+ static const int BMS_API_COMMAND_SUCCESS = 1;
+ static const int BMS_API_COMMAND_FAILED = 0;
+ static const int IMP_COULDNT_START = 0;
+
+static const int X4_DATA_SIZE_BMS = 1;
+ static const int DEV_INFO_OK = 1;
+ static const int DEV_INFO_NO_DEVICE = 0;
+ static const int DEV_INFO_WRONG_DEVICE_TYPE = -1;
+ static const int DEV_INFO_WRONG_USB_CONFIGURATION = -2;
+ static const int DEV_INFO_MISSING_CHANNEL_MAP_CONFIGURATION = -3;
+ static const int BMS_INVALID_FLEX_INFO = -4;
+ static const int BMS_START_ACQUISITION_FAILED = -5;
+ static const int BMS_INVALID_SEQUENCE = -6;
+}_BALERT_CONSTANTS_RETURN_VALUES;
+
+typedef struct TD_BMS_DEVICE{
+ static const int MAX_NUM_CH_BMS = 24;
+ static const int MAX_NUMBER_SLOW_CHANNEL_BMS = 64;
+ static const int EPOCH_SZ_BMS = 256;
+ static const int SIZE_PACKET_COUNTER_BMS = 64;
+ static const int SAMPLE_RATE_BMS = 256;
+ static const int X4_DATA_SIZE_BMS = (4+3);
+ static const int X10_DATA_SIZE = (10+3);
+ static const int X24_DATA_SIZE = (24+3);
+ static const int EVENT_TYPE_API = 0;
+ static const int EVENT_TYPE_ESU = 1;
+}_BALERT_CONSTANTS_DEVICE_BMS;
+
+#define _BALERT_CONSTANTS_DEVICE_SAMPLES_DELAY 3.90625
+
+typedef struct TD_BMS_BUFFERS{
+ static const int MAX_PACKET_SIZE = 34;
+ static const int MAX_EVENTS_NUM = 1000;
+ static const int SAMPLE_BUFFER_SIZE = 25600;
+}_BALERT_CONSTANTS_BUFFERS;
+
+typedef struct TD_BMS_OPERATING_MODE{
+ static const int BMS_IMPEDANCE_MODE = 1;
+ static const int BMS_DATA_MODE_WAIT_DATA = 1;
+ static const int BMS_DATA_MODE_GET_DATA = 2;
+ static const int BMS_DATA_MODE_UNINITIALIZED = 0;
+}_BALERT_CONSTANTS_OPERATING_MODE;
+
+#define BALERT_MAX_NUM_CHANNELS 24
+#define BALERT_MAX_CH_NAME 20
+#define BALERT_MAX_EVENT_DATA_SIZE 256
+#define ABM_DATA_X4_CHANNELS 4
+#define ABM_DATA_X24_CHANNELS 24
+#define ABM_DATA_X10_CHANNELS 10
+#define MAX_NUM_ELECTRODE 24
+#define MAX_LENGTH_CHANNEL_NAME 20
+#define MAX_NUM_EEGCHANNELS 24
+#define TILT_SIZE 3
+
+#define ABM_INVALID_VALUE -1
+
+//device type code in ini device channel map
+#define X10CODE 10
+#define X24CODE 24
+#define X8CODE_MID 101
+#define X8CODE_REF 102
+#define X8CODE_SP 103
+#define X8CODE_SPP 104
+
+//strip codes and macros
+#define STRIP_10_20 0x2021
+#define STRIP_10_20_REDUCED 0x2123
+#define STRIP_10_20_LM 0x2232
+#define STRIP_10_20_REDUCED_LM 0x2239
+#define STRIP_SENSOR_HARNESS 0x2230
+#define Is10CHStrip(x) (x==STRIP_10_20_REDUCED || x==STRIP_10_20_REDUCED_LM)
+#define IsStripLESupported(x) (x==STRIP_10_20_LM || x==STRIP_10_20_REDUCED_LM|| x==STRIP_SENSOR_HARNESS)
+#define IsSupportedStrip(x) (x==STRIP_10_20 || x==STRIP_10_20_REDUCED || x==STRIP_10_20_LM || x==STRIP_10_20_REDUCED_LM || x==STRIP_SENSOR_HARNESS)
+
+//device config functionalities error codes
+#define BMS_DEVCONFIG_SUCCESS 0
+#define BMS_DEVCONFIG_NO_ESU_FOUND -0x1
+#define BMS_DEVCONFIG_DEVICE_NOT_FOUND -0x2
+#define BMS_DEVCONFIG_ALREADY_CONNECTED -0x3
+#define BMS_DEVCONFIG_CONNECTION_FAILED -0x4
+#define BMS_DEVCONFIG_NOT_X_SERIES -0x5
+#define BMS_DEVCONFIG_NOT_OLD_RECIEVER -0x6
+#define BMS_DEVCONFIG_SEARCH_FAILED -0x7
+#define BMS_DEVCONFIG_SYNC_FAILED -0x8
+#define BMS_DEVCONFIG_UPLOAD_FW_FAILED -0x9
+#define BMS_DEVCONFIG_PARSE_FW_FAILED -0xA
+#define BMS_DEVCONFIG_RESET_FAILED -0xB
+#define BMS_DEVCONFIG_BOOT_FAILED -0xC
+#define BMS_DEVCONFIG_READ_MC_FAILED -0xD
+#define BMS_DEVCONFIG_WRITE_MC_FAILED -0xE
+#define BMS_DEVCONFIG_CHECK_MC_FAILED -0xF
+#define BMS_DEVCONFIG_ESU_WIRED -0x10
+#define BMS_DEVCONFIG_ESU_NOT_CONFIGURED -0x11
+
+#define BMS_OBSOLETE_NO_LONGER_IN_USE -0xFF
diff --git a/physiolabxr/third_party/BAlert/SDK64/include/CommonTypeDef.h b/physiolabxr/third_party/BAlert/SDK64/include/CommonTypeDef.h
new file mode 100644
index 00000000..72386411
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/SDK64/include/CommonTypeDef.h
@@ -0,0 +1,648 @@
+
+#include
+#include
+
+#pragma once
+
+#define BUFFER_SIZE_IN_RECORDS 100
+#define MAX_EDF_NUM_ALLCHANNELS 100 //the number of channels including time channels (X24 has 24 eeg + 2 time ch)
+#define CHANNEL_NAME_LENGTH 20
+#define MAX_STR_TMP 2048
+#define MAXSIZE_ERROR_MSG 1000
+
+#define FILE_CHANNELTYPES_Raw 0
+#define FILE_CHANNELTYPES_Decon 1
+#define FILE_CHANNELTYPES_RawDecon 2
+#define FILE_CHANNELTYPES_Events 3
+
+#define FILE_STORAGETYPE_Ebs 0
+#define FILE_STORAGETYPE_Edf 1
+#define FILE_STORAGETYPE_EdfPSignal 2
+#define FILE_STORAGETYPE_EdfPEvent 3
+#define FILE_STORAGETYPE_EdfFromSDCard 4
+
+#define X24_QEEG 0
+#define X24_STANDARD 1
+#define X10_STANDARD 2
+#define X4_B_ALERT 3
+#define X4_APPT 4
+#define X4_SLEEP_PROFILER 5
+#define X24t_10_20 6
+#define X10t_STANDARD 7
+#define X24t_REDUCED 8
+#define X24t_10_20_LM 9
+#define X24LE_10_20_LM 10
+#define X24t_10_20_LM_Red 11
+#define X24LE_10_20_LM_Red 12
+#define X10t_10_20_LM_Red 13
+#define X24LE_Ambulatory 14
+
+#define DEFAULT_VALUE -99999
+
+
+
+struct _BALERT_LAB_HEADER
+ {
+ int nFileStorageType; // file type (one of constants FILE_STORAGETYPE_... )
+ int nSubjectNo; //label for subject that is performing acquisition
+ int nSessionType; //type of session being performed
+ int nGroup; //group of current session
+ int nStudyType; //current study type
+ int nIteration; //current session iteration
+ int nDeviceType; //type of device used for acquisition
+ char chDeviceType[20];
+ char chFimrwareVersion[12];
+ char chESUFimrware[10];
+ char chHardwareVersion[10];
+ char chSoftwareVersion[20];
+ int nChannelsNmb;
+ TCHAR chChannelName[MAX_EDF_NUM_ALLCHANNELS][CHANNEL_NAME_LENGTH];
+ int nChannelSampleRate[MAX_EDF_NUM_ALLCHANNELS];
+ int nChannelType[MAX_EDF_NUM_ALLCHANNELS];
+ int nChannelByteSize[MAX_EDF_NUM_ALLCHANNELS];
+ float fChannelGain[MAX_EDF_NUM_ALLCHANNELS];
+ float fChannelDCOffset[MAX_EDF_NUM_ALLCHANNELS];
+ char chChannelFilters[MAX_EDF_NUM_ALLCHANNELS];
+ char chRecordingTime[20];
+ char chSerialNum[30];
+
+ char chSortDesc[50];
+ char chFullDesc[100];
+ char chHardwareSoftwareID[MAX_STR_TMP];
+ int nSamplesNmb[MAX_EDF_NUM_ALLCHANNELS];
+
+
+
+ int nESUTimestampIndex;
+ int nSysTimestampIndex;
+ int nEventsIndex;
+ int nECGChannelIndex;
+
+
+ // EDF specific
+ char chReserved[44];
+ int nNumOfDataRecords; // number of epochs in EDF
+ int nEDFHeaderSize;
+ char chTransducerType[MAX_EDF_NUM_ALLCHANNELS][80];
+ char chPhysicalDimension[MAX_EDF_NUM_ALLCHANNELS][8];
+ float fPhysicalMinimum[MAX_EDF_NUM_ALLCHANNELS];
+ float fPhysicalMaximum[MAX_EDF_NUM_ALLCHANNELS];
+ int nDigitalMinimum[MAX_EDF_NUM_ALLCHANNELS];
+ int nDigitalMaximum[MAX_EDF_NUM_ALLCHANNELS];
+ char chPrefiltering[MAX_EDF_NUM_ALLCHANNELS][80];
+ char chUserID[40];
+ char chESUSerial[12];
+ };
+
+
+struct _BALERT_LAB_FILEINFO
+ {
+ int nSubjectNo; //label for subject that is performing acquisition
+ int nSessionType; //type of session being performed
+ int nGroup; //group of current session
+ int nStudyType; //current study type
+ int nIteration; //current session iteration
+
+
+
+ int nChannelsNmb;
+ TCHAR chChannelName[MAX_EDF_NUM_ALLCHANNELS][CHANNEL_NAME_LENGTH];
+ int nChannelSampleRate[MAX_EDF_NUM_ALLCHANNELS];
+ int nChannelType[MAX_EDF_NUM_ALLCHANNELS];
+ int nChannelByteSize[MAX_EDF_NUM_ALLCHANNELS];
+ float fChannelGain[MAX_EDF_NUM_ALLCHANNELS];
+
+ TCHAR chRecordingTime[20];
+ TCHAR chSoftwareVersion[20];
+ int nSamplesNmb[MAX_EDF_NUM_ALLCHANNELS];
+ int nFileEegChannelTypes;
+
+ int nESUTimestampIndex;
+ int nSysTimestampIndex;
+ int nEventsIndex;
+
+
+ int nESUStartTime;
+ int nESUStopTime;
+ int nSysTimeStartH;
+ int nSysTimeStartMin;
+ int nSysTimeStartSec;
+ int nSysTimeStartMSec;
+
+ int nSysTimeStopH;
+ int nSysTimeStopMin;
+ int nSysTimeStopSec;
+ int nSysTimeStopMSec;
+ int nFileStorageType; // file type (one of constants FILE_STORAGETYPE_... )
+
+ float fChannelDCOffset[MAX_EDF_NUM_ALLCHANNELS];
+ TCHAR chFimrwareVersion[12]; //12 instead of 10, keep alignment as factor of 4 to marshal it easier
+ TCHAR chESUFimrware[12];
+ TCHAR chUserID[40];
+ TCHAR chDeviceType[20];
+ TCHAR chHardwareVersion[12];
+ TCHAR chESUSerial[12];
+ TCHAR chDeviceSerial[32];
+ };
+
+
+#define PARADIGM_3RD_PARTY 0
+
+#define PARADIGM_VPVT 1
+#define PARADIGM_APVT 2
+#define PARADIGM_3CVT 3
+#define PARADIGM_PAL 4
+#define PARADIGM_VMS 5
+#define PARADIGM_VPA 6
+#define PARADIGM_FDS 7
+#define PARADIGM_BDS 8
+#define PARADIGM_SIR 9
+#define PARADIGM_IIR 10
+#define PARADIGM_SNR 12
+#define PARADIGM_NIR 11
+#define PARADIGM_PNNL 13
+#define PARADIGM_UCSD 13
+
+#define PARADIGM_FA1B 14
+#define PARADIGM_FA2B 15
+#define PARADIGM_DA1B 16
+#define PARADIGM_DA2B 17
+
+#define PARADIGM_FA1BSND 18
+#define PARADIGM_FA2BSND 19
+#define PARADIGM_DA1BSND 20
+#define PARADIGM_DA2BSND 21
+
+#define PARADIGM_EORESTING 22
+#define PARADIGM_ECRESTING 23
+#define PARADIGM_AAO 35
+#define PARADIGM_PAO 36
+
+#define PARADIGM_EIR1 24
+#define PARADIGM_EIR2 25
+#define PARADIGM_EIR3 26
+
+#define PARADIGM_VMS_CI 30
+#define PARADIGM_3CVT_CI 27
+//#define PARADIGM_SIR_CI 28
+//#define PARADIGM_SIR_ALT_CI 29
+#define PARADIGM_EIR3_PART1 28
+#define PARADIGM_EIR3_PART2 29
+
+#define PARADIGM_ANY 30
+
+#define PARADIGM_EIR1_PART1 37
+#define PARADIGM_EIR1_PART2 38
+#define PARADIGM_EIR1_PART3 39
+#define PARADIGM_EIR2_PART1 40
+#define PARADIGM_EIR2_PART2 41
+#define PARADIGM_EIR2_PART3 42
+#define PARADIGM_VMS1 43
+#define PARADIGM_VMS2 44
+#define PARADIGM_VMS3 45
+#define PARADIGM_VPAO 46
+#define PARADIGM_3CVT_10m 49
+#define PARADIGM_VEP 51
+#define PARADIGM_PASSIVE_EIR1 52
+#define PARADIGM_PASSIVE_EIR2 53
+
+#define MOBILE_AMP_PARADIGM_3CVT 1
+#define MOBILE_AMP_PARADIGM_EO 2
+#define MOBILE_AMP_PARADIGM_EC 3
+#define MOBILE_AMP_PARADIGM_PAL 4
+
+#define PARADIGM_SUBTYPE_VIS_FA1B 0
+#define PARADIGM_SUBTYPE_VIS_FA2B 1
+#define PARADIGM_SUBTYPE_VIS_DA1B 2
+#define PARADIGM_SUBTYPE_VIS_DA2B 3
+#define PARADIGM_SUBTYPE_AUD_FA1B 4
+#define PARADIGM_SUBTYPE_AUD_FA2B 5
+#define PARADIGM_SUBTYPE_AUD_DA1B 6
+#define PARADIGM_SUBTYPE_AUD_DA2B 7
+
+#define PARADIGM_UNKNOWN -9999
+
+
+#define TASK_PART_Practice 1
+#define TASK_PART_PracticeTraining 2
+#define TASK_PART_PracticeTesting 3
+#define TASK_PART_Training 4
+#define TASK_PART_Testing 5
+#define TASK_PART_DS_Level 11
+#define TASK_PART_PracticeTrainingA 12
+#define TASK_PART_PracticeTestingA 13
+#define TASK_PART_PracticeTrainingB 22
+#define TASK_PART_PracticeTestingB 23
+#define TASK_PART_PracticeTrainingC 32
+#define TASK_PART_PracticeTestingC 33
+
+
+enum enmBaselineEEGQuality
+{
+ enmBaselineNone,
+ enmBaselineGood,
+ enmBaselineMarginal,
+ enmBaselineBad,
+
+};
+
+
+enum enmBaselinePerformanceQuality
+{
+ enmBaselinePerformanceNone,
+ enmBaselinePerformanceGood,
+ enmBaselineMarginalForNormative,
+ enmBaselineBadForNormative,
+ enmBaselinePerformanceBad
+};
+
+struct _BALERT_LAB_BASELINE_QUALITY
+{
+ _BALERT_LAB_BASELINE_QUALITY()
+ {
+ reset();
+
+ };
+
+
+ void reset()
+ {
+ m_fSleepOnsetPercentage = 0;
+ m_fDistractedPercentage = 0;
+ m_fLowEngagementPercentage = 0;
+ m_fHighEngagementPercentage = 0;
+ m_pEGMPercentage = 0;
+ m_fInvPercentage = 0;
+ m_fAverageSleepOnset = 0;
+ m_fAverageDistracted = 0;
+ m_fAverageLowEngagement = 0;
+ m_fAverageHighEngagement = 0;
+ m_nSleepOnsetEpochs = 0;
+ m_nDistractedEpochs = 0;
+ m_nLowEngagementEpochs = 0;
+ m_nHighEngagementEPochs = 0;
+ m_nEGMEpochs = 0;
+ m_nINVEpochs = 0;
+ m_nEMGInvEpochs = 0;
+ m_nEpTotal = 0;
+ m_nValidEp = 0;
+ m_nTaskType = 0;
+ m_fMarginalArtifactFrom = 0;
+ m_fMarginalArtifactTo = 0;
+ m_fGoodClassFrom = 0;
+ m_fMarginalFrom = 0;
+
+
+ m_fGoodArtifactTo = 0;
+ m_fPercentageCorrectMean = 0;
+ m_fReactionTimeMean = 0;
+
+ m_enmPredictionQuality = enmBaselineNone;
+ m_enmEMGQuality = enmBaselineNone;
+ m_enmInvQuality = enmBaselineNone;
+ m_enmInvAndENGQuality = enmBaselineNone;
+ m_enmPerformanceQuality = enmBaselinePerformanceNone;
+
+
+ m_fPercentageCorrect = 0;
+ m_fMeanRT = 0;
+ m_nCorrectNmb = 0;
+ m_nMissedNmb = 0;
+ m_nSlowNmb = 0;
+ // m_nMissedAndSlowRTFrom = 0;
+ m_fMarginalFromResponsesNmb = 0;
+ m_fMarginalToResponsesNmb = 0;
+
+
+ memset(m_chStatus,0,50*sizeof(char));
+ memset(m_chPerformanceStatus,0,50*sizeof(char));
+
+ }
+
+
+ /////////////////////////
+ void _BALERT_LAB_BASELINE_QUALITY::operator =(const _BALERT_LAB_BASELINE_QUALITY &quality)
+ {
+ m_fSleepOnsetPercentage = quality.m_fSleepOnsetPercentage;
+ m_fDistractedPercentage = quality.m_fDistractedPercentage;
+ m_fLowEngagementPercentage = quality.m_fLowEngagementPercentage;
+ m_fHighEngagementPercentage = quality.m_fHighEngagementPercentage;
+ m_pEGMPercentage = quality.m_pEGMPercentage;
+ m_fInvPercentage = quality.m_fInvPercentage;
+ m_fAverageSleepOnset = quality.m_fAverageSleepOnset;
+ m_fAverageDistracted = quality.m_fAverageDistracted;
+ m_fAverageLowEngagement = quality.m_fAverageLowEngagement;
+ m_fAverageHighEngagement = quality.m_fAverageHighEngagement;
+ m_nSleepOnsetEpochs = quality.m_nSleepOnsetEpochs;
+ m_nDistractedEpochs = quality.m_nDistractedEpochs;
+ m_nLowEngagementEpochs = quality.m_nLowEngagementEpochs;
+ m_nHighEngagementEPochs = quality.m_nHighEngagementEPochs;
+ m_nEGMEpochs = quality.m_nEGMEpochs;
+ m_nINVEpochs = quality.m_nINVEpochs;
+ m_nEMGInvEpochs = quality.m_nEMGInvEpochs;
+ m_nEpTotal = quality.m_nEpTotal;
+ m_nValidEp = quality.m_nValidEp;
+ m_nTaskType = quality.m_nTaskType;
+ m_fMarginalArtifactFrom = quality.m_fMarginalArtifactFrom;
+ m_fMarginalArtifactTo = quality.m_fMarginalArtifactTo;
+ m_fGoodClassFrom = quality.m_fGoodClassFrom;
+ m_fMarginalFrom = quality.m_fMarginalFrom;
+
+
+ m_fGoodArtifactTo = quality.m_fGoodArtifactTo;
+ m_fPercentageCorrectMean = quality.m_fPercentageCorrectMean;
+ m_fReactionTimeMean = quality.m_fReactionTimeMean;
+
+ m_enmPredictionQuality = quality.m_enmPredictionQuality;
+ m_enmEMGQuality = quality.m_enmEMGQuality;
+ m_enmInvQuality = quality.m_enmInvQuality;
+ m_enmInvAndENGQuality = quality.m_enmInvAndENGQuality;
+ m_enmPerformanceQuality = quality.m_enmPerformanceQuality;
+
+
+ m_fPercentageCorrect = quality.m_fPercentageCorrect;
+ m_fMeanRT = quality.m_fMeanRT;
+ m_nCorrectNmb = quality.m_nCorrectNmb;
+ m_nMissedNmb = quality.m_nMissedNmb;
+ m_nSlowNmb = quality.m_nSlowNmb;
+ //m_nMissedAndSlowRTFrom = quality.m_nMissedAndSlowRTFrom;
+ m_fMarginalFromResponsesNmb = quality.m_fMarginalFromResponsesNmb;
+ m_fMarginalToResponsesNmb = quality.m_fMarginalToResponsesNmb;
+
+
+
+ _tcscpy(m_chStatus,quality.m_chStatus);
+ _tcscpy(m_chPerformanceStatus,quality.m_chPerformanceStatus);
+
+
+ }
+
+ ///////////////////////////////
+ void _BALERT_LAB_BASELINE_QUALITY::SetType(int nClass)
+ {
+
+ m_nTaskType = nClass;
+ m_fGoodArtifactTo = 3;
+ m_fMarginalArtifactFrom = 3;
+ m_fMarginalArtifactTo = 10;
+
+ if(nClass == PARADIGM_VPVT)
+ {
+ m_fGoodClassFrom = 70;
+ m_fMarginalFrom = 64;
+
+
+ // m_nMissedAndSlowRTFrom = 5;
+ m_fMarginalFromResponsesNmb = 90;
+ m_fMarginalToResponsesNmb = 96;
+ }
+ else if(nClass == PARADIGM_APVT)
+ {
+ m_fGoodClassFrom = 82;
+ m_fMarginalFrom = 76;
+
+
+
+
+
+ //m_nMissedAndSlowRTFrom = 5;
+ m_fMarginalFromResponsesNmb = 90;
+ m_fMarginalToResponsesNmb = 96;
+ }
+ else if(nClass == PARADIGM_3CVT)
+ {
+ m_fGoodClassFrom = 75;
+ m_fMarginalFrom = 67.5;
+
+
+
+
+ m_fPercentageCorrectMean = 92;
+ m_fReactionTimeMean = 0.745000;
+
+ }
+ }
+
+
+
+ float m_fSleepOnsetPercentage;
+ float m_fDistractedPercentage;
+ float m_fLowEngagementPercentage;
+ float m_fHighEngagementPercentage;
+ float m_pEGMPercentage;
+ float m_fInvPercentage;
+ float m_fAverageSleepOnset;
+ float m_fAverageDistracted;
+ float m_fAverageLowEngagement;
+ float m_fAverageHighEngagement;
+ float m_fMarginalArtifactFrom;
+ float m_fMarginalArtifactTo;
+ float m_fGoodClassFrom;
+ float m_fMarginalFrom;
+
+
+ float m_fGoodArtifactTo;
+ float m_fPercentageCorrectMean;
+ float m_fReactionTimeMean;
+
+ int m_nSleepOnsetEpochs;
+ int m_nDistractedEpochs;
+ int m_nLowEngagementEpochs;
+ int m_nHighEngagementEPochs;
+ int m_nEGMEpochs;
+ int m_nINVEpochs;
+ int m_nEMGInvEpochs;
+ int m_nEpTotal;
+ int m_nValidEp;
+ int m_nTaskType;
+ //int m_nMissedAndSlowRTFrom;
+ float m_fMarginalFromResponsesNmb;
+ float m_fMarginalToResponsesNmb;
+
+
+
+
+ enmBaselineEEGQuality m_enmPredictionQuality;
+ enmBaselineEEGQuality m_enmEMGQuality;
+ enmBaselineEEGQuality m_enmInvQuality;
+ enmBaselineEEGQuality m_enmInvAndENGQuality;
+ enmBaselinePerformanceQuality m_enmPerformanceQuality;
+
+ float m_fPercentageCorrect;
+ float m_fMeanRT;
+ int m_nCorrectNmb;
+ int m_nMissedNmb;
+ int m_nSlowNmb;
+
+
+
+ TCHAR m_chStatus[50];
+ TCHAR m_chPerformanceStatus[50];
+
+};
+
+
+struct BALERT_ARTIFACT_INFO
+{
+public:
+
+ BALERT_ARTIFACT_INFO()
+ {
+ nArtifactType = DEFAULT_VALUE;
+ nRule = DEFAULT_VALUE;
+ nStartDataPoint = DEFAULT_VALUE;
+ nStopDataPoint = DEFAULT_VALUE;
+ memset(ucChannelName,0, 20*sizeof(char));
+ }
+
+ int nArtifactType;
+ int nStartDataPoint;
+ int nStopDataPoint;
+ char ucChannelName[20];
+ int nRule;
+
+
+};
+
+struct BALERT_OVERALL_ARTIF_INFO
+{
+ float allArtifactPercentage;
+ float allArtifactPercentageNewEB;
+ float otherArtifactsPercentage;
+ float EBPercentage;
+ float NewEBPercentage;
+
+ BALERT_OVERALL_ARTIF_INFO()
+ {
+ allArtifactPercentage = -1;
+ otherArtifactsPercentage = -1;
+ EBPercentage = -1;
+ allArtifactPercentageNewEB = -1;
+ NewEBPercentage = -1;
+
+ }
+};
+
+struct BALERT_CHANNEL_ARTIF_INFO
+{
+ BALERT_CHANNEL_ARTIF_INFO()
+ {
+ memset(ucChannelName,0, sizeof(char)*20);
+ nZeroValuesInserted = -1;
+ allArtifactPercentage = -1;
+ otherArtifactsPercentage = -1;
+ EBPercentage = -1;
+ SatPercentage = -1;
+ SpkPercentage = -1;
+ ExcPercentage = -1;
+ MBPercentage = -1;
+ nInvalid = -1;
+ area1ArtifactsPercentage = -1;
+ area2ArtifactsPercentage = -1;
+ area3ArtifactsPercentage = -1;
+ area4ArtifactsPercentage = -1;
+
+ allArtifactPercentageNewEB = -1;
+ NewEBPercentage = -1;
+ area1ArtifactsPercentageNewEB = -1;
+ area2ArtifactsPercentageNewEB = -1;
+ area3ArtifactsPercentageNewEB = -1;
+ area4ArtifactsPercentageNewEB = -1;
+
+
+ }
+
+ char ucChannelName[20];
+ int nZeroValuesInserted;
+ int nInvalid;
+ float allArtifactPercentage;
+ float allArtifactPercentageNewEB;
+ float otherArtifactsPercentage;
+ float EBPercentage;
+ float NewEBPercentage;
+ float SatPercentage;
+ float SpkPercentage;
+ float ExcPercentage;
+ float MBPercentage;
+ float area1ArtifactsPercentage;
+ float area2ArtifactsPercentage;
+ float area3ArtifactsPercentage;
+ float area4ArtifactsPercentage;
+ float area1ArtifactsPercentageNewEB;
+ float area2ArtifactsPercentageNewEB;
+ float area3ArtifactsPercentageNewEB;
+ float area4ArtifactsPercentageNewEB;
+
+
+
+
+
+};
+
+struct BALERT_EPOCH_ARTIF_INFO
+{
+public:
+ BALERT_EPOCH_ARTIF_INFO()
+ {
+ memset(ucChannelName,0, sizeof(char)*20);
+ nInvalid = DEFAULT_VALUE;
+ //nEMGLevel = DEFAULT_VALUE;
+ nZeroValuesInserted = DEFAULT_VALUE;
+ nEbEffected = DEFAULT_VALUE;
+ nSatEffected = DEFAULT_VALUE;
+ nExcEffected = DEFAULT_VALUE;
+ nSpkEffected = DEFAULT_VALUE;
+ nMissedBlock = DEFAULT_VALUE;
+ nPeriodicMissedBlock = DEFAULT_VALUE;
+ }
+
+ char ucChannelName[20];
+ int nInvalid;
+ //int nEMGLevel;
+ int nZeroValuesInserted;
+ int nEbEffected;
+ int nSatEffected;
+ int nExcEffected;
+ int nSpkEffected;
+ int nMissedBlock;
+ int nPeriodicMissedBlock;
+
+};
+
+struct BALERT_OVERLAYS_ARTIF_INFO
+{
+public:
+ BALERT_OVERLAYS_ARTIF_INFO()
+ {
+ memset(ucChannelName,0, sizeof(char)*20);
+ nInvalid = DEFAULT_VALUE;
+ //nEMGLevel = DEFAULT_VALUE;
+ nZeroValuesInserted = DEFAULT_VALUE;
+ nEbEffected = DEFAULT_VALUE;
+ nSatEffected = DEFAULT_VALUE;
+ nExcEffected = DEFAULT_VALUE;
+ nSpkEffected = DEFAULT_VALUE;
+ nMissedBlock = DEFAULT_VALUE;
+ nPeriodicMissedBlock = DEFAULT_VALUE;
+ }
+
+ char ucChannelName[20];
+ int nInvalid;
+ //int nEMGLevel;
+ int nZeroValuesInserted;
+ int nEbEffected;
+ int nSatEffected;
+ int nExcEffected;
+ int nSpkEffected;
+ int nMissedBlock;
+ int nPeriodicMissedBlock;
+
+};
+
+#define SPIKE_CODE 0
+#define EXCURSION_CODE 1
+#define SATURATION_CODE 2
+
+#define MISSED_BLOCKS_CODE 4
+#define EYE_BLINK_CODE 5
+#define PERIODIC_IMP_MISSED_BLOCKS_CODE 6
diff --git a/physiolabxr/third_party/BAlert/SDK64/include/Communication.h b/physiolabxr/third_party/BAlert/SDK64/include/Communication.h
new file mode 100644
index 00000000..c48df033
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/SDK64/include/Communication.h
@@ -0,0 +1,246 @@
+#ifndef _COMMUNICATION_LIB_H_
+#define _COMMUNICATION_LIB_H_
+
+#pragma once
+#include "..\include\TCP\ThirdPartyCommunication.h"
+
+static HINSTANCE hComLib;
+
+static int(__stdcall* STARTSERVER)(_SERVER_INFO);
+#define StartServer(server) ((*STARTSERVER)(server))
+
+static int (__stdcall *STOPSERVER)(void);
+#define StopServer() ((*STOPSERVER)())
+
+static int (__stdcall *SENDDATAGRAM)(char*, int, char*);
+#define SendDatagram(pData, nLength, messageCode) ((*SENDDATAGRAM)(pData, nLength, messageCode))
+
+static int (__stdcall *SENDRAWDATA)(float*, int);
+#define SendRawData(pData, nLength) ((*SENDRAWDATA)(pData, nLength))
+
+static int (__stdcall *SENDDECONDATA)(float*, int);
+#define SendDeconData(pData, nLength) ((*SENDDECONDATA)(pData, nLength))
+
+static int (__stdcall *SENDQUALITY)(float*, int);
+#define SendQuality(pData, nLength) ((*SENDQUALITY)(pData, nLength))
+
+static int (__stdcall *SENDCURRENTQUALITY)(float*, int);
+#define SendCurrentQuality(pData, nLength) ((*SENDCURRENTQUALITY)(pData, nLength))
+
+static int (__stdcall *SENDCLASSQUALITY)(float*, int);
+#define SendClassQuality(pData, nLength) ((*SENDCLASSQUALITY)(pData, nLength))
+
+static int (__stdcall *SENDQUALITYCHANNEL)(float*, int);
+#define SendQualityChannel(pData, nLength) ((*SENDQUALITYCHANNEL)(pData, nLength))
+
+static int (__stdcall *SENDPSDDATA)(float*, int);
+#define SendPSDData(pData, nLength) ((*SENDPSDDATA)(pData, nLength))
+
+static int (__stdcall *SENDPSDRAWDATA)(float*, int);
+#define SendPSDRawData(pData, nLength) ((*SENDPSDRAWDATA)(pData, nLength))
+
+static int (__stdcall *SENDEBDATA)(char*, int);
+#define SendEBData(pData, nLength) ((*SENDEBDATA)(pData, nLength))
+
+static int (__stdcall *SENDEXCDATA)(char*, int);
+#define SendEXCData(pData, nLength) ((*SENDEXCDATA)(pData, nLength))
+
+static int (__stdcall *SENDEMGDATA)(char*, int);
+#define SendEMGData(pData, nLength) ((*SENDEMGDATA)(pData, nLength))
+
+static int (__stdcall *SENDSATDATA)(char*, int);
+#define SendSATData(pData, nLength) ((*SENDSATDATA)(pData, nLength))
+
+static int (__stdcall *SENDSPKDATA)(char*, int);
+#define SendSPKData(pData, nLength) ((*SENDSPKDATA)(pData, nLength))
+
+static int (__stdcall *SENDEKGDATA)(float*, int);
+#define SendEKGData(pData, nLength) ((*SENDEKGDATA)(pData, nLength))
+
+static int (__stdcall *SENDBRAINSTATE)(float*, int);
+#define SendBrainState(pData, nLength) ((*SENDBRAINSTATE)(pData, nLength))
+
+//static int (__stdcall *SENDBATTERYPERCENTAGE)(int, int);
+//#define SendBatteryPercentage(nBatteryPercentage, nEpoch) ((*SENDBATTERYPERCENTAGE)(nBatteryPercentage, nEpoch))
+
+static int (__stdcall *SENDBATTERYANDIMPENDACES)(int, int, int, int[] );
+#define SendBatteryAndImpedances(nBatteryPercentage, nEpoch, nImpOnlineStatus, nImpOnlineValues) ((*SENDBATTERYANDIMPENDACES)(nBatteryPercentage, nEpoch, nImpOnlineStatus, nImpOnlineValues))
+
+static int (__stdcall *SENDMISSEDBLOCKS)(int, int);
+#define SendMissedBlocks(nMissebBlocks, nEpoch) ((*SENDMISSEDBLOCKS)(nMissebBlocks, nEpoch))
+
+
+
+static int (__stdcall *STOPSERVERTCP)(void);
+#define StopServerTCP() ((*STOPSERVERTCP)())
+
+static int (__stdcall *STOPSERVERUDP)(void);
+#define StopServerUDP() ((*STOPSERVERUDP)())
+
+static int (__stdcall *GETSTATUSSERVERTCP)(unsigned int&);
+#define GetStatusServerTCP(clients) ((*GETSTATUSSERVERTCP)(clients))
+
+static int (__stdcall *GETSTATUSSERVERUDP)(unsigned int&);
+#define GetStatusServerUDP(clients) ((*GETSTATUSSERVERUDP)(clients))
+
+static int (__stdcall *SENDUDPDATASTREAMINGTS)(unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int);
+#define SendUDPDatastreamingTS(epoch, offset, hour, minute, second, millisecond) ((*SENDUDPDATASTREAMINGTS)(epoch, offset, hour, minute, second, millisecond))
+
+static int (__stdcall *SENDDATAGRAMTCP)(char*, int, char*);
+#define SendDatagramTCP(pData, nLength, messageCode) ((*SENDDATAGRAMTCP)(pData, nLength, messageCode))
+
+
+static int (__stdcall *SETEEGCHANNELMAPINFO)(char*,int);
+#define SetEEGChannelMapInfo(chMapInfoBytes,nLength) ((*SETEEGCHANNELMAPINFO)(chMapInfoBytes,nLength))
+
+
+static int (__stdcall *SENDTCPTIMESTAMP)(unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int);
+#define SendTCPTimeStamp(epoch, offset, hour, minute, second, millisecond) ((*SENDTCPTIMESTAMP)(epoch, offset, hour, minute, second, millisecond))
+
+static float* (__stdcall *GETNOTIFICATIONS)(int&);
+#define GetNotifications(nCount) ((*GETNOTIFICATIONS)(nCount))
+
+static int (__stdcall *SENDNOTIFICATION)(float*, int);
+#define SendNotification(pData, nLength) ((*SENDNOTIFICATION)(pData, nLength))
+
+static int (__stdcall *SENDMOVEMENT)(float*, int);
+#define SendMovement(pData, nLength) ((*SENDMOVEMENT)(pData, nLength))
+
+static int (__stdcall *SENDRAWTILTS)(float*, int);
+#define SendRawTilts(pData, nLength) ((*SENDRAWTILTS)(pData, nLength))
+
+static int (__stdcall *SENDANGLES)(float*, int);
+#define SendAngles(pData, nLength) ((*SENDANGLES)(pData, nLength))
+
+static int (__stdcall *SENDZSCORE)(float*, int);
+#define SendZScore(pData, nLength) ((*SENDZSCORE)(pData, nLength))
+
+static int (__stdcall *SENDBANDOVERALLPSDDATA)(float*, int);
+#define SendBandOverallPSDData(pData, nLength) ((*SENDBANDOVERALLPSDDATA)(pData, nLength))
+
+static int (__stdcall *SENDBANDOVERALLPSDRAWDATA)(float*, int);
+#define SendBandOverallPSDRawData(pData, nLength) ((*SENDBANDOVERALLPSDRAWDATA)(pData, nLength))
+
+static int (__stdcall *SENDPSDBANDWIDTHDATA)(float*, int);
+#define SendPSDBandwidthData(pData, nLength) ((*SENDPSDBANDWIDTHDATA)(pData, nLength))
+
+static int (__stdcall *SENDPSDBANDWIDTHRAWDATA)(float*, int);
+#define SendPSDBandwidthRawData(pData, nLength) ((*SENDPSDBANDWIDTHRAWDATA)(pData, nLength))
+
+static int (__stdcall *SENDPULSERATEDATA)(float*, int);
+#define SendPulseRateData(pData, nLength) ((*SENDPULSERATEDATA)(pData, nLength))
+
+//static int (__stdcall *GETDEBUGINFOTCP)(_TCP_DEBUG_INFO* pTCPDebugInfo);
+//#define GetDebugInfoTCP(pTcpDebugInfo) ((*GETDEBUGINFOTCP)(pTCPDebugInfo))
+
+static int (__stdcall *SENDHAPTICDATA)(float*, int);
+#define SendHapticData(pData, nLength) ((*SENDHAPTICDATA)(pData, nLength))
+
+static int (__stdcall *SENDRAWOPTICALDATA)(float*, int);
+#define SendRawOpticalData(pData, nLength) ((*SENDRAWOPTICALDATA)(pData, nLength))
+
+static int (__stdcall *SENDTHIRDPARTYDATA)(char*, int);
+#define SendThirdParty(pData, nLength) ((*SENDTHIRDPARTYDATA)(pData, nLength))
+
+static int (__stdcall *SENDIMPEDANCE)(char*, int);
+#define SendImpedance(pData, nLength) ((*SENDIMPEDANCE)(pData, nLength))
+
+
+///////////////////////////////////////////////////////////////////////////////
+// DLL linkage functions (temporary)
+static HINSTANCE OpenComLib(void)
+{
+
+#ifdef _WIN64
+ //hComLib = LoadLibrary(_T("c:\\ABM\\B-Alert\\SDK64\\bin\\ABM_ThirdPartyCommunication64.dll"));
+ hComLib = LoadLibrary(_T("ABM_ThirdPartyCommunication64.dll"));
+#else
+ hComLib = LoadLibrary(_T("c:\\ABM\\B-Alert\\SDK\\bin\\ABM_ThirdPartyCommunication.dll"));
+#endif
+
+ if (hComLib != NULL)
+ {
+ STARTSERVER = (int(__stdcall *)(_SERVER_INFO))GetProcAddress(hComLib, "StartServer");
+ STOPSERVER = (int(__stdcall *)(void))GetProcAddress(hComLib, "StopServer");
+ SENDDATAGRAM = (int(__stdcall *)(char*, int, char*))GetProcAddress(hComLib, "SendDatagram");
+ SENDRAWDATA = (int(__stdcall *)(float*, int))GetProcAddress(hComLib, "SendRawData");
+ SENDDECONDATA = (int(__stdcall *)(float*, int))GetProcAddress(hComLib, "SendDeconData");
+ SENDQUALITY = (int(__stdcall *)(float*, int))GetProcAddress(hComLib, "SendQuality");
+ SENDCURRENTQUALITY = (int(__stdcall *)(float*, int))GetProcAddress(hComLib, "SendCurrentQuality");
+ SENDCLASSQUALITY = (int(__stdcall *)(float*, int))GetProcAddress(hComLib, "SendClassQuality");
+
+ SENDQUALITYCHANNEL = (int(__stdcall *)(float*, int))GetProcAddress(hComLib, "SendQualityChannel");
+ SENDPSDDATA = (int(__stdcall *)(float*, int))GetProcAddress(hComLib, "SendPSDData");
+ SENDPSDRAWDATA = (int(__stdcall *)(float*, int))GetProcAddress(hComLib, "SendPSDRawData");
+ SENDEBDATA = (int(__stdcall *)(char*, int))GetProcAddress(hComLib, "SendEBData");
+ SENDEXCDATA = (int(__stdcall *)(char*, int))GetProcAddress(hComLib, "SendEXCData");
+ SENDEMGDATA = (int(__stdcall *)(char*, int))GetProcAddress(hComLib, "SendEMGData");
+ SENDSATDATA = (int(__stdcall *)(char*, int))GetProcAddress(hComLib, "SendSATData");
+ SENDSPKDATA = (int(__stdcall *)(char*, int))GetProcAddress(hComLib, "SendSPKData");
+ SENDEKGDATA = (int(__stdcall *)(float*, int))GetProcAddress(hComLib, "SendEKGData");
+ SENDBRAINSTATE = (int(__stdcall *)(float*, int))GetProcAddress(hComLib, "SendBrainState");
+ SENDTHIRDPARTYDATA = (int(__stdcall *)(char*, int))GetProcAddress(hComLib, "SendThirdPartyData");
+ STOPSERVERTCP = (int(__stdcall *)(void))GetProcAddress(hComLib, "StopServerTCP");
+ STOPSERVERUDP = (int(__stdcall *)(void))GetProcAddress(hComLib, "StopServerUDP");
+ GETSTATUSSERVERTCP = (int(__stdcall *)(unsigned int&))GetProcAddress(hComLib, "GetStatusServerTCP");
+ GETSTATUSSERVERUDP = (int(__stdcall *)(unsigned int&))GetProcAddress(hComLib, "GetStatusServerUDP");
+ SENDUDPDATASTREAMINGTS = (int(__stdcall *)(unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int))GetProcAddress(hComLib, "SendUDPDatastreamingTS");
+ SENDDATAGRAMTCP = (int(__stdcall *)(char*, int, char*))GetProcAddress(hComLib, "SendDatagramTCP");
+ SENDTCPTIMESTAMP = (int(__stdcall *)(unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int))GetProcAddress(hComLib, "SendTCPTimeStamp");
+ SENDMOVEMENT = (int(__stdcall *)(float*, int))GetProcAddress(hComLib, "SendMovement");
+ SENDRAWTILTS = (int(__stdcall *)(float*, int))GetProcAddress(hComLib, "SendAccelerometer");
+ SENDANGLES = (int(__stdcall *)(float*, int))GetProcAddress(hComLib, "SendAngles");
+ SENDZSCORE = (int(__stdcall *)(float*, int))GetProcAddress(hComLib, "SendZScore");
+ SENDBANDOVERALLPSDDATA = (int(__stdcall *)(float*, int))GetProcAddress(hComLib, "SendBandOverallPSDData");
+ SENDBANDOVERALLPSDRAWDATA = (int(__stdcall *)(float*, int))GetProcAddress(hComLib, "SendBandOverallPSDRawData");
+ SENDPSDBANDWIDTHDATA = (int(__stdcall *)(float*, int))GetProcAddress(hComLib, "SendPSDBandwidthData");
+ SENDPSDBANDWIDTHRAWDATA = (int(__stdcall *)(float*, int))GetProcAddress(hComLib, "SendPSDBandwidthRawData");
+ SENDPULSERATEDATA = (int(__stdcall *)(float*, int))GetProcAddress(hComLib, "SendPulseRateData");
+ SENDHAPTICDATA = (int(__stdcall *)(float*, int))GetProcAddress(hComLib, "SendHapticData");
+ SENDRAWOPTICALDATA = (int(__stdcall *)(float*, int))GetProcAddress(hComLib, "SendRawOpticalData");
+ //GETDEBUGINFOTCP= (int (__stdcall*)(_TCP_DEBUG_INFO*)) GetProcAddress(hComLib, "GetDebugInfoTCP");
+ //SENDBATTERYPERCENTAGE = (int (__stdcall*)(int, int)) GetProcAddress(hComLib, "SendBatteryPercentage");
+ SENDBATTERYANDIMPENDACES = (int (__stdcall*)(int, int, int, int[])) GetProcAddress(hComLib, "SendBatteryAndImpedances");
+ SENDMISSEDBLOCKS = (int (__stdcall*)(int, int)) GetProcAddress(hComLib, "SendMissedBlocks");
+ SETEEGCHANNELMAPINFO = (int(__stdcall *)(char*, int))GetProcAddress(hComLib, "SetEEGChannelMapInfo");
+ SENDNOTIFICATION = (int(__stdcall *)(float*, int))GetProcAddress(hComLib, "SendNotification");
+ GETNOTIFICATIONS = (float*(__stdcall *)(int&))GetProcAddress(hComLib, "GetNotifications");
+ SENDIMPEDANCE = (int(__stdcall *)(char*, int))GetProcAddress(hComLib, "SendImpedance");
+
+
+ }
+
+ if (!hComLib)
+ {
+ DWORD dwError = GetLastError();
+ LPVOID lpMsgBuf;
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ dwError,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ (LPTSTR) &lpMsgBuf,
+ 0,
+ NULL
+ );
+ // Display the string.
+ ::MessageBox( NULL, (LPCTSTR)lpMsgBuf, _T("Error"), MB_OK | MB_ICONINFORMATION );
+ // Free the buffer.
+ LocalFree( lpMsgBuf );
+ }
+
+ return hComLib;
+}
+
+static BOOL CloseComLib(void)
+{
+ BOOL bRet = FreeLibrary(hComLib);
+ hComLib = NULL;
+
+ return bRet;
+}
+
+#endif
+
diff --git a/physiolabxr/third_party/BAlert/SDK64/include/EegAcqDefine.h b/physiolabxr/third_party/BAlert/SDK64/include/EegAcqDefine.h
new file mode 100644
index 00000000..0274fbcf
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/SDK64/include/EegAcqDefine.h
@@ -0,0 +1,205 @@
+
+#ifndef __EEGACQ_DEFINE__
+#define __EEGACQ_DEFINE__
+
+
+#define MAX_NUM_ELECTRODE 24//fz,cz,po,veog,heog,ref
+#define MAX_NUM_EEGCHANNELS 24
+#define MAX_NUM_ALLCHANNELS 26 //the number of channels including time channels (X24 has 24 eeg + 2 time ch)
+
+
+#define ABM_SESSION_RAW 0 // - gives RAW and RAW PSD data
+#define ABM_SESSION_DECON 1 //- gives all of ABM_SESSION_RAW plus DECON and DECON PSD
+#define ABM_SESSION_BSTATE 2 //- gives all of ABM_SESSION_DECON plus BSTATE
+#define ABM_SESSION_WORKLOAD 3 //- gives all of ABM_SESSION_BSTATE plus WORKLOAD
+
+// device codes are changed according to codes in Rome
+
+#define ABM_DEVICE_X24Flex_10_20 6
+#define ABM_DEVICE_X10Flex_Standard 7
+#define ABM_DEVICE_X24Flex_Reduced 8
+#define ABM_DEVICE_X24Flex_10_20_LM 9
+#define ABM_DEVICE_X24LE_10_20_LM 10
+#define ABM_DEVICE_X24Flex_10_20_LM_Red 11
+#define ABM_DEVICE_X24LE_10_20_LM_Red 12
+#define ABM_DEVICE_X10Flex_10_20_LM_Red 13
+#define ABM_DEVICE_X24LE_Ambulatory 14
+
+#define IS_ABM_DEVICE_X24(x) (x==ABM_DEVICE_X24Flex_10_20 || x==ABM_DEVICE_X24Flex_Reduced || x==ABM_DEVICE_X24Flex_10_20_LM || x==ABM_DEVICE_X24LE_10_20_LM || x==ABM_DEVICE_X24Flex_10_20_LM_Red || x==ABM_DEVICE_X24LE_10_20_LM_Red || x==ABM_DEVICE_X24LE_Ambulatory)
+#define IS_ABM_DEVICE_X10(x) (x==ABM_DEVICE_X10Flex_Standard || x==ABM_DEVICE_X10Flex_10_20_LM_Red)
+#define IS_ABM_DEVICE_24_CH(x) (x==ABM_DEVICE_X24Flex_10_20 || x==ABM_DEVICE_X24Flex_10_20_LM || x==ABM_DEVICE_X24LE_10_20_LM || x==ABM_DEVICE_X24LE_Ambulatory)
+#define IS_ABM_DEVICE_10_CH(x) (x==ABM_DEVICE_X10Flex_Standard || x==ABM_DEVICE_X24Flex_Reduced || x==ABM_DEVICE_X24Flex_10_20_LM_Red || x==ABM_DEVICE_X24LE_10_20_LM_Red || x==ABM_DEVICE_X10Flex_10_20_LM_Red)
+#define IS_ABM_DEVICE_24LE(x) (x==ABM_DEVICE_X24LE_10_20_LM || x==ABM_DEVICE_X24LE_10_20_LM_Red || x==ABM_DEVICE_X24LE_Ambulatory)
+
+#define ABM_THIRD_PARTY_PORTS_NUM 3
+
+#define ESU_TYPE_UNKNOWN 0
+#define ESU_TYPE_DONGLE 1
+#define ESU_TYPE_SINGLE_CHANNEL 2
+#define ESU_TYPE_MULTI_CHANNEL 3
+
+
+#define IMPEDANCE_REFERENTIAL 0
+#define IMPEDANCE_DIFERENTIAL 1
+#define IMPEDANCE_NOT_AVAILABLE 2
+#define IMPEDANCE_REFERENTIAL_SECONDARY 10
+
+
+// windows messages for communication between threads
+#define WM_DATARECEIVED WM_USER
+#define WM_COMMANDRECEIVED (WM_USER + 1)
+#define WM_NOTRECEIVING (WM_USER + 2)
+#define WM_ANSWERECEIVED (WM_USER + 3)
+#define WM_DEVCHANGEFREQ (WM_USER + 4)
+#define WM_TECHNICAL_MON_RESET (WM_USER + 5)
+#define WM_AMP_ABD_LINK_CHECKED (WM_USER + 6)
+#define WM_UPDATE_COMMUNICATION_PORTS (WM_USER + 7)
+#define WM_IMPEDANCE_MSG (WM_USER + 8)
+#define WM_TM_FINISHED_MSG (WM_USER + 9)
+#define WM_TM_START_MSG (WM_USER + 10)
+#define WM_IMPEDANCE_START_MSG (WM_USER + 11)
+
+
+#define SDK_WAITING_MODE -1
+#define SDK_NORMAL_MODE 0
+#define SDK_IMPEDANCE_MODE 1
+#define SDK_TECHNICALMON_MODE 2
+
+#define MAX_LENGTH_CHANNEL_NAME 20
+
+#define TIMESTAMP_RAW 0
+#define TIMESTAMP_PSD 1
+#define TIMESTAMP_DECON 2
+#define TIMESTAMP_CLASS 3
+#define TIMESTAMP_EKG 4
+#define TIMESTAMP_PSDRAW 5
+#define TIMESTAMP_MOVEMENT 6
+#define TIMESTAMP_BANDOVERPSD 7
+#define TIMESTAMP_PSDBANDWIDTH 8
+#define TIMESTAMP_PSDBANDWIDTHRAW 9
+#define TIMESTAMP_ZSCORE 10
+#define TIMESTAMP_PULSERATE 11
+#define TIMESTAMP_FILTERED 12
+#define TIMESTAMP_RAWRAW 13
+#define TIMESTAMP_BANDOVERPSDRAW 14
+#define TIMESTAMP_RAWTILTS 15
+#define TIMESTAMP_ANGLES 16
+#define TIMESTAMP_OPTICAL 17
+#define TIMESTAMP_HAPTIC 18
+#define TIMESTAMP_QUALITY 19
+
+#define TIMESTAMP_RAW_NEW 100
+#define TIMESTAMP_NEW 120
+
+#define ESU_TIMESTAMP_LENGTH 4
+#define SYSTEM_TIMESTAMP_LENGTH 8
+
+///block 1 host
+//#define POS_SERIAL_NUMBER_H 0
+//#define POS_HARDWARE_VERSION_H 16
+//#define POS_FIRMWARE_VERSION_H 20
+////
+//////block 2 host
+//#define POS_SYSSERIAL_NUMBER_H 0
+//#define POS_RELEASE_H 16
+////
+//////block 3 host
+//#define POS_TX_OFFSET_H 0
+//#define POS_RX_OFFSET_H 2
+//#define POS_DEFF_FRQ_CH_H 4
+//#define POS_CONFIG_WORD_H 6
+//#define POS_EEPROM_HOST 8
+//
+//
+////block 1 acq
+//#define POS_SERIAL_NUMBER_A 0
+//#define POS_HARDWARE_VERSION_A 16
+//#define POS_FIRMWARE_VERSION_A 20
+////
+//////block 2 acq
+//#define POS_SYSSERIAL_NUMBER_A 0
+//#define POS_RELEASE_A 16
+////
+//////block 3 acq
+//#define POS_TX_OFFSET_A 0
+//#define POS_RX_OFFSET_A 2
+//#define POS_DEFF_FRQ_CH_A 4
+//#define POS_TILT_ACC 5
+//#define POS_CONFIG_WORD_A 6
+//#define POS_EEPROM_ACQ 8
+////
+//
+////block 4 adc
+//#define POS_ANLG_BRD_SER_NUM_ADC 0
+//#define POS_HARDWARE_VERSION_ADC 16
+//#define POS_HEADSET 20
+//#define POS_ADC_BITSPERCH 22
+//#define POS_ECG 23
+////
+//////block 5 adc
+//#define POS_CHANN_CONFIG_ADC 0
+//#define POS_DC_OFFSET_ADC 12
+////
+//#define INDEX_BLOCK_GAIN 6
+//#define INDEX_BLOCK_VERSION 1
+//////block 6 adc
+//#define POS_GAIN_CONSTS_ADC 0
+//#define POS_IMP_CONSTS_ADC 12
+//
+//#define SEND_OFFLINE_SLEEP 60
+//
+////degug file pointers
+//#define ACQ_MESSAGE_COUNTER 0
+//#define ACQ_BATTERY 1
+//#define ACQ_VCC 2
+//#define ACQ_RSSI 3
+//#define ACQ_TEMP 4
+//#define ACQ_RECC_ERR_LAST 5
+//#define ACQ_TRSM_ERR_LAST 6
+//#define ACQ_TRSM_CHNO 7
+//#define ACQ_RECC_CHNO 8
+//#define ACQ_IMP_LEV 9
+//#define ACQ_IMP_CHANNEL 10
+//#define ACQ_SIMULATED_FLG 11
+//#define ACQ_FRQRXOFFSET 12
+//#define HOST_BATTERY 13
+//#define HOST_VCC 14
+//#define HOST_RSSI 15
+//#define HOST_TEMP 16
+//#define HOST_RECC_ERR_LAST 17
+//#define HOST_TRSM_ERR_LAST 18
+//#define HOST_TRSM_CHNO 19
+//#define HOST_RECC_CHNO 20
+//#define HOST_SIMULATED_FLG 21
+//#define HOST_FRQRXOFFSET 22
+//
+#define DC_OFFSET_RT 49
+
+////eprom
+//#define EEPROM_NOT_EXIST 0
+//#define EEPROM_EXIST_NOT_INIT 1
+//#define EEPROM_EXIST_INIT 2
+//
+////one minute
+//#define ONE_MINUTE_SEC 60
+//
+//////type of analog boards
+//#define TYPE_OLDEST_ANALOG_BOARD 0
+//#define TYPE_MEDIUM_ANALOG_BOARD 1
+//#define TYPE_NEW_ANALOG_BOARD 2
+//#define TYPE_7_EL_ANALOG_BOARD 3
+//
+//#define TYPE_ANALOG_BOARD_July05 5
+//#define TYPE_ANALOG_BOARD_209_210 6
+//#define TYPE_ANALOG_BOARD_206 7
+//#define TYPE_ANALOG_BOARD_224 8
+//#define TYPE_ANALOG_BOARD_9_CHANNEL 9
+//
+
+//#define VCP_SERIAL_PORT 0
+//#define USB_DESCRIPTION_PORT 1
+
+#define MAX_NUMBER_PACKETS 65536
+
+#endif //__EEGACQ_DEFINE__
+
diff --git a/physiolabxr/third_party/BAlert/SDK64/include/ErrorCode.h b/physiolabxr/third_party/BAlert/SDK64/include/ErrorCode.h
new file mode 100644
index 00000000..dd05fadb
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/SDK64/include/ErrorCode.h
@@ -0,0 +1,110 @@
+#define ACQ_STARTED_OK 1
+#define ACQ_STARTED_NO -1
+
+#define ACQ_STOPPED_OK 1
+#define ACQ_STOPPED_NO -1
+
+#define ACQ_PAUSED_OK 1
+#define ACQ_PAUSED_NO -1
+
+#define ACQ_RESUMED_OK 1
+#define ACQ_RESUMED_NO -1
+
+#define IMP_STARTED_OK 1
+#define IMP_STARTED_NO -1
+
+#define IMP_STOPPED_OK 1
+#define IMP_STOPPED_NO -1
+
+#define TM_STARTED_OK 1
+#define TM_STARTED_NO -1
+
+#define TM_STOPPED_OK 1
+#define TM_STOPPED_NO -1
+
+
+#define ABM_RESULT_OK 1
+#define ABM_OPERATION_FAILED -1
+
+
+#define INIT_SESSION_OK 1
+#define INIT_SESSION_NO -1
+#define INIT_SESSION_NO_DEFFILE_FAILED -2
+#define INIT_SESSION_NO_DESTFILE_FAILED -3
+
+#define SET_MARKER_OK 1
+#define SET_MARKER_NO -1
+
+#define ID_WRONG_SEQUENCY_OF_COMMAND 0
+
+#define NOT_IMPLEMENTED 0
+
+
+//errors
+#define ABM_ERROR_SDK_ACQUISITION_STOPPED 100
+#define ABM_ERROR_SDK_NO_DATA_ARRIVING 101
+#define ABM_ERROR_SDK_CREATE_MAIN_WINDOW_FAILED 110
+#define ABM_ERROR_SDK_COULDNT_FIND_DEVICE 120
+#define ABM_ERROR_SDK_COULDNT_CONNECT_DEVICE 121
+
+#define ABM_ERROR_SDK_EDF_FILE_ERROR 130
+
+#define ABM_ERROR_SDK_THIRDPARTYBYTES 140
+#define ABM_ERROR_SDK_TEAMING_BEACON_ERROR 142
+
+#define ABM_ERROR_SDK_COULDNT_START_REALTIME 150
+#define ABM_ERROR_SDK_COULDNT_START_SAVING 151
+#define ABM_ERROR_SDK_COULDNT_STOP_REAL_TIME 170
+#define ABM_ERROR_SDK_COULDNT_LOAD_CHANNEL_MAP 180
+#define ABM_ERROR_SDK_WRONG_SESSION_TYPE 190
+#define ABM_ERROR_SDK_WRONG_INPUT_SETTINGS 191
+#define ABM_ERROR_SDK_WRONG_FILE_PATHS 192
+#define ABM_ERROR_SDK_CLASSIFICATION_INIT_FAILED 193
+#define ABM_ERROR_SDK_COULDNT_CLOSE_CONNECTION 194
+#define ABM_ERROR_SDK_NOTSET_DEFFILE 195
+#define ABM_ERROR_SDK_WRONG_DESTPATH 196
+#define ABM_ERROR_SDK_TOO_LARGE_MISSED_BLOCK 197
+#define ABM_ERROR_SDK_TOO_MANY_MISSED_BLOCKS 198
+#define ABM_ERROR_SDK_NOT_INITIALIZED 199
+#define ABM_ERROR_SDK_IMPEDANCE_FAILED 200
+#define ABM_ERROR_SDK_DEVICE_QUERY_FAILED 201
+#define ABM_ERROR_SDK_INVALID_DEVICE_MODEL 202
+#define ABM_ERROR_SDK_INVALID_STRIP 203
+#define ABM_ERROR_SDK_UNKNOWN_STRIP 204
+#define ABM_ERROR_SDK_NO_STRIP 205
+#define ABM_ERROR_SDK_RECEIVER_NOT_FOUND 206
+#define ABM_ERROR_SDK_HEADSET_NOT_FOUND 207
+#define ABM_ERROR_SDK_PC_SYNCH_FAILED 208
+#define ABM_ERROR_SDK_OLD_HEADSET 209
+
+#define ABM_WARNING_SDK_OLD_CLASSIC_FW -210
+#define ABM_ERROR_NOT_ACTIVATED -211
+#define ABM_ERROR_NOT_AVAILABLE -212
+
+
+
+
+
+#define ABM_ERROR_SDK_COMMAND_IMP_START_FAILED 160
+#define ABM_ERROR_SDK_COMMAND_IMP_STOP_FAILED 161
+#define ABM_ERROR_SDK_COMMAND_IMP_HIGH_FAILED 162
+#define ABM_ERROR_SDK_COMMAND_IMP_LOW_FAILED 163
+#define ABM_ERROR_SDK_COMMAND_IMP_START_FAILED_IGNORED 164
+
+#define ABM_ERROR_SDK_INVALID_ESU_CONFIG_MULTIPLE_PORTS 140
+#define ABM_ERROR_SDK_INVALID_ESU_CONFIG_NO_PORTS 141
+#define ABM_ERROR_SDK_INVALID_ESU_CONFIG_COM1 142
+#define ABM_ERROR_SDK_INVALID_ESU_CONFIG_COM2 143
+#define ABM_ERROR_SDK_INVALID_ESU_CONFIG_COM3 144
+#define ABM_ERROR_SDK_INVALID_ESU_CONFIG_COM4 145
+#define ABM_ERROR_SDK_INVALID_ESU_CONFIG_LPT 146
+
+
+//warnings
+#define ABM_WARN_SDK_ACQUISITION_STOPPED 200
+#define ABM_WARN_SDK_COULDNT_CONNECT 230
+#define ABM_WARN_SDK_DEVICE_NOT_FOUND 250
+#define ABM_WARN_SDK_TIMESTAMP_WO_SAMPLE 260
+#define ABM_WARN_SDK_TIMESTAMP_NOT_ARRIVED 270
+
+
diff --git a/physiolabxr/third_party/BAlert/SDK64/include/PlayEbs.h b/physiolabxr/third_party/BAlert/SDK64/include/PlayEbs.h
new file mode 100644
index 00000000..bdea5aa1
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/SDK64/include/PlayEbs.h
@@ -0,0 +1,87 @@
+
+// The following ifdef block is the standard way of creating macros which make exporting
+// from a DLL simpler. All files within this DLL are compiled with the PLAYEBS_EXPORTS
+// symbol defined on the command line. this symbol should not be defined on any project
+// that uses this DLL. This way any other project whose source files include this file see
+// PLAYEBS_API functions as being imported from a DLL, whereas this DLL sees symbols
+// defined with this macro as being exported.
+#ifdef PLAYEBS_EXPORTS
+#define PLAYEBS_API __declspec(dllexport)
+#else
+#define PLAYEBS_API __declspec(dllimport)
+#endif
+
+#include "..\include\TypeDef.h"
+
+
+
+//PLAYEBS_API BOOL Open( TCHAR* sFullPath, TCHAR* definitionfile );
+
+PLAYEBS_API BOOL OpenCustom( TCHAR* sFullPath, _SESSION_INFO* pSessionInfo, int nDeviceType, BOOL bHRVAnalysis );
+
+PLAYEBS_API _SESSION_INFO_PE* __stdcall GetSessionInfo();
+
+PLAYEBS_API BOOL PlayFile(double nPauseInMiliseconds = 78.125 );
+
+PLAYEBS_API void ClosePlay();
+
+
+
+//get functions
+PLAYEBS_API _BRAIN_STATE* __stdcall GetBrainStatePE(int& );
+
+PLAYEBS_API float* __stdcall GetRawDataPE(int&);
+
+PLAYEBS_API float* __stdcall GetRawRawDataPE(int&);
+
+PLAYEBS_API float* __stdcall GetFilteredDataPE(int&);
+
+PLAYEBS_API float* __stdcall GetDeconDataPE(int& );
+
+PLAYEBS_API float* __stdcall GetQualityChannelDataPE(int& );
+
+PLAYEBS_API float* __stdcall GetPSDDataPE(int& );
+
+PLAYEBS_API float* __stdcall GetPSDDatarawPE(int& );
+
+PLAYEBS_API float* __stdcall GetEKGDataPE(int& );
+
+
+
+PLAYEBS_API float* __stdcall GetMovementDataPE(int& );
+
+PLAYEBS_API float* __stdcall GetRawTiltDataPE(int& );
+
+PLAYEBS_API float* __stdcall GetAnglesDataPE(int& );
+
+PLAYEBS_API int __stdcall InitZScoreDataPE( TCHAR* pchZScoreSourceList );
+
+PLAYEBS_API float* __stdcall GetZScoreDataPE(int&, int& );
+
+
+
+
+
+
+
+PLAYEBS_API int __stdcall SetArtifactsCallbackFuncsPE(void (__stdcall *pFuncEB)(int epstart, int offstart, float shour, float sminute, float ssecond, float smili , int epend, int offend, float ehour, float eminute, float esecond, float emili),
+ void (__stdcall *pFuncExc)(int indexch,int epstart, int offstart, float shour, float sminute, float ssecond, float smili, int epend, int offend, float ehour, float eminute, float esecond, float emili),
+ void (__stdcall *pFuncSat)(int indexch,int epstart, int offstart, float shour, float sminute, float ssecond, float smili, int epend, int offend, float ehour, float eminute, float esecond, float emili),
+ void (__stdcall *pFuncSpk)(int indexch, int epstart, int offstart, float shour, float sminute, float ssecond, float smili, int epend, int offend, float ehour, float eminute, float esecond, float emili),
+ void (__stdcall *pFuncEMG)(int indexch,int epstart, int offstart, float shour, float sminute, float ssecond, float smili, int epend, int offend, float ehour, float eminute, float esecond, float emili));
+
+PLAYEBS_API float* __stdcall GetCurrentQualityDataPE(int& );
+
+PLAYEBS_API float* __stdcall GetClassQualityDataPE(int& );
+
+PLAYEBS_API int __stdcall GetPEChannelsInfo( _EEGCHANNELS_INFO & stEEGChannelsInfo);
+PLAYEBS_API int __stdcall GetPEDeviceInfo(char* sFullPath,int& nDeviceType);
+PLAYEBS_API int __stdcall GetPEPacketChannelNmbInfo(int& nRawPacketChannelsNmb, int& nDeconPacketChannelsNmb, int& nPSDPacketChannelsNmb, int& nRawPSDPacketChannelNmb, int& nQualityPacketChannelNmb);
+PLAYEBS_API int __stdcall GetPEBandsDescription(char* pszPSDBands, int& count);
+
+
+PLAYEBS_API float* __stdcall GetPSDBandwidthRawDataPE(int& nCountPackages, int& nPackageSize);
+PLAYEBS_API float* __stdcall GetPSDBandwidthClassDataPE(int& nCountPackages, int& nPackageSize);
+PLAYEBS_API float* __stdcall GetBandOverallPSDRawDataPE(int& nCountPackages, int& nPackageSize);
+PLAYEBS_API float* __stdcall GetBandOverallPSDClassDataPE(int& nCountPackages, int& nPackageSize);
+
diff --git a/physiolabxr/third_party/BAlert/SDK64/include/SignalHandling/BAlert_SignalHandling.h b/physiolabxr/third_party/BAlert/SDK64/include/SignalHandling/BAlert_SignalHandling.h
new file mode 100644
index 00000000..21bef217
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/SDK64/include/SignalHandling/BAlert_SignalHandling.h
@@ -0,0 +1,39 @@
+//#ifdef BALERTLAB_SIGNALHANDLING_EXPORTS
+#define BALERT_SIGNALHANDLING_API __declspec(dllexport)
+//#else
+//#define BALERTLAB_SIGNALHANDLING_API __declspec(dllimport)
+//#endif
+
+
+#include "TypeDef.h"
+#include "ErrorCode.h"
+#include "Helper.h"
+
+
+
+
+
+BALERT_SIGNALHANDLING_API int __stdcall BAlert_Sig_GetHeader(WCHAR* pszFileName, _BALERT_LAB_HEADER& header);
+BALERT_SIGNALHANDLING_API int __stdcall BAlert_Sig_CheckChannelList(WCHAR* pszFileName, WCHAR* chChannelList, int nChannels);
+BALERT_SIGNALHANDLING_API int __stdcall BAlert_Sig_GetFileInfo(WCHAR* pszFileName, _BALERT_LAB_FILEINFO& fileInfo);
+BALERT_SIGNALHANDLING_API void __stdcall BAlert_Sig_GetLastError(WCHAR** pszErrorMessage);
+BALERT_SIGNALHANDLING_API void __stdcall BAlert_Sig_FreeBuffer( void* ptrBuffer);
+BALERT_SIGNALHANDLING_API int __stdcall BAlert_Sig_RepairFile( WCHAR* pszEdfFileName, WCHAR* pszOutputPath, WCHAR** pszRepairedFileNames );
+BALERT_SIGNALHANDLING_API int __stdcall BAlert_Sig_GetData(WCHAR* pszFileName, WCHAR** chNames, int& nSamples, int& nChannelsAll,
+ int& nChannelsInFile, float** fData,
+ int& nChannelsConstructed, float** fConstructedData,
+ int& nTimeChannels, unsigned char** chTimeData);
+BALERT_SIGNALHANDLING_API int __stdcall BAlert_Sig_GetEEGFileChannels( WCHAR* pszFileName,WCHAR** pszChannels , int& nChannels, bool bIncludeDeconChannels );
+BALERT_SIGNALHANDLING_API int __stdcall BAlert_Sig_GetConfigurationInfo( WCHAR* pszFileName,WCHAR** chConfigurationName, int& nDeviceTypeCode);
+BALERT_SIGNALHANDLING_API int __stdcall BAlert_Sig_GetMissedBlock(WCHAR* pszFileName, int& nSamples, int** nMissedBlock);
+BALERT_SIGNALHANDLING_API int __stdcall BAlert_Sig_GetImpMissedBlock(WCHAR* pszFileName, int& nSamples, int** nImpMissedBlock);
+BALERT_SIGNALHANDLING_API int __stdcall BAlert_Sig_GetAllMissedBlock(WCHAR* pszFileName, int& nSamples, int** nImpMissedBlock);
+
+BALERT_SIGNALHANDLING_API int __stdcall BAlert_Sig_GetChannelsForProcessing(WCHAR* pszFileName,WCHAR** pszChannels , int& nChannels);
+BALERT_SIGNALHANDLING_API int __stdcall BAlert_Sig_GetFileChannels( WCHAR* pszFileName, WCHAR** pszChannels , int& nChannels );
+BALERT_SIGNALHANDLING_API int __stdcall BAlert_Sig_GetClassificationChannels( WCHAR* pszFileName, WCHAR** pszChannels , int& nChannels );
+BALERT_SIGNALHANDLING_API int __stdcall BAlert_Sig_GetAvailableChannels( WCHAR* pszFileName, WCHAR** pszChannels , int& nChannels);
+BALERT_SIGNALHANDLING_API int __stdcall BAlert_Sig_GetEyeBlinkChannels( WCHAR* pszFileName, WCHAR** pszChannels, int& nChannels );
+BALERT_SIGNALHANDLING_API int __stdcall BAlert_Sig_GetChannelMap( WCHAR* pszFileName, int& nChannelMap );
+BALERT_SIGNALHANDLING_API int __stdcall BAlert_Sig_EditFile_CustomOutPath(WCHAR* pszFileName,WCHAR* pszOutFileType, WCHAR* pszOutputPath, WCHAR** pszOutFileName,
+ int nStartEp, int nStopEp, int nStartSample, int nStopSample, WCHAR* chChannels, int& nChannels);
\ No newline at end of file
diff --git a/physiolabxr/third_party/BAlert/SDK64/include/TCP/AbmTngrmDll.h b/physiolabxr/third_party/BAlert/SDK64/include/TCP/AbmTngrmDll.h
new file mode 100644
index 00000000..89c4b128
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/SDK64/include/TCP/AbmTngrmDll.h
@@ -0,0 +1,101 @@
+
+// The following ifdef block is the standard way of creating macros which make exporting
+// from a DLL simpler. All files within this DLL are compiled with the ABMTNGRMDLL_EXPORTS
+// symbol defined on the command line. this symbol should not be defined on any project
+// that uses this DLL. This way any other project whose source files include this file see
+// ABMTNGRMDLL_API functions as being imported from a DLL, wheras this DLL sees symbols
+// defined with this macro as being exported.
+#ifdef ABMTNGRMDLL_EXPORTS
+#define ABMTNGRMDLL_API __declspec(dllexport)
+#else
+#define ABMTNGRMDLL_API __declspec(dllimport)
+#endif
+
+#include "..\TypeDefDataTypes.h"
+
+//Error codes
+#define ABM_DS_NOT_USE_METHOD 0
+#define ABM_DS_SUCCESS 1
+#define ABM_DS_ERROR_INIT_PARAMETER -1
+#define ABM_DS_ERROR_INIT_WINSOCK2 -2
+#define ABM_DS_ERROR_CREATE_SOCKET -3
+#define ABM_DS_ERROR_GET_HOST -4
+#define ABM_DS_ERROR_CONNECT -5
+#define ABM_DS_ERROR_NON_BLOCK_MODE -6
+#define ABM_DS_ERROR_BAD_HANDLE -7
+#define ABM_DS_ERROR_TO_MANY_CONNECTIONS -8
+#define ABM_DS_ERROR_WRONG_INPUT_PARAMETER -9
+#define ABM_DS_ERROR_NONEXISTANT_CONNECTION -10
+#define ABM_DS_ERROR_CHANNELMAP_NOT_SET -11
+#define ABM_DS_ERROR_INITIALIZATION_FAILED -12
+#define ABM_DS_ERROR_UKNOWN_PROPERTY -13
+
+#define ABM_DS_CLIENT_TCP_VIEW 1
+#define ABM_DS_CLIENT_UDP 0
+#define ABM_DS_CLIENT_TCP_CONTROL 2
+
+#define ABM_DS_PROPERTY_BEACON_INTERVAL 250
+
+
+// connection control
+ABMTNGRMDLL_API long __stdcall OpenConnection(char* sInput, int &handle,int bTCP = ABM_DS_CLIENT_TCP_VIEW);
+ABMTNGRMDLL_API long __stdcall CloseConnection(int handle);
+
+ABMTNGRMDLL_API int _stdcall GetIPInfo(int &IP0, int &IP1, int &IP2, int &IP3, int &nPort, int &nLocalPort, int handle);
+ABMTNGRMDLL_API int __stdcall GetNumberOfConnections();
+
+ABMTNGRMDLL_API _ABM_DATA_DEVICE_INFO* __stdcall AgetDeviceInfo(int handle);
+ABMTNGRMDLL_API int __stdcall AgetProtocolType(int handle);
+ABMTNGRMDLL_API char* __stdcall AgetChannelMapInfo(int &nLength, int handle);
+
+ABMTNGRMDLL_API float* __stdcall AgetNotification(int& nCount, int handle );
+ABMTNGRMDLL_API int __stdcall ASendNotification( float* fNotification, int handle );
+ABMTNGRMDLL_API int __stdcall AGetBattery(int& nEpoch, int handle);
+ABMTNGRMDLL_API int __stdcall AGetImpedances(int& nEpoch, int& nImpOnLineStatus, int nImpOnLineValues[24], int handle);
+ABMTNGRMDLL_API int __stdcall AgetLastError(int& nEpoch, int handle);
+ABMTNGRMDLL_API int __stdcall AgetMissedBlocks(int& nEpoch, int handle);
+ABMTNGRMDLL_API int __stdcall ASendCommand(int nCommandType, int nCommandSubType, int nCommandSequence,
+ int param0, int param1, int nHandle);
+ABMTNGRMDLL_API float* __stdcall AgetResponse(int& nCount, int handle);
+
+
+// get data - fixed size
+ABMTNGRMDLL_API float* __stdcall AgetCWPC(int& nCount, int handle);
+ABMTNGRMDLL_API float* __stdcall AgetEKG(int& nCount, int handle);
+ABMTNGRMDLL_API float* __stdcall AgetMovement(int& nCount, int handle);
+ABMTNGRMDLL_API float* __stdcall AgetPulseRate(int& nCount, int handle);
+ABMTNGRMDLL_API float* __stdcall AgetHaptic(int& nCount, int handle);
+ABMTNGRMDLL_API float* __stdcall AgetACC(int& nCount, int handle);
+ABMTNGRMDLL_API float* __stdcall AgetAngles(int& nCount, int handle);
+ABMTNGRMDLL_API float* __stdcall AgetRawOptical(int& nCount, int handle);
+ABMTNGRMDLL_API float* __stdcall AgetQuality(int& nCount, int handle);
+ABMTNGRMDLL_API float* __stdcall AgetZScore(int& nCount, int handle);
+ABMTNGRMDLL_API float* __stdcall AgetBandOverallPSDData(int& nCount, int handle);
+ABMTNGRMDLL_API float* __stdcall AgetBandOverallPSDRawData(int& nCount, int handle);
+ABMTNGRMDLL_API float* __stdcall AgetPSDBandwidthData(int& nCount, int handle);
+ABMTNGRMDLL_API float* __stdcall AgetPSDBandwidthRawData(int& nCount, int handle);
+
+// get data - variable size
+ABMTNGRMDLL_API float* __stdcall AgetDecon(int& nCount, int handle);
+ABMTNGRMDLL_API float* __stdcall AgetRaw(int& nCount, int handle);
+ABMTNGRMDLL_API float* __stdcall AgetPSD(int& nCount, int handle);
+ABMTNGRMDLL_API float* __stdcall AgetPSDraw(int& nCount, int handle);
+ABMTNGRMDLL_API float* __stdcall AgetQualityChannel(int& nCount, int handle);
+
+
+ABMTNGRMDLL_API long __stdcall GetTimeStamp(float& hour, float& minute, float& seconds, float& miliseconds, int handle);
+ABMTNGRMDLL_API long __stdcall GetEbsTimeStamp(int& nEpoch, int& nOffset, int handle);
+ABMTNGRMDLL_API char* __stdcall AgetThirdParty( int& nCount, int handle );
+
+ABMTNGRMDLL_API int __stdcall ASetPropertyValue(int nPropertyID, int propertyValue, int handle);
+
+// data calbacks
+ABMTNGRMDLL_API int __stdcall ASetArtifactsCallbackFuncs(void (__stdcall *pFuncEB)(int epstart, int offstart, float shour, float sminute, float ssecond, float smili , int epend, int offend, float ehour, float eminute, float esecond, float emili),
+ void (__stdcall *pFuncExc)(int indexch,int epstart, int offstart, float shour, float sminute, float ssecond, float smili, int epend, int offend, float ehour, float eminute, float esecond, float emili),
+ void (__stdcall *pFuncSat)(int indexch,int epstart, int offstart, float shour, float sminute, float ssecond, float smili, int epend, int offend, float ehour, float eminute, float esecond, float emili),
+ void (__stdcall *pFuncSpk)(int indexch, int epstart, int offstart, float shour, float sminute, float ssecond, float smili, int epend, int offend, float ehour, float eminute, float esecond, float emili),
+ void (__stdcall *pFuncEMG)(int indexch,int epstart, int offstart, float shour, float sminute, float ssecond, float smili, int epend, int offend, float ehour, float eminute, float esecond, float emili), int handle);
+ABMTNGRMDLL_API int __stdcall ASetCheckImpedances(void (__stdcall *pFunc)(_ABM_DATA_ELECTRODE*, int&), int handle);
+
+ABMTNGRMDLL_API float* __stdcall AgetCurrentQuality(int& nCount, int handle);
+ABMTNGRMDLL_API float* __stdcall AgetClassQuality(int& nCount, int handle);
\ No newline at end of file
diff --git a/physiolabxr/third_party/BAlert/SDK64/include/TCP/ThirdPartyCommunication.h b/physiolabxr/third_party/BAlert/SDK64/include/TCP/ThirdPartyCommunication.h
new file mode 100644
index 00000000..298c5dbd
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/SDK64/include/TCP/ThirdPartyCommunication.h
@@ -0,0 +1,216 @@
+#ifndef __THIRDPARTYCOMMUNICATION__
+#define __THIRDPARTYCOMMUNICATION__
+
+// The following ifdef block is the standard way of creating macros which make exporting
+// from a DLL simpler. All files within this DLL are compiled with the THIRDPARTYCOMMUNICATION_EXPORTS
+// symbol defined on the command line. this symbol should not be defined on any project
+// that uses this DLL. This way any other project whose source files include this file see
+// THIRDPARTYCOMMUNICATION_API functions as being imported from a DLL, whereas this DLL sees symbols
+// defined with this macro as being exported.
+#ifdef THIRDPARTYCOMMUNICATION_EXPORTS
+#define THIRDPARTYCOMMUNICATION_API __declspec(dllexport)
+#else
+#define THIRDPARTYCOMMUNICATION_API __declspec(dllimport)
+#endif
+
+
+// Constants
+#define ABM_3RD_MAX_NUM_READERS 1000
+#define ABM_3RD_SESSION_ID_LENGTH 9
+// IP protocol
+#define ABM_3RD_PROTOCOL_TRANSPORT_CONTROL 1
+#define ABM_3RD_PROTOCOL_USER_DATAGRAM 2
+// protocol on top of streaming protocol (PROTOCOL_TRANSPORT_CONTROL 1)
+#define ABM_3RD_DATASTREAMING_PROTOCOL 1
+#define ABM_3RD_MINIMAL_PROTOCOL 2
+
+
+
+// ABM 3RD Structs
+typedef struct TD_SERVER_INFO{
+ unsigned int port; //server port to listen to
+ unsigned char chProtocolTCPIP; //wheather to use TCP or UDP on given port
+ unsigned char chDatagramProtocol; // Protocol above TCP/UDP (i.e. DATASTREAMING_PROTOCOL)
+ // 1 - no info // 10 - raw, 11 - raw+decon, 12 - raw+decon+class, 13 - raw+decon+class+workload
+
+ int nDatastreaming_RawChannels;
+ int nDatastreaming_EKGindex;
+ int nPSDBandsCount;
+ int nPSDBandsOverallCount;
+ char sessionID[ABM_3RD_SESSION_ID_LENGTH];
+ int nDeconChannels;
+ int nRawPSDChannels;
+ int nClassPSDChannels;
+ int nQualityCheckChannels;
+ // char chmaxNumClients; //maximum number of clients to accept
+ // char chDisconectUnrespondingClients; //whether to disconect unresponding clients and continue sending to other, or return without sending data
+ // char* pInetAddress;
+ // void* pServerptr;
+}_SERVER_INFO;
+
+typedef struct TD_TCP_DEBUG_INFO{
+ int nWriterPointer;
+ int nNumReaders;
+ int readerPonters[ABM_3RD_MAX_NUM_READERS];
+ int readerActive[ABM_3RD_MAX_NUM_READERS];
+ int readerIP[ABM_3RD_MAX_NUM_READERS][4];
+ int readerPort[ABM_3RD_MAX_NUM_READERS];
+ int nFirstReaderIndex;
+}_TCP_DEBUG_INFO;
+
+// controls the TCP and UDP servers
+THIRDPARTYCOMMUNICATION_API int __stdcall StartServer(_SERVER_INFO);
+THIRDPARTYCOMMUNICATION_API int __stdcall StopServer(); /* stops both TCP and UDP */
+THIRDPARTYCOMMUNICATION_API int __stdcall SetActiveServerPort(int nPort);
+THIRDPARTYCOMMUNICATION_API int __stdcall StopServerTCP();
+THIRDPARTYCOMMUNICATION_API int __stdcall StopServerUDP();
+THIRDPARTYCOMMUNICATION_API int __stdcall GetStatusServerTCP(unsigned int &nConnectedClients);
+THIRDPARTYCOMMUNICATION_API int __stdcall GetStatusServerUDP(unsigned int &nReceivingClients);
+THIRDPARTYCOMMUNICATION_API int __stdcall GetDebugInfoTCP(_TCP_DEBUG_INFO*);
+THIRDPARTYCOMMUNICATION_API float* __stdcall GetNotifications(int &nCount);
+
+
+// sends timestamps to datastreaming
+THIRDPARTYCOMMUNICATION_API int __stdcall SendDatagram(char* pData,int nLength,char* messageCode);
+// sends timestamps to datastreaming via UDP
+THIRDPARTYCOMMUNICATION_API int __stdcall SendUDPDatastreamingTS(unsigned int epoch, unsigned int offset, unsigned int hour,unsigned int minute,unsigned int second, unsigned int millisecond);
+
+// sends message via TCP
+THIRDPARTYCOMMUNICATION_API int __stdcall SendDatagramTCP(char* pData,int nLength,char messageCode);
+
+// datastreaming TCP send functions
+THIRDPARTYCOMMUNICATION_API int __stdcall SendRawData(float* pData,int nLength);
+THIRDPARTYCOMMUNICATION_API int __stdcall SendDeconData(float* pData,int nLength);
+THIRDPARTYCOMMUNICATION_API int __stdcall SendPSDData(float* pData,int nLength);
+THIRDPARTYCOMMUNICATION_API int __stdcall SendPSDRawData(float* pData,int nLength);
+THIRDPARTYCOMMUNICATION_API int __stdcall SendThirdPartyData(char* pData,int nLength);
+THIRDPARTYCOMMUNICATION_API int __stdcall SendEBData(char* pData,int nLength);
+THIRDPARTYCOMMUNICATION_API int __stdcall SendEXCData(char* pData,int nLength);
+THIRDPARTYCOMMUNICATION_API int __stdcall SendEMGData(char* pData,int nLength);
+THIRDPARTYCOMMUNICATION_API int __stdcall SendSATData(char* pData,int nLength);
+THIRDPARTYCOMMUNICATION_API int __stdcall SendSPKData(char* pData,int nLength);
+THIRDPARTYCOMMUNICATION_API int __stdcall SendEKGData(float* pData,int nLength);
+THIRDPARTYCOMMUNICATION_API int __stdcall SendBrainState(float* pData,int nLength);
+THIRDPARTYCOMMUNICATION_API int __stdcall SendQuality(float* pData,int nLength);
+THIRDPARTYCOMMUNICATION_API int __stdcall SendQualityChannel(float* pData,int nLength);
+THIRDPARTYCOMMUNICATION_API int __stdcall SendImpedance(char* pData,int nLength);
+THIRDPARTYCOMMUNICATION_API int __stdcall SendAccelerometer(float* pData,int nLength);
+THIRDPARTYCOMMUNICATION_API int __stdcall SendAngles(float* pData,int nLength);
+THIRDPARTYCOMMUNICATION_API int __stdcall SendMovement(float* pData,int nLength);
+THIRDPARTYCOMMUNICATION_API int __stdcall SendTCPTimeStamp(unsigned int epoch, unsigned int offset, unsigned int hour,unsigned int minute,unsigned int second, unsigned int millisecond);
+THIRDPARTYCOMMUNICATION_API int __stdcall SendZScore(float* pData,int nLength);
+THIRDPARTYCOMMUNICATION_API int __stdcall SendBandOverallPSDData(float* pData,int nLength);
+THIRDPARTYCOMMUNICATION_API int __stdcall SendBandOverallPSDRawData(float* pData,int nLength);
+THIRDPARTYCOMMUNICATION_API int __stdcall SendPSDBandwidthData(float* pData,int nLength);
+THIRDPARTYCOMMUNICATION_API int __stdcall SendPSDBandwidthRawData(float* pData,int nLength);
+THIRDPARTYCOMMUNICATION_API int __stdcall SendPulseRateData(float* pData,int nLength);
+THIRDPARTYCOMMUNICATION_API int __stdcall SendHapticData(float* pData,int nLength);
+THIRDPARTYCOMMUNICATION_API int __stdcall SendRawOpticalData(float* pData,int nLength);
+THIRDPARTYCOMMUNICATION_API int __stdcall SendNotification(float* pData,int nLength);
+THIRDPARTYCOMMUNICATION_API int __stdcall SendBatteryAndImpedances(int nBatteryLevel, int nEpoch, int nImpOnlineStatus, int nImpOnlineValues[24]);
+THIRDPARTYCOMMUNICATION_API int __stdcall SendMissedBlocks(int nMissedBlocks,int nEpoch);
+THIRDPARTYCOMMUNICATION_API int __stdcall SetEEGChannelMapInfo(char* chMapInfoBytes,int nLength);
+THIRDPARTYCOMMUNICATION_API int __stdcall SendCurrentQuality(float* pData,int nLength);
+THIRDPARTYCOMMUNICATION_API int __stdcall SendClassQuality(float* pData,int nLength);
+
+
+// teaming mode functions
+THIRDPARTYCOMMUNICATION_API int __stdcall EnableTeamingMode(int nReceivePort,int nSendPort); //beacon callback, port
+THIRDPARTYCOMMUNICATION_API int __stdcall StartReadingBeacons(void (__stdcall *pFunc)(int));
+THIRDPARTYCOMMUNICATION_API int __stdcall SendClassificationToServer(char* pClassification,int nBeaconCounter,int nSessionNumber);
+// teaming mode end
+
+#define ABM_3RD_TM_SEND_MULTIPLE_SESSIONS 100
+
+// Error Codes
+#define ABM_3RD_ERROR_INIT_PARAMETER -101
+#define ABM_3RD_ERROR_INIT_WINSOCK2 -102
+#define ABM_3RD_ERROR_CREATE_SOCKET -103
+#define ABM_3RD_ERROR_GET_HOST -104
+#define ABM_3RD_ERROR_CONNECT -105
+#define ABM_3RD_ERROR_NON_BLOCK_MODE -106
+#define ABM_3RD_CAN_NOT_LISTEN_ON_PORT -100
+#define ABM_3RD_ACCEPT_FAILED -200
+
+#define ABM_3RD_OPERATION_PERFORMED_SUCCESSFULLY 0
+#define ABM_3RD_ERROR_SERVER_BUFFER_OVERFLOW -1
+#define ABM_3RD_ERROR_SERVER_NOT_STARTED -2
+#define ABM_3RD_ERROR_SERVER_STATE_ERROR -3
+#define ABM_3RD_ERROR_OPERATION_NOT_SUPPORTED -4
+#define ABM_3RD_ERROR_SERVER_ALREADY_STARTED -5
+#define ABM_3RD_ERROR_SERVER_COULD_NOT_SEND -6
+#define ABM_3RD_ERROR_READERS_LIMIT_REACHED -7
+#define ABM_3RD_ERROR_ACCEPT_FAILED -8
+#define ABM_3RD_ERROR_NULL_POINTER_OPERAND -9
+#define ABM_3RD_ERROR_NO_DATA_TO_SEND -10
+#define ABM_3RD_ERROR_MESSAGE_TOO_LARGE -11
+#define ABM_3RD_ERROR_COULDNT_STOP_SERVER -12
+
+#define ABM_3RD_NO_ERROR_FOUND 0
+
+// states - TCP server
+#define ABM_3RD_SERVER_STATE_TCP_NOT_STARTED 0
+#define ABM_3RD_SERVER_STATE_TCP_STARTED 1
+#define ABM_3RD_SERVER_STATE_TCP_STOPPED 2
+#define ABM_3RD_SERVER_STATE_TCP_SERVER_ERROR 3
+
+#define ABM_3RD_TCP_READER_STOPPED 1
+#define ABM_3RD_TCP_LISTENER_STOPPED 2
+#define ABM_3RD_TCP_SOCKET_ERROR 3
+#define ABM_3RD_TCP_CLIENT_CLOSED_CONNECTION 4
+#define ABM_3RD_TCP_SHUTDOWN_FAILED 5
+
+// states - UDP server
+#define ABM_3RD_SERVER_STATE_UDP_NOT_STARTED 0
+#define ABM_3RD_SERVER_STATE_UDP_STARTED 1
+#define ABM_3RD_SERVER_STATE_UDP_STOPPED 2
+#define ABM_3RD_SERVER_STATE_UDP_SERVER_ERROR 3
+
+// Data Types
+#define ABM_DATA_TYPE_RAW 1
+#define ABM_DATA_TYPE_DECON 2
+#define ABM_DATA_TYPE_PSD 3
+#define ABM_DATA_TYPE_PSD_RAW 4
+#define ABM_DATA_TYPE_BAND_ALL_PSD 5
+#define ABM_DATA_TYPE_BAND_ALL_PSD_RAW 6
+#define ABM_DATA_TYPE_BAND_PSD 7
+#define ABM_DATA_TYPE_BAND_PSD_RAW 8
+#define ABM_DATA_TYPE_EKG 9
+#define ABM_DATA_TYPE_CLASS 10
+#define ABM_DATA_TYPE_QUALITY 11
+#define ABM_DATA_TYPE_QUALITY_CH 12
+#define ABM_DATA_TYPE_TILT 13
+#define ABM_DATA_TYPE_MOVEMENT 14
+#define ABM_DATA_TYPE_HAPTIC 15
+#define ABM_DATA_TYPE_OPTICAL_RAW 16
+#define ABM_DATA_TYPE_PULSE 17
+#define ABM_DATA_TYPE_ZSCORE 18
+#define ABM_DATA_TYPE_ART_EB 19
+#define ABM_DATA_TYPE_ART_SPK 20
+#define ABM_DATA_TYPE_ART_EXC 21
+#define ABM_DATA_TYPE_ART_SAT 22
+#define ABM_DATA_TYPE_ART_EMG 23
+#define ABM_DATA_TYPE_TIMESTAMP 24
+#define ABM_DATA_TYPE_ANGLES 25
+
+// datastreaming protocols
+#define ABM_3RD_DATAGRAMPROTOCOL_UNDEFINED 001
+#define ABM_3RD_DATAGRAMPROTOCOL_RAW 101 // sends raw
+#define ABM_3RD_DATAGRAMPROTOCOL_RAW_DECON 102 // sends raw+decon
+#define ABM_3RD_DATAGRAMPROTOCOL_RAW_DECON_CLASS 103 // sends raw+decon+class
+#define ABM_3RD_DATAGRAMPROTOCOL_RAW_DECON_CLASS_WL 104 // sends raw+decon+class+workload
+
+#define ABM_3RD_NOTIFICATION_MESSAGE_SIZE 12
+#define ABM_3RD_NOTIFICATION_BUFFER_SIZE 100
+
+//#define ABM_START_ACQUISITION_ALL 100
+//#define ABM_START_ACQUISITION_SINGLE 101 // broadcast with session id to identify
+//#define ABM_PING_ALL 120
+//#define ABM_PING_SINGLE 121 // broadcast with session id to identify
+//#define ABM_STOP_ACQUISITION_ALL 110
+//#define ABM_STOP_ACQUISITION_SINGLE 110
+//#define ABM_SET_DATA_PORT 130
+
+
+#endif __THIRDPARTYCOMMUNICATION__
+
diff --git a/physiolabxr/third_party/BAlert/SDK64/include/TypeDef.h b/physiolabxr/third_party/BAlert/SDK64/include/TypeDef.h
new file mode 100644
index 00000000..8699bd84
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/SDK64/include/TypeDef.h
@@ -0,0 +1,317 @@
+
+#ifndef __TD_DEFINE__
+#define __TD_DEFINE__
+
+
+#define __ESU_TIME_STAMP_LENGTH 4
+#define __SYS_TIME_LENGTH 8
+#define ABM_MAX_CONNECTED_DEVICES 10
+
+#include "EegAcqDefine.h"
+
+#pragma pack (1)
+
+
+typedef struct TD_ELECTRODE{
+ wchar_t chName[20]; //name of electrode
+ BOOL bImpedance; //if impedance is well (low)
+ float fImpedanceValue; //value of impedance
+}ELECTRODE;
+
+typedef struct TD_CHANNEL_INFO{
+ wchar_t chName[20]; //name of electrode
+ BOOL bTechnicalInfo; //if impedance is well (low)
+}CHANNEL_INFO;
+
+typedef struct TD_DEVICE_INFO{
+ wchar_t chDeviceName[256];//device's name
+ int nCommPort; // comm port
+ int nECGPos; //ecg position
+ int nNumberOfChannel; //number of channel
+ int nESUType; //type of connecting device
+ int nTymestampType; // type of timestamp
+ int nDeviceHandle; // handle to identify device
+ wchar_t chDeviceID[MAX_PATH]; // ESU/dongle port device ID
+}_DEVICE_INFO;
+
+typedef struct TD_STATUS_INFO{
+ float BatteryVoltage;
+ int BatteryPercentage;
+ //int Temperature;
+ int Timestamp;
+ int TotalMissedBlocks;
+ int ABMSDK_Mode;
+ int LastErrorCode;
+ int CustomMarkA;
+ int CustomMarkB;
+ int CustomMarkC;
+ int CustomMarkD;
+ int nTotalSamplesReceived;
+ int OnLineImpStatus;
+ int OnLineImpValues[24];
+ int TechEvent;
+}_STATUS_INFO;
+
+
+
+//CWPC
+typedef struct TD_BRAIN_STATE{
+ float fEpoch;
+ float fABMSDKTimeStampHour;//time stamp
+ float fABMSDKTimeStampMinute;//time stamp
+ float fABMSDKTimeStampSecond;//time stamp
+ float fABMSDKTimeStampMilsecond;//time stamp
+ float fClassificationEstimate; //information about classification
+ float fHighEngagementEstimate; //information about high-engagement
+ float fLowEngagementEstimate; //information about low-engagement
+ float fDistractionEstimate; //information about distraction
+ float fSleepOnsetEstimate; //information about drowsy
+ float fWorkloadFBDS; //information about FBDS workload
+ float fWorkloadBDS; //information about BDS workload
+ float fWorkloadAverage; //information about workload average
+}_BRAIN_STATE;
+
+typedef struct TD_SESSION_INFO{
+ wchar_t chDefinitionPath[1024]; //full path of definition file (only needed for GetBrainState)
+ wchar_t chDestionationPath[1024]; //full path for destination(ebs) file
+ DWORD wRawChannels; //markers for which channel raw data need to be provided;// LSB used for first channel...if the corresponding bit is 1, raw data will be provided for that channel
+ DWORD wDecChannels; //markers for which channel dec data need to be provided;// LSB used for first channel...if the corresponding bit is 1, raw data will be provided for that channel
+ DWORD wPsdChannels; //markers for which channel PSD need to be calculated;// LSB used for first channel...if the corresponding bit is 1, PSD will be calculated for that channel
+ DWORD dwPSD[MAX_NUM_EEGCHANNELS][4];//markers for 128 bins for one channel. LSB is marker for 1Hz bin…
+ char chName[MAX_NUM_EEGCHANNELS][MAX_LENGTH_CHANNEL_NAME];//[in]the name of channels max 20 characters
+ int inputPinPositive[MAX_NUM_EEGCHANNELS];// holds positive pin asignment for each channel
+ int inputPinNegative[MAX_NUM_EEGCHANNELS];// holds negative pin asignment for each channel (not used for referential)
+ int channelImpedanceType[MAX_NUM_EEGCHANNELS];// IMPEDANCE_REFERENTIAL 0, IMPEDANCE_DIFERENTIAL 1, IMPEDANCE_NOT_AVAILABLE 2
+ BOOL bApply65HzFilter; // not used (should be removed)
+ BYTE bBrainState; // markers for (classification, high-engagement, low-engagement, distraction, drowsy, workload
+ BYTE bPlayEbsMode; // play ebs mode
+}_SESSION_INFO;
+
+typedef struct TD_ELECTRODES_INFO{
+ int nNumElectrodes;
+ int nStabilization;
+ int nAgregationsSamples;
+ int nCurrentType;
+ wchar_t cElName[MAX_NUM_ELECTRODE][MAX_LENGTH_CHANNEL_NAME];//[in]the name of electrode max 20 characters
+ int nElCommand[MAX_NUM_ELECTRODE];// Impedance command to be sent for this electrode to be measured
+ int nElChannel[MAX_NUM_ELECTRODE];// EEG channel to be used when measuring electrode
+ int nElReferentialElectrode[MAX_NUM_ELECTRODE];// Electrode to be used when substracting ref el. (-1 for none)
+}_ELECTRODES_INFO;
+
+typedef struct TD_EEGCHANNELS_INFO{
+ char cChName[MAX_NUM_EEGCHANNELS][MAX_LENGTH_CHANNEL_NAME];//[in]the name of channels max 20 characters
+ BOOL bChUsed[MAX_NUM_EEGCHANNELS];// whether channel is used or not
+ BOOL bChUsedInQualityData[MAX_NUM_EEGCHANNELS];// whether channel is used or not for quality
+ BOOL bChCanBeDecontaminated[MAX_NUM_EEGCHANNELS];
+ BOOL bIsChEEG[MAX_NUM_EEGCHANNELS];
+ BOOL bIsFlex;
+ int nChannelMap;
+}_EEGCHANNELS_INFO;
+
+typedef struct TD_AUXDATA_INFO{
+ BOOL bIred;
+ BOOL bRed;
+ BOOL bTilt;
+ int nEcgIndex;
+ BOOL bMic;
+ BOOL bHaptic;
+}_AUXDATA_INFO;
+
+typedef struct TD_HARDWARE_INFO{
+ int nBatteryMax; //millivolts
+ int nBatteryMin; //millivolts
+ int nTiltLinearTransformA;
+ int nTiltLinearTransformB;
+}_HARDWARE_INFO;
+
+
+typedef struct TD_SESSIONTYPES_INFO{
+ BOOL bDecon; //whether decontamination is supported or not
+ BOOL bBalert;//whether b-alert classification is supported or not
+ BOOL bWorkload; //whether workload calculation is supported or not
+}_SESSIONTYPES_INFO;
+
+typedef struct TD_CHANNELMAP_INFO{
+ int nDeviceTypeCode;
+ int nSize;
+ _EEGCHANNELS_INFO stEEGChannels;
+ _ELECTRODES_INFO stElectrodes;
+ _AUXDATA_INFO stAuxData;
+ _HARDWARE_INFO stHardwareInfo;
+ _SESSIONTYPES_INFO stSessionTypes;
+}_CHANNELMAP_INFO;
+
+
+typedef struct TD_SESSION_INFO_PE{
+ int nNumberOfChannels;
+ int nEKG;
+ BOOL bApply65HzFilter;
+ wchar_t chName[MAX_NUM_EEGCHANNELS][MAX_LENGTH_CHANNEL_NAME];//[in]the name of channels max 20 characters
+}_SESSION_INFO_PE;
+
+typedef union __ESU_TIME_STAMP{
+ float time_ms;
+ BYTE pByteStream[__ESU_TIME_STAMP_LENGTH];
+}_ESU_TIME_STAMP;
+
+typedef struct __EXTERN_CALC_TABLE_NAME{
+ int iRealIndex; //index into block
+ int iIndex; //index into calculated block
+ int iCalcIndex1; //real index from real block of data
+ int iCalcIndex2; //real index from real block of data
+}_EXTERN_CALC_TABLE_NAME;
+
+// REFCOM moved struct to typedef.h
+typedef struct __BALERT_DATA_INFO{
+ int nPlayedSamples; // samples already in channels
+ int nNotReceiving; // elapsed time in milliseconds when nothing is received from device
+ int nTotalSeconds; // total number of seconds in EBS file
+ int nFirstSecond; // first second in stream and buffers
+ int nActiveSecond; // active second = slider position for EBS file
+ void* pActivTable; // pointer to active table
+ int nActiveScreen;//which screen is presented
+} _BALERT_DATA_INFO;
+
+typedef struct __ELECTRODE{
+ wchar_t elName[50];
+ int nHirose;//hirose plug-in
+ int nSwitch;//switch which need to press
+ int nChannel;//where that electrode will be seen on screen
+ int nSubChannel;//what channel we need to substract to get correct values
+ int nSubEl;//what electrode we need to substract to get correct values
+ float fImpedance;
+ int nNumberOfSaturation;//how many times saturation found on this electrode
+}_ELECTRODE;
+
+typedef struct __ESU_PORT_INFO{
+ int nESU_TYPE; // UNKNOWN - 0, DONGLE - 1,SINGLE_CH 2,MULTI_CH - 3
+ int bWired; // Wired - 1, Wireless - 0
+ int nSerialPortType[ABM_THIRD_PARTY_PORTS_NUM];
+ int nParalelPortType;
+ int bIsRegularConfig; // Regular - 1, Irregular - 0
+ wchar_t BDA[13];
+} _ESU_PORT_INFO;
+
+typedef struct __BALERT_FIRMWARE_VERSION{
+ wchar_t ucFirmwareVersion[12];
+ wchar_t ucMCESUFirmwareVersion[5];
+ wchar_t ucDONGLEFirmwareVersion[5];
+ } _BALERT_FIRMWARE_VERSION;
+
+//typedef struct __ESU_PORT_INFO_DETAILS{
+// int nESU_TYPE; // UNKNOWN - 0, DONGLE - 1,SINGLE_CH 2,MULTI_CH - 3
+// int bWired; // Wired - 1, Wireless - 0
+// int nSerialPortType[ABM_THIRD_PARTY_PORTS_NUM];
+// int nParalelPortType;
+// int bIsRegularConfig; // Regular - 1, Irregular - 0
+// char BDA[13];
+// char FirmwareVersion[5];
+// char SerialNumber[10];
+//
+//} _ESU_PORT_INFO_DETAILS;
+
+
+struct _DEVICE_INFO_DETAILS
+{
+public:
+ _DEVICE_INFO_DETAILS()
+ {
+ memset(chDeviceName,0,256 * sizeof(wchar_t));
+ memset(ucSerialReceiver, 0, 17 * sizeof(wchar_t));
+ memset(ucSerialHeadset, 0, 17 * sizeof(wchar_t));
+
+ memset(ucBtSerialNum, 0, 13 * sizeof(wchar_t));
+ memset(ucFirmwareVersion, 0, 12 * sizeof(wchar_t));
+ memset(ucHardwareVersion, 0, 5 * sizeof(wchar_t));
+ memset(ucESUFirmwareVersion, 0, 5 * sizeof(wchar_t));
+
+ memset(chDeviceInstanceID, 0, MAX_PATH * sizeof(wchar_t));
+
+ nCommPort = -1;
+ nECGPos = -1;
+ nNumberOfChannel = -1;
+ nBytesPerSample = -1;
+ nESUType = -1;
+ bTilt = FALSE;
+
+ }
+
+ wchar_t chDeviceName[256];//device's name
+ int nCommPort; //comm port
+ int nECGPos; //ecg position
+ int nNumberOfChannel; //number of channel
+ int nESUType; //type of connecting device
+ int nTymestampType; // type of timestamp
+ int nDeviceHandle; // handle to identify device
+ wchar_t chDeviceInstanceID[MAX_PATH];
+ int nBytesPerSample;
+ BOOL bTilt;
+
+ wchar_t ucSerialHeadset[17];
+ wchar_t ucSerialReceiver[17];
+
+ wchar_t ucBtSerialNum[13];
+ wchar_t ucFirmwareVersion[12];
+ wchar_t ucHardwareVersion[5];
+ wchar_t ucESUFirmwareVersion[5];
+
+ int nChannelsConfigurationAdc[MAX_NUM_EEGCHANNELS * 2];
+ int nDCoffsetAdc[MAX_NUM_EEGCHANNELS];
+
+ int nImpedanceOffsetAdc[MAX_NUM_EEGCHANNELS];
+ int nImpedanceConstAdc[MAX_NUM_EEGCHANNELS];
+
+
+
+
+};
+
+ struct _LSLSTREAMING_INFO {
+
+public:
+ _LSLSTREAMING_INFO()
+ {
+ bLSLRawEEG = false;
+ bLSLFilteredEEG = false;
+ bLSLTimestamp = false;
+ bLSLBAlertMetric = false;
+ bLSLHR = false;
+ bLSLHRV = false;
+ bLSLHRVFreq = false;
+
+
+ }
+ BOOL bLSLRawEEG;
+ BOOL bLSLFilteredEEG;
+ BOOL bLSLTimestamp;
+ BOOL bLSLBAlertMetric;
+ BOOL bLSLHR;
+ BOOL bLSLHRV;
+ BOOL bLSLHRVFreq;
+
+
+ void operator =(_LSLSTREAMING_INFO& info)
+ {
+ bLSLBAlertMetric = info.bLSLBAlertMetric;
+ bLSLFilteredEEG = info.bLSLFilteredEEG;
+ bLSLRawEEG = info.bLSLRawEEG;
+ bLSLTimestamp = info.bLSLTimestamp;
+ bLSLHR = info.bLSLHR;
+ bLSLHRV = info.bLSLHRV;
+ bLSLHRVFreq = info.bLSLHRVFreq;
+
+ }
+
+ bool StreamingRequested()
+ {
+ return bLSLBAlertMetric || bLSLFilteredEEG || bLSLRawEEG || bLSLTimestamp || bLSLHR || bLSLHRV || bLSLHRVFreq;
+ }
+
+
+
+};
+
+#pragma pack()
+
+
+#endif //__TD_DEFINE__
diff --git a/physiolabxr/third_party/BAlert/SDK64/include/TypeDefDataTypes.h b/physiolabxr/third_party/BAlert/SDK64/include/TypeDefDataTypes.h
new file mode 100644
index 00000000..3cdb374a
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/SDK64/include/TypeDefDataTypes.h
@@ -0,0 +1,208 @@
+#ifndef __TDEXPORT_DEFINE__
+#define __TDEXPORT_DEFINE__
+
+#define ABM_DATA_SESSION_ID_LENGTH 9
+#define ABM_DATA_NUM_NOTIFICATION_PARAMS 10
+#define ABM_DATA_NUM_COMMAND_PARAMS 4
+#define ABM_DATA_MAX_NUM_CHANNELS 24
+#define ABM_DATA_PSD_BINS 128
+#define ABM_DATA_SIZE_BW 1024
+#define ABM_DATA_SIZE_BW_OA 60
+#define ABM_DATA_SIZE_ZSCORE 606
+
+
+enum _ABM_DATA_NOTIFICATION_TYPE
+{
+ ABM_DATA_CLIENT_COMMAND = 110,
+ ABM_DATA_SERVER_RESPONSE = 111,
+ ABM_TEAMING_COMMAND = 120,
+ ABM_TEAMING_RESPONSE = 121,
+ ABM_3RD_DATASTREAMING_INFO = 200,
+ ABM_3RD_BEACON = 201,
+};
+
+
+enum _ABM_DATA_COMMAND_SYB_TYPE
+{
+ ABM_DATA_COMMAND_START_ACQUISITION = 301,
+ ABM_DATA_COMMAND_STOP_ACQUISITION = 302,
+ ABM_DATA_COMMAND_PAUSE_ACQUISITION = 303,
+ ABM_DATA_COMMAND_RESUME_ACQUISITION = 304,
+ ABM_DATA_COMMAND_CHECK_IMPEDANCE = 305,
+ ABM_DATA_COMMAND_CHECK_DATAQUALITY = 306,
+ ABM_DATA_COMMAND_GET_SDK_MODE = 307,
+ ABM_DATA_COMMAND_INIT_SESSION = 308,
+ ABM_DATA_COMMAND_CHECK_SELECTED_IMPEDANCE = 309,
+};
+
+enum _ABM_DATA_DS_INFO_SYB_TYPE
+{
+ ABM_3RD_DS_INFO_BATTERY = 100,
+ ABM_3RD_DS_INFO_MISSED_BLOCKS = 101,
+ ABM_3RD_DS_INFO_ERROR = 200,
+ ABM_3RD_DS_INFO_ELECTRODE_FINISHED = 210,
+};
+
+
+typedef struct __ATIME_DATA_WITH_OFFSET{
+ float epoch;
+ float offset;
+ float abmHour;
+ float abmMin;
+ float abmSec;
+ float abmMilli;
+}_ABM_DATA_TIME;
+
+typedef struct __ATIME_DATA_NO_OFFSET{
+ float epoch;
+ float abmHour;
+ float abmMin;
+ float abmSec;
+ float abmMilli;
+}_ABM_DATA_TIME_NO_OFFSET;
+
+typedef struct __QUALITY_DATA{
+ _ABM_DATA_TIME time;
+ float practice;
+ float training;
+ float testing;
+}_ABM_DATA_QUALITY_OVERALL;
+
+typedef struct __AEKG_DATA{
+ _ABM_DATA_TIME time;
+ float heartRate;
+ float interBeatInterval;
+ float beatQuality;
+ float packetType;
+}_ABM_DATA_EKG;
+
+//typedef struct __APULSE_RATE_DATA{
+// _ABM_DATA_TIME time;
+// float heartRate;
+// float interBeatInterval;
+// float beatQuality;
+// float packetType;
+//}_ABM_DATA_PULSE_RATE;
+
+typedef struct __MOVEMENT_DATA{
+ _ABM_DATA_TIME_NO_OFFSET time;
+ float value;
+ float level;
+}_ABM_DATA_MOVEMENT;
+
+//typedef struct __HAPTIC_DATA{
+// _ABM_DATA_TIME time;
+// float state;
+//}_ABM_DATA_HAPTIC;
+
+typedef struct __PSD_BANDWIDTH_DATA{
+ _ABM_DATA_TIME_NO_OFFSET time;
+ float bandwidth[ABM_DATA_SIZE_BW];
+}_ABM_DATA_BANDWIDTH;
+
+typedef struct __PSD_BANDWIDTH_OVERALL_DATA{
+ _ABM_DATA_TIME_NO_OFFSET time;
+ float bandwidthOverall[ABM_DATA_SIZE_BW_OA];
+}_ABM_DATA_BANDWIDTH_OVERALL;
+
+typedef struct __ZSCORE_DATA{
+ _ABM_DATA_TIME_NO_OFFSET time;
+ float zscore[ABM_DATA_SIZE_ZSCORE];
+}_ABM_DATA_ZSCORE;
+
+typedef struct __RAW_OPTICAL_DATA{
+ _ABM_DATA_TIME time;
+ float sampleValue;
+}_ABM_DATA_RAW_OPTICAL;
+
+typedef struct __AACC_DATA{
+ _ABM_DATA_TIME time;
+ float rawTiltX;
+ float rawTiltY;
+ float rawTiltZ;
+}_ABM_DATA_ACCELEROMETER;
+
+typedef struct __AAngles_DATA{
+ _ABM_DATA_TIME time;
+ float angleX;
+ float angleY;
+ float angleZ;
+}_ABM_DATA_ANGLES;
+
+
+typedef struct __TD_DEVICE_INFO{
+ wchar_t chDeviceName[256];//device's name
+ int nCommPort; //comm port
+ int nECGPos; //ecg position
+ int nNumberOfChannel; //number of channel
+ int nNumberPSDBands; //number of PSD bandwidths
+ int nNumberPSDBandsOverall; //number of PSD bandwidths (overall)
+ int nDeconChannels;
+ int nPSDRawChannels;
+ int nPSDClassChannels;
+ int nQualityCheckChannels;
+ char sessionID[ABM_DATA_SESSION_ID_LENGTH]; //SessionID
+}_ABM_DATA_DEVICE_INFO;
+
+typedef struct __TD_BRAIN_STATE{
+ _ABM_DATA_TIME_NO_OFFSET time;
+ float fClassificationEstimate; //information about classification
+ float fHighEngagementEstimate; //information about high-engagement
+ float fLowEngagementEstimate; //information about low-engagement
+ float fDistractionEstimate; //information about distraction
+ float fDrowsyEstimate; //information about drowsy
+ float fWorkloadFBDSEstimate; //information about workload - task FBDS
+ float fWorkloadBDSEstimate; //information about workload - task BDS
+ float fWorkloadAverageEstimate; //information about workload - average across tasks
+}_ABM_DATA_BRAIN_STATE;
+
+typedef struct __TD__NOTIFICATION{
+ float fNotificationType;
+ float fNotificationSubType;
+ float fNotificationParams[ABM_DATA_NUM_NOTIFICATION_PARAMS];
+}_ABM_DATA_NOTIFICATION;
+
+typedef struct __TD_COMMAND_INFO_DATA{
+// notification used for commands and responses
+ float fNotificationType;
+ float fNotificationSubType;
+ float sequenceNumber;
+ float timestampHour;
+ float timestampMinute;
+ float timestampSecond;
+ float timestampMillisecond;
+ float commandStatus;
+ float fCommandParams[ABM_DATA_NUM_COMMAND_PARAMS];
+}_ABM_DATA_COMMAND_INFO;
+
+typedef struct TD_SAMPLES_DATA{
+ _ABM_DATA_TIME time;
+ float samples[ABM_DATA_MAX_NUM_CHANNELS];
+}_ABM_DATA_SAMPLES;
+
+typedef struct TD_QUALITY_CHANNEL_DATA{
+ _ABM_DATA_TIME time;
+ float values[2*ABM_DATA_MAX_NUM_CHANNELS];
+}_ABM_DATA_QUALITY_PER_CHANNEL;
+
+
+typedef struct TD_BINS_DATA{
+ _ABM_DATA_TIME_NO_OFFSET time;
+ float bins[ABM_DATA_MAX_NUM_CHANNELS][ABM_DATA_PSD_BINS];
+}_ABM_DATA_BINS;
+
+typedef struct __TD_ELECTRODE{
+ char chName[20]; //name of electrode
+ BOOL bImpedance; //if impedance is well (low)
+ float fImpedanceValue; //value of impedance
+}_ABM_DATA_ELECTRODE;
+
+typedef struct TD_DATA_CLASSIFICATION_PACKAGE
+{
+ int nBeaconValue;
+ int sessionInfo;
+ _ABM_DATA_BRAIN_STATE brainState;
+}_ABM_DATA_CLASSIFICATION_PACKAGE;
+
+
+#endif //__TDEXPORT_DEFINE__
\ No newline at end of file
diff --git a/physiolabxr/third_party/BAlert/SDK64/include/lsl/common.h b/physiolabxr/third_party/BAlert/SDK64/include/lsl/common.h
new file mode 100644
index 00000000..3c81c798
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/SDK64/include/lsl/common.h
@@ -0,0 +1,229 @@
+#pragma once
+
+//! @file common.h Global constants for liblsl
+
+#if defined(LIBLSL_FFI)
+// Skip any typedefs that might confuse a FFI header parser, e.g. cffi
+#elif defined(_MSC_VER) && _MSC_VER < 1600
+typedef signed char int8_t;
+typedef signed short int16_t;
+typedef signed int int32_t;
+typedef signed long long int64_t;
+typedef unsigned int uint32_t;
+#else
+#include
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER < 1900
+#define __func__ __FUNCTION__
+#endif
+
+/// LIBLSL_C_API expands function attributes needed for the linker
+#if defined(LIBLSL_STATIC) || defined(LIBLSL_FFI)
+#define LIBLSL_C_API
+#elif defined _WIN32 || defined __CYGWIN__
+#if defined LIBLSL_EXPORTS
+#define LIBLSL_C_API __declspec(dllexport)
+#else
+#define LIBLSL_C_API __declspec(dllimport)
+#ifndef LSLNOAUTOLINK
+#pragma comment(lib, "lsl.lib")
+#endif
+#endif
+#pragma warning(disable : 4275)
+#else // Linux / OS X
+#define LIBLSL_C_API __attribute__((visibility("default")))
+#endif
+
+/// Constant to indicate that a stream has variable sampling rate.
+#define LSL_IRREGULAR_RATE 0.0
+
+/**
+ * Constant to indicate that a sample has the next successive time stamp.
+ *
+ * This is an optional optimization to transmit less data per sample.
+ * The stamp is then deduced from the preceding one according to the stream's
+ * sampling rate (in the case of an irregular rate, the same time stamp as
+ * before will is assumed). */
+#define LSL_DEDUCED_TIMESTAMP -1.0
+
+/// A very large time value (ca. 1 year); can be used in timeouts.
+#define LSL_FOREVER 32000000.0
+
+/**
+ * Constant to indicate that there is no preference about how a data stream
+ * shall be chunked for transmission.
+ * (can be used for the chunking parameters in the inlet or the outlet).
+ */
+#define LSL_NO_PREFERENCE 0
+
+/// Data format of a channel (each transmitted sample holds an array of channels), 4 bytes wide
+typedef enum {
+ /** For up to 24-bit precision measurements in the appropriate physical unit (e.g., microvolts).
+ * Integers from -16777216 to 16777216 are represented accurately. */
+ cft_float32 = 1,
+ /** For universal numeric data as long as permitted by network & disk budget.
+ * The largest representable integer is 53-bit. */
+ cft_double64 = 2,
+ /** For variable-length ASCII strings or data blobs, such as video frames, complex event
+ descriptions, etc. */
+ cft_string = 3,
+ /** For high-rate digitized formats that require 32-bit precision.
+ * Depends critically on meta-data to represent meaningful units.
+ * Useful for application event codes or other coded data. */
+ cft_int32 = 4,
+ /** For very high rate signals (40Khz+) or consumer-grade audio.
+ * For professional audio float is recommended. */
+ cft_int16 = 5,
+ /// For binary signals or other coded data. Not recommended for encoding string data.
+ cft_int8 = 6,
+ /** 64 bit integers. Support for this type is not yet exposed in all languages.
+ * Also, some builds of liblsl will not be able to send or receive data of this type. */
+ cft_int64 = 7,
+ /// Can not be transmitted.
+ cft_undefined = 0,
+
+ // prevent compilers from assuming an instance fits in a single byte
+ _cft_maxval = 0x7f000000
+} lsl_channel_format_t;
+
+// Abort compilation if lsl_channel_format_t isn't exactly 4 bytes wide
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
+_Static_assert(sizeof(lsl_channel_format_t) == 4, "lsl_channel_format_t size breaks the LSL ABI");
+#elif defined(__cplusplus) && __cplusplus >= 201103L
+static_assert (sizeof(lsl_channel_format_t) == 4, "lsl_channel_format_t size breaks the LSL ABI");
+#elif !defined(LIBLSL_FFI)
+static char _lsl_channel_format_size_check[1 - 2*!(sizeof(lsl_channel_format_t)==4)];
+#endif
+
+/// Post-processing options for stream inlets.
+typedef enum {
+ /** No automatic post-processing; return the ground-truth time stamps for manual
+ post-processing. This is the default behavior of the inlet. */
+ proc_none = 0,
+
+ /** Perform automatic clock synchronization; equivalent to manually adding the time_correction()
+ value to the received time stamps. */
+ proc_clocksync = 1,
+
+ /** Remove jitter from time stamps.
+ *
+ * This will apply a smoothing algorithm to the received time stamps; the smoothing needs to see
+ * a minimum number of samples (30-120 seconds worst-case) until the remaining jitter is
+ * consistently below 1ms. */
+ proc_dejitter = 2,
+
+ /** Force the time-stamps to be monotonically ascending.
+ *
+ * Only makes sense if timestamps are dejittered. */
+ proc_monotonize = 4,
+
+ /** Post-processing is thread-safe (same inlet can be read from by multiple threads);
+ * uses somewhat more CPU. */
+ proc_threadsafe = 8,
+
+ /// The combination of all possible post-processing options.
+ proc_ALL = 1 | 2 | 4 | 8,
+
+ // prevent compilers from assuming an instance fits in a single byte
+ _proc_maxval = 0x7f000000
+} lsl_processing_options_t;
+
+/// Possible error codes.
+typedef enum {
+ /// No error occurred
+ lsl_no_error = 0,
+
+ /// The operation failed due to a timeout.
+ lsl_timeout_error = -1,
+
+ /// The stream has been lost.
+ lsl_lost_error = -2,
+
+ /// An argument was incorrectly specified (e.g., wrong format or wrong length).
+ lsl_argument_error = -3,
+
+ /// Some other internal error has happened.
+ lsl_internal_error = -4,
+
+ // prevent compilers from assuming an instance fits in a single byte
+ _lsl_error_code_maxval = 0x7f000000
+} lsl_error_code_t;
+
+/// Flags for outlet_ex and inlet_ex
+typedef enum {
+ /// Keep legacy behavior: max_buffered / max_buflen is in seconds; use asynch transfer.
+ transp_default = 0,
+
+ /// The supplied max_buf value is in samples.
+ transp_bufsize_samples = 1,
+
+ /// The supplied max_buf should be scaled by 0.001.
+ transp_bufsize_thousandths = 2,
+
+ // prevent compilers from assuming an instance fits in a single byte
+ _lsl_transport_options_maxval = 0x7f000000
+} lsl_transport_options_t;
+
+/// Return an explanation for the last error
+extern LIBLSL_C_API const char *lsl_last_error(void);
+
+/**
+ * LSL version the binary was compiled against
+ *
+ * Used either to check if the same version is used
+ * (`if(lsl_protocol_version()!=LIBLSL_COMPILE_HEADER_VERSION`) …
+ * or to require a certain set of features:
+ * ```
+ * #if LIBLSL_COMPILE_HEADER_VERSION > 113
+ * do_stuff();
+ * #endif
+ * ```
+ * */
+#define LIBLSL_COMPILE_HEADER_VERSION 114
+
+/**
+ * Protocol version.
+ *
+ * The major version is `protocol_version() / 100;`
+ * The minor version is `protocol_version() % 100;`
+ *
+ * Clients with different minor versions are protocol-compatible while clients
+ * with different major versions will refuse to work together.
+ */
+extern LIBLSL_C_API int32_t lsl_protocol_version();
+
+/**
+ * Version of the liblsl library.
+ *
+ * The major version is `library_version() / 100;`
+ * The minor version is `library_version() % 100;`
+ */
+extern LIBLSL_C_API int32_t lsl_library_version();
+
+/**
+ * Get a string containing library information.
+ *
+ * The format of the string shouldn't be used for anything important except giving a debugging
+ * person a good idea which exact library version is used. */
+extern LIBLSL_C_API const char *lsl_library_info(void);
+
+/**
+ * Obtain a local system time stamp in seconds.
+ *
+ * The resolution is better than a millisecond.
+ * This reading can be used to assign time stamps to samples as they are being acquired.
+ * If the "age" of a sample is known at a particular time (e.g., from USB transmission
+ * delays), it can be used as an offset to lsl_local_clock() to obtain a better estimate of
+ * when a sample was actually captured. See lsl_push_sample() for a use case.
+ */
+extern LIBLSL_C_API double lsl_local_clock();
+
+/**
+ * Deallocate a string that has been transferred to the application.
+ *
+ * Rarely used: the only use case is to deallocate the contents of
+ * string-valued samples received from LSL in an application where
+ * no free() method is available (e.g., in some scripting languages).
+ */
+extern LIBLSL_C_API void lsl_destroy_string(char *s);
diff --git a/physiolabxr/third_party/BAlert/SDK64/include/lsl/inlet.h b/physiolabxr/third_party/BAlert/SDK64/include/lsl/inlet.h
new file mode 100644
index 00000000..78aa60d9
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/SDK64/include/lsl/inlet.h
@@ -0,0 +1,309 @@
+#pragma once
+#include "common.h"
+#include "types.h"
+
+
+/// @file inlet.h Stream inlet functions
+
+/** @defgroup lsl_inlet The lsl_inlet object
+ * @{
+ */
+
+/**
+ * Construct a new stream inlet from a resolved stream info.
+ * @param info A resolved stream info object (as coming from one of the resolver functions).
+ * @note The inlet makes a copy of the info object at its construction.
+ * @note The stream_inlet may also be constructed with a fully-specified stream_info, if the desired
+ * channel format and count is already known up-front, but this is strongly discouraged and should
+ * only ever be done if there is no time to resolve the stream up-front (e.g., due to limitations
+ * in the client program).
+ * @param max_buflen Optionally the maximum amount of data to buffer (in seconds if there is a
+ * nominal sampling rate, otherwise x100 in samples).
+ *
+ * Recording applications want to use a fairly large buffer size here, while real-time applications
+ * would only buffer as much as they need to perform their next calculation.
+ *
+ * A good default is 360, which corresponds to 6 minutes of data.
+ * @param max_chunklen Optionally the maximum size, in samples, at which chunks are transmitted.
+ * If specified as 0, the chunk sizes preferred by the sender are used.
+ * Recording applications can use a generous size here (leaving it to the network how to pack
+ * things), while real-time applications may want a finer (perhaps 1-sample) granularity.
+ * @param recover Try to silently recover lost streams that are recoverable (=those that that have a
+ * source_id set).
+ *
+ * It is generally a good idea to enable this, unless the application wants to act in a special way
+ * when a data provider has temporarily crashed.
+ *
+ * If recover is 0 or the stream is not recoverable, most outlet functions will return an
+ * #lsl_lost_error if the stream's source is lost.
+ * @return A newly created lsl_inlet handle or NULL in the event that an error occurred.
+ */
+extern LIBLSL_C_API lsl_inlet lsl_create_inlet(lsl_streaminfo info, int32_t max_buflen, int32_t max_chunklen, int32_t recover);
+/** @copydoc lsl_create_inlet()
+ * @param flags An integer that is the result of bitwise OR'ing one or more options from
+ * #lsl_transport_options_t together (e.g., #transp_bufsize_samples)
+ */
+extern LIBLSL_C_API lsl_inlet lsl_create_inlet_ex(lsl_streaminfo info, int32_t max_buflen,
+ int32_t max_chunklen, int32_t recover, lsl_transport_options_t flags);
+
+/**
+* Destructor.
+* The inlet will automatically disconnect if destroyed.
+*/
+extern LIBLSL_C_API void lsl_destroy_inlet(lsl_inlet in);
+
+/**
+ * Retrieve the complete information of the given stream, including the extended description.
+ * Can be invoked at any time of the stream's lifetime.
+ * @param in The lsl_inlet object to act on.
+ * @param timeout Timeout of the operation. Use LSL_FOREVER to effectively disable it.
+ * @param[out] ec Error code: if nonzero, can be either lsl_timeout_error (if the timeout has
+ * expired) or #lsl_lost_error (if the stream source has been lost).
+ * @return A copy of the full streaminfo of the inlet or NULL in the event that an error happened.
+ * @note It is the user's responsibility to destroy it when it is no longer needed.
+ */
+extern LIBLSL_C_API lsl_streaminfo lsl_get_fullinfo(lsl_inlet in, double timeout, int32_t *ec);
+
+/**
+ * Subscribe to the data stream.
+ *
+ * All samples pushed in at the other end from this moment onwards will be queued and
+ * eventually be delivered in response to pull_sample() calls.
+ * Pulling a sample without some preceding lsl_open_stream() is permitted (the stream will then be
+ * opened implicitly).
+ * @param in The lsl_inlet object to act on.
+ * @param timeout Optional timeout of the operation. Use LSL_FOREVER to effectively disable it.
+ * @param[out] ec Error code: if nonzero, can be either #lsl_timeout_error (if the timeout has
+ * expired) or lsl_lost_error (if the stream source has been lost).
+ */
+extern LIBLSL_C_API void lsl_open_stream(lsl_inlet in, double timeout, int32_t *ec);
+
+/**
+* Drop the current data stream.
+*
+* All samples that are still buffered or in flight will be dropped and transmission
+* and buffering of data for this inlet will be stopped. If an application stops being
+* interested in data from a source (temporarily or not) but keeps the outlet alive,
+* it should call lsl_close_stream() to not waste unnecessary system and network
+* resources.
+*/
+extern LIBLSL_C_API void lsl_close_stream(lsl_inlet in);
+
+/**
+ * @brief Retrieve an estimated time correction offset for the given stream.
+ *
+ * The first call to this function takes several milliseconds until a reliable first estimate is
+ * obtained. Subsequent calls are instantaneous (and rely on periodic background updates).
+ *
+ * On a well-behaved network, the precision of these estimates should be below 1 ms (empirically it
+ * is within +/-0.2 ms).
+ *
+ * To get a measure of whether the network is well-behaved, use #lsl_time_correction_ex and check
+ * uncertainty (which maps to round-trip-time). 0.2 ms is typical of wired networks.
+ *
+ * 2 ms is typical of wireless networks. The number can be much higher on poor networks.
+ *
+ * @param in The lsl_inlet object to act on.
+ * @param timeout Timeout to acquire the first time-correction estimate.
+ * Use LSL_FOREVER to defuse the timeout.
+ * @param[out] ec Error code: if nonzero, can be either #lsl_timeout_error (if the timeout has
+ * expired) or lsl_lost_error (if the stream source has been lost).
+ * @return The time correction estimate.
+ * This is the number that needs to be added to a time stamp that was remotely generated via
+ * lsl_local_clock() to map it into the local clock domain of this machine.
+ */
+extern LIBLSL_C_API double lsl_time_correction(lsl_inlet in, double timeout, int32_t *ec);
+/** @copydoc lsl_time_correction()
+ * @param remote_time The current time of the remote computer that was used to generate this
+ * time_correction.
+ * If desired, the client can fit time_correction vs remote_time to improve the real-time
+ * time_correction further.
+ * @param uncertainty The maximum uncertainty of the given time correction.
+ */
+extern LIBLSL_C_API double lsl_time_correction_ex(lsl_inlet in, double *remote_time, double *uncertainty, double timeout, int32_t *ec);
+
+
+/**
+ * Set post-processing flags to use.
+ *
+ * By default, the inlet performs NO post-processing and returns the ground-truth time stamps, which
+ * can then be manually synchronized using time_correction(), and then smoothed/dejittered if
+ * desired.
+ *
+ * This function allows automating these two and possibly more operations.
+ * @warning When you enable this, you will no longer receive or be able to recover the original time
+ * stamps.
+ * @param in The lsl_inlet object to act on.
+ * @param flags An integer that is the result of bitwise OR'ing one or more options from
+ * #lsl_processing_options_t together (e.g., #proc_clocksync|#proc_dejitter);
+ * a good setting is to use #proc_ALL.
+ * @return The error code: if nonzero, can be #lsl_argument_error if an unknown flag was passed in.
+ */
+extern LIBLSL_C_API int32_t lsl_set_postprocessing(lsl_inlet in, uint32_t flags);
+
+
+/* === Pulling a sample from the inlet === */
+
+/**
+ * Pull a sample from the inlet and read it into a pointer to values.
+ * Handles type checking & conversion.
+ * @param in The #lsl_inlet object to act on.
+ * @param[out] buffer A pointer to hold the resulting values.
+ * @param buffer_elements The number of samples allocated in the buffer.
+ * @attention It is the responsibility of the user to allocate enough memory.
+ * @param timeout The timeout for this operation, if any.
+ * Use #LSL_FOREVER to effectively disable it. It is also permitted to use 0.0 here;
+ * in this case a sample is only returned if one is currently buffered.
+ * @param[out] ec Error code: can be either no error or #lsl_lost_error
+ * (if the stream source has been lost).
+ * @note If the timeout expires before a new sample was received the function returns 0.0;
+ * ec is *not* set to #lsl_timeout_error (because this case is not considered an error condition).
+ * @return The capture time of the sample on the remote machine, or 0.0 if no new sample was
+ * available. To remap this time stamp to the local clock, add the value returned by
+ * lsl_time_correction() to it.
+ * @{
+ */
+extern LIBLSL_C_API double lsl_pull_sample_f(lsl_inlet in, float *buffer, int32_t buffer_elements, double timeout, int32_t *ec);
+extern LIBLSL_C_API double lsl_pull_sample_d(lsl_inlet in, double *buffer, int32_t buffer_elements, double timeout, int32_t *ec);
+extern LIBLSL_C_API double lsl_pull_sample_l(lsl_inlet in, int64_t *buffer, int32_t buffer_elements, double timeout, int32_t *ec);
+extern LIBLSL_C_API double lsl_pull_sample_i(lsl_inlet in, int32_t *buffer, int32_t buffer_elements, double timeout, int32_t *ec);
+extern LIBLSL_C_API double lsl_pull_sample_s(lsl_inlet in, int16_t *buffer, int32_t buffer_elements, double timeout, int32_t *ec);
+extern LIBLSL_C_API double lsl_pull_sample_c(lsl_inlet in, char *buffer, int32_t buffer_elements, double timeout, int32_t *ec);
+extern LIBLSL_C_API double lsl_pull_sample_str(lsl_inlet in, char **buffer, int32_t buffer_elements, double timeout, int32_t *ec);
+///@}
+
+/** @copydoc lsl_pull_sample_f
+ * These strings may contains 0's, therefore the lengths are read into the buffer_lengths array.
+ * @param buffer_lengths
+ * A pointer to an array that holds the resulting lengths for each returned binary string.*/
+extern LIBLSL_C_API double lsl_pull_sample_buf(lsl_inlet in, char **buffer, uint32_t *buffer_lengths, int32_t buffer_elements, double timeout, int32_t *ec);
+
+/**
+ * Pull a sample from the inlet and read it into a custom struct or buffer.
+ *
+ * Overall size checking but no type checking or conversion are done.
+ * Do not use for variable-size/string-formatted streams.
+ * @param in The #lsl_inlet object to act on.
+ * @param[out] buffer A pointer to hold the resulting values.
+ * @param buffer_bytes Length of the array held by buffer in bytes, not items
+ * @param timeout The timeout for this operation, if any.
+ * Use #LSL_FOREVER to effectively disable it. It is also permitted to use 0.0 here;
+ * in this case a sample is only returned if one is currently buffered.
+ * @param[out] ec Error code: can be either no error or #lsl_lost_error
+ * (if the stream source has been lost).
+ * @note If the timeout expires before a new sample was received the function returns 0.0;
+ * ec is *not* set to #lsl_timeout_error (because this case is not considered an error condition).
+ * @return The capture time of the sample on the remote machine, or 0.0 if no new sample was
+ * available. To remap this time stamp to the local clock, add the value returned by
+ * lsl_time_correction() to it.
+ */
+extern LIBLSL_C_API double lsl_pull_sample_v(lsl_inlet in, void *buffer, int32_t buffer_bytes, double timeout, int32_t *ec);
+
+/**
+ * Pull a chunk of data from the inlet and read it into a buffer.
+ *
+ * Handles type checking & conversion.
+ *
+ * @attention Note that the provided data buffer size is measured in channel values (e.g. floats)
+ * rather than in samples.
+ * @param in The lsl_inlet object to act on.
+ * @param[out] data_buffer A pointer to a buffer of data values where the results shall be stored.
+ * @param[out] timestamp_buffer A pointer to a double buffer where time stamps shall be stored.
+ *
+ * If this is NULL, no time stamps will be returned.
+ * @param data_buffer_elements The size of the data buffer, in channel data elements (of type T).
+ * Must be a multiple of the stream's channel count.
+ * @param timestamp_buffer_elements The size of the timestamp buffer.
+ *
+ * If a timestamp buffer is provided then this must correspond to the same number of samples as
+ * data_buffer_elements.
+ * @param timeout The timeout for this operation, if any.
+ *
+ * When the timeout expires, the function may return before the entire buffer is filled.
+ * The default value of 0.0 will retrieve only data available for immediate pickup.
+ * @param[out] ec Error code: can be either no error or #lsl_lost_error (if the stream source has
+ * been lost).
+ * @note if the timeout expires before a new sample was received the function returns 0.0;
+ * ec is *not* set to #lsl_timeout_error (because this case is not considered an error condition).
+ * @return data_elements_written Number of channel data elements written to the data buffer.
+ * @{
+ */
+extern LIBLSL_C_API unsigned long lsl_pull_chunk_f(lsl_inlet in, float *data_buffer, double *timestamp_buffer, unsigned long data_buffer_elements, unsigned long timestamp_buffer_elements, double timeout, int32_t *ec);
+extern LIBLSL_C_API unsigned long lsl_pull_chunk_d(lsl_inlet in, double *data_buffer, double *timestamp_buffer, unsigned long data_buffer_elements, unsigned long timestamp_buffer_elements, double timeout, int32_t *ec);
+extern LIBLSL_C_API unsigned long lsl_pull_chunk_l(lsl_inlet in, int64_t *data_buffer, double *timestamp_buffer, unsigned long data_buffer_elements, unsigned long timestamp_buffer_elements, double timeout, int32_t *ec);
+extern LIBLSL_C_API unsigned long lsl_pull_chunk_i(lsl_inlet in, int32_t *data_buffer, double *timestamp_buffer, unsigned long data_buffer_elements, unsigned long timestamp_buffer_elements, double timeout, int32_t *ec);
+extern LIBLSL_C_API unsigned long lsl_pull_chunk_s(lsl_inlet in, int16_t *data_buffer, double *timestamp_buffer, unsigned long data_buffer_elements, unsigned long timestamp_buffer_elements, double timeout, int32_t *ec);
+extern LIBLSL_C_API unsigned long lsl_pull_chunk_c(lsl_inlet in, char *data_buffer, double *timestamp_buffer, unsigned long data_buffer_elements, unsigned long timestamp_buffer_elements, double timeout, int32_t *ec);
+extern LIBLSL_C_API unsigned long lsl_pull_chunk_str(lsl_inlet in, char **data_buffer, double *timestamp_buffer, unsigned long data_buffer_elements, unsigned long timestamp_buffer_elements, double timeout, int32_t *ec);
+
+///@}
+
+/**
+ * Pull a chunk of data from the inlet and read it into an array of binary strings.
+ *
+ * These strings may contains 0's, therefore the lengths are read into the lengths_buffer array.
+ * Handles type checking & conversion.
+ * IMPORTANT: Note that the provided data buffer size is measured in channel values (e.g., floats)
+ * rather than in samples.
+ * @param in The lsl_inlet object to act on.
+ * @param[out] data_buffer A pointer to a buffer of data values where the results shall be stored.
+ * @param[out] lengths_buffer A pointer to an array that holds the resulting lengths for each
+ * returned binary string.
+ * @param timestamp_buffer A pointer to a buffer of timestamp values where time stamps shall be
+ * stored. If this is NULL, no time stamps will be returned.
+ * @param data_buffer_elements The size of the data buffer, in channel data elements (of type T).
+ * Must be a multiple of the stream's channel count.
+ * @param timestamp_buffer_elements The size of the timestamp buffer. If a timestamp buffer is
+ * provided then this must correspond to the same number of samples as data_buffer_elements.
+ * @param timeout The timeout for this operation, if any.
+ *
+ * When the timeout expires, the function may return before the entire buffer is filled.
+ *
+ * The default value of 0.0 will retrieve only data available for immediate pickup.
+ * @param[out] ec Error code: can be either no error or #lsl_lost_error (if the stream source has
+ * been lost).
+ * @note If the timeout expires before a new sample was received the function returns 0.0; ec is
+ * *not* set to #lsl_timeout_error (because this case is not considered an error condition).
+ * @return data_elements_written Number of channel data elements written to the data buffer.
+ */
+
+extern LIBLSL_C_API unsigned long lsl_pull_chunk_buf(lsl_inlet in, char **data_buffer, uint32_t *lengths_buffer, double *timestamp_buffer, unsigned long data_buffer_elements, unsigned long timestamp_buffer_elements, double timeout, int32_t *ec);
+
+/**
+* Query whether samples are currently available for immediate pickup.
+*
+* Note that it is not a good idea to use samples_available() to determine whether
+* a pull_*() call would block: to be sure, set the pull timeout to 0.0 or an acceptably
+* low value. If the underlying implementation supports it, the value will be the number of
+* samples available (otherwise it will be 1 or 0).
+*/
+extern LIBLSL_C_API uint32_t lsl_samples_available(lsl_inlet in);
+
+/// Drop all queued not-yet pulled samples, return the nr of dropped samples
+extern LIBLSL_C_API uint32_t lsl_inlet_flush(lsl_inlet in);
+
+/**
+* Query whether the clock was potentially reset since the last call to lsl_was_clock_reset().
+*
+* This is rarely-used function is only needed for applications that combine multiple time_correction
+* values to estimate precise clock drift if they should tolerate cases where the source machine was
+* hot-swapped or restarted.
+*/
+extern LIBLSL_C_API uint32_t lsl_was_clock_reset(lsl_inlet in);
+
+/**
+ * Override the half-time (forget factor) of the time-stamp smoothing.
+ *
+ * The default is 90 seconds unless a different value is set in the config file.
+ *
+ * Using a longer window will yield lower jitter in the time stamps, but longer windows will have
+ * trouble tracking changes in the clock rate (usually due to temperature changes); the default is
+ * able to track changes up to 10 degrees C per minute sufficiently well.
+ * @param in The lsl_inlet object to act on.
+ * @param value The new value, in seconds. This is the time after which a past sample
+ * will be weighted by 1/2 in the exponential smoothing window.
+ * @return The error code: if nonzero, can be #lsl_argument_error if an unknown flag was passed in.
+ */
+extern LIBLSL_C_API int32_t lsl_smoothing_halftime(lsl_inlet in, float value);
+
+/// @}
diff --git a/physiolabxr/third_party/BAlert/SDK64/include/lsl/outlet.h b/physiolabxr/third_party/BAlert/SDK64/include/lsl/outlet.h
new file mode 100644
index 00000000..87c32538
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/SDK64/include/lsl/outlet.h
@@ -0,0 +1,251 @@
+#pragma once
+#include "./common.h"
+#include "types.h"
+
+/// @file outlet.h Stream outlet functions
+
+/** @defgroup outlet The lsl_outlet object
+ *
+ * This object represents an outlet sending data to all connected inlets.
+ *
+ * The data is pushed sample-by-sample or chunk-by-chunk into the outlet, and can consist of single-
+ * or multichannel data, regular or irregular sampling rate, with uniform value types (integers,
+ * floats, doubles, strings).
+ *
+ * Streams can have arbitrary XML meta-data (akin to a file header).
+ * By creating an outlet the stream is made visible to a collection of computers (defined by the
+ * network settings/layout) where one can subscribe to it by creating an inlet.
+ * @{
+ */
+
+/**
+ * Establish a new stream outlet. This makes the stream discoverable.
+ * @param info The stream information to use for creating this stream.
+ * Stays constant over the lifetime of the outlet.
+ * @note the outlet makes a copy of the streaminfo object upon construction (so the old info should
+ * still be destroyed.)
+ * @param chunk_size Optionally the desired chunk granularity (in samples) for transmission.
+ * If specified as 0, each push operation yields one chunk.
+ * Stream recipients can have this setting bypassed.
+ * @param max_buffered Optionally the maximum amount of data to buffer (in seconds if there is a
+ * nominal sampling rate, otherwise x100 in samples). A good default is 360, which corresponds to 6
+ * minutes of data. Note that, for high-bandwidth data you will almost certainly want to use a lower
+ * value here to avoid running out of RAM.
+ * @return A newly created lsl_outlet handle or NULL in the event that an error occurred.
+ */
+extern LIBLSL_C_API lsl_outlet lsl_create_outlet(lsl_streaminfo info, int32_t chunk_size, int32_t max_buffered);
+/** @copydoc lsl_create_outlet()
+ * @param flags An integer that is the result of bitwise OR'ing one or more options from
+ * #lsl_transport_options_t together (e.g., #transp_bufsize_samples|#transp_bufsize_thousandths)
+ */
+extern LIBLSL_C_API lsl_outlet lsl_create_outlet_ex(
+ lsl_streaminfo info, int32_t chunk_size, int32_t max_buffered, lsl_transport_options_t flags);
+
+/**
+ * Destroy an outlet.
+ * The outlet will no longer be discoverable after destruction and all connected inlets will stop
+ * delivering data.
+ */
+extern LIBLSL_C_API void lsl_destroy_outlet(lsl_outlet out);
+
+/** Push a pointer to some values as a sample into the outlet.
+ * Handles type checking & conversion.
+ * @param out The lsl_outlet object through which to push the data.
+ * @param data A pointer to values to push. The number of values pointed to must be no less than the
+ * number of channels in the sample.
+ * #lsl_local_clock(); if omitted, the current time is used.
+ * @return Error code of the operation or lsl_no_error if successful (usually attributed to the
+ * wrong data type).
+ * @{
+ */
+extern LIBLSL_C_API int32_t lsl_push_sample_f(lsl_outlet out, const float *data);
+extern LIBLSL_C_API int32_t lsl_push_sample_d(lsl_outlet out, const double *data);
+extern LIBLSL_C_API int32_t lsl_push_sample_l(lsl_outlet out, const int64_t *data);
+extern LIBLSL_C_API int32_t lsl_push_sample_i(lsl_outlet out, const int32_t *data);
+extern LIBLSL_C_API int32_t lsl_push_sample_s(lsl_outlet out, const int16_t *data);
+extern LIBLSL_C_API int32_t lsl_push_sample_c(lsl_outlet out, const char *data);
+extern LIBLSL_C_API int32_t lsl_push_sample_str(lsl_outlet out, const char **data);
+extern LIBLSL_C_API int32_t lsl_push_sample_v(lsl_outlet out, const void *data);
+/// @}
+/** @copydoc lsl_push_sample_f
+ * @param timestamp Optionally the capture time of the sample, in agreement with
+ * @{
+ */
+extern LIBLSL_C_API int32_t lsl_push_sample_ft(lsl_outlet out, const float *data, double timestamp);
+extern LIBLSL_C_API int32_t lsl_push_sample_dt(lsl_outlet out, const double *data, double timestamp);
+extern LIBLSL_C_API int32_t lsl_push_sample_lt(lsl_outlet out, const int64_t *data, double timestamp);
+extern LIBLSL_C_API int32_t lsl_push_sample_it(lsl_outlet out, const int32_t *data, double timestamp);
+extern LIBLSL_C_API int32_t lsl_push_sample_st(lsl_outlet out, const int16_t *data, double timestamp);
+extern LIBLSL_C_API int32_t lsl_push_sample_ct(lsl_outlet out, const char *data, double timestamp);
+extern LIBLSL_C_API int32_t lsl_push_sample_strt(lsl_outlet out, const char **data, double timestamp);
+extern LIBLSL_C_API int32_t lsl_push_sample_vt(lsl_outlet out, const void *data, double timestamp);
+/// @}
+/** @copydoc lsl_push_sample_ft
+ * @param pushthrough Whether to push the sample through to the receivers instead of buffering it
+ * with subsequent samples. Note that the chunk_size, if specified at outlet construction, takes
+ * precedence over the pushthrough flag.
+ * @{
+ */
+extern LIBLSL_C_API int32_t lsl_push_sample_ftp(lsl_outlet out, const float *data, double timestamp, int32_t pushthrough);
+extern LIBLSL_C_API int32_t lsl_push_sample_dtp(lsl_outlet out, const double *data, double timestamp, int32_t pushthrough);
+extern LIBLSL_C_API int32_t lsl_push_sample_ltp(lsl_outlet out, const int64_t *data, double timestamp, int32_t pushthrough);
+extern LIBLSL_C_API int32_t lsl_push_sample_itp(lsl_outlet out, const int32_t *data, double timestamp, int32_t pushthrough);
+extern LIBLSL_C_API int32_t lsl_push_sample_stp(lsl_outlet out, const int16_t *data, double timestamp, int32_t pushthrough);
+extern LIBLSL_C_API int32_t lsl_push_sample_ctp(lsl_outlet out, const char *data, double timestamp, int32_t pushthrough);
+extern LIBLSL_C_API int32_t lsl_push_sample_strtp(lsl_outlet out, const char **data, double timestamp, int32_t pushthrough);
+extern LIBLSL_C_API int32_t lsl_push_sample_vtp(lsl_outlet out, const void *data, double timestamp, int32_t pushthrough);
+///@}
+
+/** @copybrief lsl_push_sample_ftp
+ * @see lsl_push_sample_ftp
+ * @param out The lsl_outlet object through which to push the data.
+ * @param data A pointer to values to push. The number of values pointed to must be no less than the
+ * number of channels in the sample.
+ * @param lengths A pointer the number of elements to push for each channel (string lengths).
+ */
+extern LIBLSL_C_API int32_t lsl_push_sample_buf(lsl_outlet out, const char **data, const uint32_t *lengths);
+/** @copydoc lsl_push_sample_buf
+ * @param timestamp @see lsl_push_sample_ftp */
+extern LIBLSL_C_API int32_t lsl_push_sample_buft(lsl_outlet out, const char **data, const uint32_t *lengths, double timestamp);
+/** @copydoc lsl_push_sample_buft
+ * @param pushthrough @see lsl_push_sample_ftp */
+extern LIBLSL_C_API int32_t lsl_push_sample_buftp(lsl_outlet out, const char **data, const uint32_t *lengths, double timestamp, int32_t pushthrough);
+
+/** Push a chunk of multiplexed samples into the outlet. One timestamp per sample is provided.
+ *
+ * @attention Note that the provided buffer size is measured in channel values (e.g. floats) rather
+ * than in samples.
+ *
+ * Handles type checking & conversion.
+ * @param out The lsl_outlet object through which to push the data.
+ * @param data A buffer of channel values holding the data for zero or more successive samples to
+ * send.
+ * @param data_elements The number of data values (of type T) in the data buffer. Must be a multiple
+ * of the channel count.
+ * @return Error code of the operation (usually attributed to the wrong data type).
+ * @{
+ */
+extern LIBLSL_C_API int32_t lsl_push_chunk_f(lsl_outlet out, const float *data, unsigned long data_elements);
+extern LIBLSL_C_API int32_t lsl_push_chunk_d(lsl_outlet out, const double *data, unsigned long data_elements);
+extern LIBLSL_C_API int32_t lsl_push_chunk_l(lsl_outlet out, const int64_t *data, unsigned long data_elements);
+extern LIBLSL_C_API int32_t lsl_push_chunk_i(lsl_outlet out, const int32_t *data, unsigned long data_elements);
+extern LIBLSL_C_API int32_t lsl_push_chunk_s(lsl_outlet out, const int16_t *data, unsigned long data_elements);
+extern LIBLSL_C_API int32_t lsl_push_chunk_c(lsl_outlet out, const char *data, unsigned long data_elements);
+extern LIBLSL_C_API int32_t lsl_push_chunk_str(lsl_outlet out, const char **data, unsigned long data_elements);
+/// @}
+
+/** @copydoc lsl_push_chunk_f
+ * @param timestamp Optionally the capture time of the most recent sample, in agreement with
+ * lsl_local_clock(); if omitted, the current time is used.
+ * The time stamps of other samples are automatically derived based on the sampling rate of the
+ * stream.
+ * @{
+ */
+extern LIBLSL_C_API int32_t lsl_push_chunk_ft(lsl_outlet out, const float *data, unsigned long data_elements, double timestamp);
+extern LIBLSL_C_API int32_t lsl_push_chunk_dt(lsl_outlet out, const double *data, unsigned long data_elements, double timestamp);
+extern LIBLSL_C_API int32_t lsl_push_chunk_lt(lsl_outlet out, const int64_t *data, unsigned long data_elements, double timestamp);
+extern LIBLSL_C_API int32_t lsl_push_chunk_it(lsl_outlet out, const int32_t *data, unsigned long data_elements, double timestamp);
+extern LIBLSL_C_API int32_t lsl_push_chunk_st(lsl_outlet out, const int16_t *data, unsigned long data_elements, double timestamp);
+extern LIBLSL_C_API int32_t lsl_push_chunk_ct(lsl_outlet out, const char *data, unsigned long data_elements, double timestamp);
+extern LIBLSL_C_API int32_t lsl_push_chunk_strt(lsl_outlet out, const char **data, unsigned long data_elements, double timestamp);
+/// @}
+
+/** @copydoc lsl_push_chunk_ft
+ * @param pushthrough Whether to push the chunk through to the receivers instead of buffering it
+ * with subsequent samples. Note that the chunk_size, if specified at outlet construction, takes
+ * precedence over the pushthrough flag.
+ * @{
+ */
+extern LIBLSL_C_API int32_t lsl_push_chunk_ftp(lsl_outlet out, const float *data, unsigned long data_elements, double timestamp, int32_t pushthrough);
+extern LIBLSL_C_API int32_t lsl_push_chunk_dtp(lsl_outlet out, const double *data, unsigned long data_elements, double timestamp, int32_t pushthrough);
+extern LIBLSL_C_API int32_t lsl_push_chunk_ltp(lsl_outlet out, const int64_t *data, unsigned long data_elements, double timestamp, int32_t pushthrough);
+extern LIBLSL_C_API int32_t lsl_push_chunk_itp(lsl_outlet out, const int32_t *data, unsigned long data_elements, double timestamp, int32_t pushthrough);
+extern LIBLSL_C_API int32_t lsl_push_chunk_stp(lsl_outlet out, const int16_t *data, unsigned long data_elements, double timestamp, int32_t pushthrough);
+extern LIBLSL_C_API int32_t lsl_push_chunk_ctp(lsl_outlet out, const char *data, unsigned long data_elements, double timestamp, int32_t pushthrough);
+extern LIBLSL_C_API int32_t lsl_push_chunk_strtp(lsl_outlet out, const char **data, unsigned long data_elements, double timestamp, int32_t pushthrough);
+/// @}
+/** @copydoc lsl_push_chunk_f
+ * @param timestamps Buffer holding one time stamp for each sample in the data buffer.
+ * @{
+ */
+extern LIBLSL_C_API int32_t lsl_push_chunk_ftn(lsl_outlet out, const float *data, unsigned long data_elements, const double *timestamps);
+extern LIBLSL_C_API int32_t lsl_push_chunk_dtn(lsl_outlet out, const double *data, unsigned long data_elements, const double *timestamps);
+extern LIBLSL_C_API int32_t lsl_push_chunk_ltn(lsl_outlet out, const int64_t *data, unsigned long data_elements, const double *timestamps);
+extern LIBLSL_C_API int32_t lsl_push_chunk_itn(lsl_outlet out, const int32_t *data, unsigned long data_elements, const double *timestamps);
+extern LIBLSL_C_API int32_t lsl_push_chunk_stn(lsl_outlet out, const int16_t *data, unsigned long data_elements, const double *timestamps);
+extern LIBLSL_C_API int32_t lsl_push_chunk_ctn(lsl_outlet out, const char *data, unsigned long data_elements, const double *timestamps);
+extern LIBLSL_C_API int32_t lsl_push_chunk_strtn(lsl_outlet out, const char **data, unsigned long data_elements, const double *timestamps);
+/// @}
+
+/** @copydoc lsl_push_chunk_ftn
+ * @param pushthrough Whether to push the chunk through to the receivers instead of buffering it
+ * with subsequent samples. Note that the chunk_size, if specified at outlet construction, takes
+ * precedence over the pushthrough flag.
+ * @{
+ */
+extern LIBLSL_C_API int32_t lsl_push_chunk_ftnp(lsl_outlet out, const float *data, unsigned long data_elements, const double *timestamps, int32_t pushthrough);
+extern LIBLSL_C_API int32_t lsl_push_chunk_dtnp(lsl_outlet out, const double *data, unsigned long data_elements, const double *timestamps, int32_t pushthrough);
+extern LIBLSL_C_API int32_t lsl_push_chunk_ltnp(lsl_outlet out, const int64_t *data, unsigned long data_elements, const double *timestamps, int32_t pushthrough);
+extern LIBLSL_C_API int32_t lsl_push_chunk_itnp(lsl_outlet out, const int32_t *data, unsigned long data_elements, const double *timestamps, int32_t pushthrough);
+extern LIBLSL_C_API int32_t lsl_push_chunk_stnp(lsl_outlet out, const int16_t *data, unsigned long data_elements, const double *timestamps, int32_t pushthrough);
+extern LIBLSL_C_API int32_t lsl_push_chunk_ctnp(lsl_outlet out, const char *data, unsigned long data_elements, const double *timestamps, int32_t pushthrough);
+extern LIBLSL_C_API int32_t lsl_push_chunk_strtnp(lsl_outlet out, const char **data, unsigned long data_elements, const double *timestamps, int32_t pushthrough);
+///@}
+
+/** @copybrief lsl_push_chunk_ftp
+ * @sa lsl_push_chunk_ftp
+ * @param out The lsl_outlet object through which to push the data.
+ * @param data An array of channel values holding the data to push.
+ * @param lengths Pointer the number of elements to push for each value (string lengths) so that
+ * `size(data[i])==lengths[i]`.
+ * @param data_elements The number of data values in the data buffer.
+ * Must be a multiple of the channel count.
+ */
+extern LIBLSL_C_API int32_t lsl_push_chunk_buf(lsl_outlet out, const char **data, const uint32_t *lengths, unsigned long data_elements);
+
+/** @copydoc lsl_push_chunk_buf @sa lsl_push_chunk_ftp @sa lsl_push_chunk_buf
+ * @param timestamp Optionally the capture time of the most recent sample, in agreement with
+ * lsl_local_clock(); if omitted, the current time is used.
+ * The time stamps of other samples are automatically derived based on the sampling rate of the
+ * stream. */
+extern LIBLSL_C_API int32_t lsl_push_chunk_buft(lsl_outlet out, const char **data, const uint32_t *lengths, unsigned long data_elements, double timestamp);
+
+/** @copydoc lsl_push_chunk_buft @sa lsl_push_chunk_ftp @sa lsl_push_chunk_buf
+ * @param pushthrough Whether to push the chunk through to the receivers instead of buffering it
+ * with subsequent samples. Note that the chunk_size, if specified at outlet construction, takes
+ * precedence over the pushthrough flag. */
+extern LIBLSL_C_API int32_t lsl_push_chunk_buftp(lsl_outlet out, const char **data, const uint32_t *lengths, unsigned long data_elements, double timestamp, int32_t pushthrough);
+
+/** @copydoc lsl_push_chunk_buf @sa lsl_push_chunk_ftp @sa lsl_push_chunk_buf
+ * @param timestamps Buffer holding one time stamp for each sample in the data buffer. */
+extern LIBLSL_C_API int32_t lsl_push_chunk_buftn(lsl_outlet out, const char **data, const uint32_t *lengths, unsigned long data_elements, const double *timestamps);
+
+/** @copydoc lsl_push_chunk_buftn @sa lsl_push_chunk_ftp @sa lsl_push_chunk_buf
+ * @param pushthrough Whether to push the chunk through to the receivers instead of buffering it
+ * with subsequent samples. Note that the chunk_size, if specified at outlet construction, takes
+ * precedence over the pushthrough flag. */
+extern LIBLSL_C_API int32_t lsl_push_chunk_buftnp(lsl_outlet out, const char **data, const uint32_t *lengths, unsigned long data_elements, const double *timestamps, int32_t pushthrough);
+
+/**
+* Check whether consumers are currently registered.
+* While it does not hurt, there is technically no reason to push samples if there is no consumer.
+*/
+extern LIBLSL_C_API int32_t lsl_have_consumers(lsl_outlet out);
+
+/**
+* Wait until some consumer shows up (without wasting resources).
+* @return True if the wait was successful, false if the timeout expired.
+*/
+extern LIBLSL_C_API int32_t lsl_wait_for_consumers(lsl_outlet out, double timeout);
+
+/**
+ * Retrieve a handle to the stream info provided by this outlet.
+ * This is what was used to create the stream (and also has the Additional Network Information
+ * fields assigned).
+ * @return A copy of the streaminfo of the outlet or NULL in the event that an error occurred.
+ * @note It is the user's responsibility to destroy it when it is no longer needed.
+ * @sa lsl_destroy_string()
+ */
+extern LIBLSL_C_API lsl_streaminfo lsl_get_info(lsl_outlet out);
+
+///@}
diff --git a/physiolabxr/third_party/BAlert/SDK64/include/lsl/resolver.h b/physiolabxr/third_party/BAlert/SDK64/include/lsl/resolver.h
new file mode 100644
index 00000000..db7419fc
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/SDK64/include/lsl/resolver.h
@@ -0,0 +1,156 @@
+#pragma once
+#include "common.h"
+#include "types.h"
+
+/// @file resolver.h Stream resolution functions
+
+/** @defgroup continuous_resolver The lsl_continuous_resolver
+ * @ingroup resolve
+ *
+ * Streams can be resolved at a single timepoint once (@ref resolve) or continuously in the
+ * background.
+ * @{
+ */
+
+/**
+ * Construct a new #lsl_continuous_resolver that resolves all streams on the network.
+ *
+ * This is analogous to the functionality offered by the free function lsl_resolve_streams().
+ * @param forget_after When a stream is no longer visible on the network (e.g. because it was shut
+ * down), this is the time in seconds after which it is no longer reported by the resolver.
+ *
+ * The recommended default value is 5.0.
+ */
+extern LIBLSL_C_API lsl_continuous_resolver lsl_create_continuous_resolver(double forget_after);
+
+/**
+ * Construct a new lsl_continuous_resolver that resolves all streams with a specific value for a given
+ * property.
+ *
+ * This is analogous to the functionality provided by the free function lsl_resolve_byprop()
+ * @param prop The #lsl_streaminfo property that should have a specific value (e.g., "name", "type",
+ * "source_id", or "desc/manufaturer").
+ * @param value The string value that the property should have (e.g., "EEG" as the type property).
+ * @param forget_after When a stream is no longer visible on the network (e.g., because it was shut
+ * down), this is the time in seconds after which it is no longer reported by the resolver.
+ * The recommended default value is 5.0.
+ */
+extern LIBLSL_C_API lsl_continuous_resolver lsl_create_continuous_resolver_byprop(const char *prop, const char *value, double forget_after);
+
+/**
+ * Construct a new lsl_continuous_resolver that resolves all streams that match a given XPath 1.0
+ * predicate.
+ *
+ * This is analogous to the functionality provided by the free function lsl_resolve_bypred()
+ * @param pred The predicate string, e.g.
+ * `"name='BioSemi'" or "type='EEG' and starts-with(name,'BioSemi') and count(info/desc/channel)=32"`
+ * @param forget_after When a stream is no longer visible on the network (e.g., because it was shut
+ * down), this is the time in seconds after which it is no longer reported by the resolver.
+ * The recommended default value is 5.0.
+ */
+extern LIBLSL_C_API lsl_continuous_resolver lsl_create_continuous_resolver_bypred(const char *pred, double forget_after);
+
+/**
+ * Obtain the set of currently present streams on the network (i.e. resolve result).
+ *
+ * @param res A continuous resolver (previously created with one of the
+ * lsl_create_continuous_resolver() functions).
+ * @param buffer A user-allocated buffer to hold the current resolve results.
+ * @attention It is the user's responsibility to either destroy the resulting streaminfo objects or
+ * to pass them back to the LSL during during creation of an inlet.
+ * @attention The stream_infos returned by the resolver are only short versions that do not include
+ * the lsl_get_desc() field (which can be arbitrarily big).
+ *
+ * To obtain the full stream information you need to call lsl_get_info() on the inlet after you have
+ * created one.
+ * @param buffer_elements The user-provided buffer length.
+ * @return The number of results written into the buffer (never more than the provided # of slots)
+ * or a negative number if an error has occurred (values corresponding to #lsl_error_code_t).
+ */
+extern LIBLSL_C_API int32_t lsl_resolver_results(lsl_continuous_resolver res, lsl_streaminfo *buffer, uint32_t buffer_elements);
+
+/// Destructor for the continuous resolver.
+extern LIBLSL_C_API void lsl_destroy_continuous_resolver(lsl_continuous_resolver res);
+
+/// @}
+
+/** @defgroup resolve Resolving streams on the network
+ * @{*/
+
+/**
+ * Resolve all streams on the network.
+ *
+ * This function returns all currently available streams from any outlet on the network.
+ * The network is usually the subnet specified at the local router, but may also include a multicast
+ * group of machines (given that the network supports it), or a list of hostnames.
+ * These details may optionally be customized by the experimenter in a configuration file
+ * (see page Network Connectivity in the LSL wiki).
+ * This is the default mechanism used by the browsing programs and the recording program.
+ * @param[out] buffer A user-allocated buffer to hold the resolve results.
+ * @attention It is the user's responsibility to either destroy the resulting streaminfo objects or
+ * to pass them back to the LSL during during creation of an inlet.
+ *
+ * @attention The stream_info's returned by the resolver are only short versions that do not include
+ * the lsl_get_desc() field (which can be arbitrarily big).
+ * To obtain the full stream information you need to call lsl_get_info() on the inlet after you have
+ * created one.
+ * @param buffer_elements The user-provided buffer length.
+ * @param wait_time The waiting time for the operation, in seconds, to search for streams.
+ * The recommended wait time is 1 second (or 2 for a busy and large recording operation).
+ * @warning If this is too short (<0.5s) only a subset (or none) of the outlets that are present on
+ * the network may be returned.
+ * @return The number of results written into the buffer (never more than the provided # of slots)
+ * or a negative number if an error has occurred (values corresponding to lsl_error_code_t).
+ */
+extern LIBLSL_C_API int32_t lsl_resolve_all(lsl_streaminfo *buffer, uint32_t buffer_elements, double wait_time);
+
+/**
+ * Resolve all streams with a given value for a property.
+ *
+ * If the goal is to resolve a specific stream, this method is preferred over resolving all streams
+ * and then selecting the desired one.
+ * @param[out] buffer A user-allocated buffer to hold the resolve results.
+ * @attention It is the user's responsibility to either destroy the resulting streaminfo objects or
+ * to pass them back to the LSL during during creation of an inlet.
+ *
+ * @attention The stream_info's returned by the resolver are only short versions that do not include
+ * the lsl_get_desc() field (which can be arbitrarily big). To obtain the full stream information
+ * you need to call lsl_get_info() on the inlet after you have created one.
+ * @param buffer_elements The user-provided buffer length.
+ * @param prop The streaminfo property that should have a specific value (`"name"`, `"type"`,
+ * `"source_id"`, or, e.g., `"desc/manufaturer"` if present).
+ * @param value The string value that the property should have (e.g., "EEG" as the type).
+ * @param minimum Return at least this number of streams.
+ * @param timeout Optionally a timeout of the operation, in seconds (default: no timeout).
+ * If the timeout expires, less than the desired number of streams (possibly none) will be returned.
+ * @return The number of results written into the buffer (never more than the provided # of slots)
+ * or a negative number if an error has occurred (values corresponding to #lsl_error_code_t).
+ */
+extern LIBLSL_C_API int32_t lsl_resolve_byprop(lsl_streaminfo *buffer, uint32_t buffer_elements, const char *prop, const char *value, int32_t minimum, double timeout);
+
+/**
+ * Resolve all streams that match a given predicate.
+ *
+ * Advanced query that allows to impose more conditions on the retrieved streams;
+ * the given string is an [XPath 1.0 predicate](http://en.wikipedia.org/w/index.php?title=XPath_1.0)
+ * for the `` node (omitting the surrounding []'s)
+ * @param[out] buffer A user-allocated buffer to hold the resolve results.
+ * @attention It is the user's responsibility to either destroy the resulting streaminfo objects or
+ * to pass them back to the LSL during during creation of an inlet.
+ *
+ * @attention The stream_info's returned by the resolver are only short versions that do not include
+ * the lsl_get_desc() field (which can be arbitrarily big). To obtain the full stream information
+ * you need to call lsl_get_info() on the inlet after you have created one.
+ * @param buffer_elements The user-provided buffer length.
+ * @param pred The predicate string, e.g.
+ * `name='BioSemi'` or `type='EEG' and starts-with(name,'BioSemi') and count(info/desc/channel)=32`
+ * @param minimum Return at least this number of streams.
+ * @param timeout Optionally a timeout of the operation, in seconds (default: no timeout).
+ * If the timeout expires, less than the desired number of streams (possibly none)
+ * will be returned.
+ * @return The number of results written into the buffer (never more than the provided # of slots)
+ * or a negative number if an error has occurred (values corresponding to lsl_error_code_t).
+ */
+extern LIBLSL_C_API int32_t lsl_resolve_bypred(lsl_streaminfo *buffer, uint32_t buffer_elements, const char *pred, int32_t minimum, double timeout);
+
+/// @}
diff --git a/physiolabxr/third_party/BAlert/SDK64/include/lsl/streaminfo.h b/physiolabxr/third_party/BAlert/SDK64/include/lsl/streaminfo.h
new file mode 100644
index 00000000..2ecfff0a
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/SDK64/include/lsl/streaminfo.h
@@ -0,0 +1,196 @@
+#pragma once
+#include "common.h"
+#include "types.h"
+
+/// @file streaminfo.h Stream info functions
+
+/** @defgroup streaminfo The lsl_streaminfo object
+ *
+ * The #lsl_streaminfo object keeps a stream's meta data and connection settings.
+ * @{
+ */
+
+/**
+ * Construct a new streaminfo object.
+ *
+ * Core stream information is specified here. Any remaining meta-data can be added later.
+ * @param name Name of the stream.
+ * Describes the device (or product series) that this stream makes available
+ * (for use by programs, experimenters or data analysts). Cannot be empty.
+ * @param type Content type of the stream. Please see https://github.com/sccn/xdf/wiki/Meta-Data (or
+ * web search for: XDF meta-data) for pre-defined content-type names, but you can also make up your
+ * own. The content type is the preferred way to find streams (as opposed to searching by name).
+ * @param channel_count Number of channels per sample.
+ * This stays constant for the lifetime of the stream.
+ * @param nominal_srate The sampling rate (in Hz) as advertised by the
+ * datasource, if regular (otherwise set to #LSL_IRREGULAR_RATE).
+ * @param channel_format Format/type of each channel.
+ * If your channels have different formats, consider supplying multiple streams
+ * or use the largest type that can hold them all (such as #cft_double64).
+ *
+ * A good default is #cft_float32.
+ * @param source_id Unique identifier of the source or device, if available (e.g. a serial number).
+ * Allows recipients to recover from failure even after the serving app or device crashes.
+ * May in some cases also be constructed from device settings.
+ * @return A newly created streaminfo handle or NULL in the event that an error occurred.
+ */
+extern LIBLSL_C_API lsl_streaminfo lsl_create_streaminfo(const char *name, const char *type, int32_t channel_count, double nominal_srate, lsl_channel_format_t channel_format, const char *source_id);
+
+/// Destroy a previously created streaminfo object.
+extern LIBLSL_C_API void lsl_destroy_streaminfo(lsl_streaminfo info);
+
+/// Copy an existing streaminfo object (rarely used).
+extern LIBLSL_C_API lsl_streaminfo lsl_copy_streaminfo(lsl_streaminfo info);
+
+/**
+ * Name of the stream.
+ *
+ * This is a human-readable name.
+ * For streams offered by device modules, it refers to the type of device or product series that is
+ * generating the data of the stream. If the source is an application, the name may be a more
+ * generic or specific identifier. Multiple streams with the same name can coexist, though
+ * potentially at the cost of ambiguity (for the recording app or experimenter).
+ * @return An immutable library-owned pointer to the string value. @sa lsl_destroy_string()
+ */
+extern LIBLSL_C_API const char *lsl_get_name(lsl_streaminfo info);
+
+/**
+ * Content type of the stream.
+ *
+ * The content type is a short string such as "EEG", "Gaze" which describes the content carried by
+ * the channel (if known). If a stream contains mixed content this value need not be assigned but
+ * may instead be stored in the description of channel types. To be useful to applications and
+ * automated processing systems using the recommended content types is preferred. Content types
+ * usually follow those pre-defined in the [wiki](https://github.com/sccn/xdf/wiki/Meta-Data) (or
+ * web search for: XDF meta-data).
+ * @return An immutable library-owned pointer to the string value. @sa lsl_destroy_string()
+ */
+extern LIBLSL_C_API const char *lsl_get_type(lsl_streaminfo info);
+
+/**
+* Number of channels of the stream.
+* A stream has at least one channels; the channel count stays constant for all samples.
+*/
+extern LIBLSL_C_API int32_t lsl_get_channel_count(lsl_streaminfo info);
+
+/**
+ * Sampling rate of the stream, according to the source (in Hz).
+ *
+ * If a stream is irregularly sampled, this should be set to #LSL_IRREGULAR_RATE.
+ *
+ * Note that no data will be lost even if this sampling rate is incorrect or if a device has
+ * temporary hiccups, since all samples will be recorded anyway (except for those dropped by the
+ * device itself). However, when the recording is imported into an application, a good importer may
+ * correct such errors more accurately if the advertised sampling rate was close to the specs of the
+ * device.
+ */
+extern LIBLSL_C_API double lsl_get_nominal_srate(lsl_streaminfo info);
+
+/**
+ * Channel format of the stream.
+ * All channels in a stream have the same format.
+ * However, a device might offer multiple time-synched streams each with its own format.
+ */
+extern LIBLSL_C_API lsl_channel_format_t lsl_get_channel_format(lsl_streaminfo info);
+
+/**
+ * Unique identifier of the stream's source, if available.
+ *
+ * The unique source (or device) identifier is an optional piece of information that, if available,
+ * allows that endpoints (such as the recording program) can re-acquire a stream automatically once
+ * it is back online.
+ * @return An immutable library-owned pointer to the string value. @sa lsl_destroy_string()
+ */
+extern LIBLSL_C_API const char *lsl_get_source_id(lsl_streaminfo info);
+
+/**
+* Protocol version used to deliver the stream.
+*/
+extern LIBLSL_C_API int32_t lsl_get_version(lsl_streaminfo info);
+
+/**
+* Creation time stamp of the stream.
+*
+* This is the time stamp when the stream was first created
+* (as determined via local_clock() on the providing machine).
+*/
+extern LIBLSL_C_API double lsl_get_created_at(lsl_streaminfo info);
+
+/**
+ * Unique ID of the stream outlet (once assigned).
+ *
+ * This is a unique identifier of the stream outlet, and is guaranteed to be different
+ * across multiple instantiations of the same outlet (e.g., after a re-start).
+ * @return An immutable library-owned pointer to the string value. @sa lsl_destroy_string()
+ */
+extern LIBLSL_C_API const char *lsl_get_uid(lsl_streaminfo info);
+
+/**
+ * Session ID for the given stream.
+ *
+ * The session id is an optional human-assigned identifier of the recording session.
+ * While it is rarely used, it can be used to prevent concurrent recording activitites
+ * on the same sub-network (e.g., in multiple experiment areas) from seeing each other's streams
+ * (assigned via a configuration file by the experimenter, see Network Connectivity on the LSL
+ * wiki).
+ * @return An immutable library-owned pointer to the string value. @sa lsl_destroy_string()
+ */
+extern LIBLSL_C_API const char *lsl_get_session_id(lsl_streaminfo info);
+
+/// Hostname of the providing machine (once bound to an outlet). Modification is not permitted.
+extern LIBLSL_C_API const char *lsl_get_hostname(lsl_streaminfo info);
+
+/**
+* Extended description of the stream.
+*
+* It is highly recommended that at least the channel labels are described here.
+* See code examples on the LSL wiki. Other information, such as amplifier settings,
+* measurement units if deviating from defaults, setup information, subject information, etc.,
+* can be specified here, as well. Meta-data recommendations follow the XDF file format project
+* (github.com/sccn/xdf/wiki/Meta-Data or web search for: XDF meta-data).
+*
+* @attention if you use a stream content type for which meta-data recommendations exist, please
+* try to lay out your meta-data in agreement with these recommendations for compatibility with other applications.
+*/
+extern LIBLSL_C_API lsl_xml_ptr lsl_get_desc(lsl_streaminfo info);
+
+/**
+ * Retrieve the entire streaminfo in XML format.
+ *
+ * This yields an XML document (in string form) whose top-level element is ``. The info
+ * element contains one element for each field of the streaminfo class, including:
+ *
+ * - the core elements ``, ``, ``,
+ * ``, ``
+ * - the misc elements ``, ``, ``, ``,
+ * ``, ``, ``, ``, ``,
+ * ``
+ * - the extended description element `` with user-defined sub-elements.
+ * @return A pointer to a copy of the XML text or NULL in the event that an error occurred.
+ * @note It is the user's responsibility to deallocate this string when it is no longer needed.
+ */
+extern LIBLSL_C_API char *lsl_get_xml(lsl_streaminfo info);
+
+/// Number of bytes occupied by a channel (0 for string-typed channels).
+extern LIBLSL_C_API int32_t lsl_get_channel_bytes(lsl_streaminfo info);
+
+/// Number of bytes occupied by a sample (0 for string-typed channels).
+extern LIBLSL_C_API int32_t lsl_get_sample_bytes(lsl_streaminfo info);
+
+/**
+ * Tries to match the stream info XML element @p info against an
+ * XPath query.
+ *
+ * Example query strings:
+ * @code
+ * channel_count>5 and type='EEG'
+ * type='TestStream' or contains(name,'Brain')
+ * name='ExampleStream'
+ * @endcode
+ */
+extern LIBLSL_C_API int32_t lsl_stream_info_matches_query(lsl_streaminfo info, const char *query);
+
+/// Create a streaminfo object from an XML representation
+extern LIBLSL_C_API lsl_streaminfo lsl_streaminfo_from_xml(const char *xml);
+
+/// @}
diff --git a/physiolabxr/third_party/BAlert/SDK64/include/lsl/types.h b/physiolabxr/third_party/BAlert/SDK64/include/lsl/types.h
new file mode 100644
index 00000000..95b9c275
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/SDK64/include/lsl/types.h
@@ -0,0 +1,60 @@
+#ifndef LSL_TYPES
+#define LSL_TYPES
+
+/**
+ * @class lsl_streaminfo
+ * Handle to a stream info object.
+ *
+ * Stores the declaration of a data stream.
+ * Represents the following information:
+ *
+ * - stream data format (number of channels, channel format)
+ * - core information (stream name, content type, sampling rate)
+ * - optional meta-data about the stream content (channel labels, measurement units, etc.)
+ *
+ * Whenever a program wants to provide a new stream on the lab network it will typically first
+ * create an lsl_streaminfo to describe its properties and then construct an #lsl_outlet with it to
+ * create the stream on the network. Other parties who discover/resolve the outlet on the network
+ * can query the stream info; it is also written to disk when recording the stream (playing a
+ * similar role as a file header).
+ */
+typedef struct lsl_streaminfo_struct_ *lsl_streaminfo;
+
+/**
+ * @class lsl_outlet
+ * A stream outlet handle.
+ * Outlets are used to make streaming data (and the meta-data) available on the lab network.
+ */
+typedef struct lsl_outlet_struct_ *lsl_outlet;
+
+/**
+ * @class lsl_inlet
+ * A stream inlet handle.
+ * Inlets are used to receive streaming data (and meta-data) from the lab network.
+ */
+typedef struct lsl_inlet_struct_ *lsl_inlet;
+
+/**
+ * @class lsl_xml_ptr
+ * A lightweight XML element tree handle; models the description of a streaminfo object.
+ * XML elements behave like advanced pointers into memory that is owned by some respective
+ * streaminfo.
+ * Has a name and can have multiple named children or have text content as value;
+ * attributes are omitted.
+ * @note The interface is modeled after a subset of pugixml's node type and is compatible with it.
+ * Type-casts between pugi::xml_node_struct* and #lsl_xml_ptr are permitted (in both directions)
+ * since the types are binary compatible.
+ * @sa [pugixml documentation](https://pugixml.org/docs/manual.html#access).
+ */
+typedef struct lsl_xml_ptr_struct_ *lsl_xml_ptr;
+
+/**
+ * @class lsl_continuous_resolver
+ *
+ * Handle to a convenience object that resolves streams continuously in the background throughout
+ * its lifetime and which can be queried at any time for the set of streams that are currently
+ * visible on the network.
+ */
+typedef struct lsl_continuous_resolver_ *lsl_continuous_resolver;
+
+#endif // LSL_TYPES
diff --git a/physiolabxr/third_party/BAlert/SDK64/include/lsl/xml.h b/physiolabxr/third_party/BAlert/SDK64/include/lsl/xml.h
new file mode 100644
index 00000000..2ab7cea2
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/SDK64/include/lsl/xml.h
@@ -0,0 +1,103 @@
+#pragma once
+#include "common.h"
+#include "types.h"
+
+/// @file inlet.h XML functions
+
+/** @defgroup xml_ptr The lsl_xml_ptr object
+ * @{
+ */
+
+// XML Tree Navigation
+
+/** Get the first child of the element. */
+extern LIBLSL_C_API lsl_xml_ptr lsl_first_child(lsl_xml_ptr e);
+
+/** Get the last child of the element. */
+extern LIBLSL_C_API lsl_xml_ptr lsl_last_child(lsl_xml_ptr e);
+
+/** Get the next sibling in the children list of the parent node. */
+extern LIBLSL_C_API lsl_xml_ptr lsl_next_sibling(lsl_xml_ptr e);
+
+/** Get the previous sibling in the children list of the parent node. */
+extern LIBLSL_C_API lsl_xml_ptr lsl_previous_sibling(lsl_xml_ptr e);
+
+/** Get the parent node. */
+extern LIBLSL_C_API lsl_xml_ptr lsl_parent(lsl_xml_ptr e);
+
+
+// XML Tree Navigation by Name
+
+/** Get a child with a specified name. */
+extern LIBLSL_C_API lsl_xml_ptr lsl_child(lsl_xml_ptr e, const char *name);
+
+/** Get the next sibling with the specified name. */
+extern LIBLSL_C_API lsl_xml_ptr lsl_next_sibling_n(lsl_xml_ptr e, const char *name);
+
+/** Get the previous sibling with the specified name. */
+extern LIBLSL_C_API lsl_xml_ptr lsl_previous_sibling_n(lsl_xml_ptr e, const char *name);
+
+
+// Content Queries
+
+/** Whether this node is empty. */
+extern LIBLSL_C_API int32_t lsl_empty(lsl_xml_ptr e);
+
+/** Whether this is a text body (instead of an XML element). True both for plain char data and CData. */
+extern LIBLSL_C_API int32_t lsl_is_text(lsl_xml_ptr e);
+
+/** Name of the element. */
+extern LIBLSL_C_API const char *lsl_name(lsl_xml_ptr e);
+
+/** Value of the element. */
+extern LIBLSL_C_API const char *lsl_value(lsl_xml_ptr e);
+
+/** Get child value (value of the first child that is text). */
+extern LIBLSL_C_API const char *lsl_child_value(lsl_xml_ptr e);
+
+/** Get child value of a child with a specified name. */
+extern LIBLSL_C_API const char *lsl_child_value_n(lsl_xml_ptr e, const char *name);
+
+
+// Data Modification
+
+/// Append a child node with a given name, which has a (nameless) plain-text child with the given text value.
+extern LIBLSL_C_API lsl_xml_ptr lsl_append_child_value(lsl_xml_ptr e, const char *name, const char *value);
+
+/// Prepend a child node with a given name, which has a (nameless) plain-text child with the given text value.
+extern LIBLSL_C_API lsl_xml_ptr lsl_prepend_child_value(lsl_xml_ptr e, const char *name, const char *value);
+
+/// Set the text value of the (nameless) plain-text child of a named child node.
+extern LIBLSL_C_API int32_t lsl_set_child_value(lsl_xml_ptr e, const char *name, const char *value);
+
+/**
+* Set the element's name.
+* @return 0 if the node is empty (or if out of memory).
+*/
+extern LIBLSL_C_API int32_t lsl_set_name(lsl_xml_ptr e, const char *rhs);
+
+/**
+* Set the element's value.
+* @return 0 if the node is empty (or if out of memory).
+*/
+extern LIBLSL_C_API int32_t lsl_set_value(lsl_xml_ptr e, const char *rhs);
+
+/** Append a child element with the specified name. */
+extern LIBLSL_C_API lsl_xml_ptr lsl_append_child(lsl_xml_ptr e, const char *name);
+
+/** Prepend a child element with the specified name. */
+extern LIBLSL_C_API lsl_xml_ptr lsl_prepend_child(lsl_xml_ptr e, const char *name);
+
+/** Append a copy of the specified element as a child. */
+extern LIBLSL_C_API lsl_xml_ptr lsl_append_copy(lsl_xml_ptr e, lsl_xml_ptr e2);
+
+/** Prepend a child element with the specified name. */
+extern LIBLSL_C_API lsl_xml_ptr lsl_prepend_copy(lsl_xml_ptr e, lsl_xml_ptr e2);
+
+/** Remove a child element with the specified name. */
+extern LIBLSL_C_API void lsl_remove_child_n(lsl_xml_ptr e, const char *name);
+
+/** Remove a specified child element. */
+extern LIBLSL_C_API void lsl_remove_child(lsl_xml_ptr e, lsl_xml_ptr e2);
+
+/// @}
diff --git a/physiolabxr/third_party/BAlert/SDK64/include/lsl_c.h b/physiolabxr/third_party/BAlert/SDK64/include/lsl_c.h
new file mode 100644
index 00000000..0a6d2e93
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/SDK64/include/lsl_c.h
@@ -0,0 +1,36 @@
+#ifndef LSL_C_H
+#define LSL_C_H
+
+/** @file lsl_c.h LSL C API for the lab streaming layer
+ *
+ * The lab streaming layer provides a set of functions to make instrument data accessible
+ * in real time within a lab network. From there, streams can be picked up by recording programs,
+ * viewing programs or custom experiment applications that access data streams in real time.
+ *
+ * The API covers two areas:
+ * - The "push API" allows to create stream outlets and to push data (regular or irregular
+ * measurement time series, event data, coded audio/video frames, etc.) into them.
+ * - The "pull API" allows to create stream inlets and read time-synched experiment data from them
+ * (for recording, viewing or experiment control).
+ *
+ * To use this library you need to link to the liblsl library that comes with
+ * this header. Under Visual Studio the library is linked in automatically.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "lsl/common.h"
+#include "lsl/inlet.h"
+#include "lsl/outlet.h"
+#include "lsl/resolver.h"
+#include "lsl/streaminfo.h"
+#include "lsl/types.h"
+#include "lsl/xml.h"
+
+#ifdef __cplusplus
+} /* end extern "C" */
+#endif
+
+#endif
diff --git a/physiolabxr/third_party/BAlert/SDK64/include/lsl_cpp.h b/physiolabxr/third_party/BAlert/SDK64/include/lsl_cpp.h
new file mode 100644
index 00000000..72d58819
--- /dev/null
+++ b/physiolabxr/third_party/BAlert/SDK64/include/lsl_cpp.h
@@ -0,0 +1,1721 @@
+#ifndef LSL_CPP_H
+#define LSL_CPP_H
+
+/**
+ * @file lsl_cpp.h
+ *
+ * C++ API for the lab streaming layer.
+ *
+ * The lab streaming layer provides a set of functions to make instrument data accessible
+ * in real time within a lab network. From there, streams can be picked up by recording programs,
+ * viewing programs or custom experiment applications that access data streams in real time.
+ *
+ * The API covers two areas:
+ * - The "push API" allows to create stream outlets and to push data (regular or irregular
+ * measurement time series, event data, coded audio/video frames, etc.) into them.
+ * - The "pull API" allows to create stream inlets and read time-synched experiment data from them
+ * (for recording, viewing or experiment control).
+ *
+ * To use this library you need to link to the shared library (lsl) that comes with
+ * this header. Under Visual Studio the library is linked in automatically.
+ */
+
+#include
+#include
+#include
+#include
+
+extern "C" {
+#include "lsl_c.h"
+}
+
+namespace lsl {
+/// Assert that no error happened; throw appropriate exception otherwise
+int32_t check_error(int32_t ec);
+
+/// Constant to indicate that a stream has variable sampling rate.
+const double IRREGULAR_RATE = 0.0;
+
+/**
+ * Constant to indicate that a sample has the next successive time stamp.
+ *
+ * This is an optional optimization to transmit less data per sample.
+ * The stamp is then deduced from the preceding one according to the stream's sampling rate
+ * (in the case of an irregular rate, the same time stamp as before will is assumed).
+ */
+const double DEDUCED_TIMESTAMP = -1.0;
+
+/**
+ * A very large time duration (> 1 year) for timeout values.
+ *
+ * Note that significantly larger numbers can cause the timeout to be invalid on some operating
+ * systems (e.g., 32-bit UNIX).
+ */
+const double FOREVER = 32000000.0;
+
+/// Data format of a channel (each transmitted sample holds an array of channels).
+enum channel_format_t {
+ /** For up to 24-bit precision measurements in the appropriate physical unit (e.g., microvolts).
+ Integers from -16777216 to 16777216 are represented accurately.*/
+ cf_float32 = 1,
+ /// For universal numeric data as long as permitted by network & disk budget.
+ /// The largest representable integer is 53-bit.
+ cf_double64 = 2,
+ /// For variable-length ASCII strings or data blobs, such as video frames, complex event
+ /// descriptions, etc.
+ cf_string = 3,
+ /// For high-rate digitized formats that require 32-bit precision.
+ /// Depends critically on meta-data to represent meaningful units.
+ /// Useful for application event codes or other coded data.
+ cf_int32 = 4,
+ /// For very high rate signals (40Khz+) or consumer-grade audio (for professional audio float is
+ /// recommended).
+ cf_int16 = 5,
+ /// For binary signals or other coded data. Not recommended for encoding string data.
+ cf_int8 = 6,
+ /// For now only for future compatibility. Support for this type is not yet exposed in all
+ /// languages. Also, some builds of liblsl will not be able to send or receive data of this
+ /// type.
+ cf_int64 = 7,
+ /// Can not be transmitted.
+ cf_undefined = 0
+};
+
+/// Post-processing options for stream inlets.
+enum processing_options_t {
+ /// No automatic post-processing; return the ground-truth time stamps for manual post-processing
+ /// (this is the default behavior of the inlet).
+ post_none = 0,
+ /// Perform automatic clock synchronization; equivalent to manually adding the time_correction()
+ /// value to the received time stamps.
+ post_clocksync = 1,
+ /// Remove jitter from time stamps. This will apply a smoothing algorithm to the received time
+ /// stamps; the smoothing needs to see a minimum number of samples (30-120 seconds worst-case)
+ /// until the remaining jitter is consistently below 1ms.
+ post_dejitter = 2,
+ /// Force the time-stamps to be monotonically ascending (only makes sense if timestamps are
+ /// dejittered).
+ post_monotonize = 4,
+ /// Post-processing is thread-safe (same inlet can be read from by multiple threads); uses
+ /// somewhat more CPU.
+ post_threadsafe = 8,
+ /// The combination of all possible post-processing options.
+ post_ALL = 1 | 2 | 4 | 8
+};
+
+/**
+ * Protocol version.
+ *
+ * The major version is `protocol_version() / 100`;
+ * The minor version is `protocol_version() % 100`;
+ * Clients with different minor versions are protocol-compatible with each other
+ * while clients with different major versions will refuse to work together.
+ */
+inline int32_t protocol_version() { return lsl_protocol_version(); }
+
+/// @copydoc ::lsl_library_version()
+inline int32_t library_version() { return lsl_library_version(); }
+
+/**
+ * Get a string containing library information.
+ *
+ * The format of the string shouldn't be used for anything important except giving a a debugging
+ * person a good idea which exact library version is used. */
+inline const char *library_info() { return lsl_library_info(); }
+
+/**
+ * Obtain a local system time stamp in seconds.
+ *
+ * The resolution is better than a millisecond.
+ * This reading can be used to assign time stamps to samples as they are being acquired.
+ * If the "age" of a sample is known at a particular time (e.g., from USB transmission
+ * delays), it can be used as an offset to local_clock() to obtain a better estimate of
+ * when a sample was actually captured. See stream_outlet::push_sample() for a use case.
+ */
+inline double local_clock() { return lsl_local_clock(); }
+
+
+/// @section Stream Declaration
+
+class xml_element;
+
+/**
+ * The stream_info object stores the declaration of a data stream.
+ *
+ * Represents the following information:
+ * a) stream data format (number of channels, channel format)
+ * b) core information (stream name, content type, sampling rate)
+ * c) optional meta-data about the stream content (channel labels, measurement units, etc.)
+ *
+ * Whenever a program wants to provide a new stream on the lab network it will typically first
+ * create a stream_info to describe its properties and then construct a stream_outlet with it to
+ * create the stream on the network. Recipients who discover the outlet can query the stream_info;
+ * it is also written to disk when recording the stream (playing a similar role as a file header).
+ */
+class stream_info {
+public:
+ /**
+ * Construct a new stream_info object.
+ *
+ * Core stream information is specified here. Any remaining meta-data can be added later.
+ * @param name Name of the stream. Describes the device (or product series) that this stream
+ * makes available (for use by programs, experimenters or data analysts). Cannot be empty.
+ * @param type Content type of the stream. Please see https://github.com/sccn/xdf/wiki/Meta-Data
+ * (or web search for: XDF meta-data) for pre-defined content-type names, but you can also make
+ * up your own. The content type is the preferred way to find streams (as opposed to searching
+ * by name).
+ * @param channel_count Number of channels per sample. This stays constant for the lifetime of
+ * the stream.
+ * @param nominal_srate The sampling rate (in Hz) as advertised by the data source, if regular
+ * (otherwise set to IRREGULAR_RATE).
+ * @param channel_format Format/type of each channel. If your channels have different formats,
+ * consider supplying multiple streams or use the largest type that can hold them all (such as
+ * cf_double64).
+ * @param source_id Unique identifier of the device or source of the data, if available (such as
+ * the serial number). This is critical for system robustness since it allows recipients to
+ * recover from failure even after the serving app, device or computer crashes (just by finding
+ * a stream with the same source id on the network again). Therefore, it is highly recommended
+ * to always try to provide whatever information can uniquely identify the data source itself.
+ */
+ stream_info(const std::string &name, const std::string &type, int32_t channel_count = 1,
+ double nominal_srate = IRREGULAR_RATE, channel_format_t channel_format = cf_float32,
+ const std::string &source_id = std::string())
+ : obj(lsl_create_streaminfo((name.c_str()), (type.c_str()), channel_count, nominal_srate,
+ (lsl_channel_format_t)channel_format, (source_id.c_str())), &lsl_destroy_streaminfo) {
+ if (obj == nullptr) throw std::invalid_argument(lsl_last_error());
+ }
+
+ /// Default contructor.
+ stream_info(): stream_info("untitled", "", 0, 0, cf_undefined, ""){}
+
+ /// Copy constructor. Only increments the reference count! @see clone()
+ stream_info(const stream_info &) noexcept = default;
+ stream_info(lsl_streaminfo handle) : obj(handle, &lsl_destroy_streaminfo) {}
+
+ /// Clones a streaminfo object.
+ stream_info clone() { return stream_info(lsl_copy_streaminfo(obj.get())); }
+
+
+ // ========================
+ // === Core Information ===
+ // ========================
+ // (these fields are assigned at construction)
+
+ /**
+ * Name of the stream.
+ *
+ * This is a human-readable name. For streams offered by device modules, it refers to the type
+ * of device or product series that is generating the data of the stream. If the source is an
+ * application, the name may be a more generic or specific identifier. Multiple streams with the
+ * same name can coexist, though potentially at the cost of ambiguity (for the recording app or
+ * experimenter).
+ */
+ std::string name() const { return lsl_get_name(obj.get()); }
+
+ /**
+ * Content type of the stream.
+ *
+ * The content type is a short string such as "EEG", "Gaze" which describes the content carried
+ * by the channel (if known). If a stream contains mixed content this value need not be assigned
+ * but may instead be stored in the description of channel types. To be useful to applications
+ * and automated processing systems using the recommended content types is preferred. Content
+ * types usually follow those pre-defined in https://github.com/sccn/xdf/wiki/Meta-Data (or web
+ * search for: XDF meta-data).
+ */
+ std::string type() const { return lsl_get_type(obj.get()); }
+
+ /**
+ * Number of channels of the stream.
+ *
+ * A stream has at least one channel; the channel count stays constant for all samples.
+ */
+ int32_t channel_count() const { return lsl_get_channel_count(obj.get()); }
+
+ /**
+ * Sampling rate of the stream, according to the source (in Hz).
+ *
+ * If a stream is irregularly sampled, this should be set to IRREGULAR_RATE.
+ *
+ * Note that no data will be lost even if this sampling rate is incorrect or if a device has
+ * temporary hiccups, since all samples will be recorded anyway (except for those dropped by the
+ * device itself). However, when the recording is imported into an application, a good importer
+ * may correct such errors more accurately if the advertised sampling rate was close to the
+ * specs of the device.
+ */
+ double nominal_srate() const { return lsl_get_nominal_srate(obj.get()); }
+
+ /**
+ * Channel format of the stream.
+ *
+ * All channels in a stream have the same format. However, a device might offer multiple
+ * time-synched streams each with its own format.
+ */
+ channel_format_t channel_format() const {
+ return static_cast(lsl_get_channel_format(obj.get()));
+ }
+
+ /**
+ * Unique identifier of the stream's source, if available.
+ *
+ * The unique source (or device) identifier is an optional piece of information that, if
+ * available, allows that endpoints (such as the recording program) can re-acquire a stream
+ * automatically once it is back online.
+ */
+ std::string source_id() const { return lsl_get_source_id(obj.get()); }
+
+
+ // ======================================
+ // === Additional Hosting Information ===
+ // ======================================
+ // (these fields are implicitly assigned once bound to an outlet/inlet)
+
+ /// Protocol version used to deliver the stream.
+ int32_t version() const { return lsl_get_version(obj.get()); }
+
+ /**
+ * Creation time stamp of the stream.
+ *
+ * This is the time stamp when the stream was first created
+ * (as determined via #lsl::local_clock() on the providing machine).
+ */
+ double created_at() const { return lsl_get_created_at(obj.get()); }
+
+ /**
+ * Unique ID of the stream outlet instance (once assigned).
+ *
+ * This is a unique identifier of the stream outlet, and is guaranteed to be different
+ * across multiple instantiations of the same outlet (e.g., after a re-start).
+ */
+ std::string uid() const { return lsl_get_uid(obj.get()); }
+
+ /**
+ * Session ID for the given stream.
+ *
+ * The session id is an optional human-assigned identifier of the recording session.
+ * While it is rarely used, it can be used to prevent concurrent recording activitites
+ * on the same sub-network (e.g., in multiple experiment areas) from seeing each other's streams
+ * (assigned via a configuration file by the experimenter, see Network Connectivity in the LSL
+ * wiki).
+ */
+ std::string session_id() const { return lsl_get_session_id(obj.get()); }
+
+ /// Hostname of the providing machine.
+ std::string hostname() const { return lsl_get_hostname(obj.get()); }
+
+
+ // ========================
+ // === Data Description ===
+ // ========================
+
+ /**
+ * Extended description of the stream.
+ *
+ * It is highly recommended that at least the channel labels are described here.
+ * See code examples on the LSL wiki. Other information, such as amplifier settings,
+ * measurement units if deviating from defaults, setup information, subject information, etc.,
+ * can be specified here, as well. Meta-data recommendations follow the XDF file format project
+ * (github.com/sccn/xdf/wiki/Meta-Data or web search for: XDF meta-data).
+ *
+ * Important: if you use a stream content type for which meta-data recommendations exist, please
+ * try to lay out your meta-data in agreement with these recommendations for compatibility with
+ * other applications.
+ */
+ xml_element desc();
+
+ /// lsl_stream_info_matches_query
+ bool matches_query(const char *query) const {
+ return lsl_stream_info_matches_query(obj.get(), query);
+ }
+
+
+ // ===============================
+ // === Miscellaneous Functions ===
+ // ===============================
+
+ /** Retrieve the entire streaminfo in XML format.
+ * This yields an XML document (in string form) whose top-level element is ``. The info
+ * element contains one element for each field of the streaminfo class, including:
+ *
+ * - the core elements ``, ``, ``,
+ * ``, ``
+ * - the misc elements ``, ``, ``, ``,
+ * ``, ``, ``, ``, ``,
+ * ``
+ * - the extended description element `` with user-defined sub-elements.
+ */
+ std::string as_xml() const {
+ char *tmp = lsl_get_xml(obj.get());
+ std::string result(tmp);
+ lsl_destroy_string(tmp);
+ return result;
+ }
+
+ /// Number of bytes occupied by a channel (0 for string-typed channels).
+ int32_t channel_bytes() const { return lsl_get_channel_bytes(obj.get()); }
+
+ /// Number of bytes occupied by a sample (0 for string-typed channels).
+ int32_t sample_bytes() const { return lsl_get_sample_bytes(obj.get()); }
+
+ /// Get the implementation handle.
+ std::shared_ptr handle() const { return obj; }
+
+ /// Assignment operator.
+ stream_info &operator=(const stream_info &rhs) {
+ if (this != &rhs) obj = stream_info(rhs).handle();
+ return *this;
+ }
+
+ stream_info(stream_info &&rhs) noexcept = default;
+
+ stream_info &operator=(stream_info &&rhs) noexcept = default;
+
+ /// Utility function to create a stream_info from an XML representation
+ static stream_info from_xml(const std::string &xml) {
+ return stream_info(lsl_streaminfo_from_xml(xml.c_str()));
+ }
+
+private:
+ std::shared_ptr obj;
+};
+
+
+// =======================
+// ==== Stream Outlet ====
+// =======================
+
+/** A stream outlet.
+ * Outlets are used to make streaming data (and the meta-data) available on the lab network.
+ */
+class stream_outlet {
+public:
+ /** Establish a new stream outlet. This makes the stream discoverable.
+ * @param info The stream information to use for creating this stream. Stays constant over the
+ * lifetime of the outlet.
+ * @param chunk_size Optionally the desired chunk granularity (in samples) for transmission. If
+ * unspecified, each push operation yields one chunk. Inlets can override this setting.
+ * @param max_buffered Optionally the maximum amount of data to buffer (in seconds if there is a
+ * nominal sampling rate, otherwise x100 in samples). The default is 6 minutes of data.
+ */
+ stream_outlet(const stream_info &info, int32_t chunk_size = 0, int32_t max_buffered = 360,
+ lsl_transport_options_t flags = transp_default)
+ : channel_count(info.channel_count()), sample_rate(info.nominal_srate()),
+ obj(lsl_create_outlet_ex(info.handle().get(), chunk_size, max_buffered, flags),
+ &lsl_destroy_outlet) {}
+
+ // ========================================
+ // === Pushing a sample into the outlet ===
+ // ========================================
+
+ /** Push a C array of values as a sample into the outlet.
+ * Each entry in the array corresponds to one channel.
+ * The function handles type checking & conversion.
+ * @param data An array of values to push (one per channel).
+ * @param timestamp Optionally the capture time of the sample, in agreement with
+ * lsl::local_clock(); if omitted, the current time is used.
+ * @param pushthrough Whether to push the sample through to the receivers instead of
+ * buffering it with subsequent samples.
+ * Note that the chunk_size, if specified at outlet construction, takes precedence over the
+ * pushthrough flag.
+ */
+ template
+ void push_sample(const T data[N], double timestamp = 0.0, bool pushthrough = true) {
+ check_numchan(N);
+ push_sample(&data[0], timestamp, pushthrough);
+ }
+
+ /** Push a std vector of values as a sample into the outlet.
+ * Each entry in the vector corresponds to one channel. The function handles type checking &
+ * conversion.
+ * @param data A vector of values to push (one for each channel).
+ * @param timestamp Optionally the capture time of the sample, in agreement with local_clock();
+ * if omitted, the current time is used.
+ * @param pushthrough Whether to push the sample through to the receivers instead of buffering
+ * it with subsequent samples. Note that the chunk_size, if specified at outlet construction,
+ * takes precedence over the pushthrough flag.
+ */
+ template
+ void push_sample(
+ const std::vector &data, double timestamp = 0.0, bool pushthrough = true) {
+ check_numchan(data.size());
+ push_sample(data.data(), timestamp, pushthrough);
+ }
+
+ /** Push a pointer to some values as a sample into the outlet.
+ * This is a lower-level function for cases where data is available in some buffer.
+ * Handles type checking & conversion.
+ * @param data A pointer to values to push. The number of values pointed to must not be less
+ * than the number of channels in the sample.
+ * @param timestamp Optionally the capture time of the sample, in agreement with local_clock();
+ * if omitted, the current time is used.
+ * @param pushthrough Whether to push the sample through to the receivers instead of buffering
+ * it with subsequent samples. Note that the chunk_size, if specified at outlet construction,
+ * takes precedence over the pushthrough flag.
+ */
+ void push_sample(const float *data, double timestamp = 0.0, bool pushthrough = true) {
+ lsl_push_sample_ftp(obj.get(), (data), timestamp, pushthrough);
+ }
+ void push_sample(const double *data, double timestamp = 0.0, bool pushthrough = true) {
+ lsl_push_sample_dtp(obj.get(), (data), timestamp, pushthrough);
+ }
+ void push_sample(const int64_t *data, double timestamp = 0.0, bool pushthrough = true) {
+ lsl_push_sample_ltp(obj.get(), (data), timestamp, pushthrough);
+ }
+ void push_sample(const int32_t *data, double timestamp = 0.0, bool pushthrough = true) {
+ lsl_push_sample_itp(obj.get(), (data), timestamp, pushthrough);
+ }
+ void push_sample(const int16_t *data, double timestamp = 0.0, bool pushthrough = true) {
+ lsl_push_sample_stp(obj.get(), (data), timestamp, pushthrough);
+ }
+ void push_sample(const char *data, double timestamp = 0.0, bool pushthrough = true) {
+ lsl_push_sample_ctp(obj.get(), (data), timestamp, pushthrough);
+ }
+ void push_sample(const std::string *data, double timestamp = 0.0, bool pushthrough = true) {
+ std::vector lengths(channel_count);
+ std::vector pointers(channel_count);
+ for (int32_t k = 0; k < channel_count; k++) {
+ pointers[k] = data[k].c_str();
+ lengths[k] = (uint32_t)data[k].size();
+ }
+ lsl_push_sample_buftp(obj.get(), pointers.data(), lengths.data(), timestamp, pushthrough);
+ }
+
+ /** Push a packed C struct (of numeric data) as one sample into the outlet (search for
+ * [`#``pragma pack`](https://stackoverflow.com/a/3318475/73299) for information on packing
+ * structs appropriately).
+ * Overall size checking but no type checking or conversion are done.
+ * Can not be used forvariable-size / string-formatted data.
+ * @param sample The sample struct to push.
+ * @param timestamp Optionally the capture time of the sample, in agreement with
+ * local_clock(); if omitted, the current time is used.
+ * @param pushthrough Whether to push the sample through to the receivers instead of
+ * buffering it with subsequent samples. Note that the chunk_size, if specified at outlet
+ * construction, takes precedence over the pushthrough flag.
+ */
+ template
+ void push_numeric_struct(const T &sample, double timestamp = 0.0, bool pushthrough = true) {
+ if (info().sample_bytes() != sizeof(T))
+ throw std::runtime_error(
+ "Provided object size does not match the stream's sample size.");
+ push_numeric_raw((void *)&sample, timestamp, pushthrough);
+ }
+
+ /** Push a pointer to raw numeric data as one sample into the outlet.
+ * This is the lowest-level function; performs no checking whatsoever. Cannot be used for
+ * variable-size / string-formatted channels.
+ * @param sample A pointer to the raw sample data to push.
+ * @param timestamp Optionally the capture time of the sample, in agreement with local_clock();
+ * if omitted, the current time is used.
+ * @param pushthrough Whether to push the sample through to the receivers instead of buffering
+ * it with subsequent samples. Note that the chunk_size, if specified at outlet construction,
+ * takes precedence over the pushthrough flag.
+ */
+ void push_numeric_raw(const void *sample, double timestamp = 0.0, bool pushthrough = true) {
+ lsl_push_sample_vtp(obj.get(), (sample), timestamp, pushthrough);
+ }
+
+
+ // ===================================================
+ // === Pushing an chunk of samples into the outlet ===
+ // ===================================================
+
+ /** Push a chunk of samples (batched into an STL vector) into the outlet.
+ * @param samples A vector of samples in some supported format (each sample can be a data
+ * pointer, data array, or std vector of data).
+ * @param timestamp Optionally the capture time of the most recent sample, in agreement with
+ * local_clock(); if omitted, the current time is used. The time stamps of other samples are
+ * automatically derived according to the sampling rate of the stream.
+ * @param pushthrough Whether to push the chunk through to the receivers instead of buffering it
+ * with subsequent samples. Note that the chunk_size, if specified at outlet construction, takes
+ * precedence over the pushthrough flag.
+ */
+ template
+ void push_chunk(
+ const std::vector &samples, double timestamp = 0.0, bool pushthrough = true) {
+ if (!samples.empty()) {
+ if (timestamp == 0.0) timestamp = local_clock();
+ if (sample_rate != IRREGULAR_RATE)
+ timestamp = timestamp - (samples.size() - 1) / sample_rate;
+ push_sample(samples[0], timestamp, pushthrough && samples.size() == 1);
+ for (std::size_t k = 1; k < samples.size(); k++)
+ push_sample(samples[k], DEDUCED_TIMESTAMP, pushthrough && k == samples.size() - 1);
+ }
+ }
+
+ /** Push a chunk of samples (batched into an STL vector) into the outlet.
+ * Allows to specify a separate time stamp for each sample (for irregular-rate streams).
+ * @param samples A vector of samples in some supported format (each sample can be a data
+ * pointer, data array, or std vector of data).
+ * @param timestamps A vector of capture times for each sample, in agreement with local_clock().
+ * @param pushthrough Whether to push the chunk through to the receivers instead of buffering it
+ * with subsequent samples. Note that the chunk_size, if specified at outlet construction, takes
+ * precedence over the pushthrough flag.
+ */
+ template
+ void push_chunk(const std::vector &samples, const std::vector ×tamps,
+ bool pushthrough = true) {
+ for (unsigned k = 0; k < samples.size() - 1; k++)
+ push_sample(samples[k], timestamps[k], false);
+ if (!samples.empty()) push_sample(samples.back(), timestamps.back(), pushthrough);
+ }
+
+ /** Push a chunk of numeric data as C-style structs (batched into an STL vector) into the
+ * outlet. This performs some size checking but no type checking. Can not be used for
+ * variable-size / string-formatted data.
+ * @param samples A vector of samples, as C structs.
+ * @param timestamp Optionally the capture time of the sample, in agreement with local_clock();
+ * if omitted, the current time is used.
+ * @param pushthrough Whether to push the chunk through to the receivers instead of buffering it
+ * with subsequent samples. Note that the chunk_size, if specified at outlet construction, takes
+ * precedence over the pushthrough flag.
+ */
+ template
+ void push_chunk_numeric_structs(
+ const std::vector &samples, double timestamp = 0.0, bool pushthrough = true) {
+ if (!samples.empty()) {
+ if (timestamp == 0.0) timestamp = local_clock();
+ if (sample_rate != IRREGULAR_RATE)
+ timestamp = timestamp - (samples.size() - 1) / sample_rate;
+ push_numeric_struct(samples[0], timestamp, pushthrough && samples.size() == 1);
+ for (std::size_t k = 1; k < samples.size(); k++)
+ push_numeric_struct(
+ samples[k], DEDUCED_TIMESTAMP, pushthrough && k == samples.size() - 1);
+ }
+ }
+
+ /** Push a chunk of numeric data from C-style structs (batched into an STL vector), into the
+ * outlet. This performs some size checking but no type checking. Can not be used for
+ * variable-size / string-formatted data.
+ * @param samples A vector of samples, as C structs.
+ * @param timestamps A vector of capture times for each sample, in agreement with local_clock().
+ * @param pushthrough Whether to push the chunk through to the receivers instead of buffering it
+ * with subsequent samples. Note that the chunk_size, if specified at outlet construction, takes
+ * precedence over the pushthrough flag.
+ */
+ template
+ void push_chunk_numeric_structs(const std::vector &samples,
+ const std::vector ×tamps, bool pushthrough = true) {
+ for (unsigned k = 0; k < samples.size() - 1; k++)
+ push_numeric_struct(samples[k], timestamps[k], false);
+ if (!samples.empty()) push_numeric_struct(samples.back(), timestamps.back(), pushthrough);
+ }
+
+ /** Push a chunk of multiplexed data into the outlet.
+ * @name Push functions
+ * @param buffer A buffer of channel values holding the data for zero or more successive samples
+ * to send.
+ * @param timestamp Optionally the capture time of the most recent sample, in agreement with
+ * local_clock(); if omitted, the current time is used. The time stamps of other samples are
+ * automatically derived according to the sampling rate of the stream.
+ * @param pushthrough Whether to push the chunk through to the receivers instead of buffering it
+ * with subsequent samples. Note that the chunk_size, if specified at outlet construction, takes
+ * precedence over the pushthrough flag.
+ */
+ template
+ void push_chunk_multiplexed(
+ const std::vector &buffer, double timestamp = 0.0, bool pushthrough = true) {
+ if (!buffer.empty())
+ push_chunk_multiplexed(
+ buffer.data(), static_cast(buffer.size()), timestamp, pushthrough);
+ }
+
+ /** Push a chunk of multiplexed data into the outlet. One timestamp per sample is provided.
+ * Allows to specify a separate time stamp for each sample (for irregular-rate streams).
+ * @param buffer A buffer of channel values holding the data for zero or more successive samples
+ * to send.
+ * @param timestamps A buffer of timestamp values holding time stamps for each sample in the
+ * data buffer.
+ * @param pushthrough Whether to push the chunk through to the receivers instead of buffering it
+ * with subsequent samples. Note that the chunk_size, if specified at outlet construction, takes
+ * precedence over the pushthrough flag.
+ */
+ template
+ void push_chunk_multiplexed(const std::vector &buffer,
+ const std::vector ×tamps, bool pushthrough = true) {
+ if (!buffer.empty() && !timestamps.empty())
+ push_chunk_multiplexed(
+ buffer.data(), static_cast(buffer.size()), timestamps.data(), pushthrough);
+ }
+
+ /** Push a chunk of multiplexed samples into the outlet. Single timestamp provided.
+ * @warning The provided buffer size is measured in channel values (e.g., floats), not samples.
+ * @param buffer A buffer of channel values holding the data for zero or more successive samples
+ * to send.
+ * @param buffer_elements The number of channel values (of type T) in the buffer. Must be a
+ * multiple of the channel count.
+ * @param timestamp Optionally the capture time of the most recent sample, in agreement with
+ * local_clock(); if omitted, the current time is used. The time stamps of other samples are
+ * automatically derived based on the sampling rate of the stream.
+ * @param pushthrough Whether to push the chunk through to the receivers instead of buffering it
+ * with subsequent samples. Note that the stream_outlet() constructur parameter @p chunk_size,
+ * if specified at outlet construction, takes precedence over the pushthrough flag.
+ */
+ void push_chunk_multiplexed(const float *buffer, std::size_t buffer_elements,
+ double timestamp = 0.0, bool pushthrough = true) {
+ lsl_push_chunk_ftp(obj.get(), buffer, static_cast(buffer_elements), timestamp, pushthrough);
+ }
+ void push_chunk_multiplexed(const double *buffer, std::size_t buffer_elements,
+ double timestamp = 0.0, bool pushthrough = true) {
+ lsl_push_chunk_dtp(obj.get(), buffer, static_cast(buffer_elements), timestamp, pushthrough);
+ }
+ void push_chunk_multiplexed(const int64_t *buffer, std::size_t buffer_elements,
+ double timestamp = 0.0, bool pushthrough = true) {
+ lsl_push_chunk_ltp(obj.get(), buffer, static_cast(buffer_elements), timestamp, pushthrough);
+ }
+ void push_chunk_multiplexed(const int32_t *buffer, std::size_t buffer_elements,
+ double timestamp = 0.0, bool pushthrough = true) {
+ lsl_push_chunk_itp(obj.get(), buffer, static_cast(buffer_elements), timestamp, pushthrough);
+ }
+ void push_chunk_multiplexed(const int16_t *buffer, std::size_t buffer_elements,
+ double timestamp = 0.0, bool pushthrough = true) {
+ lsl_push_chunk_stp(obj.get(), buffer, static_cast(buffer_elements), timestamp, pushthrough);
+ }
+ void push_chunk_multiplexed(const char *buffer, std::size_t buffer_elements,
+ double timestamp = 0.0, bool pushthrough = true) {
+ lsl_push_chunk_ctp(obj.get(), buffer, static_cast(buffer_elements), timestamp, pushthrough);
+ }
+ void push_chunk_multiplexed(const std::string *buffer, std::size_t buffer_elements,
+ double timestamp = 0.0, bool pushthrough = true) {
+ if (buffer_elements) {
+ std::vector lengths(buffer_elements);
+ std::vector pointers(buffer_elements);
+ for (std::size_t k = 0; k < buffer_elements; k++) {
+ pointers[k] = buffer[k].c_str();
+ lengths[k] = (uint32_t)buffer[k].size();
+ }
+ lsl_push_chunk_buftp(obj.get(), pointers.data(), lengths.data(),
+ static_cast(buffer_elements), timestamp, pushthrough);
+ }
+ }
+
+ /** Push a chunk of multiplexed samples into the outlet. One timestamp per sample is provided.
+ * @warning Note that the provided buffer size is measured in channel values (e.g., floats)
+ * rather than in samples.
+ * @param data_buffer A buffer of channel values holding the data for zero or more successive
+ * samples to send.
+ * @param timestamp_buffer A buffer of timestamp values holding time stamps for each sample in
+ * the data buffer.
+ * @param data_buffer_elements The number of data values (of type T) in the data buffer. Must be
+ * a multiple of the channel count.
+ * @param pushthrough Whether to push the chunk through to the receivers instead of buffering it
+ * with subsequent samples. Note that the chunk_size, if specified at outlet construction, takes
+ * precedence over the pushthrough flag.
+ */
+ void push_chunk_multiplexed(const float *data_buffer, const double *timestamp_buffer,
+ std::size_t data_buffer_elements, bool pushthrough = true) {
+ lsl_push_chunk_ftnp(obj.get(), data_buffer, static_cast(data_buffer_elements),
+ (timestamp_buffer), pushthrough);
+ }
+ void push_chunk_multiplexed(const double *data_buffer, const double *timestamp_buffer,
+ std::size_t data_buffer_elements, bool pushthrough = true) {
+ lsl_push_chunk_dtnp(obj.get(), data_buffer, static_cast(data_buffer_elements),
+ (timestamp_buffer), pushthrough);
+ }
+ void push_chunk_multiplexed(const int64_t *data_buffer, const double *timestamp_buffer,
+ std::size_t data_buffer_elements, bool pushthrough = true) {
+ lsl_push_chunk_ltnp(obj.get(), data_buffer, static_cast(data_buffer_elements),
+ (timestamp_buffer), pushthrough);
+ }
+ void push_chunk_multiplexed(const int32_t *data_buffer, const double *timestamp_buffer,
+ std::size_t data_buffer_elements, bool pushthrough = true) {
+ lsl_push_chunk_itnp(obj.get(), data_buffer, static_cast(data_buffer_elements),
+ (timestamp_buffer), pushthrough);
+ }
+ void push_chunk_multiplexed(const int16_t *data_buffer, const double *timestamp_buffer,
+ std::size_t data_buffer_elements, bool pushthrough = true) {
+ lsl_push_chunk_stnp(obj.get(), data_buffer, static_cast(data_buffer_elements),
+ (timestamp_buffer), pushthrough);
+ }
+ void push_chunk_multiplexed(const char *data_buffer, const double *timestamp_buffer,
+ std::size_t data_buffer_elements, bool pushthrough = true) {
+ lsl_push_chunk_ctnp(obj.get(), data_buffer, static_cast(data_buffer_elements),
+ (timestamp_buffer), pushthrough);
+ }
+
+ void push_chunk_multiplexed(const std::string *data_buffer, const double *timestamp_buffer,
+ std::size_t data_buffer_elements, bool pushthrough = true) {
+ if (data_buffer_elements) {
+ std::vector lengths(data_buffer_elements);
+ std::vector pointers(data_buffer_elements);
+ for (std::size_t k = 0; k < data_buffer_elements; k++) {
+ pointers[k] = data_buffer[k].c_str();
+ lengths[k] = (uint32_t)data_buffer[k].size();
+ }
+ lsl_push_chunk_buftnp(obj.get(), pointers.data(), lengths.data(),
+ static_cast(data_buffer_elements), timestamp_buffer, pushthrough);
+ }
+ }
+
+
+ // ===============================
+ // === Miscellaneous Functions ===
+ // ===============================
+
+ /** Check whether consumers are currently registered.
+ * While it does not hurt, there is technically no reason to push samples if there is no
+ * consumer.
+ */
+ bool have_consumers() { return lsl_have_consumers(obj.get()) != 0; }
+
+ /** Wait until some consumer shows up (without wasting resources).
+ * @return True if the wait was successful, false if the timeout expired.
+ */
+ bool wait_for_consumers(double timeout) { return lsl_wait_for_consumers(obj.get(), timeout) != 0; }
+
+ /** Retrieve the stream info provided by this outlet.
+ * This is what was used to create the stream (and also has the Additional Network Information
+ * fields assigned).
+ */
+ stream_info info() const { return stream_info(lsl_get_info(obj.get())); }
+
+ /// Return a shared pointer to pass to C-API functions that aren't wrapped yet
+ ///
+ /// Example: @code lsl_push_chunk_buft(outlet.handle().get(), data, …); @endcode
+ std::shared_ptr handle() { return obj; }
+
+ /** Destructor.
+ * The stream will no longer be discoverable after destruction and all paired inlets will stop
+ * delivering data.
+ */
+ ~stream_outlet() = default;
+
+ /// stream_outlet move constructor
+ stream_outlet(stream_outlet &&res) noexcept = default;
+
+ stream_outlet &operator=(stream_outlet &&rhs) noexcept = default;
+
+
+private:
+ // The outlet is a non-copyable object.
+ stream_outlet(const stream_outlet &rhs);
+ stream_outlet &operator=(const stream_outlet &rhs);
+
+ /// Check whether a given data length matches the number of channels; throw if not
+ void check_numchan(std::size_t N) const {
+ if (N != static_cast(channel_count))
+ throw std::runtime_error("Provided element count (" + std::to_string(N) +
+ ") does not match the stream's channel count (" +
+ std::to_string(channel_count) + '.');
+ }
+
+ int32_t channel_count;
+ double sample_rate;
+ std::shared_ptr obj;
+};
+
+
+// ===========================
+// ==== Resolve Functions ====
+// ===========================
+
+/** Resolve all streams on the network.
+ * This function returns all currently available streams from any outlet on the network.
+ * The network is usually the subnet specified at the local router, but may also include
+ * a multicast group of machines (given that the network supports it), or list of hostnames.
+ * These details may optionally be customized by the experimenter in a configuration file
+ * (see Network Connectivity in the LSL wiki).
+ * This is the default mechanism used by the browsing programs and the recording program.
+ * @param wait_time The waiting time for the operation, in seconds, to search for streams.
+ * If this is too short (<0.5s) only a subset (or none) of the outlets that are present on the
+ * network may be returned.
+ * @return A vector of stream info objects (excluding their desc field), any of which can
+ * subsequently be used to open an inlet. The full info can be retrieve from the inlet.
+ */
+inline std::vector resolve_streams(double wait_time = 1.0) {
+ lsl_streaminfo buffer[1024];
+ int nres = check_error(lsl_resolve_all(buffer, sizeof(buffer), wait_time));
+ return std::vector(&buffer[0], &buffer[nres]);
+}
+
+/** Resolve all streams with a specific value for a given property.
+ * If the goal is to resolve a specific stream, this method is preferred over resolving all streams
+ * and then selecting the desired one.
+ * @param prop The stream_info property that should have a specific value (e.g., "name", "type",
+ * "source_id", or "desc/manufaturer").
+ * @param value The string value that the property should have (e.g., "EEG" as the type property).
+ * @param minimum Return at least this number of streams.
+ * @param timeout Optionally a timeout of the operation, in seconds (default: no timeout).
+ * If the timeout expires, less than the desired number of streams (possibly none)
+ * will be returned.
+ * @return A vector of matching stream info objects (excluding their meta-data), any of
+ * which can subsequently be used to open an inlet.
+ */
+inline std::vector resolve_stream(const std::string &prop, const std::string &value,
+ int32_t minimum = 1, double timeout = FOREVER) {
+ lsl_streaminfo buffer[1024];
+ int nres = check_error(
+ lsl_resolve_byprop(buffer, sizeof(buffer), prop.c_str(), value.c_str(), minimum, timeout));
+ return std::vector(&buffer[0], &buffer[nres]);
+}
+
+/** Resolve all streams that match a given predicate.
+ *
+ * Advanced query that allows to impose more conditions on the retrieved streams; the given
+ * string is an [XPath 1.0](http://en.wikipedia.org/w/index.php?title=XPath_1.0) predicate for
+ * the `` node (omitting the surrounding []'s)
+ * @param pred The predicate string, e.g. `name='BioSemi'` or
+ * `type='EEG' and starts-with(name,'BioSemi') and count(info/desc/channel)=32`
+ * @param minimum Return at least this number of streams.
+ * @param timeout Optionally a timeout of the operation, in seconds (default: no timeout).
+ * If the timeout expires, less than the desired number of streams (possibly
+ * none) will be returned.
+ * @return A vector of matching stream info objects (excluding their meta-data), any of
+ * which can subsequently be used to open an inlet.
+ */
+inline std::vector resolve_stream(
+ const std::string &pred, int32_t minimum = 1, double timeout = FOREVER) {
+ lsl_streaminfo buffer[1024];
+ int nres =
+ check_error(lsl_resolve_bypred(buffer, sizeof(buffer), pred.c_str(), minimum, timeout));
+ return std::vector(&buffer[0], &buffer[nres]);
+}
+
+
+// ======================
+// ==== Stream Inlet ====
+// ======================
+
+/** A stream inlet.
+ * Inlets are used to receive streaming data (and meta-data) from the lab network.
+ */
+class stream_inlet {
+public:
+ /**
+ * Construct a new stream inlet from a resolved stream info.
+ * @param info A resolved stream info object (as coming from one of the resolver functions).
+ * Note: The stream_inlet may also be constructed with a fully-specified stream_info, if the
+ * desired channel format and count is already known up-front, but this is strongly discouraged
+ * and should only ever be done if there is no time to resolve the stream up-front (e.g., due
+ * to limitations in the client program).
+ * @param max_buflen Optionally the maximum amount of data to buffer (in seconds if there is a
+ * nominal sampling rate, otherwise x100 in samples). Recording applications want to use a
+ * fairly large buffer size here, while real-time applications would only buffer as much as
+ * they need to perform their next calculation.
+ * @param max_chunklen Optionally the maximum size, in samples, at which chunks are transmitted
+ * (the default corresponds to the chunk sizes used by the sender).
+ * Recording applications can use a generous size here (leaving it to the network how to pack
+ * things), while real-time applications may want a finer (perhaps 1-sample) granularity.
+ * If left unspecified (=0), the sender determines the chunk granularity.
+ * @param recover Try to silently recover lost streams that are recoverable (=those that that
+ * have a source_id set).
+ * In all other cases (recover is false or the stream is not recoverable) functions may throw a
+ * lsl::lost_error if the stream's source is lost (e.g., due to an app or computer crash).
+ */
+ stream_inlet(const stream_info &info, int32_t max_buflen = 360, int32_t max_chunklen = 0,
+ bool recover = true, lsl_transport_options_t flags = transp_default)
+ : channel_count(info.channel_count()),
+ obj(lsl_create_inlet_ex(info.handle().get(), max_buflen, max_chunklen, recover, flags),
+ &lsl_destroy_inlet) {}
+
+ /// Return a shared pointer to pass to C-API functions that aren't wrapped yet
+ ///
+ /// Example: @code lsl_pull_sample_buf(inlet.handle().get(), buf, …); @endcode
+ std::shared_ptr handle() { return obj; }
+
+ /// Move constructor for stream_inlet
+ stream_inlet(stream_inlet &&rhs) noexcept = default;
+ stream_inlet &operator=(stream_inlet &&rhs) noexcept= default;
+
+
+ /** Retrieve the complete information of the given stream, including the extended description.
+ * Can be invoked at any time of the stream's lifetime.
+ * @param timeout Timeout of the operation (default: no timeout).
+ * @throws timeout_error (if the timeout expires), or lost_error (if the stream source has been
+ * lost).
+ */
+ stream_info info(double timeout = FOREVER) {
+ int32_t ec = 0;
+ lsl_streaminfo res = lsl_get_fullinfo(obj.get(), timeout, &ec);
+ check_error(ec);
+ return stream_info(res);
+ }
+
+ /** Subscribe to the data stream.
+ * All samples pushed in at the other end from this moment onwards will be queued and
+ * eventually be delivered in response to pull_sample() or pull_chunk() calls.
+ * Pulling a sample without some preceding open_stream() is permitted (the stream will then be
+ * opened implicitly).
+ * @param timeout Optional timeout of the operation (default: no timeout).
+ * @throws timeout_error (if the timeout expires), or lost_error (if the stream source has been
+ * lost).
+ */
+ void open_stream(double timeout = FOREVER) {
+ int32_t ec = 0;
+ lsl_open_stream(obj.get(), timeout, &ec);
+ check_error(ec);
+ }
+
+ /** Drop the current data stream.
+ *
+ * All samples that are still buffered or in flight will be dropped and transmission
+ * and buffering of data for this inlet will be stopped. If an application stops being
+ * interested in data from a source (temporarily or not) but keeps the outlet alive,
+ * it should call close_stream() to not waste unnecessary system and network
+ * resources.
+ */
+ void close_stream() { lsl_close_stream(obj.get()); }
+
+ /** Retrieve an estimated time correction offset for the given stream.
+ *
+ * The first call to this function takes several milliseconds until a reliable first estimate
+ * is obtained. Subsequent calls are instantaneous (and rely on periodic background updates).
+ * On a well-behaved network, the precision of these estimates should be below 1 ms
+ * (empirically it is within +/-0.2 ms).
+ *
+ * To get a measure of whether the network is well-behaved, use the extended version
+ * time_correction(double*,double*,double) and check uncertainty (i.e. the round-trip-time).
+ *
+ * 0.2 ms is typical of wired networks. 2 ms is typical of wireless networks.
+ * The number can be much higher on poor networks.
+ *
+ * @param timeout Timeout to acquire the first time-correction estimate (default: no timeout).
+ * @return The time correction estimate. This is the number that needs to be added to a time
+ * stamp that was remotely generated via lsl_local_clock() to map it into the local clock
+ * domain of this machine.
+ * @throws #lsl::timeout_error (if the timeout expires), or #lsl::lost_error (if the stream
+ * source has been lost).
+ */
+
+ double time_correction(double timeout = FOREVER) {
+ int32_t ec = 0;
+ double res = lsl_time_correction(obj.get(), timeout, &ec);
+ check_error(ec);
+ return res;
+ }
+ /** @copydoc time_correction(double)
+ * @param remote_time The current time of the remote computer that was used to generate this
+ * time_correction. If desired, the client can fit time_correction vs remote_time to improve
+ * the real-time time_correction further.
+ * @param uncertainty The maximum uncertainty of the given time correction.
+ */
+ double time_correction(double *remote_time, double *uncertainty, double timeout = FOREVER) {
+ int32_t ec = 0;
+ double res = lsl_time_correction_ex(obj.get(), remote_time, uncertainty, timeout, &ec);
+ check_error(ec);
+ return res;
+ }
+
+ /** Set post-processing flags to use.
+ *
+ * By default, the inlet performs NO post-processing and returns the ground-truth time
+ * stamps, which can then be manually synchronized using .time_correction(), and then
+ * smoothed/dejittered if desired.
+ * This function allows automating these two and possibly more operations.
+ * @warning When you enable this, you will no longer receive or be able to recover the original
+ * time stamps.
+ * @param flags An integer that is the result of bitwise OR'ing one or more options from
+ * processing_options_t together (e.g., `post_clocksync|post_dejitter`); the default is to
+ * enable all options.
+ */
+ void set_postprocessing(uint32_t flags = post_ALL) {
+ check_error(lsl_set_postprocessing(obj.get(), flags));
+ }
+
+ // =======================================
+ // === Pulling a sample from the inlet ===
+ // =======================================
+
+ /** Pull a sample from the inlet and read it into an array of values.
+ * Handles type checking & conversion.
+ * @param sample An array to hold the resulting values.
+ * @param timeout The timeout for this operation, if any. Use 0.0 to make the function
+ * non-blocking.
+ * @return The capture time of the sample on the remote machine, or 0.0 if no new sample was
+ * available. To remap this time stamp to the local clock, add the value returned by
+ * .time_correction() to it.
+ * @throws lost_error (if the stream source has been lost).
+ */
+ template double pull_sample(T sample[N], double timeout = FOREVER) {
+ return pull_sample(&sample[0], N, timeout);
+ }
+
+ /** Pull a sample from the inlet and read it into a std vector of values.
+ * Handles type checking & conversion and allocates the necessary memory in the vector if
+ * necessary.
+ * @param sample An STL vector to hold the resulting values.
+ * @param timeout The timeout for this operation, if any. Use 0.0 to make the function
+ * non-blocking.
+ * @return The capture time of the sample on the remote machine, or 0.0 if no new sample was
+ * available. To remap this time stamp to the local clock, add the value returned by
+ * .time_correction() to it.
+ * @throws lost_error (if the stream source has been lost).
+ */
+ double pull_sample(std::vector &sample, double timeout = FOREVER) {
+ sample.resize(channel_count);
+ return pull_sample(&sample[0], (int32_t)sample.size(), timeout);
+ }
+ double pull_sample(std::vector &sample, double timeout = FOREVER) {
+ sample.resize(channel_count);
+ return pull_sample(&sample[0], (int32_t)sample.size(), timeout);
+ }
+ double pull_sample(std::vector &sample, double timeout = FOREVER) {
+ sample.resize(channel_count);
+ return pull_sample(&sample[0], (int32_t)sample.size(), timeout);
+ }
+ double pull_sample(std::vector &sample, double timeout = FOREVER) {
+ sample.resize(channel_count);
+ return pull_sample(&sample[0], (int32_t)sample.size(), timeout);
+ }
+ double pull_sample(std::vector &sample, double timeout = FOREVER) {
+ sample.resize(channel_count);
+ return pull_sample(&sample[0], (int32_t)sample.size(), timeout);
+ }
+ double pull_sample(std::vector &sample, double timeout = FOREVER) {
+ sample.resize(channel_count);
+ return pull_sample(&sample[0], (int32_t)sample.size(), timeout);
+ }
+ double pull_sample(std::vector &sample, double timeout = FOREVER) {
+ sample.resize(channel_count);
+ return pull_sample(&sample[0], (int32_t)sample.size(), timeout);
+ }
+
+ /** Pull a sample from the inlet and read it into a pointer to values.
+ * Handles type checking & conversion.
+ * @param buffer A pointer to hold the resulting values.
+ * @param buffer_elements The number of samples allocated in the buffer. Note: it is the
+ * responsibility of the user to allocate enough memory.
+ * @param timeout The timeout for this operation, if any. Use 0.0 to make the function
+ * non-blocking.
+ * @return The capture time of the sample on the remote machine, or 0.0 if no new sample was
+ * available. To remap this time stamp to the local clock, add the value returned by
+ * .time_correction() to it.
+ * @throws lost_error (if the stream source has been lost).
+ */
+ double pull_sample(float *buffer, int32_t buffer_elements, double timeout = FOREVER) {
+ int32_t ec = 0;
+ double res = lsl_pull_sample_f(obj.get(), buffer, buffer_elements, timeout, &ec);
+ check_error(ec);
+ return res;
+ }
+ double pull_sample(double *buffer, int32_t buffer_elements, double timeout = FOREVER) {
+ int32_t ec = 0;
+ double res = lsl_pull_sample_d(obj.get(), buffer, buffer_elements, timeout, &ec);
+ check_error(ec);
+ return res;
+ }
+ double pull_sample(int64_t *buffer, int32_t buffer_elements, double timeout = FOREVER) {
+ int32_t ec = 0;
+ double res = lsl_pull_sample_l(obj.get(), buffer, buffer_elements, timeout, &ec);
+ check_error(ec);
+ return res;
+ }
+ double pull_sample(int32_t *buffer, int32_t buffer_elements, double timeout = FOREVER) {
+ int32_t ec = 0;
+ double res = lsl_pull_sample_i(obj.get(), buffer, buffer_elements, timeout, &ec);
+ check_error(ec);
+ return res;
+ }
+ double pull_sample(int16_t *buffer, int32_t buffer_elements, double timeout = FOREVER) {
+ int32_t ec = 0;
+ double res = lsl_pull_sample_s(obj.get(), buffer, buffer_elements, timeout, &ec);
+ check_error(ec);
+ return res;
+ }
+ double pull_sample(char *buffer, int32_t buffer_elements, double timeout = FOREVER) {
+ int32_t ec = 0;
+ double res = lsl_pull_sample_c(obj.get(), buffer, buffer_elements, timeout, &ec);
+ check_error(ec);
+ return res;
+ }
+ double pull_sample(std::string *buffer, int32_t buffer_elements, double timeout = FOREVER) {
+ int32_t ec = 0;
+ if (buffer_elements) {
+ std::vector result_strings(buffer_elements);
+ std::vector result_lengths(buffer_elements);
+ double res = lsl_pull_sample_buf(
+ obj.get(), result_strings.data(), result_lengths.data(), buffer_elements, timeout, &ec);
+ check_error(ec);
+ for (int32_t k = 0; k < buffer_elements; k++) {
+ buffer[k].assign(result_strings[k], result_lengths[k]);
+ lsl_destroy_string(result_strings[k]);
+ }
+ return res;
+ } else
+ throw std::runtime_error(
+ "Provided element count does not match the stream's channel count.");
+ }
+
+ /**
+ * Pull a sample from the inlet and read it into a custom C-style struct.
+ *
+ * Overall size checking but no type checking or conversion are done.
+ * Do not use for variable-size/string-formatted streams.
+ * @param sample The raw sample object to hold the data (packed C-style struct).
+ * Search for [`#``pragma pack`](https://stackoverflow.com/a/3318475/73299) for information
+ * on how to pack structs correctly.
+ * @param timeout The timeout for this operation, if any. Use 0.0 to make the function
+ * non-blocking.
+ * @return The capture time of the sample on the remote machine, or 0.0 if no new sample was
+ * available. To remap this time stamp to the local clock, add the value returned by
+ * .time_correction() to it.
+ * @throws lost_error (if the stream source has been lost).
+ */
+ template double pull_numeric_struct(T &sample, double timeout = FOREVER) {
+ return pull_numeric_raw((void *)&sample, sizeof(T), timeout);
+ }
+
+ /**
+ * Pull a sample from the inlet and read it into a pointer to raw data.
+ *
+ * No type checking or conversions are done (not recommended!).
+ * Do not use for variable-size/string-formatted streams.
+ * @param sample A pointer to hold the resulting raw sample data.
+ * @param buffer_bytes The number of bytes allocated in the buffer.
+ * Note: it is the responsibility of the user to allocate enough memory.
+ * @param timeout The timeout for this operation, if any. Use 0.0 to make the function
+ * non-blocking.
+ * @return The capture time of the sample on the remote machine, or 0.0 if no new sample was
+ * available. To remap this time stamp to the local clock, add the value returned by
+ * .time_correction() to it.
+ * @throws lost_error (if the stream source has been lost).
+ */
+ double pull_numeric_raw(void *sample, int32_t buffer_bytes, double timeout = FOREVER) {
+ int32_t ec = 0;
+ double res = lsl_pull_sample_v(obj.get(), sample, buffer_bytes, timeout, &ec);
+ check_error(ec);
+ return res;
+ }
+
+
+ // =================================================
+ // === Pulling a chunk of samples from the inlet ===
+ // =================================================
+
+ /**
+ * Pull a chunk of samples from the inlet.
+ *
+ * This is the most complete version, returning both the data and a timestamp for each sample.
+ * @param chunk A vector of vectors to hold the samples.
+ * @param timestamps A vector to hold the time stamps.
+ * @return True if some data was obtained.
+ * @throws lost_error (if the stream source has been lost).
+ */
+ template
+ bool pull_chunk(std::vector> &chunk, std::vector ×tamps) {
+ std::vector sample;
+ chunk.clear();
+ timestamps.clear();
+ while (double ts = pull_sample(sample, 0.0)) {
+ chunk.push_back(sample);
+ timestamps.push_back(ts);
+ }
+ return !chunk.empty();
+ }
+
+ /**
+ * Pull a chunk of samples from the inlet.
+ *
+ * This version returns only the most recent sample's time stamp.
+ * @param chunk A vector of vectors to hold the samples.
+ * @return The time when the most recent sample was captured
+ * on the remote machine, or 0.0 if no new sample was available.
+ * @throws lost_error (if the stream source has been lost)
+ */
+ template double pull_chunk(std::vector> &chunk) {
+ double timestamp = 0.0;
+ std::vector sample;
+ chunk.clear();
+ while (double ts = pull_sample(sample, 0.0)) {
+ chunk.push_back(sample);
+ timestamp = ts;
+ }
+ return timestamp;
+ }
+
+ /**
+ * Pull a chunk of samples from the inlet.
+ *
+ * This function does not return time stamps for the samples. Invoked as: mychunk =
+ * pull_chunk();
+ * @return A vector of vectors containing the obtained samples; may be empty.
+ * @throws lost_error (if the stream source has been lost)
+ */
+ template std::vector> pull_chunk() {
+ std::vector> result;
+ std::vector sample;
+ while (pull_sample(sample, 0.0)) result.push_back(sample);
+ return result;
+ }
+
+ /**
+ * Pull a chunk of data from the inlet into a pre-allocated buffer.
+ *
+ * This is a high-performance function that performs no memory allocations
+ * (useful for very high data rates or on low-powered devices).
+ * @warning The provided buffer size is measured in channel values (e.g., floats), not samples.
+ * @param data_buffer A pointer to a buffer of data values where the results shall be stored.
+ * @param timestamp_buffer A pointer to a buffer of timestamp values where time stamps shall be
+ * stored. If this is NULL, no time stamps will be returned.
+ * @param data_buffer_elements The size of the data buffer, in channel data elements (of type
+ * T). Must be a multiple of the stream's channel count.
+ * @param timestamp_buffer_elements The size of the timestamp buffer. If a timestamp buffer is
+ * provided then this must correspond to the same number of samples as data_buffer_elements.
+ * @param timeout The timeout for this operation, if any. When the timeout expires, the function
+ * may return before the entire buffer is filled. The default value of 0.0 will retrieve only
+ * data available for immediate pickup.
+ * @return data_elements_written Number of channel data elements written to the data buffer.
+ * @throws lost_error (if the stream source has been lost).
+ */
+ std::size_t pull_chunk_multiplexed(float *data_buffer, double *timestamp_buffer,
+ std::size_t data_buffer_elements, std::size_t timestamp_buffer_elements,
+ double timeout = 0.0) {
+ int32_t ec = 0;
+ std::size_t res = lsl_pull_chunk_f(obj.get(), data_buffer, timestamp_buffer,
+ (unsigned long)data_buffer_elements, (unsigned long)timestamp_buffer_elements, timeout,
+ &ec);
+ check_error(ec);
+ return res;
+ }
+ std::size_t pull_chunk_multiplexed(double *data_buffer, double *timestamp_buffer,
+ std::size_t data_buffer_elements, std::size_t timestamp_buffer_elements,
+ double timeout = 0.0) {
+ int32_t ec = 0;
+ std::size_t res = lsl_pull_chunk_d(obj.get(), data_buffer, timestamp_buffer,
+ (unsigned long)data_buffer_elements, (unsigned long)timestamp_buffer_elements, timeout,
+ &ec);
+ check_error(ec);
+ return res;
+ }
+ std::size_t pull_chunk_multiplexed(int64_t *data_buffer, double *timestamp_buffer,
+ std::size_t data_buffer_elements, std::size_t timestamp_buffer_elements,
+ double timeout = 0.0) {
+ int32_t ec = 0;
+ std::size_t res = lsl_pull_chunk_l(obj.get(), data_buffer, timestamp_buffer,
+ (unsigned long)data_buffer_elements, (unsigned long)timestamp_buffer_elements, timeout,
+ &ec);
+ check_error(ec);
+ return res;
+ }
+ std::size_t pull_chunk_multiplexed(int32_t *data_buffer, double *timestamp_buffer,
+ std::size_t data_buffer_elements, std::size_t timestamp_buffer_elements,
+ double timeout = 0.0) {
+ int32_t ec = 0;
+ std::size_t res = lsl_pull_chunk_i(obj.get(), data_buffer, timestamp_buffer,
+ (unsigned long)data_buffer_elements, (unsigned long)timestamp_buffer_elements, timeout,
+ &ec);
+ check_error(ec);
+ return res;
+ }
+ std::size_t pull_chunk_multiplexed(int16_t *data_buffer, double *timestamp_buffer,
+ std::size_t data_buffer_elements, std::size_t timestamp_buffer_elements,
+ double timeout = 0.0) {
+ int32_t ec = 0;
+ std::size_t res = lsl_pull_chunk_s(obj.get(), data_buffer, timestamp_buffer,
+ (unsigned long)data_buffer_elements, (unsigned long)timestamp_buffer_elements, timeout,
+ &ec);
+ check_error(ec);
+ return res;
+ }
+ std::size_t pull_chunk_multiplexed(char *data_buffer, double *timestamp_buffer,
+ std::size_t data_buffer_elements, std::size_t timestamp_buffer_elements,
+ double timeout = 0.0) {
+ int32_t ec = 0;
+ std::size_t res = lsl_pull_chunk_c(obj.get(), data_buffer, timestamp_buffer,
+ static_cast(data_buffer_elements), static_cast(timestamp_buffer_elements), timeout,
+ &ec);
+ check_error(ec);
+ return res;
+ }
+ std::size_t pull_chunk_multiplexed(std::string *data_buffer, double *timestamp_buffer,
+ std::size_t data_buffer_elements, std::size_t timestamp_buffer_elements,
+ double timeout = 0.0) {
+ int32_t ec = 0;
+ if (data_buffer_elements) {
+ std::vector result_strings(data_buffer_elements);
+ std::vector result_lengths(data_buffer_elements);
+ std::size_t num = lsl_pull_chunk_buf(obj.get(), result_strings.data(), result_lengths.data(),
+ timestamp_buffer, static_cast(data_buffer_elements),
+ static_cast(timestamp_buffer_elements), timeout, &ec);
+ check_error(ec);
+ for (std::size_t k = 0; k < num; k++) {
+ data_buffer[k].assign(result_strings[k], result_lengths[k]);
+ lsl_destroy_string(result_strings[k]);
+ }
+ return num;
+ };
+ return 0;
+ }
+
+ /**
+ * Pull a multiplexed chunk of samples and optionally the sample timestamps from the inlet.
+ *
+ * @param chunk A vector to hold the multiplexed (Sample 1 Channel 1,
+ * S1C2, S2C1, S2C2, S3C1, S3C2, ...) samples
+ * @param timestamps A vector to hold the timestamps or nullptr
+ * @param timeout Time to wait for the first sample. The default value of 0.0 will not wait
+ * for data to arrive, pulling only samples already received.
+ * @param append (True:) Append data or (false:) clear them first
+ * @return True if some data was obtained.
+ * @throws lost_error (if the stream source has been lost).
+ */
+ template
+ bool pull_chunk_multiplexed(std::vector &chunk, std::vector *timestamps = nullptr,
+ double timeout = 0.0, bool append = false) {
+ if (!append) {
+ chunk.clear();
+ if (timestamps) timestamps->clear();
+ }
+ std::vector sample;
+ double ts;
+ if ((ts = pull_sample(sample, timeout)) == 0.0) return false;
+ chunk.insert(chunk.end(), sample.begin(), sample.end());
+ if (timestamps) timestamps->push_back(ts);
+ const auto target = samples_available();
+ chunk.reserve(chunk.size() + target * this->channel_count);
+ if (timestamps) timestamps->reserve(timestamps->size() + target);
+ while ((ts = pull_sample(sample, 0.0)) != 0.0) {
+#if LSL_CPP11
+ chunk.insert(chunk.end(), std::make_move_iterator(sample.begin()),
+ std::make_move_iterator(sample.end()));
+#else
+ chunk.insert(chunk.end(), sample.begin(), sample.end());
+#endif
+ if (timestamps) timestamps->push_back(ts);
+ }
+ return true;
+ }
+
+ /**
+ * Pull a chunk of samples from the inlet.
+ *
+ * This is the most complete version, returning both the data and a timestamp for each sample.
+ * @param chunk A vector of C-style structs to hold the samples.
+ * @param timestamps A vector to hold the time stamps.
+ * @return True if some data was obtained.
+ * @throws lost_error (if the stream source has been lost)
+ */
+ template
+ bool pull_chunk_numeric_structs(std::vector &chunk, std::vector ×tamps) {
+ T sample;
+ chunk.clear();
+ timestamps.clear();
+ while (double ts = pull_numeric_struct(sample, 0.0)) {
+ chunk.push_back(sample);
+ timestamps.push_back(ts);
+ }
+ return !chunk.empty();
+ }
+
+ /**
+ * Pull a chunk of samples from the inlet.
+ *
+ * This version returns only the most recent sample's time stamp.
+ * @param chunk A vector of C-style structs to hold the samples.
+ * @return The time when the most recent sample was captured
+ * on the remote machine, or 0.0 if no new sample was available.
+ * @throws lost_error (if the stream source has been lost)
+ */
+ template double pull_chunk_numeric_structs(std::vector &chunk) {
+ double timestamp = 0.0;
+ T sample;
+ chunk.clear();
+ while (double ts = pull_numeric_struct(sample, 0.0)) {
+ chunk.push_back(sample);
+ timestamp = ts;
+ }
+ return timestamp;
+ }
+
+ /**
+ * Pull a chunk of samples from the inlet.
+ *
+ * This function does not return time stamps. Invoked as: mychunk = pull_chunk();
+ * @return A vector of C-style structs containing the obtained samples; may be empty.
+ * @throws lost_error (if the stream source has been lost)
+ */
+ template std::vector pull_chunk_numeric_structs() {
+ std::vector result;
+ T sample;
+ while (pull_numeric_struct(sample, 0.0)) result.push_back(sample);
+ return result;
+ }
+
+ /**
+ * Query whether samples are currently available for immediate pickup.
+ *
+ * Note that it is not a good idea to use samples_available() to determine whether
+ * a pull_*() call would block: to be sure, set the pull timeout to 0.0 or an acceptably
+ * low value. If the underlying implementation supports it, the value will be the number of
+ * samples available (otherwise it will be 1 or 0).
+ */
+ std::size_t samples_available() { return lsl_samples_available(obj.get()); }
+
+ /// Drop all queued not-yet pulled samples, return the nr of dropped samples
+ uint32_t flush() noexcept { return lsl_inlet_flush(obj.get()); }
+
+ /**
+ * Query whether the clock was potentially reset since the last call to was_clock_reset().
+ *
+ * This is a rarely-used function that is only useful to applications that combine multiple
+ * time_correction values to estimate precise clock drift; it allows to tolerate cases where the
+ * source machine was hot-swapped or restarted in between two measurements.
+ */
+ bool was_clock_reset() { return lsl_was_clock_reset(obj.get()) != 0; }
+
+ /**
+ * Override the half-time (forget factor) of the time-stamp smoothing.
+ *
+ * The default is 90 seconds unless a different value is set in the config file.
+ * Using a longer window will yield lower jitter in the time stamps, but longer
+ * windows will have trouble tracking changes in the clock rate (usually due to
+ * temperature changes); the default is able to track changes up to 10
+ * degrees C per minute sufficiently well.
+ */
+ void smoothing_halftime(float value) { check_error(lsl_smoothing_halftime(obj.get(), value)); }
+
+ int get_channel_count() const { return channel_count; }
+
+private:
+ // The inlet is a non-copyable object.
+ stream_inlet(const stream_inlet &rhs);
+ stream_inlet &operator=(const stream_inlet &rhs);
+
+ int32_t channel_count;
+ std::shared_ptr obj;
+};
+
+
+// =====================
+// ==== XML Element ====
+// =====================
+
+/**
+ * A lightweight XML element tree; models the .desc() field of stream_info.
+ *
+ * Has a name and can have multiple named children or have text content as value; attributes are
+ * omitted. Insider note: The interface is modeled after a subset of pugixml's node type and is
+ * compatible with it. See also
+ * http://pugixml.googlecode.com/svn/tags/latest/docs/manual/access.html for additional
+ * documentation.
+ */
+class xml_element {
+public:
+ /// Constructor.
+ xml_element(lsl_xml_ptr obj = 0) : obj(obj) {}
+
+
+ // === Tree Navigation ===
+
+ /// Get the first child of the element.
+ xml_element first_child() const { return lsl_first_child(obj); }
+
+ /// Get the last child of the element.
+ xml_element last_child() const { return lsl_last_child(obj); }
+
+ /// Get the next sibling in the children list of the parent node.
+ xml_element next_sibling() const { return lsl_next_sibling(obj); }
+
+ /// Get the previous sibling in the children list of the parent node.
+ xml_element previous_sibling() const { return lsl_previous_sibling(obj); }
+
+ /// Get the parent node.
+ xml_element parent() const { return lsl_parent(obj); }
+
+
+ // === Tree Navigation by Name ===
+
+ /// Get a child with a specified name.
+ xml_element child(const std::string &name) const { return lsl_child(obj, (name.c_str())); }
+
+ /// Get the next sibling with the specified name.
+ xml_element next_sibling(const std::string &name) const {
+ return lsl_next_sibling_n(obj, (name.c_str()));
+ }
+
+ /// Get the previous sibling with the specified name.
+ xml_element previous_sibling(const std::string &name) const {
+ return lsl_previous_sibling_n(obj, (name.c_str()));
+ }
+
+
+ // === Content Queries ===
+
+ /// Whether this node is empty.
+ bool empty() const { return lsl_empty(obj) != 0; }
+
+ /// Is this a text body (instead of an XML element)? True both for plain char data and CData.
+ bool is_text() const { return lsl_is_text(obj) != 0; }
+
+ /// Name of the element.
+ const char *name() const { return lsl_name(obj); }
+
+ /// Value of the element.
+ const char *value() const { return lsl_value(obj); }
+
+ /// Get child value (value of the first child that is text).
+ const char *child_value() const { return lsl_child_value(obj); }
+
+ /// Get child value of a child with a specified name.
+ const char *child_value(const std::string &name) const {
+ return lsl_child_value_n(obj, (name.c_str()));
+ }
+
+
+ // === Modification ===
+
+ /// Append a child node with a given name, which has a (nameless) plain-text child with the
+ /// given text value.
+ xml_element append_child_value(const std::string &name, const std::string &value) {
+ return lsl_append_child_value(obj, (name.c_str()), (value.c_str()));
+ }
+
+ /// Prepend a child node with a given name, which has a (nameless) plain-text child with the
+ /// given text value.
+ xml_element prepend_child_value(const std::string &name, const std::string &value) {
+ return lsl_prepend_child_value(obj, (name.c_str()), (value.c_str()));
+ }
+
+ /// Set the text value of the (nameless) plain-text child of a named child node.
+ bool set_child_value(const std::string &name, const std::string &value) {
+ return lsl_set_child_value(obj, (name.c_str()), (value.c_str())) != 0;
+ }
+
+ /**
+ * Set the element's name.
+ * @return False if the node is empty (or if out of memory).
+ */
+ bool set_name(const std::string &rhs) { return lsl_set_name(obj, rhs.c_str()) != 0; }
+
+ /**
+ * Set the element's value.
+ * @return False if the node is empty (or if out of memory).
+ */
+ bool set_value(const std::string &rhs) { return lsl_set_value(obj, rhs.c_str()) != 0; }
+
+ /// Append a child element with the specified name.
+ xml_element append_child(const std::string &name) {
+ return lsl_append_child(obj, name.c_str());
+ }
+
+ /// Prepend a child element with the specified name.
+ xml_element prepend_child(const std::string &name) {
+ return lsl_prepend_child(obj, (name.c_str()));
+ }
+
+ /// Append a copy of the specified element as a child.
+ xml_element append_copy(const xml_element &e) { return lsl_append_copy(obj, e.obj); }
+
+ /// Prepend a child element with the specified name.
+ xml_element prepend_copy(const xml_element &e) { return lsl_prepend_copy(obj, e.obj); }
+
+ /// Remove a child element with the specified name.
+ void remove_child(const std::string &name) { lsl_remove_child_n(obj, (name.c_str())); }
+
+ /// Remove a specified child element.
+ void remove_child(const xml_element &e) { lsl_remove_child(obj, e.obj); }
+
+private:
+ lsl_xml_ptr obj;
+};
+
+inline xml_element stream_info::desc() { return lsl_get_desc(obj.get()); }
+
+
+// =============================
+// ==== Continuous Resolver ====
+// =============================
+
+/**
+ * A convenience class that resolves streams continuously in the background throughout
+ * its lifetime and which can be queried at any time for the set of streams that are currently
+ * visible on the network.
+ */
+class continuous_resolver {
+public:
+ /**
+ * Construct a new continuous_resolver that resolves all streams on the network.
+ *
+ * This is analogous to the functionality offered by the free function resolve_streams().
+ * @param forget_after When a stream is no longer visible on the network (e.g., because it was
+ * shut down), this is the time in seconds after which it is no longer reported by the resolver.
+ */
+ continuous_resolver(double forget_after = 5.0)
+ : obj(lsl_create_continuous_resolver(forget_after), &lsl_destroy_continuous_resolver) {}
+
+ /**
+ * Construct a new continuous_resolver that resolves all streams with a specific value for a
+ * given property.
+ *
+ * This is analogous to the functionality provided by the free function resolve_stream(prop,value).
+ * @param prop The stream_info property that should have a specific value (e.g., "name", "type",
+ * "source_id", or "desc/manufaturer").
+ * @param value The string value that the property should have (e.g., "EEG" as the type
+ * property).
+ * @param forget_after When a stream is no longer visible on the network (e.g., because it was
+ * shut down), this is the time in seconds after which it is no longer reported by the resolver.
+ */
+ continuous_resolver(
+ const std::string &prop, const std::string &value, double forget_after = 5.0)
+ : obj(lsl_create_continuous_resolver_byprop((prop.c_str()), (value.c_str()), forget_after),
+ &lsl_destroy_continuous_resolver) {}
+
+ /**
+ * Construct a new continuous_resolver that resolves all streams that match a given XPath 1.0
+ * predicate.
+ *
+ * This is analogous to the functionality provided by the free function resolve_stream(pred).
+ * @param pred The predicate string, e.g.
+ * `name='BioSemi'` or
+ * `type='EEG' and starts-with(name,'BioSemi') and count(info/desc/channel)=32`
+ * @param forget_after When a stream is no longer visible on the network (e.g., because it was
+ * shut down), this is the time in seconds after which it is no longer reported by the resolver.
+ */
+ continuous_resolver(const std::string &pred, double forget_after = 5.0)
+ : obj(lsl_create_continuous_resolver_bypred((pred.c_str()), forget_after), &lsl_destroy_continuous_resolver) {}
+
+ /**
+ * Obtain the set of currently present streams on the network (i.e. resolve result).
+ * @return A vector of matching stream info objects (excluding their meta-data), any of
+ * which can subsequently be used to open an inlet.
+ */
+ std::vector results() {
+ lsl_streaminfo buffer[1024];
+ return std::vector(
+ buffer, buffer + check_error(lsl_resolver_results(obj.get(), buffer, sizeof(buffer))));
+ }
+
+ /// Move constructor for stream_inlet
+ continuous_resolver(continuous_resolver &&rhs) noexcept = default;
+ continuous_resolver &operator=(continuous_resolver &&rhs) noexcept = default;
+
+private:
+ std::unique_ptr obj;
+};
+
+
+// ===============================
+// ==== Exception Definitions ====
+// ===============================
+
+/// Exception class that indicates that a stream inlet's source has been irrecoverably lost.
+class lost_error : public std::runtime_error {
+public:
+ explicit lost_error(const std::string &msg) : std::runtime_error(msg) {}
+};
+
+
+/// Exception class that indicates that an operation failed due to a timeout.
+class timeout_error : public std::runtime_error {
+public:
+ explicit timeout_error(const std::string &msg) : std::runtime_error(msg) {}
+};
+
+/// Check error codes returned from the C interface and translate into appropriate exceptions.
+inline int32_t check_error(int32_t ec) {
+ if (ec < 0) {
+ switch (ec) {
+ case lsl_timeout_error: throw timeout_error("The operation has timed out.");
+ case lsl_lost_error:
+ throw timeout_error(
+ "The stream has been lost; to continue reading, you need to re-resolve it.");
+ case lsl_argument_error:
+ throw std::invalid_argument("An argument was incorrectly specified.");
+ case lsl_internal_error: throw std::runtime_error("An internal error has occurred.");
+ default: throw std::runtime_error("An unknown error has occurred.");
+ }
+ }
+ return ec;
+}
+
+} // namespace lsl
+
+#endif // LSL_CPP_H
diff --git a/physiolabxr/ui/DeviceWidget.py b/physiolabxr/ui/DeviceWidget.py
index ac4445a6..afd89068 100644
--- a/physiolabxr/ui/DeviceWidget.py
+++ b/physiolabxr/ui/DeviceWidget.py
@@ -73,9 +73,13 @@ def start_stop_stream_btn_clicked(self):
self.set_button_icons()
self.main_parent.update_active_streams()
except CustomDeviceStartStreamError as e:
+ show_label_movie(self.waiting_label, False) # Stop loading animation
+ self.set_button_icons() # Reset button state
self.main_parent.current_dialog = dialog_popup(msg=str(e), title='ERROR')
return
except CustomDeviceStreamInterruptedError as e:
+ show_label_movie(self.waiting_label, False)
+ self.set_button_icons()
self.main_parent.current_dialog = dialog_popup(msg=str(e), title='ERROR')
return
except ChannelMismatchError as e: # only LSL's channel mismatch can be checked at this time, zmq's channel mismatch can only be checked when receiving data