Skip to content

Commit 886c280

Browse files
Merge pull request #27 from davidmarcelbaum/device_modularity
Device modularity
2 parents 2a8400e + 3c19b00 commit 886c280

9 files changed

Lines changed: 203 additions & 298 deletions

dist/neurigui-2.81.1.tar.gz

-666 KB
Binary file not shown.

dist/neurigui-2.82.0.tar.gz

574 KB
Binary file not shown.

neuri/backend/configure_board.py

Lines changed: 3 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -7,61 +7,10 @@ class ConfigureBoard:
77
def __init__(self, parameter):
88

99
self.pm = parameter
10-
# self.search_device()
11-
self.connect_board()
12-
13-
14-
def search_device(self):
15-
# =================================================================
16-
# Scans all ports and fills av_ports with valid serial COM values
17-
# INPUT
18-
# /
19-
# OUTPUT
20-
# av_ports = Dictionnary of COM values for connection
21-
# types (object)
22-
# =================================================================
23-
24-
self.av_ports = {'USB': None, 'BT': None}
25-
26-
# Look for device
27-
# -----------------------------------------------------------------
28-
ports = list(serial.tools.list_ports.comports())
29-
30-
dummyser = serial.Serial()
31-
dummyser.baudrate = self.pm.baud_rate
32-
dummyser.timeout = 1
33-
dummyser.write_timeout = 1
34-
for port in ports:
35-
if 'UART Bridge' in port.description:
36-
self.av_ports["USB"] = port.device
37-
print('Found Helment connected via USB')
38-
continue
39-
else:
40-
# Testing for Bluetooth device
41-
dummyser.port = port.device
42-
print('Searching for Neuri via Bluetooth on ' + port.device)
43-
dummyser.open()
44-
try:
45-
time.sleep(1)
46-
dummyser.write(bytes(str(int(3)), 'utf-8')) # Force BT state on board
47-
for _ in range(1000):
48-
line = str(dummyser.readline())
49-
if '{"c1":' in line and '"c2":' in line:
50-
self.av_ports["BT"] = port.device
51-
print('Found Helment connected via Bluetooth')
52-
break
53-
except:
54-
pass
55-
dummyser.read(dummyser.inWaiting()) # Eliminate message queue at port
56-
dummyser.close() # Necessary to lierate board
57-
58-
if all(val == None for val in list(self.av_ports.values())):
59-
raise Exception('Device could not be found')
60-
else:
61-
print(self.av_ports)
10+
self.define_connection()
6211

6312

64-
def connect_board(self):
13+
def define_connection(self):
6514
# =================================================================
6615
# Connects to device, preferrably by USB
6716
# INPUT
@@ -79,41 +28,4 @@ def connect_board(self):
7928
self.ser.baudrate = self.pm.baud_rate
8029
self.ser.timeout = self.pm.time_out
8130
self.ser.port = self.pm.port
82-
str_comtype = 'Board prepared to receive input'
83-
print(str_comtype)
84-
85-
# self.inform_board(self.pm.firmfeedback)
86-
87-
88-
def inform_board(self, state):
89-
90-
if state == 0: # "Non-sense" mode (sends defined string)
91-
print('Asking if board alive')
92-
elif state == 1: # Standby mode of the board
93-
print('Putting board to standby. Waiting for new state...')
94-
elif state == 2: # Start sampling
95-
print('Preparing sampling via USB')
96-
elif state == 3: # Start sampling
97-
print('Preparing sampling via Bluetooth')
98-
elif state == 4: # Configuration mode
99-
print('Not implemented: Send configuration')
100-
elif state == 5: # Reset device
101-
print('Resetting device')
102-
103-
# Make board aware of key press: Set state of board
104-
self.ser.open() # Resets automatically the board
105-
time.sleep(1)
106-
state = bytes(str(state), 'utf-8')
107-
self.ser.write(state)
108-
self.ser.read(self.ser.inWaiting()) # Eliminate message queue at port
109-
self.ser.close()
110-
print('Communicated changes to board')
111-
112-
113-
def reconfigure(self, cong_string):
114-
# Apply firmware config to board
115-
pass
116-
117-
def end_session(self):
118-
# Close down all processes and conections and terminate script
119-
pass
31+
print('Ready to connect to board')

neuri/backend/signal_sampling.py

Lines changed: 93 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def __init__(self, parameter):
2626
file.close() # Important for data to get written
2727

2828

