Skip to content

Commit 0c928e6

Browse files
Merge pull request #310 from JohnGriffiths/add_serial_backend
added functionality for serial port triggers backend
2 parents e74c41d + 3ef802b commit 0c928e6

File tree

3 files changed

+68
-9
lines changed

3 files changed

+68
-9
lines changed

eegnb/devices/eeg.py

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
from muselsl import stream, list_muses, record, constants as mlsl_cnsts
1919
from pylsl import StreamInfo, StreamOutlet, StreamInlet, resolve_byprop
2020

21+
from serial import Serial, EIGHTBITS, PARITY_NONE, STOPBITS_ONE
22+
2123
from eegnb.devices.utils import (
2224
get_openbci_usb,
2325
create_stim_array,
@@ -108,6 +110,9 @@ def initialize_backend(self):
108110
self._muse_get_recent()
109111
elif self.backend == "kernelflow":
110112
self._init_kf()
113+
elif self.backend == "serialport":
114+
self._init_serial()
115+
111116

112117
def _get_backend(self, device_name):
113118
if device_name in brainflow_devices:
@@ -116,6 +121,8 @@ def _get_backend(self, device_name):
116121
return "muselsl"
117122
elif device_name in ["kernelflow"]:
118123
return "kernelflow"
124+
elif device_name in ["biosemi"]:
125+
return "serialport"
119126

120127

121128
#####################
@@ -554,7 +561,51 @@ def _kf_sendeventinfo(self, event_info):
554561
event_info_pack = json.dumps(event_info).encode("utf-8")
555562
msg = struct.pack("!I", len(event_info_pack)) + event_info_pack
556563
self.kf_socket.sendall(msg)
557-
564+
565+
566+
567+
###########################
568+
# Serial Port Function #
569+
###########################
570+
571+
572+
def _init_serial(self):
573+
if self.serial_port: # if a port name is supplied, open a serial port.
574+
self.serial = self._serial_open_port(PORT_ID=self.serial_port)
575+
# (otherwise, don't open; assuming serial obj will be
576+
# manually added)
577+
578+
579+
def _serial_push_sample(self, marker, clearandflush=True, pulse_ms=5):
580+
581+
if not (0 <= marker <= 255): raise ValueError("marker code must be 045255")
582+
self.serial.write(bytes([marker]))
583+
if clearandflush:
584+
self.serial.flush() # push immediately
585+
sleep(pulse_ms / 1000.0)
586+
self.serial.write(b"\x00") # clear back to zero
587+
self.serial.flush()
588+
589+
590+
def _serial_open_port(self,PORT_ID="COM4", BAUD=115200):
591+
"""
592+
PORT_ID = "COM4" # Example of a stimulus delivery computer USB out port name
593+
# on windows it should be sth like # PORT_ID = "COM4"
594+
# on linux it should be sth like # PORT_ID = "/dev/ttyUSB0"
595+
# on macOS it should be sth like # PORT_ID = "/dev/tty.usbserial-XXXX"
596+
BAUD = 115200 # -> This matches BioSemi ActiView's serial settings
597+
"""
598+
my_serial = Serial(PORT_ID, BAUD, bytesize=EIGHTBITS, parity=PARITY_NONE,
599+
stopbits=STOPBITS_ONE, timeout=0, write_timeout=0)
600+
601+
print("\nOpened Serial Port %s\n" %PORT_ID)
602+
603+
return my_serial
604+
605+
606+
607+
608+
558609

559610
#################################
560611
# Highlevel device functions #
@@ -576,6 +627,9 @@ def start(self, fn, duration=None):
576627
self._start_muse(duration)
577628
elif self.backend == "kernelflow":
578629
self._start_kf()
630+
elif self.backend == "serialport":
631+
pass
632+
579633

580634
def push_sample(self, marker, timestamp, marker_name=None):
581635
"""
@@ -591,6 +645,9 @@ def push_sample(self, marker, timestamp, marker_name=None):
591645
self._muse_push_sample(marker=marker, timestamp=timestamp)
592646
elif self.backend == "kernelflow":
593647
self._kf_push_sample(marker=marker,timestamp=timestamp, marker_name=marker_name)
648+
elif self.backend == "serialport":
649+
self._serial_push_sample(marker=marker)
650+
594651

595652
def stop(self):
596653
if self.backend == "brainflow":

eegnb/devices/utils.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727
"notion2": BoardShim.get_eeg_names(BoardIds.NOTION_2_BOARD.value),
2828
"crown": BoardShim.get_eeg_names(BoardIds.CROWN_BOARD.value),
2929
"freeeeg32": [f"eeg_{i}" for i in range(0, 32)],
30-
"kernelflow": []
30+
"kernelflow": [],
31+
"biosemi": [],
3132
}
3233

3334
BRAINFLOW_CHANNELS = {
@@ -58,6 +59,7 @@
5859
"crown": BoardShim.get_eeg_channels(BoardIds.CROWN_BOARD.value),
5960
"freeeeg32": BoardShim.get_eeg_channels(BoardIds.FREEEEG32_BOARD.value),
6061
"kernelflow": [],
62+
"biosemi": [],
6163
}
6264

6365
SAMPLE_FREQS = {
@@ -81,6 +83,7 @@
8183
"crown": BoardShim.get_sampling_rate(BoardIds.CROWN_BOARD.value),
8284
"freeeeg32": BoardShim.get_sampling_rate(BoardIds.FREEEEG32_BOARD.value),
8385
"kernelflow": [],
86+
"biosemi": [],
8487
}
8588

8689

eegnb/experiments/Experiment.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,8 @@ def setup(self, instructions=True):
130130

131131
# Checking for EEG to setup the EEG stream
132132
if self.eeg:
133-
# If no save_fn passed, generate a new unnamed save file
134-
if self.save_fn is None:
133+
# If no save_fn passed, and data is being streamed, generate a new unnamed save file
134+
if self.save_fn is None and self.eeg.backend not in ['serialport', 'kernelflow']:
135135
# Generating a random int for the filename
136136
random_id = random.randint(1000,10000)
137137
# Generating save function
@@ -316,13 +316,12 @@ def run(self, instructions=True):
316316
# Setup the experiment
317317
self.setup(instructions)
318318

319-
print("Wait for the EEG-stream to start...")
320-
321319
# Start EEG Stream, wait for signal to settle, and then pull timestamp for start point
322320
if self.eeg:
323-
self.eeg.start(self.save_fn, duration=self.record_duration + 5)
324-
325-
print("EEG Stream started")
321+
if self.eeg.backend not in ['serialport']:
322+
print("Wait for the EEG-stream to start...")
323+
self.eeg.start(self.save_fn, duration=self.record_duration + 5)
324+
print("EEG Stream started")
326325

327326
# Record experiment until a key is pressed or duration has expired.
328327
record_start_time = time()

0 commit comments

Comments
 (0)