diff --git a/muselsl/__main__.py b/muselsl/__main__.py index c394339..93f9c9f 100644 --- a/muselsl/__main__.py +++ b/muselsl/__main__.py @@ -17,6 +17,7 @@ def main(): -n --name Device name (e.g. Muse-41D2). -b --backend BLE backend to use. can be auto, bluemuse, gatt or bgapi. -i --interface The interface to use, 'hci0' for gatt or a com port for bgapi. + -t --timeout Length of timeout before giving up on connecting to an identified device. -p --ppg Include PPG data -c --acc Include accelerometer data -g --gyro Include gyroscope data @@ -41,6 +42,7 @@ def main(): -n --name Device name (e.g. Muse-41D2). -b --backend BLE backend to use. can be auto, bluemuse, gatt or bgapi. -i --interface The interface to use, 'hci0' for gatt or a com port for bgapi. + -t --timeout Length of timeout before giving up on connecting to an identified device. ''') parser.add_argument('command', help='Command to run.') diff --git a/muselsl/backends.py b/muselsl/backends.py index 7045cf5..0a1afcc 100644 --- a/muselsl/backends.py +++ b/muselsl/backends.py @@ -32,15 +32,16 @@ def scan(self, timeout=10): raise bleak devices = _wait(bleak.BleakScanner.discover(timeout)) return [{'name':device.name, 'address':device.address} for device in devices] - def connect(self, address): - result = BleakDevice(self, address) + def connect(self, address, connection_timeout=None): + result = BleakDevice(self, address, connection_timeout) result.connect() return result class BleakDevice: - def __init__(self, adapter, address): + def __init__(self, adapter, address, connection_timeout=None): self._adapter = adapter - self._client = bleak.BleakClient(address) + self._timeout = connection_timeout + self._client = bleak.BleakClient(address, timeout=self._timeout) # <- CRITICAL timeout value HERE def connect(self): _wait(self._client.connect()) self._adapter.connected.add(self) diff --git a/muselsl/cli.py b/muselsl/cli.py index 13f1bc6..b557ffc 100644 --- a/muselsl/cli.py +++ b/muselsl/cli.py @@ -63,6 +63,13 @@ def stream(self): default=None, help= "The interface to use, 'hci0' for gatt or a com port for bgapi.") + parser.add_argument( + "-t", + "--timeout", + dest="timeout", + type=float, + default=10.0, + help="Length of timeout before giving up on connecting to an identified device.") parser.add_argument("-P", "--preset", type=int, @@ -104,7 +111,7 @@ def stream(self): from . import stream stream(args.address, args.backend, args.interface, args.name, args.ppg, - args.acc, args.gyro, args.disable_eeg, args.preset, args.disable_light) + args.acc, args.gyro, args.disable_eeg, args.preset, args.disable_light, args.timeout) def record(self): parser = argparse.ArgumentParser( @@ -173,6 +180,13 @@ def record_direct(self): default=None, help= "The interface to use, 'hci0' for gatt or a com port for bgapi.") + parser.add_argument( + "-t", + "--timeout", + dest="timeout", + type=float, + default=10.0, + help="Length of timeout before giving up on connecting to an identified device.") parser.add_argument( "-d", "--duration", @@ -190,7 +204,7 @@ def record_direct(self): args = parser.parse_args(sys.argv[2:]) from . import record_direct record_direct(args.duration, args.address, args.filename, args.backend, - args.interface, args.name) + args.interface, args.name, args.timeout) def view(self): parser = argparse.ArgumentParser( diff --git a/muselsl/constants.py b/muselsl/constants.py index f1981b3..f71f8ab 100644 --- a/muselsl/constants.py +++ b/muselsl/constants.py @@ -41,7 +41,7 @@ MUSE_GYRO_SCALE_FACTOR = 0.0074768 MUSE_SCAN_TIMEOUT = 10.5 -AUTO_DISCONNECT_DELAY = 3 +# AUTO_DISCONNECT_DELAY = 3 LSL_SCAN_TIMEOUT = 5 LSL_BUFFER = 360 diff --git a/muselsl/muse.py b/muselsl/muse.py index b23c3eb..a7fea4c 100644 --- a/muselsl/muse.py +++ b/muselsl/muse.py @@ -31,7 +31,8 @@ def __init__(self, time_func=time, name=None, preset=None, - disable_light=False): + disable_light=False, + timeout=None): """Initialize callback_eeg -- callback for eeg data, function(data, timestamps) @@ -45,6 +46,7 @@ def __init__(self, """ self.address = address + self.timeout = timeout self.name = name self.callback_eeg = callback_eeg self.callback_telemetry = callback_telemetry @@ -76,7 +78,7 @@ def connect(self, interface=None): else: logger.info('Connecting to %s: %s...' % (self.name if self.name else 'Muse', - self.address)) + self.address, int(self.timeout))) if self.backend == 'gatt': self.interface = self.interface or 'hci0' self.adapter = pygatt.GATTToolBackend(self.interface) @@ -87,7 +89,7 @@ def connect(self, interface=None): serial_port=self.interface) self.adapter.start() - self.device = self.adapter.connect(self.address) + self.device = self.adapter.connect(self.address, self.timeout) if(self.preset != None): self.select_preset(self.preset) diff --git a/muselsl/record.py b/muselsl/record.py index 30a41cb..bb29641 100644 --- a/muselsl/record.py +++ b/muselsl/record.py @@ -183,7 +183,8 @@ def record_direct(duration, filename=None, backend='auto', interface=None, - name=None): + name=None, + timeout=None): if backend == 'bluemuse': raise (NotImplementedError( 'Direct record not supported with BlueMuse backend. Use record after starting stream instead.' @@ -211,7 +212,8 @@ def save_eeg(new_samples, new_timestamps): eeg_samples.append(new_samples) timestamps.append(new_timestamps) - muse = Muse(address, save_eeg, backend=backend) + muse = Muse(address, save_eeg, backend=backend, timeout=timeout) + print("Recording direct received", str(timeout), "for timeout!") muse.connect() muse.start() diff --git a/muselsl/stream.py b/muselsl/stream.py index b7a2298..640ca47 100644 --- a/muselsl/stream.py +++ b/muselsl/stream.py @@ -11,7 +11,7 @@ from . import backends from . import helper from .muse import Muse -from .constants import MUSE_SCAN_TIMEOUT, AUTO_DISCONNECT_DELAY, \ +from .constants import MUSE_SCAN_TIMEOUT, \ MUSE_NB_EEG_CHANNELS, MUSE_SAMPLING_EEG_RATE, LSL_EEG_CHUNK, \ MUSE_NB_PPG_CHANNELS, MUSE_SAMPLING_PPG_RATE, LSL_PPG_CHUNK, \ MUSE_NB_ACC_CHANNELS, MUSE_SAMPLING_ACC_RATE, LSL_ACC_CHUNK, \ @@ -133,7 +133,7 @@ def stream( eeg_disabled=False, preset=None, disable_light=False, - timeout=AUTO_DISCONNECT_DELAY, + timeout=None ): # If no data types are enabled, we warn the user and return immediately. if eeg_disabled and not ppg_enabled and not acc_enabled and not gyro_enabled: @@ -216,8 +216,7 @@ def push(data, timestamps, outlet): push_gyro = partial(push, outlet=gyro_outlet) if gyro_enabled else None muse = Muse(address=address, callback_eeg=push_eeg, callback_ppg=push_ppg, callback_acc=push_acc, callback_gyro=push_gyro, - backend=backend, interface=interface, name=name, preset=preset, disable_light=disable_light) - + backend=backend, interface=interface, name=name, preset=preset, disable_light=disable_light, timeout=timeout) didConnect = muse.connect() if(didConnect):