29-
def bin_to_voltage(self, s_bin, pga):
29+
def bin_to_voltage(self, s_bin, pga, board_code):
3030
# =================================================================
3131
# Convert binary into volts
3232
# Input
@@ -36,29 +36,36 @@ def bin_to_voltage(self, s_bin, pga):
3636
# Output
3737
# - voltage Float (microvolts)
3838
# =================================================================
39-
s_bin = int(s_bin) # requieres int
40-
sign_bit = 0
41-
if s_bin == 0:
42-
return 0
43-
if s_bin > 0 and s_bin <= 8388607:
44-
sign_bit = s_bin
45-
elif s_bin > 8388607 and s_bin <= 2*8388607:
46-
sign_bit = -2*8388607 + s_bin - 1
39+
40+
if board_code == 1:
41+
return s_bin
4742
else:
48-
print('sign_bit not assigned, returning 0')
49-
50-
voltage = (4.5*sign_bit)/(pga*8388607.0)
51-
voltage = voltage * 1000000 # Convert to microvolts
43+
s_bin = int(s_bin) # requieres int
44+
sign_bit = 0
45+
if s_bin == 0:
46+
return 0
47+
if s_bin > 0 and s_bin <= 8388607:
48+
sign_bit = s_bin
49+
elif s_bin > 8388607 and s_bin <= 2*8388607:
50+
sign_bit = -2*8388607 + s_bin - 1
51+
else:
52+
print('sign_bit not assigned, returning 0')
53+
54+
voltage = (4.5*sign_bit)/(pga*8388607.0)
55+
voltage = voltage * 1000000 # Convert to microvolts
5256

53-
#voltage = random.randrange(-200, 200)
54-
return voltage
57+
#voltage = random.randrange(-200, 200)
58+
return voltage
5559

5660

