Skip to content

Commit

Permalink
Merge pull request #948 from OpenBCI/development
Browse files Browse the repository at this point in the history
GUI v5.0.3 - Public Release Jan 2021
  • Loading branch information
retiutut authored Jan 29, 2021
2 parents 8aa9633 + c85460a commit 4b3dfbd
Show file tree
Hide file tree
Showing 15 changed files with 503 additions and 222 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,7 @@ application.*
*.autosave
.vscode/*
temp/*
libBoardController.so
libDataHandler.so
libGanglionLib.so
libGanglionScan.so
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
# v5.0.3

### Improvements
* Increase sampling rate for Pulse data output in Networking Widget

### Bug Fixes
* Fix Pulse LSL output error #943
* Fix Accel/Aux UDP output #944
* Fix Expert Mode unplanned keyboard shortcuts crash GUI #941
* Fix bugs found when loading Session Settings #942

# v5.0.2

### Improvements
Expand Down
58 changes: 58 additions & 0 deletions Networking-Test-Kit/LSL/lslStreamTest_AnalogPinPulse.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
"""Example program to show how to read a multi-channel time series from LSL."""
import time
from pylsl import StreamInlet, resolve_stream
from time import sleep
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import style
from collections import deque

# 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])
duration = 10

sleep(0)

def testLSLSamplingRate():
start = time.time()
numSamples = 0
numChunks = 0

while time.time() <= start + duration:
# get chunks of samples
chunk, timestamp = inlet.pull_chunk()
if timestamp:
numChunks += 1
for sample in chunk:
numSamples += 1

print( "Number of Chunks == {}".format(numChunks) )
print( "Avg Sampling Rate == {}".format(numSamples / duration) )


testLSLSamplingRate()

print("gathering data to plot...")

def testLSLPulseData():
start = time.time()
raw_pulse_signal = []

while time.time() <= start + duration:
chunk, timestamp = inlet.pull_chunk()
if timestamp:
for sample in chunk:
# print(sample)
raw_pulse_signal.append(sample[1])

print(raw_pulse_signal)
print( "Avg Sampling Rate == {}".format(len(raw_pulse_signal) / duration) )
plt.plot(raw_pulse_signal)
plt.ylabel('raw analog signal')
plt.show()

testLSLPulseData()
16 changes: 12 additions & 4 deletions Networking-Test-Kit/UDP/udp_receive.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@
# Print received message to console
def print_message(*args):
try:
obj = json.loads(args[0])
print obj.get('data')
print(args[0]) #added to see raw data
obj = json.loads(args[0].decode())
print(obj.get('data'))
except BaseException as e:
print e
print(e)
# print("(%s) RECEIVED MESSAGE: " % time.time() +
# ''.join(str(struct.unpack('>%df' % int(length), args[0]))))

Expand Down Expand Up @@ -78,9 +79,16 @@ def close_file(*args):

# Receive messages
print("Listening...")
while True:
start = time.time()
numSamples = 0
duration = 10
while time.time() <= start + duration:
data, addr = sock.recvfrom(20000) # buffer size is 20000 bytes
if args.option=="print":
print_message(data)
numSamples += 1
elif args.option=="record":
record_to_file(data)
print( "Samples == {}".format(numSamples) )
print( "Duration == {}".format(duration) )
print( "Avg Sampling Rate == {}".format(numSamples / duration) )
106 changes: 106 additions & 0 deletions Networking-Test-Kit/UDP/udp_receive_pulse.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import socket
import sys
import time
import argparse
import signal
import struct
import os
import json
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import style

raw_pulse_signal = []

# Print received message to console
def print_message(*args):
try:
# print(args[0]) #added to see raw data
obj = json.loads(args[0].decode())
print(obj.get('data'))
except BaseException as e:
print(e)
# print("(%s) RECEIVED MESSAGE: " % time.time() +
# ''.join(str(struct.unpack('>%df' % int(length), args[0]))))

# Clean exit from print mode
def exit_print(signal, frame):
print("Closing listener")
sys.exit(0)

# Record received message in text file
def record_to_file(*args):
textfile.write(str(time.time()) + ",")
textfile.write(''.join(str(struct.unpack('>%df' % length,args[0]))))
textfile.write("\n")

# Save recording, clean exit from record mode
def close_file(*args):
print("\nFILE SAVED")
textfile.close()
sys.exit(0)

if __name__ == "__main__":
# Collect command line arguments
parser = argparse.ArgumentParser()
parser.add_argument("--ip",
default="127.0.0.1", help="The ip to listen on")
parser.add_argument("--port",
type=int, default=12345, help="The port to listen on")
parser.add_argument("--address",default="/openbci", help="address to listen to")
parser.add_argument("--option",default="print",help="Debugger option")
parser.add_argument("--len",default=8,help="Debugger option")
args = parser.parse_args()

# Set up necessary parameters from command line
length = args.len
if args.option=="print":
signal.signal(signal.SIGINT, exit_print)
elif args.option=="record":
i = 0
while os.path.exists("udp_test%s.txt" % i):
i += 1
filename = "udp_test%i.txt" % i
textfile = open(filename, "w")
textfile.write("time,address,messages\n")
textfile.write("-------------------------\n")
print("Recording to %s" % filename)
signal.signal(signal.SIGINT, close_file)

# Connect to socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_address = (args.ip, args.port)
sock.bind(server_address)

# Display socket attributes
print('--------------------')
print("-- UDP LISTENER -- ")
print('--------------------')
print("IP:", args.ip)
print("PORT:", args.port)
print('--------------------')
print("%s option selected" % args.option)

# Receive messages
print("Listening...")
start = time.time()
numSamples = 0
duration = 3

while time.time() <= start + duration:
data, addr = sock.recvfrom(20000) # buffer size is 20000 bytes
if args.option=="print":
print_message(data)
sample = json.loads(data.decode()).get('data')[1]
raw_pulse_signal.append(sample)
numSamples += 1
elif args.option=="record":
record_to_file(data)

print( "Samples == {}".format(numSamples) )
print( "Duration == {}".format(duration) )
print( "Avg Sampling Rate == {}".format(numSamples / duration) )
plt.plot(raw_pulse_signal)
plt.ylabel('raw analog signal')
plt.show()
4 changes: 2 additions & 2 deletions OpenBCI_GUI/DataProcessing.pde
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ class DataProcessing {
float data_std_uV[];
float polarity[];
boolean newDataToSend;
BandPassRanges bpRange = BandPassRanges.FiveToFifty;
BandStopRanges bsRange = BandStopRanges.Sixty;
public BandPassRanges bpRange = BandPassRanges.FiveToFifty;
public BandStopRanges bsRange = BandStopRanges.Sixty;
final int[] processing_band_low_Hz = {
1, 4, 8, 13, 30
}; //lower bound for each frequency band of interest (2D classifier only)
Expand Down
44 changes: 33 additions & 11 deletions OpenBCI_GUI/FilterEnums.pde
Original file line number Diff line number Diff line change
@@ -1,21 +1,32 @@
public enum BandStopRanges
{
Sixty(60.0d),
Fifty(50.0d),
None(null);
Sixty(0, 60.0d),
Fifty(1, 50.0d),
None(2, null);

private int index;
private Double freq;

private static BandStopRanges[] vals = values();

BandStopRanges(Double freq) {
BandStopRanges(int index, Double freq) {
this.index = index;
this.freq = freq;
}

public int getIndex() {
return index;
}

public Double getFreq() {
return freq;
}

public static BandStopRanges getByIndex(int i)
{
return vals[i];
}

public BandStopRanges next()
{
return vals[(this.ordinal() + 1) % vals.length];
Expand All @@ -31,22 +42,28 @@ public enum BandStopRanges

public enum BandPassRanges
{
FiveToFifty(5.0d, 50.0d),
SevenToThirteen(7.0d, 13.0d),
FifteenToFifty(15.0d, 50.0d),
OneToFifty(1.0d, 50.0d),
OneToHundred(1.0d, 100.0d),
None(null, null);
FiveToFifty(0, 5.0d, 50.0d),
SevenToThirteen(1, 7.0d, 13.0d),
FifteenToFifty(2, 15.0d, 50.0d),
OneToFifty(3, 1.0d, 50.0d),
OneToHundred(4, 1.0d, 100.0d),
None(5, null, null);

private int index;
private Double start;
private Double stop;

private static BandPassRanges[] vals = values();

BandPassRanges(Double start, Double stop) {
BandPassRanges(int index, Double start, Double stop) {
this.index = index;
this.start = start;
this.stop = stop;
}

public int getIndex() {
return index;
}

public Double getStart() {
return start;
Expand All @@ -56,6 +73,11 @@ public enum BandPassRanges
return stop;
}

public static BandPassRanges getByIndex(int i)
{
return vals[i];
}

public BandPassRanges next()
{
return vals[(this.ordinal() + 1) % vals.length];
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>5.0.2</string>
<string>5.0.3</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>NSHumanReadableCopyright</key>
<string>MIT License

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

@@jvm_runtime@@
Expand Down
Loading

0 comments on commit 4b3dfbd

Please sign in to comment.