Skip to content

Commit

Permalink
Merge pull request #651 from OpenBCI/development
Browse files Browse the repository at this point in the history
Development 4.1.7 -> Master
  • Loading branch information
retiutut authored Nov 26, 2019
2 parents 6a258db + 3857cd6 commit 0618d59
Show file tree
Hide file tree
Showing 55 changed files with 7,551 additions and 7,819 deletions.
35 changes: 35 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,38 @@
# v4.1.7
Use OpenBCIHub v2.1.0 please.

## Beta 3

### Bug Fixes
* Update graphica library so GUI sessions load faster on Mac #630
* Catch Invalid Playback File Exception #649

### Improvements
* Add LSL FFT example Python sketch

## Beta 2

### Improvements
* Add prominent time display for all data modes #635
* Add button for Networking Data Ouputs Guide #643
* Add button to open Sample Data file directory #645

### Bug Fixes
* BandPower: Activate all channels by default #634
* Fix streaming 16ch Filtered TimeSeries w/ high sample rate #638 Ty @Joe-Westra
* Cp5 error in networking stops session init #642 #637 #622
* Check internet connection on app start to avoid GUI crashing #555

## Beta 0

### Improvements
* Dropped Packet Interpolation!
* Make UDPx3 default Transfer protocol Cyton+Wifi

### Bug Fixes
* Playback mode update and bug fixes #633
* Update channelSelect in BandPower and SSVEP widgets when new playback file is loaded

# v4.1.6
Use OpenBCIHub v2.1.0 please.

Expand Down
40 changes: 40 additions & 0 deletions Networking-Test-Kit/LSL/lslStreamTest_FFTplot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
### Run the OpenBCI GUI
### Set Networking mode to LSL, FFT data type, and # Chan to 125
### Thanks to @Sentdex - Nov 2019
from pylsl import StreamInlet, resolve_stream
import numpy as np
import time
import matplotlib.pyplot as plt
from matplotlib import style
from collections import deque


last_print = time.time()
fps_counter = deque(maxlen=150)

# first resolve an EEG stream on the lab network
print("looking for an EEG stream...")
streams = resolve_stream('type', 'EEG')
# create a new inlet to read from the stream
inlet = StreamInlet(streams[0])

channel_data = {}

for i in range(5): # how many iterations. Eventually this would be a while True

for i in range(16): # each of the 16 channels here
sample, timestamp = inlet.pull_sample()
if i not in channel_data:
channel_data[i] = sample
else:
channel_data[i].append(sample)

fps_counter.append(time.time() - last_print)
last_print = time.time()
cur_raw_hz = 1/(sum(fps_counter)/len(fps_counter))
print(cur_raw_hz)


for chan in channel_data:
plt.plot(channel_data[chan][:60])
plt.show()
85 changes: 56 additions & 29 deletions OpenBCI_GUI/ControlPanel.pde
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ Button autoSessionName; // Reuse these buttons for Cyton and Ganglion
Button outputBDF;
Button outputODF;

Button sampleDataButton; // Used to easily find GUI sample data for Playback mode #645

Button chanButton8;
Button chanButton16;
Button selectPlaybackFile;
Expand Down Expand Up @@ -173,10 +175,10 @@ public void controlEvent(ControlEvent theEvent) {
latencyCyton10ms.setColorNotPressed(isSelected_color);
latencyCyton20ms.setColorNotPressed(colorNotPressed);
hub.setLatency(LATENCY_10_MS);
wifiInternetProtocolCytonTCP.setColorNotPressed(isSelected_color);
wifiInternetProtocolCytonTCP.setColorNotPressed(colorNotPressed);
wifiInternetProtocolCytonUDP.setColorNotPressed(colorNotPressed);
wifiInternetProtocolCytonUDPBurst.setColorNotPressed(colorNotPressed);
hub.setWifiInternetProtocol(TCP);
wifiInternetProtocolCytonUDPBurst.setColorNotPressed(isSelected_color);
hub.setWifiInternetProtocol(UDP_BURST);
hub.setWiFiStyle(WIFI_DYNAMIC);
wifiIPAddressDynamic.setColorNotPressed(isSelected_color);
wifiIPAddressStatic.setColorNotPressed(colorNotPressed);
Expand Down Expand Up @@ -249,32 +251,32 @@ public void controlEvent(ControlEvent theEvent) {
}
}

