Example #1
0
def _get_stream_inlet(lsl_predicate):
    """Return the stream that fits the given predicate. Raise ValueError if
    multiple streams or zero streams match the predicate.

    Parameters
    ----------
    lsl_predicate : str
        Predicate used to find LabStreamingLayer stream. See
        `default_predicates.py` for more info.

    Returns
    -------
    inlet : pylsl.StreamInlet
        The LSL stream that matches the given predicate.
    """
    stream = resolve_bypred(lsl_predicate)  # Times out after ~ 1 year.
    if len(stream) == 1:
        inlet = StreamInlet(stream[0])
        logger.info("Connected to stream.")
    else:
        msg = ("Multiple streams match the given predicate. Only one "
               "stream must match the predicate.")
        logger.error(msg)
        raise ValueError(msg)
    return inlet
    def _resolve(self):
        """
    Search for available EEG streams on LSL and connect to them by saving them as Stream objects
    """
        # resolve EEG streams and retrieve their information
        streams_info = resolve_bypred("type='EEG'", 0, 2.5)
        streams_active = []
        self.logger.debug("Found {} available streams".format(
            len(streams_info)))

        # iterate for each stream
        for stream_info in streams_info:
            # uid = stream_info.source_id() if stream_info.source_id() else stream_info.uid()  # retrieve 'source_id'
            uid = stream_info.source_id() + ' | ' + stream_info.uid()
            streams_active.append(uid)

            # if the current stream has not been saved, then connect to the current stream
            if uid not in self.streams_by_uid:
                if self._validate_stream_signature(stream_info):
                    self._connect_to(uid, stream_info)

            # if the current stream is already saved, but is not running, then disconnect
            if uid in self.streams_by_uid:
                if self.streams_by_uid[uid].running == False:
                    self._disconnect_from({uid})

        self._disconnect_from(
            list(set(self.streams_by_uid.keys()) - set(streams_active)))
Example #3
0
 def sub_live_streams(data: List[Dict[str, Union[str, dict]]], queue: asyncio.Queue):
   # source = <source_id> | type = <desc/stream/name>
   stream_query: List[Tuple[str, str, dict]] = [(
     str(d.get('source', '')),
     str(d.get('stream', {}).get('name', {})),
     dict(d.get('attributes', {}))
   ) for d in data]
   pred_str = RelayMode.gen_pred_str(stream_query)
   logger.debug('predicate: %s', pred_str)
   # count of queries and tasks
   num_queries = len(stream_query)
   num_tasks = 0
   # run one query to get a superset of the requested streams
   available_live_stream_info: List[pylsl.StreamInfo] = pylsl.resolve_bypred(pred_str)
   logger.debug('found %d live stream match(es) for predicate', len(available_live_stream_info))
   # iterate each query and start live streams
   for live_stream_info in available_live_stream_info:
     # create task to live-stream data
     inlet = pylsl.StreamInlet(live_stream_info, max_chunklen=1, recover=False)
     asyncio.create_task(RelayMode.start_live_stream(inlet, queue))
     num_tasks += 1
   logger.info("started %d live stream tasks for the %d queries", num_tasks, num_queries)
   return {
     'command': 'notification',
     'data': {'message': f'started {num_tasks} live stream tasks for the {num_queries} queries'},
     'error': None
   }
Example #4
0
def _get_stream_inlet(lsl_predicate):
    """Return the stream that fits the given predicate. Raise ValueError if
    multiple streams or zero streams match the predicate.

    Parameters
    ----------
    lsl_predicate : str
        Predicate used to find LabStreamingLayer stream. See
        `default_eeg_predicates.py` for more info.

    Returns
    -------
    inlet : pylsl.StreamInlet
        The LSL stream that matches the given predicate.
    """
    stream = resolve_bypred(lsl_predicate)  # Should timeout be specified?
    if len(stream) == 1:
        inlet = StreamInlet(stream[0])
        print("Connected to stream.")  # TODO: change this to logging.
    elif not stream:  # This would never happen without a timeout.
        raise ValueError("Zero streams match the given predicate.")
    else:
        raise ValueError(
            "Multiple streams match the given predicate. Only one "
            "stream must match the predicate.")
    return inlet
Example #5
0
def _resolve_streams(verbose=True) -> list:
    if verbose:
        logger.info("Finding stream...")
    # Get the Muse EEG stream
    streams = pylsl.resolve_bypred("name='Muse' and type='EEG'", timeout=10)
    if not streams:
        logger.error("No appropriate stream could be found")
        exit(1)
    return streams
Example #6
0
    def __init__(self, name=LSL_STREAM_NAMES[2], only_this_host=False):
        if not only_this_host:
            streams = resolve_byprop('name', name, timeout=LSL_RESOLVE_TIMEOUT)
        else:
            streams = resolve_bypred("name='{}' and hostname='{}'".format(name, socket.gethostname()))

        self.inlet = None
        self.dtype = 'float64'
        if len(streams) > 0:
            self.inlet = FixedStreamInlet(streams[0], max_buflen=2)
            # self.dtype = fmt2string[self.inlet.info().channel_format()]
            print(self.dtype)
