diff --git a/examples/lsl_inlet_example.py b/examples/lsl_inlet_example.py index 1f2d3ef..b21666d 100644 --- a/examples/lsl_inlet_example.py +++ b/examples/lsl_inlet_example.py @@ -1,52 +1,19 @@ -from typing import Optional - import ezmsg.core as ez -from ezmsg.lsl.units import LSLInletUnit, LSLInletSettings, LSLInfo -from ezmsg.util.debuglog import DebugLog, DebugLogSettings +from ezmsg.lsl.units import LSLInletUnit, LSLInfo +from ezmsg.util.debuglog import DebugLog import typer # from ezmsg.util.messagelogger import MessageLogger, MessageLoggerSettings -class LSLDemoSystemSettings(ez.Settings): - stream_name: str = "" - stream_type: str = "EEG" - logger_name: str = "DEBUG" # Useful name for logger - logger_max_length: Optional[int] = 400 # No limit if `None`` - - -class LSLDemoSystem(ez.Collection): - SETTINGS: LSLDemoSystemSettings - - INLET = LSLInletUnit() - LOGGER = DebugLog() - # LOGGER = MessageLogger() - - def configure(self) -> None: - self.INLET.apply_settings( - LSLInletSettings( - info=LSLInfo( - name=self.SETTINGS.stream_name, - type=self.SETTINGS.stream_type, - ) - ) - ) - self.LOGGER.apply_settings( - DebugLogSettings( - name=self.SETTINGS.logger_name, - max_length=self.SETTINGS.logger_max_length, - ) - ) - - def network(self) -> ez.NetworkDefinition: - return ((self.INLET.OUTPUT_SIGNAL, self.LOGGER.INPUT),) - - def main(stream_name: str = "", stream_type: str = "EEG"): - system = LSLDemoSystem() - system.apply_settings( - LSLDemoSystemSettings(stream_name=stream_name, stream_type=stream_type) + comps = { + "SRC": LSLInletUnit(info=LSLInfo(name=stream_name, type=stream_type)), + "LOGGER": DebugLog(name="DEBUG", max_length=400), # MessageLogger(output=file_path), + } + conns = ( + (comps["SRC"].OUTPUT_SIGNAL, comps["LOGGER"].INPUT), ) - ez.run(SYSTEM=system) + ez.run(components=comps, connections=conns) if __name__ == "__main__": diff --git a/src/ezmsg/lsl/outlet.py b/src/ezmsg/lsl/outlet.py index 74d8b31..e658982 100644 --- a/src/ezmsg/lsl/outlet.py +++ b/src/ezmsg/lsl/outlet.py @@ -24,9 +24,11 @@ class LSLOutletSettings(ez.Settings): stream_name: typing.Optional[str] = None stream_type: typing.Optional[str] = None - map_file: typing.Optional[str] = ( - None # Path to file containing a list of channel names and locations. - ) + map_file: typing.Optional[str] = None + """ + Path to file containing a list of channel names and locations. + This feature is experimental and not tested. + """ class LSLOutletState(ez.State): @@ -106,5 +108,5 @@ async def lsl_outlet(self, msg: AxisArray) -> None: ts = msg.axes["time"].data else: ts = msg.axes["time"].value(dat.shape[0]) - ts = self.clock_sync.system2lsl(ts) + ts = self._clock_sync.system2lsl(ts) self.STATE.outlet.push_chunk(dat.reshape(dat.shape[0], -1), timestamp=ts) diff --git a/src/ezmsg/lsl/util.py b/src/ezmsg/lsl/util.py index 8038675..1cdc49e 100644 --- a/src/ezmsg/lsl/util.py +++ b/src/ezmsg/lsl/util.py @@ -37,17 +37,18 @@ def __init__(self, alpha: float = 0.1, min_interval: float = 0.1): if not hasattr(self, "_initialized"): self._alpha = alpha self._interval = min_interval - self._offset: typing.Optional[float] = None - self._running = True - self._initialized = True + # Do first burst so we have a real offset even before the thread starts. + xs, ys = collect_timestamp_pairs(100) + self._offset: float = np.mean(ys - xs) + self._thread = threading.Thread(target=self._run) self._thread.daemon = True + self._initialized = True + self._running = True self._thread.start() def _run(self): - xs, ys = collect_timestamp_pairs(100) - self._offset = np.mean(ys - xs) while self._running: time.sleep(self._interval) xs, ys = collect_timestamp_pairs(4)