Skip to content

Commit ac2ff3e

Browse files
authored
Merge pull request #961 from OpenBCI/focus-widget-2021
Focus widget 2021
2 parents 1064545 + a13ba33 commit ac2ff3e

13 files changed

+896
-49
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
# v5.0.5
2+
3+
### Improvements
4+
* Implement Focus Widget using BrainFlow Metrics
5+
6+
### Bug Fixes
7+
* Fix Y axis Autoscale in TimeSeries when all values are less than zero. Example: Cyton with filters off
8+
19
# v5.0.4
210

311
### Improvements
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import argparse
2+
import time
3+
import numpy as np
4+
import brainflow
5+
from brainflow.board_shim import BoardShim, BrainFlowInputParams, LogLevels, BoardIds
6+
from brainflow.data_filter import DataFilter, FilterTypes, AggOperations
7+
from pylsl import StreamInfo, StreamOutlet
8+
9+
#from queue import Queue
10+
BoardShim.enable_dev_board_logger()
11+
params = BrainFlowInputParams()
12+
params.serial_port = '/dev/cu.usbserial-DM00D7TW'
13+
board = BoardShim(BoardIds.CYTON_BOARD.value, params) # added cyton board id here
14+
srate = board.get_sampling_rate(BoardIds.CYTON_BOARD.value)
15+
board.prepare_session()
16+
board.start_stream()
17+
eeg_chan = BoardShim.get_eeg_channels(BoardIds.CYTON_BOARD.value)
18+
aux_chan = BoardShim.get_accel_channels(BoardIds.CYTON_BOARD.value)
19+
20+
print('EEG channels:')
21+
print(eeg_chan)
22+
print('Accelerometer channels')
23+
print(aux_chan)
24+
25+
# define lsl streams
26+
27+
# Defining stream info:
28+
name = 'OpenBCIEEG'
29+
ID = 'OpenBCIEEG'
30+
channels = 8
31+
sample_rate = 250
32+
datatype = 'float32'
33+
streamType = 'EEG'
34+
35+
print(f"Creating LSL stream for EEG. \nName: {name}\nID: {ID}\n")
36+
info_eeg = StreamInfo(name, streamType, channels, sample_rate, datatype, ID)
37+
chns = info_eeg.desc().append_child("channels")
38+
for label in ["AFp1", "AFp2", "C3", "C4", "P7", "P8", "O1", "O2"]:
39+
ch = chns.append_child("channel")
40+
ch.append_child_value("label", label)
41+
info_aux = StreamInfo('OpenBCIAUX', 'AUX', 3, 250, 'float32', 'OpenBCItestAUX')
42+
chns = info_aux.desc().append_child("channels")
43+
for label in ["X", "Y", "Z"]:
44+
ch = chns.append_child("channel")
45+
ch.append_child_value("label", label)
46+
outlet_aux = StreamOutlet(info_aux)
47+
outlet_eeg = StreamOutlet(info_eeg)
48+
49+
# construct a numpy array that contains only eeg channels and aux channels with correct scaling
50+
# this streams to lsl
51+
while True:
52+
data = board.get_board_data() # this gets data continiously
53+
# don't send empty data
54+
if len(data[0]) < 1 : continue
55+
eeg_data = data[eeg_chan]
56+
aux_data = data[aux_chan]
57+
#print(scaled_eeg_data)
58+
#print(scaled_aux_data)
59+
#print('------------------------------------------------------------------------------------------')
60+
eegchunk = []
61+
for i in range(len(eeg_data[0])):
62+
eegchunk.append((eeg_data[:,i]).tolist()) #scale data here
63+
outlet_eeg.push_chunk(eegchunk)
64+
auxchunk = []
65+
for i in range(len(aux_data[0])):
66+
auxchunk.append((aux_data[:,i]).tolist()) #scale data here
67+
outlet_aux.push_chunk(auxchunk)

OpenBCI_GUI/ADS1299SettingsController.pde

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ class ADS1299SettingsController {
218218
resizeDropdowns(chanBar_h);
219219

220220
resizeCustomCommandUI();
221+
221222
}
222223

223224
//Returns true if board and UI are in sync
@@ -382,10 +383,10 @@ class ADS1299SettingsController {
382383
}
383384

