diff --git a/eegnb/devices/eeg.py b/eegnb/devices/eeg.py index e3e872b8..f1581f66 100644 --- a/eegnb/devices/eeg.py +++ b/eegnb/devices/eeg.py @@ -18,6 +18,8 @@ from muselsl import stream, list_muses, record, constants as mlsl_cnsts from pylsl import StreamInfo, StreamOutlet, StreamInlet, resolve_byprop +from serial import Serial, EIGHTBITS, PARITY_NONE, STOPBITS_ONE + from eegnb.devices.utils import ( get_openbci_usb, create_stim_array, @@ -108,6 +110,9 @@ def initialize_backend(self): self._muse_get_recent() elif self.backend == "kernelflow": self._init_kf() + elif self.backend == "serialport": + self._init_serial() + def _get_backend(self, device_name): if device_name in brainflow_devices: @@ -116,6 +121,8 @@ def _get_backend(self, device_name): return "muselsl" elif device_name in ["kernelflow"]: return "kernelflow" + elif device_name in ["biosemi"]: + return "serialport" ##################### @@ -554,7 +561,51 @@ def _kf_sendeventinfo(self, event_info): event_info_pack = json.dumps(event_info).encode("utf-8") msg = struct.pack("!I", len(event_info_pack)) + event_info_pack self.kf_socket.sendall(msg) - + + + + ########################### + # Serial Port Function # + ########################### + + + def _init_serial(self): + if self.serial_port: # if a port name is supplied, open a serial port. + self.serial = self._serial_open_port(PORT_ID=self.serial_port) + # (otherwise, don't open; assuming serial obj will be + # manually added) + + + def _serial_push_sample(self, marker, clearandflush=True, pulse_ms=5): + + if not (0 <= marker <= 255): raise ValueError("marker code must be 045255") + self.serial.write(bytes([marker])) + if clearandflush: + self.serial.flush() # push immediately + sleep(pulse_ms / 1000.0) + self.serial.write(b"\x00") # clear back to zero + self.serial.flush() + + + def _serial_open_port(self,PORT_ID="COM4", BAUD=115200): + """ + PORT_ID = "COM4" # Example of a stimulus delivery computer USB out port name + # on windows it should be sth like # PORT_ID = "COM4" + # on linux it should be sth like # PORT_ID = "/dev/ttyUSB0" + # on macOS it should be sth like # PORT_ID = "/dev/tty.usbserial-XXXX" + BAUD = 115200 # -> This matches BioSemi ActiView's serial settings + """ + my_serial = Serial(PORT_ID, BAUD, bytesize=EIGHTBITS, parity=PARITY_NONE, + stopbits=STOPBITS_ONE, timeout=0, write_timeout=0) + + print("\nOpened Serial Port %s\n" %PORT_ID) + + return my_serial + + + + + ################################# # Highlevel device functions # @@ -576,6 +627,9 @@ def start(self, fn, duration=None): self._start_muse(duration) elif self.backend == "kernelflow": self._start_kf() + elif self.backend == "serialport": + pass + def push_sample(self, marker, timestamp, marker_name=None): """ @@ -591,6 +645,9 @@ def push_sample(self, marker, timestamp, marker_name=None): self._muse_push_sample(marker=marker, timestamp=timestamp) elif self.backend == "kernelflow": self._kf_push_sample(marker=marker,timestamp=timestamp, marker_name=marker_name) + elif self.backend == "serialport": + self._serial_push_sample(marker=marker) + def stop(self): if self.backend == "brainflow": diff --git a/eegnb/devices/utils.py b/eegnb/devices/utils.py index de5f3f9b..38579196 100644 --- a/eegnb/devices/utils.py +++ b/eegnb/devices/utils.py @@ -27,7 +27,8 @@ "notion2": BoardShim.get_eeg_names(BoardIds.NOTION_2_BOARD.value), "crown": BoardShim.get_eeg_names(BoardIds.CROWN_BOARD.value), "freeeeg32": [f"eeg_{i}" for i in range(0, 32)], - "kernelflow": [] + "kernelflow": [], + "biosemi": [], } BRAINFLOW_CHANNELS = { @@ -58,6 +59,7 @@ "crown": BoardShim.get_eeg_channels(BoardIds.CROWN_BOARD.value), "freeeeg32": BoardShim.get_eeg_channels(BoardIds.FREEEEG32_BOARD.value), "kernelflow": [], + "biosemi": [], } SAMPLE_FREQS = { @@ -81,6 +83,7 @@ "crown": BoardShim.get_sampling_rate(BoardIds.CROWN_BOARD.value), "freeeeg32": BoardShim.get_sampling_rate(BoardIds.FREEEEG32_BOARD.value), "kernelflow": [], + "biosemi": [], } diff --git a/eegnb/experiments/Experiment.py b/eegnb/experiments/Experiment.py index 87ccaaae..c2a006cc 100644 --- a/eegnb/experiments/Experiment.py +++ b/eegnb/experiments/Experiment.py @@ -130,8 +130,8 @@ def setup(self, instructions=True): # Checking for EEG to setup the EEG stream if self.eeg: - # If no save_fn passed, generate a new unnamed save file - if self.save_fn is None: + # If no save_fn passed, and data is being streamed, generate a new unnamed save file + if self.save_fn is None and self.eeg.backend not in ['serialport', 'kernelflow']: # Generating a random int for the filename random_id = random.randint(1000,10000) # Generating save function @@ -316,13 +316,12 @@ def run(self, instructions=True): # Setup the experiment self.setup(instructions) - print("Wait for the EEG-stream to start...") - # Start EEG Stream, wait for signal to settle, and then pull timestamp for start point if self.eeg: - self.eeg.start(self.save_fn, duration=self.record_duration + 5) - - print("EEG Stream started") + if self.eeg.backend not in ['serialport']: + print("Wait for the EEG-stream to start...") + self.eeg.start(self.save_fn, duration=self.record_duration + 5) + print("EEG Stream started") # Record experiment until a key is pressed or duration has expired. record_start_time = time()