//Check for event in PlaybackHistory Widget MenuList
if (eegDataSource == DATASOURCE_PLAYBACKFILE) {
if(theEvent.isFrom("playbackMenuList")) {
//Check to make sure value of clicked item is in valid range. Fixes #480
float valueOfItem = theEvent.getValue();
if (valueOfItem < 0 || valueOfItem > (((MenuList)theEvent.getController()).items.size() - 1) ) {
//println("CP: No such item " + value + " found in list.");
} else {
Map m = ((MenuList)theEvent.getController()).getItem(int(valueOfItem));
//println("got a menu event from item " + value + " : " + m);
userSelectedPlaybackMenuList(m.get("copy").toString(), int(valueOfItem));
}
//Check for event in PlaybackHistory Dropdown List in Control Panel
if (theEvent.isFrom("recentFiles")) {
int s = (int)(theEvent.getController()).getValue();
//println("got a menu event from item " + s);
String filePath = controlPanel.recentPlaybackBox.longFilePaths.get(s);
if (new File(filePath).isFile()) {
playbackFileSelected(filePath, s);
} else {
outputError("Playback History: Selected file does not exist. Try another file or clear settings to remove this entry.");
}
}

//Check control events from widgets
if (systemMode >= SYSTEMMODE_POSTINIT) {
//Check for event in PlaybackHistory Dropdown List in Control Panel
if (theEvent.isFrom("recentFiles")) {
int s = (int)(theEvent.getController()).getValue();
//println("got a menu event from item " + s);
String filePath = controlPanel.recentPlaybackBox.longFilePaths.get(s);
if (new File(filePath).isFile()) {
playbackFileSelected(filePath, s);
} else {
outputError("Playback History: Selected file does not exist. Try another file or clear settings to remove this entry.");
//Check for event in PlaybackHistory Widget MenuList
if (eegDataSource == DATASOURCE_PLAYBACKFILE) {
if(theEvent.isFrom("playbackMenuList")) {
//Check to make sure value of clicked item is in valid range. Fixes #480
float valueOfItem = theEvent.getValue();
if (valueOfItem < 0 || valueOfItem > (((MenuList)theEvent.getController()).items.size() - 1) ) {
//println("CP: No such item " + value + " found in list.");
} else {
Map m = ((MenuList)theEvent.getController()).getItem(int(valueOfItem));
//println("got a menu event from item " + value + " : " + m);
userSelectedPlaybackMenuList(m.get("copy").toString(), int(valueOfItem));
}
}
}
//Check for event in band power channel select checkBoxes, if needed
Expand Down Expand Up @@ -1083,6 +1085,10 @@ class ControlPanel {
selectSDFile.setIsActive(true);
selectSDFile.wasPressed = true;
}
if (sampleDataButton.isMouseHere()) {
sampleDataButton.setIsActive(true);
sampleDataButton.wasPressed = true;
}
}

//active buttons during DATASOURCE_SYNTHETIC
Expand Down Expand Up @@ -1502,7 +1508,9 @@ class ControlPanel {

if (selectPlaybackFile.isMouseHere() && selectPlaybackFile.wasPressed) {
output("Select a file for playback");
selectInput("Select a pre-recorded file for playback:", "playbackFileSelected");
selectInput("Select a pre-recorded file for playback:",
"playbackFileSelected",
new File(settings.guiDataPath + "Recordings"));
}

if (selectSDFile.isMouseHere() && selectSDFile.wasPressed) {
Expand All @@ -1511,6 +1519,15 @@ class ControlPanel {
selectInput("Select an SD file to convert for playback:", "sdFileSelected");
}

if (sampleDataButton.isMouseHere() && sampleDataButton.wasPressed) {
output("Select a file for playback");
selectInput("Select a pre-recorded file for playback:",
"playbackFileSelected",
new File(settings.guiDataPath +
"Sample_Data" + System.getProperty("file.separator") +
"OpenBCI-sampleData-2-meditation.txt"));
}

//reset all buttons to false
noHubShowDoc.setIsActive(false);
noHubShowDoc.wasPressed = false;
Expand Down Expand Up @@ -1595,6 +1612,8 @@ class ControlPanel {
selectPlaybackFile.wasPressed = false;
selectSDFile.setIsActive(false);
selectSDFile.wasPressed = false;
sampleDataButton.setIsActive(false);
sampleDataButton.wasPressed = false;
}
};

Expand Down Expand Up @@ -2743,7 +2762,6 @@ class RecentPlaybackBox {
StringList shortFileNames = new StringList();
StringList longFilePaths = new StringList();
private String filePickedShort = "Select Recent Playback File";

ControlP5 cp5_recentPlayback_dropdown;

RecentPlaybackBox(int _x, int _y, int _w, int _h, int _padding) {
Expand Down Expand Up @@ -2795,11 +2813,8 @@ class RecentPlaybackBox {
textAlign(LEFT, TOP);
text("PLAYBACK HISTORY", x + padding, y + padding);
popStyle();

cp5_recentPlayback_dropdown.get(ScrollableList.class, "recentFiles").setVisible(true);
pushStyle();
cp5_recentPlayback_dropdown.draw();
pushStyle();
}

private void getRecentPlaybackFiles() {
Expand Down Expand Up @@ -2877,6 +2892,8 @@ class RecentPlaybackBox {

class PlaybackFileBox {
int x, y, w, h, padding; //size and position
int sampleDataButton_w = 100;
int sampleDataButton_h = 20;

PlaybackFileBox(int _x, int _y, int _w, int _h, int _padding) {
x = _x;
Expand All @@ -2887,6 +2904,15 @@ class PlaybackFileBox {

selectPlaybackFile = new Button (x + padding, y + padding*2 + 13, w - padding*2, 24, "SELECT PLAYBACK FILE", fontInfo.buttonLabel_size);
selectPlaybackFile.setHelpText("Click to open a dialog box to select an OpenBCI playback file (.txt or .csv).");

// Sample data button
sampleDataButton = new Button(x + w - sampleDataButton_w - padding, y + padding - 2, sampleDataButton_w, sampleDataButton_h, "Sample Data", 14);
sampleDataButton.setCornerRoundess((int)(sampleDataButton_h));
sampleDataButton.setFont(p4, 14);
sampleDataButton.setColorNotPressed(color(57,128,204));
sampleDataButton.setFontColorNotActive(color(255));
sampleDataButton.setHelpText("Click to open the folder containing OpenBCI GUI Sample Data.");
sampleDataButton.hasStroke(false);
}

public void update() {
Expand All @@ -2905,6 +2931,7 @@ class PlaybackFileBox {
popStyle();

selectPlaybackFile.draw();
sampleDataButton.draw();
}
};

Expand Down
2 changes: 1 addition & 1 deletion OpenBCI_GUI/DataLogging.pde
Original file line number Diff line number Diff line change
Expand Up @@ -1548,7 +1548,7 @@ void convert8channelLine() {
}
}
dataWriter.println();
println(consoleMsg);
println("convert8channelLine: " + consoleMsg);
return;
}
for (int i=0; i<hexNums.length; i++) {
Expand Down
15 changes: 9 additions & 6 deletions OpenBCI_GUI/DataProcessing.pde
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,21 @@ void process_input_file() throws Exception {
try {
while (!hasRepeated) {
currentTableRowIndex = getPlaybackDataFromTable(playbackData_table, currentTableRowIndex, cyton.get_scale_fac_uVolts_per_count(), cyton.get_scale_fac_accel_G_per_count(), dataPacketBuff[lastReadDataPacketInd]);
if (!curTimestamp.equals("null")) {
if (curTimestamp != null) {
index_of_times.put(indices, curTimestamp.substring(1)); //remove white space from timestamp
} else {
index_of_times.put(indices, "notFound");
}
indices++;
}
println("number of indexes "+indices);
println("Finished filling hashmap");
has_processed = true;
}
catch (Exception e) {
e.printStackTrace();
throw new Exception();
}
println("number of indexes "+indices);
println("Finished filling hashmap");
has_processed = true;
}

/*************************/
Expand Down Expand Up @@ -308,14 +311,14 @@ int getPlaybackDataFromTable(Table datatable, int currentTableRowIndex, float sc
}
}
// if available, get time stamp for use in playback
if (row.getColumnCount() == nchan + NUM_ACCEL_DIMS + 2) {
if (row.getColumnCount() >= nchan + NUM_ACCEL_DIMS + 2) {
try{
if (!isOldData) curTimestamp = row.getString(row.getColumnCount() - 1);
} catch (ArrayIndexOutOfBoundsException e) {
println("Data does not exist... possibly an old file.");
}
} else {
curTimestamp = "null";
curTimestamp = "-1";
}
} //end else
return currentTableRowIndex;
Expand Down
35 changes: 35 additions & 0 deletions OpenBCI_GUI/Extras.pde
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,39 @@ String shortenString(String str, float maxWidth, PFont font) {
return s1 + "..." + s2;
}

int lerpInt(int first, int second, float bias)
{
return round(lerp(first, second, bias));
}

// creates an DataPacket_ADS1299 with interpolated values.
// the bias is a float between 0 and 1. It's the weight between the two packets.
// a bias of 0 will return packet "first"
// a bias of 1 will return packet "second"
// a bias of 0.5 will return the average of the two.
// This is exactly the behavior of a lerp() function
DataPacket_ADS1299 CreateInterpolatedPacket(DataPacket_ADS1299 first, DataPacket_ADS1299 second, float bias) {
int nValues = first.values.length;
int nAuxValues = first.auxValues.length;

DataPacket_ADS1299 interpolated = new DataPacket_ADS1299(nValues, nAuxValues);
first.copyTo(interpolated);

interpolated.interpolated = true;

for (int i=0; i < nValues; i++) {
interpolated.values[i] = lerpInt(first.values[i], second.values[i], bias);
}

for (int i=0; i < nAuxValues; i++) {
interpolated.auxValues[i] = lerpInt(first.auxValues[i], second.auxValues[i], bias);
}

interpolated.sampleIndex = lerpInt(first.sampleIndex, second.sampleIndex, bias);

return interpolated;
}

//------------------------------------------------------------------------
// Classes
//------------------------------------------------------------------------
Expand Down Expand Up @@ -231,6 +264,7 @@ class DataPacket_ADS1299 {
int[] auxValues;
byte[][] rawValues;
byte[][] rawAuxValues;
boolean interpolated;

//constructor, give it "nValues", which should match the number of values in the
//data payload in each data packet from the Arduino. This is likely to be at least
Expand All @@ -241,6 +275,7 @@ class DataPacket_ADS1299 {
auxValues = new int[nAuxValues];
rawValues = new byte[nValues][rawAdsSize];
rawAuxValues = new byte[nAuxValues][rawAdsSize];
interpolated = false; // default
}

int copyTo(DataPacket_ADS1299 target) { return copyTo(target, 0, 0); }
Expand Down
4 changes: 2 additions & 2 deletions OpenBCI_GUI/Info.plist.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<key>CFBundleShortVersionString</key>
<string>4</string>
<key>CFBundleVersion</key>
<string>4.1.6</string>
<string>4.1.7</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>NSHumanReadableCopyright</key>
Expand All @@ -32,7 +32,7 @@
Copyright © 2019 OpenBCI
</string>
<key>CFBundleGetInfoString</key>
<string>September 2019</string>
<string>November 2019</string>
<!-- End of the set that can be customized -->

@@jvm_runtime@@
Expand Down
Loading

0 comments on commit 0618d59

Please sign in to comment.