def configure(self, **kwargs): """Configure the lsl stream. This method finds running lsl streams and picks the first `EEG` and `Markers` streams. """ # open EEG lsl stream logger.debug('Opening EEG stream...') eeg_streams = pylsl.resolve_byprop('type', 'EEG', timeout=2) try: if len(eeg_streams) == 0: self.bool_eeg_streams = False # raise RuntimeError("Can't find EEG stream") if len(eeg_streams) > 1: self.bool_eeg_streams = True logger.warning( 'Number of EEG streams is > 0, picking the first one.') except RuntimeError as x: print("Can't find EEG stream") self.eeg_stream_name = pylsl.StreamInfo.name(eeg_streams[0]) print(self.eeg_stream_name + " is found!") self.lsl_inlet = pylsl.StreamInlet(eeg_streams[0]) # lsl time sample correction self.lsl_inlet.time_correction() # open marker lsl stream logger.debug('Opening Marker stream...') # TODO: should add a timeout here in case there is no marker # stream marker_streams = pylsl.resolve_byprop('type', 'Markers', timeout=2) if marker_streams: self.bool_marker_streams = True if len(marker_streams) > 1: logger.warning( 'Number of Marker streams is > 0, picking the first one.') marker_stream_name = pylsl.StreamInfo.name(marker_streams[0]) print(marker_stream_name + " is found!") self.lsl_marker_inlet = pylsl.StreamInlet(marker_streams[0]) # lsl time sample correction self.lsl_marker_inlet.time_correction() else: self.bool_marker_streams = False print("Can't find Markers stream") # Parse channel name and sampling frequency info = self.lsl_inlet.info() # self.fs = pylsl.StreamInfo.nominal_srate(eeg_streams[0]) self.n_channels = info.channel_count() self.channels = ['Ch %i' % i for i in range(self.n_channels)] self.fs = info.nominal_srate() logger.debug('Initializing time correction...') # lsl buffer defined self.max_samples = int(self.fs * self.buffer_size) logger.debug('Configuration done.')
def configure(self, **kwargs): """Configure the lsl device. This method looks for open lsl streams and picks the first `EEG` and `Markers` streams and opens lsl inlets for them. Note that lsl amplifiers cannot be configured via lsl, as the protocol was not designed for that. You can only connect (i.e. subscribe) to devices that connected (publishing) via the lsl protocol. """ self.markers_list = [] # lsl defined #self.max_samples = 4096 self.max_samples = 1024 # open EEG stream logger.debug('Opening EEG stream...') streams = pylsl.resolve_stream('type', 'EEG') if len(streams) > 1: logger.warning( 'Number of EEG streams is > 0, picking the first one.') self.lsl_inlet = pylsl.StreamInlet(streams[0], max_buflen=30) # open marker stream logger.debug('Opening Marker stream...') # TODO: should add a timeout here in case there is no marker # stream streams = pylsl.resolve_stream('type', 'Markers') if len(streams) > 1: logger.warning( 'Number of Marker streams is > 0, picking the first one.') self.lsl_marker_inlet = pylsl.StreamInlet(streams[0], max_buflen=30) info = self.lsl_inlet.info() self.n_channels = info.channel_count() self.channels = ['Ch %i' % i for i in range(self.n_channels)] self.fs = info.nominal_srate() logger.debug('Initializing time correction...') self.do_time_correction = True try: self.lsl_marker_inlet.time_correction(timeout=2.0) except Exception: self.do_time_correction = False logger.debug('Timeout whe tying marker_inlet time_correction') try: self.lsl_inlet.time_correction(timeout=2.0) except Exception: self.do_time_correction = False logger.debug('Timeout whe tying marker_inlet time_correction') logger.debug('Configuration done.')
def search_lsl(ignore_markers=False): import pylsl, time # look for LSL servers amp_list = [] amp_list_backup = [] while True: streamInfos = pylsl.resolve_streams() if len(streamInfos) > 0: for index, si in enumerate(streamInfos): amp_serial = pylsl.StreamInlet(si).info().desc().child( 'acquisition').child_value('serial_number').strip() amp_name = si.name() if 'Markers' in amp_name: amp_list_backup.append((index, amp_name, amp_serial)) else: amp_list.append((index, amp_name, amp_serial)) break print('No server available yet on the network...') time.sleep(1) if ignore_markers is False: amp_list += amp_list_backup qc.print_c('-- List of servers --', 'W') for i, (index, amp_name, amp_serial) in enumerate(amp_list): if amp_serial == '': amp_ser = 'N/A' else: amp_ser = amp_serial qc.print_c('%d: %s (Serial %s)' % (i, amp_name, amp_ser), 'W') if len(amp_list) == 1: index = 0 dong = 0 else: dong = 1 index = raw_input( 'Amp index? Hit enter without index to select the first server.\n>> ' ).strip() index = int(index) # dong #amp_index, amp_name, amp_serial= [(0, u'g.USBamp-1',u'UB-2010.06.31')] #qc.shell() amp_index, amp_name, amp_serial = amp_list[index] #if dong == 1: #amp_index = 0 #print('!!!!!!!!!!!!!!!') si = streamInfos[amp_index] assert amp_name == si.name() assert amp_serial == pylsl.StreamInlet(si).info().desc().child( 'acquisition').child_value('serial_number').strip() print('Selected %s (Serial: %s)' % (amp_name, amp_serial)) return amp_name, amp_serial
def update_streams(self): if not self.streams: self.streams = pylsl.resolve_streams(wait_time=1.0) for k, stream in enumerate(self.streams): n = stream.name() stream_params = copy.deepcopy(self.def_stream_parms) stream_params['metadata'].update({ "name": n, "ch_count": stream.channel_count(), "ch_format": stream.channel_format(), "srate": stream.nominal_srate() }) # ch = stream.desc().child("channels").child("channel") # for ch_ix in range(stream.channel_count()): # print(" " + ch.child_value("label")) # ch = ch.next_sibling() stream_params['inlet'] = pylsl.StreamInlet(stream) stream_params['is_marker'] = stream.channel_format() in ["String", pylsl.cf_string]\ and stream.nominal_srate() == pylsl.IRREGULAR_RATE if not stream_params['is_marker']: if self.sig_strm_idx < 0: self.sig_strm_idx = k srate = stream.nominal_srate() stream_params['downSampling'] = srate > 1000 stream_params['chunkSize'] = round(srate / self.chunksPerScreen * self.seconds_per_screen) if stream_params['downSampling']: stream_params['downSamplingFactor'] = round(srate / 1000) n_buff = round(stream_params['chunkSize'] / stream_params['downSamplingFactor']) stream_params['downSamplingBuffer'] = [[0] * int(stream.channel_count())] * n_buff self.stream_params.append(stream_params) self.updateStreamNames.emit([_['metadata'] for _ in self.stream_params], self.sig_strm_idx) self.start()
def _initialize(self): stream_infos = lsl.resolve_byprop( 'name', self.source_name, timeout=self.SECONDS_TO_WAIT_FOR_THE_STREAM) if len(stream_infos) == 0: raise ValueError( 'Could not find an LSL stream with name {}'.format( self.source_name)) elif len(stream_infos) > 1: raise ValueError( 'There are multiple LSL streams with name {}, so I don' 't know which to use'.format(self.source_name)) else: info = stream_infos[0] self._inlet = lsl.StreamInlet(info) self._inlet.open_stream() frequency = info.nominal_srate() self.dtype = DTYPE channel_labels, channel_types = read_channel_labels_from_info( self._inlet.info()) self.mne_info = mne.create_info(channel_labels, frequency, ch_types=channel_types)
def __init__(self, stream, buf_size, col="w", chnames=False, invert=False): """ Initializes the grapher. Args: stream: <pylsl.StreamInfo instance> pointer to a stream buf_size: <integer> visualization buffer length in samples col: <char> color of the line plot (b,r,g,c,m,y,k and w) """ self.stream = stream self.inlet = pylsl.StreamInlet(stream) self.buf_size = buf_size self.channel_count = self.inlet.channel_count self.gbuffer = np.zeros(self.buf_size * self.channel_count) self.gtimes = np.zeros(self.buf_size) + pylsl.local_clock() self.col = col if chnames: if self.channel_count == len(chnames): self.chnames = chnames else: print("Channel names vs channel count mismatch, skipping") else: self.chnames = False if invert: pg.setConfigOption('background', 'w') pg.setConfigOption('foreground', 'k') self.fill_buffer() self.start_graph()
def start_client(server_name, state=mp.Value('i', 1)): """ Search for an LSL outlet (server) and open an LSL inlet (client). Parameters ---------- server_name: str Name of the server to search. state : Multiprocessing.Value Used to stop searching from another process. Returns ------- LSL inlet: LSL client object. """ while state.value == 1: logger.info(f'Searching for LSL server {server_name} ...') streamInfos = pylsl.resolve_byprop("name", server_name, timeout=1) if not streamInfos: continue for sinfo in streamInfos: logger.info(f'Found {sinfo.name()}') sinfo = streamInfos[0] break return pylsl.StreamInlet(sinfo)
def setup_inlets(self): """ Search for all the inlets with names in self.inlet_names """ for iname in self.inlet_names: streams = pylsl.resolve_stream('name', iname) self.inlet_list.append(pylsl.StreamInlet(streams[0]))
def getAvailableStreams(self): self.isAvailable = False # Resets availability of streams -> Always false unless stream is found self.lslobj.clear( ) # Clears container of lsl inlets for new batch of inlets streams = pylsl.resolve_streams( wait_time=1.0 ) # Contains information about all available lsl inlets # If streams list is empty, no streams are available # Clear the channelLayout of all previously listed channels, since no streams are available if len(streams) == 0: print("No streams available.") self.clearChannels() else: self.isAvailable = True print("Got all available streams. Starting streams now.....") for s in streams: lsl_inlet = pylsl.StreamInlet(s, max_buflen=4) lsl_inlet.open_stream() lsl = LSLRINGBUFFER(lsl_type=lsl_inlet.info().type(), name=lsl_inlet.info().name(), inlet=lsl_inlet,\ fs=lsl_inlet.info().nominal_srate(), buffer_duration=4.0, \ num_channels=lsl_inlet.info().channel_count(), uid=lsl_inlet.info().uid(),\ hostname=lsl_inlet.info().hostname(), channel_format='float64') self.lslobj[lsl_inlet.info().name()] = lsl
def __init__(self, stream, 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.stream_type = name self.inlet = None self.dtype = 'float64' self.stream_name = pylsl.StreamInfo.name(stream) # self.fs = pylsl.StreamInfo.nominal_srate(stream) print("Trying to connect to {} LSL stream.....".format( self.stream_name)) try: # if len(streams) > 0: self.inlet = pylsl.StreamInlet(stream, max_buflen=4) # def start(self): """Open the lsl inlets. """ logger.debug('Opening lsl streams.') self.inlet.open_stream() # self.dtype = fmt2string[self.inlet.info().channel_format()] print('Connected to {} LSL stream successfully'.format(name)) self.n_channels = self.inlet.info().channel_count() self.channels = ['Ch %i' % i for i in range(self.n_channels)] # else: # raise ConnectionError('Cannot connect to "{}" LSL stream'.format(name)) except ConnectionError as e: print('Cannot connect to "{}" LSL stream'.format(name))
def open_stream(**kwargs) -> StreamInlet: """get only a single streaminlets which matches kwargs raises a ConnectionError if more than one match is found args ---- **kwargs: keyword arguments to identify the desired stream returns ------- stream: StreamInlet a single StreamInlet matching the kwargs. Example:: import liesl stream = liesl.open_stream(name="Liesl-Mock-EEG") """ infos = get_streaminfos_matching(**kwargs) if infos is None: return None elif len(infos) > 1: raise ConnectionError("Found too many streaminfos") else: return pylsl.StreamInlet(infos[0])
def start_client(server_name, state=mp.Value('i', 1)): """ Search and connect to an LSL server Params ------ server_name: Name of the server to search state: Multiprocessing.Value used to stop from the GUI, 1: acquire 0:stop Returns ------- inlet: LSL client object """ while True: if not state.value: sys.exit(-1) logger.info('Searching for LSL server %s ...' % server_name) streamInfos = pylsl.resolve_byprop("name", server_name, timeout=1) if not streamInfos: continue for sinfo in streamInfos: logger.info('Found %s' % sinfo.name()) if len(streamInfos) == 0: logger.info('No desired LSL server found. Keep searching...') time.sleep(1.0) else: sinfo = streamInfos[0] break return pylsl.StreamInlet(sinfo)
def create_data_inlet(self): logger.info('Trying to resolve data inlet stream.') streams = pylsl.resolve_stream('name', self.client_config['lsl']['inlet']['name']) self.data_inlet = pylsl.StreamInlet(streams[0]) logger.info('Data inlet created successfully. Running first time correction so subsequent ones are instantaneous.') self.data_inlet.time_correction() logger.info('First time correction done.')
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 }
def start_client(server_name): """ Search and connect to an LSL server Params ------ server_name: Name of the server to search Returns ------- inlet: LSL client object """ while True: logger.info('Searching for LSL server %s ...' % server_name) streamInfos = pylsl.resolve_byprop("name", server_name, timeout=1) if not streamInfos: continue for sinfo in streamInfos: logger.info('Found %s' % sinfo.name()) if len(streamInfos) == 0: logger.info('No desired LSL server found. Keep searching...') time.sleep(1.0) else: sinfo = streamInfos[0] break return pylsl.StreamInlet(sinfo)
def __init__(self, parent=None): super(WaveViewer, self).__init__(parent) # a figure instance to plot on self.figure = plt.figure(figsize=(20, 5)) # data self.signals = None # this is the Canvas Widget that displays the `figure` # it takes the `figure` instance as a parameter to __init__ self.canvas = FigureCanvas(self.figure) # this is the Navigation widget it takes the Canvas widget and a parent self.toolbar = NavigationToolbar(self.canvas, self) # Just some timer connected to `plot` method self.timer = QtCore.QTimer() self.timer.timeout.connect(self.update) self.timer.start(self.FRAME_REFRESH) # set the layout layout = QtWidgets.QVBoxLayout() layout.addWidget(self.toolbar) layout.addWidget(self.canvas) self.setLayout(layout) # resolve an EEG stream on the lab network logging.info("looking for an EEG stream...") streams = pylsl.resolve_stream('type', 'EEG') # create a new inlet to read from the stream self.inlet = pylsl.StreamInlet(streams[0])
def get_data(self) -> types.GeneratorType: """ Resolve a lsl stream of type 'EEG' Yield ----- data: :obj:`list` of n_channels Data for all channels on one interation Raises ------ Exception: Fails to resolve data from stream """ # first resolve an EEG stream on the lab network print("looking for an EEG stream...") streams = pylsl.resolve_byprop('type', 'EEG', timeout=30) if (len(streams) == 0): raise acquisition.AcquisitionError( 'unable to resolve an EEG stream') inlet = pylsl.StreamInlet(streams[0], recover=False) while True: chunk, timestamp = inlet.pull_chunk() # sometimes... this loop is faster than chunk receiving if (timestamp): for i in range(len(timestamp)): yield (chunk[i])
def get_streams_matching(**kwargs) -> List[StreamInlet]: """get all streaminlets matching kwargs args ---- **kwargs: keyword arguments to identify the desired stream returns ------- streams: List[StreamInlet] a list of StreamInlets matching the kwargs Example:: import liesl streams = liesl.get_streams_matching(name="Liesl-Mock-EEG") """ infos = get_streaminfos_matching(**kwargs) if infos is None: return None else: streams = [] for info in infos: streams.append(pylsl.StreamInlet(info)) return streams
def get_inlet_amp(config): printm('Resolving LSL stream from amplifier...') streams = pylsl.resolve_byprop('name', config['amp_config']['lsl_stream_name_amp']) inlet_amp = pylsl.StreamInlet(streams[0], max_buflen = config['amp_config'].getint('max_buflen'), max_chunklen = config['amp_config'].getint('max_chunklen')) printm('LSL stream \"{}\" resolved'.format(config['amp_config']['lsl_stream_name_amp'])) return inlet_amp
def init_lsl(stream_index): """init_lsl() - initialize an LSL stream containing EEG data @stream_index: LSL supports multiple concurrent streams, this selects one. Returns: A stream inlet that can be read from. """ streams = pylsl.resolve_stream('type', 'EEG') inlet = pylsl.StreamInlet(streams[stream_index]) return inlet
def hook_before(self): fs = self._lsl_inlet_info.nominal_srate() if fs not in [self.sample_rate, pylsl.IRREGULAR_RATE]: self.set_sample_rate(fs) nch = self._lsl_inlet_info.channel_count() self._check_num_channel(nch) maxbuf = int(self.sample_time if fs else (self.window_size // 100 + 1)) self._lsl_inlet = pylsl.StreamInlet(self._lsl_inlet_info, maxbuf) self.input_source = '{}@{}'.format( self._lsl_inlet_info.name(), self._lsl_inlet_info.source_id())
def look_for_eeg_stream(): """returns an inlet of the first eeg stream outlet found.""" print("looking for an EEG stream...") streams = pylsl.resolve_byprop('type', 'EEG', timeout=2) if len(streams) == 0: raise (RuntimeError, "Can't find EEG stream") print("Start acquiring data") eeg_inlet = pylsl.StreamInlet(streams[0], max_chunklen=1) return eeg_inlet
def __init__(self, stream_info, max_sec, **inlet_keyargs): assert isinstance(max_sec, int), "The 'max_sec' should be integer." self.inlet = pylsl.StreamInlet( stream_info, max_sec, **inlet_keyargs ) self.sampling_rate = self.inlet.info().nominal_srate()#stream_info.nominal_srate() maxlen = int(max_sec * self.sampling_rate) self._data_deque = collections.deque(maxlen=maxlen) self._time_deque = collections.deque(maxlen=maxlen)
def look_for_markers_stream(): """returns an inlet for the first markers stream outlet if found.""" print("looking for a Markers stream") streams = pylsl.resolve_byprop('name', 'Markers', timeout=30) if len(streams) == 0: raise (RuntimeError, "Can't find Markers stream") print("Start acquiring data") marker_inlet = pylsl.StreamInlet(streams[0]) return marker_inlet
def get_lsl_inlets(streams=None, with_source_ids=('', ), with_types=('', ), max_chunklen=0): """Return LSL stream inlets for given/discovered LSL streams. If `streams` is not given, will automatically discover all available streams. Args: streams: List of `pylsl.StreamInfo` or source/type mapping. See `streams_dict_from_streams` for additional documentation of the difference between the two data types. with_source_id (Iterable[str]): Return only inlets whose source ID contains one of these strings. Case-sensitive; e.g. "Muse" might work if "muse" doesn't. with_type (Iterable[str]): Return only inlets with these stream types. Returns: dict[str, dict[str, pylsl.StreamInlet]]: LSL inlet objects. Keys are the source IDs; values are dicts where the keys are stream types and values are stream inlets. TODO: * Try leveraging lsl.resolve_byprop or lsl.resolve_bypred * inlet time_correction necessary for remotely generated timestamps? """ if streams is None: streams = get_lsl_streams() else: # ensure streams is in streams_dict format try: # quack streams.keys() list(streams.values())[0].keys() except AttributeError: streams = streams_dict_from_streams(streams) streams_dict = streams inlets = dict.fromkeys(streams_dict.keys(), {}) for source_id, streams in streams_dict.items(): if any(id_str in source_id for id_str in with_source_ids): for stream_type, stream in streams.items(): if any(type_str in stream_type for type_str in with_types): inlets[source_id][stream_type] = lsl.StreamInlet(stream) # make sure no empty devices are included following inclusion rules inlets = { source_id: inlets for source_id, inlets in inlets.items() if not inlets == {} } if inlets == {}: print("No inlets created based on the available streams/given rules") return inlets
def connect_lsl_receiver_eeg(): global lsl_inlet_eeg print('lsl connect receiver of EEG-Data (from NeurOne)...', end='') stream_infos = [] while len(stream_infos) == 0: stream_infos = lsl.resolve_stream('name', LSL_RECEIVER_EEG_NAME) if len(stream_infos) > 1: print('WARNING: more than one stream from NeurOne found.') lsl_inlet_eeg = lsl.StreamInlet(stream_infos[0]) print('[done]')
def connect_lsl_receiver_labels(): global lsl_inlet_labels print('lsl connect receiver of labels (from UnityGame)...', end='') stream_infos = [] while len(stream_infos) == 0: stream_infos = lsl.resolve_stream('name', LSL_RECEIVER_LABELS_NAME) if len(stream_infos) > 1: print('WARNING: more than one stream from Unity game found.') lsl_inlet_labels = lsl.StreamInlet(stream_infos[0]) print('[done]')
def look_for_markers_stream(): """returns an inlet for the first markers stream outlet if found.""" print("looking for a Markers stream") marker_streams = pylsl.resolve_byprop('name', 'Markers', timeout=2) if marker_streams: marker_inlet = pylsl.StreamInlet(marker_streams[0]) return marker_inlet else: print("Can't find Markers stream") return 0
def connect(self): """Connect to the data source.""" # Streams can be queried by name, type (xdf file format spec), and # other metadata. # NOTE: According to the documentation this is a blocking call that can # only be performed on the main thread in Linux systems. So far testing # seems fine when done in a separate multiprocessing.Process. eeg_streams = pylsl.resolve_stream('type', 'EEG') marker_streams = pylsl.resolve_stream('type', 'Markers') assert eeg_streams, "One or more EEG streams must be present" assert marker_streams, "One or more Marker streams must be present" self._inlet = pylsl.StreamInlet(eeg_streams[0]) self._marker_inlets = [pylsl.StreamInlet(inlet) for inlet in marker_streams] # initialize the current_markers for each marker stream. for inlet in self._marker_inlets: self.current_markers[inlet_name(inlet)] = Marker.empty()
def peek(stream_name): """ Connects to the specified stream and checks if it outputs samples """ # TODO This functionality does not work yet stream = pylsl.resolve_byprop('name', stream_name)[0] if stream: inlet = pylsl.StreamInlet(stream) time.sleep(3) try: while True: sample, time_stamp = inlet.pull_sample(timeout=0) print('[%d] %s' % (time_stamp, sample)) except KeyboardInterrupt: print('Terminating peek')