57-
def channel_assignment(self, str_message, s_chans):
61+
def messge_to_samples(self, str_message, s_chans, board_code):
5862
# -----------------------------------------------------------------
5963
# Extract samples from board
6064
# Input
61-
# str_message Raw message string coming from board
65+
# str_message (str) Raw message string coming from board
66+
# s_chans (int) How many channels shall the samples be
67+
# assigned to
68+
# board code (int) Defines code pipeline based on board type
6269
# Default in case of faulty message
6370
eeg_array = expand_dims(
6471
array([0] * s_chans, dtype=float), # Crucial to set float
@@ -68,66 +75,83 @@ def channel_assignment(self, str_message, s_chans):
6875
# eeg_valid Boolean whether workable data or not
6976
# -----------------------------------------------------------------
7077

71-
str_message = str_message[
72-
str_message.find('{'):str_message.find('}')+1]
73-
74-
# Build Python dictionnary
75-
try:
76-
chanDict = loads(str_message)
77-
except decoder.JSONDecodeError:
78-
# Corrupt message: not all channels present
79-
print("Skipped message")
80-
return eeg_array, eeg_valid
81-
82-
if len(chanDict) != s_chans:
78+
if board_code == 0: # Neuri board
79+
str_message = str_message[
80+
str_message.find('{'):str_message.find('}')+1]
81+
82+
# Build Python dictionnary
83+
try:
84+
chanDict = loads(str_message)
85+
except decoder.JSONDecodeError:
86+
# Corrupt message: not all channels present
87+
print("Skipped message")
88+
return eeg_array, eeg_valid
89+
90+
if len(chanDict) != s_chans:
91+
return eeg_array, eeg_valid
92+
93+
eeg_array = expand_dims(
94+
fromiter(chanDict.values(), dtype=float), # Crucial to set float
95+
axis=1)
96+
eeg_valid = True
97+
8398
return eeg_array, eeg_valid
8499

85-
eeg_array = expand_dims(
86-
fromiter(chanDict.values(), dtype=float), # Crucial to set float
87-
axis=1)
88-
eeg_valid = True
89-
90-
return eeg_array, eeg_valid
91-
92-
93-
def fetch_sample(self, receiver, transmitter, parameter, shared_buffer, shared_timestamp, gui_running):
100+
elif board_code == 1: # Upside Down Labs
101+
str_message = str_message.replace("b'", "")
102+
str_message = str_message.replace("\\r\\n\'", "")
103+
104+
try:
105+
eeg_array[0, 0] = float(str_message)
106+
except ValueError:
107+
return eeg_array, eeg_valid
108+
109+
eeg_valid = True
110+
return eeg_array, eeg_valid
111+
94112

95-
if parameter.firmfeedback == 2: # USB
113+
def setup_neuri_board(self, receiver, start_code):
114+
# TO-DO: These functions below do not empty the buffer at the
115+
# port as they are supposed to do
116+
receiver.flush()
117+
receiver.reset_input_buffer()
118+
receiver.reset_output_buffer()
119+
receiver.write(bytes(str(start_code), 'utf-8'))
120+
121+
board_booting = True
122+
print('Board is booting up ...')
123+
while board_booting:
124+
raw_message = str(receiver.readline())
125+
print(raw_message)
126+
if 'Listening ...' in raw_message:
127+
receiver.write(bytes(str(start_code), 'utf-8')) # Try again
128+
sleep(1)
129+
elif '{' in raw_message and '}' in raw_message:
130+
print('Fully started')
131+
board_booting = False
132+
133+
134+
def fetch_sample(self, receiver, transmitter, parameter, shared_buffer,
135+
shared_timestamp, gui_running):
136+
137+
if "Neuri" in parameter.board:
138+
board_code = 0
96139
s_per_buffer = 1
140+
if parameter.start_code == 3:
141+
s_per_buffer = 10
142+
print('Ordered board to send data via Bluetooth. Switching mode ...')
143+
elif "EXG Pill" in parameter.board:
144+
s_per_buffer = 1 # all boards
145+
board_code = 1
97146
print('Ordered board to send data via USB. Switching mode ...')
98-
elif parameter.firmfeedback == 3: # Bluetooth
99-
s_per_buffer = 10
100-
print('Ordered board to send data via Bluetooth. Switching mode ...')
101-
102-
if receiver.port == '':
103-
raise Exception('Verify that desired connection type (USB or Bluetooth) are indeed available')
104147

105148
with receiver as r:
106149

107150
# Open communication ----------------------------------------------
108151
sleep(1)
109152

110-
# TO-DO: These functions below do not empty the buffer at the
111-
# port as they are supposed to do
112-
r.flush()
113-
r.reset_input_buffer()
114-
r.reset_output_buffer()
115-
116-
r.write(bytes(str(parameter.firmfeedback), 'utf-8'))
117-
# time.sleep(1)
118-
119-
board_booting = True
120-
print('Board is booting up ...')
121-
while board_booting:
122-
raw_message = str(r.readline())
123-
print(raw_message)
124-
if 'Listening ...' in raw_message:
125-
r.write(bytes(str(parameter.firmfeedback), 'utf-8')) # Try again
126-
sleep(1)
127-
elif '{' in raw_message and '}' in raw_message:
128-
print('Fully started')
129-
board_booting = False
130-
153+
if board_code == 0:
154+
self.setup_neuri_board(r, parameter.start_code)
131155

132156
# Prealloate values of loop ---------------------------------------
133157
start_time = int(perf_counter() * 1000)
@@ -162,7 +186,8 @@ def fetch_sample(self, receiver, transmitter, parameter, shared_buffer, shared_t
162186

163187
raw_message = str(r.readline())
164188

165-
buffer_in, valid_eeg = self.channel_assignment(raw_message, s_chans)
189+
buffer_in, valid_eeg = self.messge_to_samples(
190+
raw_message, s_chans, board_code)
166191

167192
if not valid_eeg:
168193
# TO-DO: Implement an interpolation system
@@ -186,7 +211,7 @@ def fetch_sample(self, receiver, transmitter, parameter, shared_buffer, shared_t
186211

187212
# Convert binary to voltage values
188213
for iBin in range(s_chans):
189-
sample[iBin] = self.bin_to_voltage(sample[iBin], pga)
214+
sample[iBin] = self.bin_to_voltage(sample[iBin], pga, board_code)
190215
relay_array["".join(["c", str(iBin+1)])] = str(sample[iBin])
191216

192217
update_buffer = concatenate((buffer, expand_dims(sample, 1)), axis=1)
@@ -202,7 +227,6 @@ def fetch_sample(self, receiver, transmitter, parameter, shared_buffer, shared_t
202227
# Update shared memory allocations for frontend
203228
shared_buffer[:] = reshape(buffer, buffer.size) # Has left edge for filtering
204229
shared_timestamp.value = time_stamp_now
205-
# pipe_conn.put((buffer, time_stamp_now))
206230

207231
# Write out samples to file -----------------------------------
208232
if sample_count == saving_interval:

0 commit comments

Comments
 (0)