Skip to content

Commit

Permalink
Merge pull request #673 from OpenBCI/development
Browse files Browse the repository at this point in the history
GUI 4.2.0
  • Loading branch information
retiutut authored Feb 1, 2020
2 parents cab9e9f + 9247cdc commit f907e6a
Show file tree
Hide file tree
Showing 15 changed files with 913 additions and 143 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
# v4.2.0
Please use OpenBCIHub v2.1.0 and Processing 4.

# Improvements
* Update to Processing 4 and Java 11! #671
* Add functional Spectrogram Widget! #416
* Clean up Marker Mode UDP listener #305
* Display "Starting Session" overlay when Start Session button is clicked #628

# v4.1.7
Use OpenBCIHub v2.1.0 please.

Expand Down
30 changes: 13 additions & 17 deletions OpenBCI_GUI/ControlPanel.pde
Original file line number Diff line number Diff line change
Expand Up @@ -1670,6 +1670,8 @@ public void initButtonPressed(){
cyton.closePort();
}
sessionName = cp5.get(Textfield.class, "fileNameCyton").getText(); // store the current text field value of "File Name" to be passed along to dataFiles
controlPanel.serialBox.autoConnect.setIgnoreHover(false); //reset the auto-connect button
controlPanel.serialBox.autoConnect.setColorNotPressed(255);
} else if(eegDataSource == DATASOURCE_GANGLION){
verbosePrint("ControlPanel — port is open: " + ganglion.isPortOpen());
if (ganglion.isPortOpen()) {
Expand All @@ -1687,13 +1689,8 @@ public void initButtonPressed(){
println("Static IP address of " + wifi_ipAddress);
}
midInit = true;
println("initButtonPressed: Calling initSystem()");
try {
initSystem(); //found in OpenBCI_GUI.pde
} catch (Exception e) {
println(e.getMessage());
haltSystem();
}
output("Attempting to Start Session...");
println("initButtonPressed: Calling initSystem() after next draw()");
}
} else {
//if system is already active ... stop session and flip button state back
Expand Down Expand Up @@ -1812,7 +1809,7 @@ class SerialBox {
h = 70;
padding = _padding;

autoConnect = new Button(x + padding, y + padding*3 + 4, w - padding*3 - 70, 24, "AUTO", fontInfo.buttonLabel_size);
autoConnect = new Button(x + padding, y + padding*3 + 4, w - padding*3 - 70, 24, "AUTO-CONNECT", fontInfo.buttonLabel_size);
autoConnect.setHelpText("Attempt to auto-connect to Cyton. Try \"Manual\" if this does not work.");
popOutRadioConfigButton = new Button(x + w - 70 - padding, y + padding*3 + 4, 70, 24,"Manual >",fontInfo.buttonLabel_size);
popOutRadioConfigButton.setHelpText("Having trouble connecting to Cyton? Click here to access Radio Configuration tools.");
Expand Down Expand Up @@ -1856,9 +1853,6 @@ class SerialBox {
if (ableToConnect(comPort, _regex)) return;
} //end for loop for all com ports

if (!openBCI_portName.equals("N/A")) {
outputError("Unable to auto-connect...");
}
} //end attempAutoConnectCyton

private boolean ableToConnect(String _comPort, String _regex) {
Expand Down Expand Up @@ -3121,13 +3115,15 @@ class RadioConfigBox {
h = 275; //255 + 20 for larger autoscan button
padding = _padding;
isShowing = false;

getChannel = new Button(x + padding, y + padding*3 + 18 + 24, (w-padding*3)/2, 24, "GET CHANNEL", fontInfo.buttonLabel_size);
systemStatus = new Button(x + padding, y + padding*2 + 18, (w-padding*3)/2, 24, "STATUS", fontInfo.buttonLabel_size);
setChannel = new Button(x + 2*padding + (w-padding*3)/2, y + padding*2 + 18, (w-padding*3)/2, 24, "CHANGE CHAN.", fontInfo.buttonLabel_size);
ovrChannel = new Button(x + 2*padding + (w-padding*3)/2, y + padding*3 + 18 + 24, (w-padding*3)/2, 24, "OVERRIDE DONGLE", fontInfo.buttonLabel_size);

//typical button height + 20 for larger autoscan button
autoscan = new Button(x + padding, y + padding*4 + 18 + 24*2, w-(padding*2), 24 + 20, "AUTOSCAN", fontInfo.buttonLabel_size);
autoscan = new Button(x + padding, y + padding + 18, w-(padding*2), 24 + 20, "AUTOSCAN", fontInfo.buttonLabel_size);
//smaller buttons below autoscan
getChannel = new Button(x + padding, y + padding*3 + 18 + 24 + 44, (w-padding*3)/2, 24, "GET CHANNEL", fontInfo.buttonLabel_size);
systemStatus = new Button(x + padding, y + padding*2 + 18 + 44, (w-padding*3)/2, 24, "STATUS", fontInfo.buttonLabel_size);
setChannel = new Button(x + 2*padding + (w-padding*3)/2, y + padding*2 + 18 + 44, (w-padding*3)/2, 24, "CHANGE CHAN.", fontInfo.buttonLabel_size);
ovrChannel = new Button(x + 2*padding + (w-padding*3)/2, y + padding*3 + 18 + 24 + 44, (w-padding*3)/2, 24, "OVERRIDE DONGLE", fontInfo.buttonLabel_size);


//Set help text
getChannel.setHelpText("Get the current channel of your Cyton and USB Dongle.");
Expand Down
27 changes: 21 additions & 6 deletions OpenBCI_GUI/DataProcessing.pde
Original file line number Diff line number Diff line change
Expand Up @@ -201,15 +201,30 @@ void synthesizeData(int nchan, float fs_Hz, float scale_fac_uVolts_per_count, Da
if (sine_phase_rad[Ichan] > 2.0f*PI) sine_phase_rad[Ichan] -= 2.0f*PI;
val_uV += 10.0f * sqrt(2.0)*sin(sine_phase_rad[Ichan]);
} else if (Ichan==2) {
//50 Hz interference at 50 uVrms
sine_phase_rad[Ichan] += 2.0f*PI * 50.0f / fs_Hz; //60 Hz
//15 Hz interference at 20 uVrms
sine_phase_rad[Ichan] += 2.0f*PI * 15.0f / fs_Hz; //15 Hz
if (sine_phase_rad[Ichan] > 2.0f*PI) sine_phase_rad[Ichan] -= 2.0f*PI;
val_uV += 50.0f * sqrt(2.0)*sin(sine_phase_rad[Ichan]); //20 uVrms
val_uV += 20.0f * sqrt(2.0)*sin(sine_phase_rad[Ichan]); //20 uVrms
} else if (Ichan==3) {
//60 Hz interference at 50 uVrms
sine_phase_rad[Ichan] += 2.0f*PI * 60.0f / fs_Hz; //50 Hz
//20 Hz interference at 30 uVrms
sine_phase_rad[Ichan] += 2.0f*PI * 20.0f / fs_Hz; //20 Hz
if (sine_phase_rad[Ichan] > 2.0f*PI) sine_phase_rad[Ichan] -= 2.0f*PI;
val_uV += 50.0f * sqrt(2.0)*sin(sine_phase_rad[Ichan]); //20 uVrms
val_uV += 30.0f * sqrt(2.0)*sin(sine_phase_rad[Ichan]); //30 uVrms
} else if (Ichan==4) {
//25 Hz interference at 40 uVrms
sine_phase_rad[Ichan] += 2.0f*PI * 25.0f / fs_Hz; //25 Hz
if (sine_phase_rad[Ichan] > 2.0f*PI) sine_phase_rad[Ichan] -= 2.0f*PI;
val_uV += 40.0f * sqrt(2.0)*sin(sine_phase_rad[Ichan]); //40 uVrms
} else if (Ichan==5) {
//30 Hz interference at 50 uVrms
sine_phase_rad[Ichan] += 2.0f*PI * 30.0f / fs_Hz; //30 Hz
if (sine_phase_rad[Ichan] > 2.0f*PI) sine_phase_rad[Ichan] -= 2.0f*PI;
val_uV += 50.0f * sqrt(2.0)*sin(sine_phase_rad[Ichan]); //50 uVrms
} else if (Ichan==6) {
//60 Hz interference at 20 uVrms
sine_phase_rad[Ichan] += 2.0f*PI * 60.0f / fs_Hz; //60 Hz
if (sine_phase_rad[Ichan] > 2.0f*PI) sine_phase_rad[Ichan] -= 2.0f*PI;
val_uV += 20.0f * sqrt(2.0)*sin(sine_phase_rad[Ichan]); //20 uVrms
}
} else {
val_uV = 0.0f;
Expand Down
4 changes: 4 additions & 0 deletions OpenBCI_GUI/Extras.pde
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ float log10(float val) {
return (float)Math.log10(val);
}

float log10(int val) {
return (float)Math.log10(val);
}

float filterWEA_1stOrderIIR(float[] filty, float learn_fac, float filt_state) {
float prev = filt_state;
for (int i=0; i < filty.length; i++) {
Expand Down
6 changes: 3 additions & 3 deletions OpenBCI_GUI/Info.plist.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,16 @@
<key>CFBundleShortVersionString</key>
<string>4</string>
<key>CFBundleVersion</key>
<string>4.1.7</string>
<string>4.2.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>NSHumanReadableCopyright</key>
<string>MIT License

Copyright © 2019 OpenBCI
Copyright © 2020 OpenBCI
</string>
<key>CFBundleGetInfoString</key>
<string>November 2019</string>
<string>January 2020</string>
<!-- End of the set that can be customized -->

@@jvm_runtime@@
Expand Down
102 changes: 48 additions & 54 deletions OpenBCI_GUI/OpenBCI_GUI.pde
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import java.text.DateFormat; //Used in DataLogging.pde
import java.text.SimpleDateFormat;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
// import java.net.InetAddress; // Used for ping, however not working right now.
import java.util.Random;
import java.awt.Robot; //used for simulating mouse clicks
Expand All @@ -60,8 +61,8 @@ import com.sun.jna.Pointer;
// Global Variables & Instances
//------------------------------------------------------------------------
//Used to check GUI version in TopNav.pde and displayed on the splash screen on startup
String localGUIVersionString = "v4.1.7";
String localGUIVersionDate = "November 2019";
String localGUIVersionString = "v4.2.0";
String localGUIVersionDate = "January 2020";
String guiLatestReleaseLocation = "https://github.com/OpenBCI/OpenBCI_GUI/releases/latest";
Boolean guiVersionCheckHasOccured = false;
DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss.SSS");
Expand All @@ -74,6 +75,7 @@ final int SYSTEMMODE_POSTINIT = 10;
int systemMode = SYSTEMMODE_INTROANIMATION; /* Modes: -10 = intro sequence; 0 = system stopped/control panel setings; 10 = gui; 20 = help guide */

boolean midInit = false;
boolean midInitCheck2 = false;
boolean abandonInit = false;
boolean systemHasHalted = false;

Expand All @@ -85,9 +87,6 @@ PImage cog;
Gif loadingGIF;
Gif loadingGIF_blue;

// ---- Define variables related to OpenBCI_GUI UDPMarker functionality
UDP udpRX;

//choose where to get the EEG data
final int DATASOURCE_CYTON = 0; // new default, data from serial with Accel data CHIP 2014-11-03
final int DATASOURCE_GANGLION = 1; //looking for signal from OpenBCI board via Serial/COM port, no Aux data
Expand Down Expand Up @@ -408,20 +407,6 @@ void delayedSetup() {

myPresentation = new Presentation();

// UDPMarker functionality
// Setup the UDP receiver // This needs to be done only when marker mode is enabled
int portRX = 51000; // this is the UDP port the application will be listening on
String ip = "127.0.0.1"; // Currently only localhost is supported as UDP Marker source

// Create new object for receiving
udpRX=new UDP(this,portRX,ip);
udpRX.setReceiveHandler("udpReceiveHandler");
udpRX.log(true);
udpRX.listen(true);
// Print some useful diagnostics
println("OpenBCI_GUI::Setup: Is RX mulitcast: "+udpRX.isMulticast());
println("OpenBCI_GUI::Setup: Has RX joined multicast: "+udpRX.isJoined());

// Create GUI data folder and copy sample data if meditation file doesn't exist
copyGUISampleData();

Expand Down Expand Up @@ -476,35 +461,6 @@ public void copyGUISampleData(){

//====================== END-OF-SETUP ==========================//

//====================UDP Packet Handler==========================//
// This function handles the received UDP packet
// See the documentation for the Java UDP class here:
// https://ubaa.net/shared/processing/udp/udp_class_udp.htm

String udpReceiveString = null;

void udpReceiveHandler(byte[] data, String ip, int portRX) {

String udpString = new String(data);
println(udpString+" from: "+ip+" and port: "+portRX);
if (udpString.length() >=5 && udpString.indexOf("MARK") >= 0) {

int intValue = Integer.parseInt(udpString.substring(4));

if (intValue > 0 && intValue < 96) { // Since we only send single char ascii value markers (from space to char(126)
String sendString = "`"+char(intValue+31);
println("Marker value: "+udpString+" with numeric value of char("+intValue+") as : "+sendString);
hub.sendCommand(sendString);

} else {
println("udpReceiveHandler::Warning:invalid UDP STIM of value: "+intValue+" Received String: "+udpString);
}
} else {
println("udpReceiveHandler::Warning:invalid UDP marker packet: "+udpString);

}
}

//======================== DRAW LOOP =============================//

synchronized void draw() {
Expand All @@ -514,6 +470,11 @@ synchronized void draw() {
drawLoop_counter++; //signPost("10");
systemUpdate(); //signPost("20");
systemDraw(); //signPost("30");
if (midInit) {
//If Start Session was clicked, wait 2 draw cycles to show overlay, then init session.
//When Init session is started, the screen will seem to hang.
systemInitSession();
}
} else if (systemMode == SYSTEMMODE_INTROANIMATION) {
if (settings.introAnimationInit == 0) {
settings.introAnimationInit = millis();
Expand Down Expand Up @@ -1314,12 +1275,6 @@ void systemDraw() { //for drawing to the screen
if (!attemptingToConnect) {
output("Attempting to establish a connection with your OpenBCI Board...");
attemptingToConnect = true;
} else {
//@TODO: Fix this so that it shows during successful system inits ex. Cyton+Daisy w/ UserSettings
pushStyle();
imageMode(CENTER);
image(loadingGIF, width/2, height/2, 128, 128);//render loading gif...
popStyle();
}

if (millis() - timeOfInit > settings.initTimeoutThreshold) {
Expand All @@ -1344,6 +1299,26 @@ void systemDraw() { //for drawing to the screen

buttonHelpText.draw();
mouseOutOfBounds(); // to fix

if (midInit) {
drawOverlay();
}
}

//Always Called after systemDraw()
void systemInitSession() {
if (midInitCheck2) {
println("OpenBCI_GUI: Start session. Calling initSystem().");
try {
initSystem(); //found in OpenBCI_GUI.pde
} catch (Exception e) {
println(e.getMessage());
haltSystem();
}
midInitCheck2 = false;
} else {
midInitCheck2 = true;
}
}

void introAnimation() {
Expand Down Expand Up @@ -1407,6 +1382,25 @@ void openConsole()
ConsoleWindow.display();
}

void drawOverlay() {
//Draw a gray overlay when the Start Session button is pressed
pushStyle();
//imageMode(CENTER);
fill(124, 142);
rect(0, 0, width, height);
popStyle();

pushStyle();
textFont(p0, 24);
fill(boxColor, 255);
stroke(bgColor, 200);
rect(width/2 - 240/2, height/2 - 80/2, 240, 80);
fill(bgColor, 255);
String s = "Starting Session...";
text(s, width/2 - textWidth(s)/2, height/2 + 8);
popStyle();
}

//CODE FOR FIXING WEIRD EXIT CRASH ISSUE -- 7/27/16 ===========================
boolean mouseInFrame = false;
boolean windowOriginSet = false;
Expand Down
5 changes: 5 additions & 0 deletions OpenBCI_GUI/Radios_Config.pde
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ boolean print_bytes(RadioConfigBox rc){
rcStringReceived = board_message.toString();
if(rcStringReceived.equals("Failure: System is Down")) {
rcStringReceived = "Cyton dongle could not connect to the board. Perhaps they are on different channels? Try pressing AUTOSCAN.";
} else if (rcStringReceived.equals("Success: System is Up")) {
rcStringReceived = "Success: Cyton and Dongle are paired. \n\nReady to Start Session!";
} else if (rcStringReceived.startsWith("Success: Host override")) {
rcStringReceived = "Please press AUTOSCAN one more time.";
}
rc.print_onscreen(rcStringReceived);
return true;
Expand Down Expand Up @@ -188,6 +192,7 @@ void system_status(RadioConfigBox rcConfig){
} else {
String[] s = split(rcStringReceived, ':');
if (s[0].equals("Success")) {
print_bytes(rcConfig);
outputSuccess("Successfully connected to Cyton using " + openBCI_portName);
} else {
outputError("Failed to connect using " + openBCI_portName + ". Check hardware or try pressing 'Autoscan'.");
Expand Down
Loading

0 comments on commit f907e6a

Please sign in to comment.