384385
private void createCustomCommandUI() {
385-
final Textfield _tf = hwsCp5.addTextfield("customCommand")
386+
customCommandTF = hwsCp5.addTextfield("customCommand")
386387
.setPosition(0, 0)
387388
.setCaptionLabel("")
388-
.setSize(10, 10)
389+
.setSize(120, 20)
389390
.setFont(f2)
390391
.setFocus(false)
391392
.setColor(color(26, 26, 26))
@@ -398,22 +399,21 @@ class ADS1299SettingsController {
398399
.align(5, 10, 20, 40)
399400
.setAutoClear(false) //Don't clear textfield when pressing Enter key
400401
;
401-
_tf.setDescription("Type a custom command and Send to board.");
402+
customCommandTF.setDescription("Type a custom command and Send to board.");
402403
//Clear textfield on double click
403-
_tf.onDoublePress(new CallbackListener() {
404+
customCommandTF.onDoublePress(new CallbackListener() {
404405
public void controlEvent(CallbackEvent theEvent) {
405406
output("[ExpertMode] Enter the custom command you would like to send to the board.");
406-
_tf.clear();
407+
customCommandTF.clear();
407408
}
408409
});
409-
_tf.addCallback(new CallbackListener() {
410+
customCommandTF.addCallback(new CallbackListener() {
410411
public void controlEvent(CallbackEvent theEvent) {
411412
if ((theEvent.getAction() == ControlP5.ACTION_BROADCAST) || (theEvent.getAction() == ControlP5.ACTION_LEAVE)) {
412-
_tf.setFocus(false);
413+
customCommandTF.setFocus(false);
413414
}
414415
}
415416
});
416-
customCommandTF = _tf;
417417

418418
sendCustomCmdButton = createButton(hwsCp5, "sendCustomCommand", "Send Custom Command", 0, 0, 10, 10);
419419
sendCustomCmdButton.setBorderColor(OBJECT_BORDER_GREY);
@@ -434,7 +434,7 @@ class ADS1299SettingsController {
434434
resizeCustomCommandUI();
435435
}
436436

437-
private void resizeCustomCommandUI() {
437+
public void resizeCustomCommandUI() {
438438
customCmdUI_x = x;
439439
customCmdUI_w = w + 1;
440440
int tf_w = Math.round(button_w * 1.8);
@@ -445,7 +445,8 @@ class ADS1299SettingsController {
445445
//int tf_w = Math.round((customCmdUI_w - padding_3*2) * .75);
446446
int tf_h = commandBarH - padding_3*2;
447447
customCommandTF.setPosition(tf_x, tf_y);
448-
customCommandTF.setSize(tf_w, tf_h);
448+
customCommandTF.setWidth(tf_w);
449+
customCommandTF.setHeight(tf_h);
449450
int but_x = tf_x + customCommandTF.getWidth() + padding_3;
450451
sendCustomCmdButton.setPosition(but_x, tf_y);
451452
sendCustomCmdButton.setSize(but_w, tf_h - 1);

OpenBCI_GUI/DataProcessing.pde

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ void processNewData() {
3333

3434
//update the data buffers
3535
for (int Ichan=0; Ichan < channelCount; Ichan++) {
36-
3736
for(int i = 0; i < getCurrentBoardBufferSize(); i++) {
3837
dataProcessingRawBuffer[Ichan][i] = (float)currentData.get(i)[exgChannels[Ichan]];
3938
}

OpenBCI_GUI/FocusEnums.pde

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
/// Here are the enums used by the Focus Widget, found in W_Focus.pde
2+
3+
// color enums
4+
public enum FocusColors {
5+
GREEN, CYAN, ORANGE
6+
}
7+
8+
interface FocusEnum {
9+
public int getIndex();
10+
public String getString();
11+
}
12+
13+
public enum FocusXLim implements FocusEnum
14+
{
15+
FIVE (0, 5, "5 sec"),
16+
TEN (1, 10, "10 sec"),
17+
TWENTY (2, 20, "20 sec"),
18+
THIRTY (3, 30, "30 sec");
19+
20+
private int index;
21+
private int value;
22+
private String label;
23+
24+
private static FocusXLim[] vals = values();
25+
26+
FocusXLim(int _index, int _value, String _label) {
27+
this.index = _index;
28+
this.value = _value;
29+
this.label = _label;
30+
}
31+
32+
public int getValue() {
33+
return value;
34+
}
35+
36+
@Override
37+
public String getString() {
38+
return label;
39+
}
40+
41+
@Override
42+
public int getIndex() {
43+
return index;
44+
}
45+
46+
public static List<String> getEnumStringsAsList() {
47+
List<String> enumStrings = new ArrayList<String>();
48+
for (FocusEnum val : vals) {
49+
enumStrings.add(val.getString());
50+
}
51+
return enumStrings;
52+
}
53+
}
54+
55+
public enum FocusMetric implements FocusEnum
56+
{
57+
CONCENTRATION (0, "Concentration", BrainFlowMetrics.CONCENTRATION, "Concentrating"),
58+
RELAXATION (1, "Relaxation", BrainFlowMetrics.RELAXATION, "Relaxing");
59+
60+
private int index;
61+
private String label;
62+
private BrainFlowMetrics metric;
63+
private String idealState;
64+
65+
private static FocusMetric[] vals = values();
66+
67+
FocusMetric(int _index, String _label, BrainFlowMetrics _metric, String _idealState) {
68+
this.index = _index;
69+
this.label = _label;
70+
this.metric = _metric;
71+
this.idealState = _idealState;
72+
}
73+
74+
@Override
75+
public String getString() {
76+
return label;
77+
}
78+
79+
@Override
80+
public int getIndex() {
81+
return index;
82+
}
83+
84+
public BrainFlowMetrics getMetric() {
85+
return metric;
86+
}
87+
88+
public String getIdealStateString() {
89+
return idealState;
90+
}
91+
92+
public static List<String> getEnumStringsAsList() {
93+
List<String> enumStrings = new ArrayList<String>();
94+
for (FocusEnum val : vals) {
95+
enumStrings.add(val.getString());
96+
}
97+
return enumStrings;
98+
}
99+
}
100+
101+
public enum FocusClassifier implements FocusEnum
102+
{
103+
REGRESSION (0, "Regression", BrainFlowClassifiers.REGRESSION),
104+
KNN (1, "KNN", BrainFlowClassifiers.KNN),
105+
SVM (2, "SVM", BrainFlowClassifiers.SVM),
106+
LDA (3, "LDA", BrainFlowClassifiers.LDA);
107+
108+
private int index;
109+
private int value;
110+
private String label;
111+
private BrainFlowClassifiers classifier;
112+
113+
private static FocusClassifier[] vals = values();
114+
115+
FocusClassifier(int _index, String _label, BrainFlowClassifiers _classifier) {
116+
this.index = _index;
117+
this.label = _label;
118+
this.classifier = _classifier;
119+
}
120+
121+
@Override
122+
public String getString() {
123+
return label;
124+
}
125+
126+
@Override
127+
public int getIndex() {
128+
return index;
129+
}
130+
131+
public BrainFlowClassifiers getClassifier() {
132+
return classifier;
133+
}
134+
135+
public static List<String> getEnumStringsAsList() {
136+
List<String> enumStrings = new ArrayList<String>();
137+
for (FocusEnum val : vals) {
138+
enumStrings.add(val.getString());
139+
}
140+
return enumStrings;
141+
}
142+
}
143+
144+
public enum FocusThreshold implements FocusEnum
145+
{
146+
FIVE_TENTHS (0, .5, "0.5"),
147+
SIX_TENTHS (1, .6, "0.6"),
148+
SEVEN_TENTHS (2, .7, "0.7"),
149+
EIGHT_TENTHS (3, .8, "0.8"),
150+
NINE_TENTHS (4, .9, "0.9");
151+
152+
private int index;
153+
private float value;
154+
private String label;
155+
156+
private static FocusThreshold[] vals = values();
157+
158+
FocusThreshold(int _index, float _value, String _label) {
159+
this.index = _index;
160+
this.value = _value;
161+
this.label = _label;
162+
}
163+
164+
public float getValue() {
165+
return value;
166+
}
167+
168+
@Override
169+
public String getString() {
170+
return label;
171+
}
172+
173+
@Override
174+
public int getIndex() {
175+
return index;
176+
}
177+
178+
public static List<String> getEnumStringsAsList() {
179+
List<String> enumStrings = new ArrayList<String>();
180+
for (FocusEnum val : vals) {
181+
enumStrings.add(val.getString());
182+
}
183+
return enumStrings;
184+
}
185+
}

OpenBCI_GUI/OpenBCI_GUI.pde

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ import http.requests.*;
6565
// Global Variables & Instances
6666
//------------------------------------------------------------------------
6767
//Used to check GUI version in TopNav.pde and displayed on the splash screen on startup
68-
String localGUIVersionString = "v5.0.4";
69-
String localGUIVersionDate = "March 2021";
68+
String localGUIVersionString = "v5.0.5-alpha.3";
69+
String localGUIVersionDate = "May 2021";
7070
String guiLatestVersionGithubAPI = "https://api.github.com/repos/OpenBCI/OpenBCI_GUI/releases/latest";
7171
String guiLatestReleaseLocation = "https://github.com/OpenBCI/OpenBCI_GUI/releases/latest";
7272

@@ -724,7 +724,7 @@ void stopRunning() {
724724

725725
//halt the data collection
726726
void haltSystem() {
727-
if (!systemHasHalted) { //prevents system from halting more than once\
727+
if (!systemHasHalted) { //prevents system from halting more than once
728728
println("openBCI_GUI: haltSystem: Halting system for reconfiguration of settings...");
729729

730730
//Reset the text for the Start Session buttonscreen. Skip when reiniting board while already in playback mode session.
@@ -736,6 +736,10 @@ void haltSystem() {
736736
w_networking.stopNetwork();
737737
println("openBCI_GUI: haltSystem: Network streams stopped");
738738
}
739+
740+
if (w_focus != null) {
741+
w_focus.endSession();
742+
}
739743

740744
stopRunning(); //stop data transfer
741745

OpenBCI_GUI/SessionSettings.pde

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ class SessionSettings {
145145

146146
//Used to set text in dropdown menus when loading Networking settings
147147
String[] nwProtocolArray = {"Serial", "LSL", "UDP", "OSC"};
148-
String[] nwDataTypesArray = {"None", "TimeSeries", "FFT", "EMG", "BandPower", "Accel/Aux", "Pulse"};
148+
String[] nwDataTypesArray = {"None", "TimeSeries", "Focus", "EMG", "BandPower", "Accel/Aux", "FFT", "Pulse"};
149149
String[] nwBaudRatesArray = {"57600", "115200", "250000", "500000"};
150150

151151
//Used to set text in dropdown menus when loading Analog Read settings

0 commit comments

Comments
 (0)