Example #7
0
    def __init__(self, name=LSL_STREAM_NAMES[2], only_this_host=False):
        if not only_this_host:
            streams = resolve_byprop('name', name, timeout=LSL_RESOLVE_TIMEOUT)
        else:
            streams = resolve_bypred("name='{}' and hostname='{}'".format(name, socket.gethostname()))

        self.inlet = None
        self.dtype = 'float64'
        if len(streams) > 0:
            self.inlet = FixedStreamInlet(streams[0], max_buflen=2)
            # self.dtype = fmt2string[self.inlet.info().channel_format()]
            print(self.dtype)
Example #8
0
    def __init__(self, name=LSL_STREAM_NAMES[2], only_this_host=False):
        if not only_this_host:
            streams = resolve_byprop('name', name, timeout=LSL_RESOLVE_TIMEOUT)
        else:
            streams = resolve_bypred("name='{}' and hostname='{}'".format(name, socket.gethostname()))

        self.inlet = None
        self.dtype = 'float64'
        if len(streams) > 0:
            self.inlet = FixedStreamInlet(streams[0], max_buflen=2)
            # self.dtype = fmt2string[self.inlet.info().channel_format()]
            print('Connected to {} LSL stream successfully'.format(name))
            self.n_channels = self.inlet.info().channel_count()
        else:
            raise ConnectionError('Cannot connect to "{}" LSL stream'.format(name))
 def __init__(self):
     self.task = {'phase':'precue', 'class':1, 'target':1}
     print("Looking for stream with type Markers")
     streams = resolve_bypred("type='Markers'", minimum=1)
     proc_flags = 0  # Marker events are relatively rare. No need to post-process.
     self.inlet = StreamInlet(streams[0], processing_flags=proc_flags)
     # The following is an example of how to read stream info
     stream_info = self.inlet.info()
     stream_Fs = stream_info.nominal_srate()
     stream_xml = stream_info.desc()
     chans_xml = stream_xml.child("channels")
     chan_xml_list = []
     ch = chans_xml.child("channel")
     while ch.name() == "channel":
         chan_xml_list.append(ch)
         ch = ch.next_sibling("channel")
     stream_ch_names = [ch_xml.child_value("label") for ch_xml in chan_xml_list]
     print("Reading from inlet named {} with channels {}".format(stream_info.name(), stream_ch_names))
 def __init__(self):
     self.task = {'phase': 'precue', 'class': 1, 'target': 1}
     print("Looking for stream with type Markers")
     streams = resolve_bypred("type='Markers'", minimum=1)
     proc_flags = 0  # Marker events are relatively rare. No need to post-process.
     self.inlet = StreamInlet(streams[0], processing_flags=proc_flags)
     # The following is an example of how to read stream info
     stream_info = self.inlet.info()
     stream_Fs = stream_info.nominal_srate()
     stream_xml = stream_info.desc()
     chans_xml = stream_xml.child("channels")
     chan_xml_list = []
     ch = chans_xml.child("channel")
     while ch.name() == "channel":
         chan_xml_list.append(ch)
         ch = ch.next_sibling("channel")
     stream_ch_names = [
         ch_xml.child_value("label") for ch_xml in chan_xml_list
     ]
     print("Reading from inlet named {} with channels {}".format(
         stream_info.name(), stream_ch_names))
Example #11
0
    def _resolve(self):
        streams_info = resolve_bypred("type='EEG'", 0, 2.5)
        streams_active = []

        self.logger.debug("Found {} available streams".format(
            len(streams_info)))

        for stream_info in streams_info:
            uid = stream_info.source_id() if stream_info.source_id(
            ) else stream_info.uid()
            streams_active.append(uid)

            if uid not in self.streams_by_uid:
                if self._validate_stream_signature(stream_info):
                    self._connect_to(uid, stream_info)

            if uid in self.streams_by_uid:
                if self.streams_by_uid[uid].running == False:
                    self._disconnect_from({uid})  #werkt soms niet?
                    # streams_active.remove(uid) #werkt

        self._disconnect_from(
            list(set(self.streams_by_uid.keys()) - set(streams_active)))
Example #12
0
 def run(self):
     streams = resolve_bypred("*", timeout=5)
     self.streams = [StreamInlet(stream).info() for stream in streams]
     self.taskFinished.emit()
Example #13
0
def plot(device: str):
    """Plot existing LSL stream"""
    from eegwatch.lslutils import PULL_INTERVAL, PLOT_DURATION, _get_inlets

    assert device.startswith("muse"), "Only Muse devices supported for now"
    # print(eeg_device)

    # TODO: Get the live data and do basic stuff to check signal quality, such as:
    #        - Checking signal variance.
    #        - Transforming into the frequency domain.

    offset = datetime.now(tz=timezone.utc).timestamp() - pylsl.local_clock()

    def local_clock_to_timestamp(local_clock):
        return local_clock + offset

    streams = pylsl.resolve_bypred("name='Muse' and type='EEG'", timeout=10)
    if not streams:
        print("No stream could be found")
        exit(1)

    for s in streams:
        logger.debug(streams)

    # Create the pyqtgraph window
    pw = pg.plot(title="LSL Plot")
    plt = pw.getPlotItem()
    plt.enableAutoRange(x=False, y=True)

    inlets = _get_inlets(plt=plt)

    def scroll():
        """Move the view so the data appears to scroll"""
        # We show data only up to a timepoint shortly before the current time
        # so new data doesn't suddenly appear in the middle of the plot
        fudge_factor = PULL_INTERVAL * 0.002
        plot_time = local_clock_to_timestamp(pylsl.local_clock())
        pw.setXRange(plot_time - PLOT_DURATION + fudge_factor,
                     plot_time - fudge_factor)

    def update():
        # Read data from the inlet. Use a timeout of 0.0 so we don't block GUI interaction.
        mintime = local_clock_to_timestamp(pylsl.local_clock()) - PLOT_DURATION
        # call pull_and_plot for each inlet.
        # Special handling of inlet types (markers, continuous data) is done in
        # the different inlet classes.
        for inlet in inlets:
            inlet.pull_and_plot(mintime, plt)

    # create a timer that will move the view every update_interval ms
    update_timer = QtCore.QTimer()
    update_timer.timeout.connect(scroll)
    update_timer.start(UPDATE_INTERVAL)

    # create a timer that will pull and add new data occasionally
    pull_timer = QtCore.QTimer()
    pull_timer.timeout.connect(update)
    pull_timer.start(PULL_INTERVAL)

    import sys

    # Start Qt event loop unless running in interactive mode or using pyside.
    if (sys.flags.interactive != 1) or not hasattr(QtCore, "PYQT_VERSION"):
        QtGui.QApplication.instance().exec_()
Example #14
0
def find_pylsl_outlets(v=None, **kwargs):  # noqa: C901
    '''
    This function is easier to use than func `pylsl.resolve_stream`.

    Examples
    --------
    >>> find_pylsl_outlets()   # same as pylsl.resolve_streams()
    >>> find_pylsl_outlets(1)  # same as pylsl.resolve_streams(timeout=1)

    >>> find_pylsl_outlets('type', 'EEG')  # Invalid
    >>> find_pylsl_outlets("type='EEG'")   # pylsl.resolve_bypred("type='EEG'")
    >>> find_pylsl_outlets(type='EEG')    # pylsl.resolve_byprop('type', 'EEG')

    If no wanted pylsl stream outlets found, ``RuntimeError`` will be raised.
    '''
    timeout = v if isinstance(v, (int, float)) else kwargs.pop('timeout', 1)
    keys = set(kwargs.keys()).intersection({
        'name', 'type', 'channel_count', 'nominal_srate', 'channel_format',
        'source_id'
    })

    if isinstance(v, str):
        infos = pylsl.resolve_bypred(v, 0, timeout)
    elif not keys:
        infos = pylsl.resolve_streams(timeout)
    else:
        infos = []
    for key in keys:
        infos += pylsl.resolve_byprop(key, kwargs[key], 0, timeout)

    streams = dict()
    for info in infos:
        if info.uid() not in streams:
            streams[info.uid()] = info
    stream_list = list(streams.values())

    if len(stream_list) == 0:
        raise RuntimeError('No stream available! Abort.')
    elif len(stream_list) == 1:
        stream = stream_list[0]
    else:
        # Display stream as: $No $Name $Type - $CHx$Format $SourceID
        prompt = ('Please choose one from all available streams:\n    ' +
                  '\n    '.join([
                      '{:2d} {:s}({:s}) CH{:d}x{:s} - `{}`@ {}'.format(
                          n, s.name(), s.type(), s.channel_count(),
                          pylsl.pylsl.fmt2type[s.channel_format()]._type_,
                          s.source_id() and '`%s` ' % s.source_id() or '',
                          s.hostname()) for n, s in enumerate(stream_list)
                  ]) + '\nstream num (default 0): ')
        answer = {str(i): stream_list[i] for i in range(len(stream_list))}
        answer[''] = stream_list[0]
        try:
            stream = check_input(prompt, answer)
            if stream == '':
                stream = answer[stream]
        except KeyboardInterrupt:
            raise RuntimeError('No stream selected! Abort.')
    logger.info('Using stream `{}`({}) `{}`@ {}'.format(
        stream.name(), stream.type(), stream.source_id(), stream.hostname()))
    return stream