Skip to content

Commit 7b971f2

Browse files
authored
Merge pull request #1140 from OpenBCI/june2023-networking-refactor
Refactor Networking Widget - June 2023
2 parents bf3372b + c6b44ae commit 7b971f2

10 files changed

Lines changed: 1314 additions & 1356 deletions

Networking-Test-Kit/LSL/lslStreamTest.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
# create a new inlet to read from the stream
1111
inlet = StreamInlet(streams[0])
12-
duration = 5
12+
duration = 10
1313

1414
sleep(1)
1515

@@ -24,12 +24,13 @@ def testLSLSamplingRate():
2424
# get chunks of samples
2525
chunk, timestamp = inlet.pull_chunk()
2626
if chunk:
27+
print("\nNew chunk!")
2728
numChunks += 1
2829
# print( len(chunk) )
2930
totalNumSamples += len(chunk)
30-
# print(chunk);
31+
# print(chunk)
3132
for sample in chunk:
32-
# print(sample)
33+
print(sample)
3334
validSamples += 1
3435

3536
print( "Number of Chunks and Samples == {} , {}".format(numChunks, totalNumSamples) )

Networking-Test-Kit/LSL/lslStreamTest_3Streams.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import time
1111

1212
numStreams = 3
13-
duration_seconds = 20
13+
duration_seconds = 10
1414
# first resolve an EEG stream on the lab network
1515
print("looking for an EEG stream...")
1616
stream_1 = resolve_stream('type', 'EEG')
@@ -19,8 +19,8 @@
1919

2020
# create a new inlet to read from the stream
2121
inlet = StreamInlet(stream_1[0])
22-
intlet_2 = StreamInlet(stream_2[0])
23-
intlet_3 = StreamInlet(stream_3[0])
22+
inlet_2 = StreamInlet(stream_2[0])
23+
inlet_3 = StreamInlet(stream_3[0])
2424

2525
def testLSLSamplingRates():
2626
print( "Testing Sampling Rates for {} seconds".format(duration_seconds) )
@@ -40,13 +40,13 @@ def testLSLSamplingRates():
4040
num_samples_1 += 1
4141
#print(sample)
4242
elif i == 1:
43-
chunk, timestamps_2 = intlet_2.pull_chunk()
43+
chunk, timestamps_2 = inlet_2.pull_chunk()
4444
if timestamps_2:
4545
for sample in chunk:
4646
num_samples_2 += 1
4747
#print(sample)
4848
elif i == 2:
49-
chunk, timestamps_3 = intlet_3.pull_chunk()
49+
chunk, timestamps_3 = inlet_3.pull_chunk()
5050
if timestamps_3:
5151
for sample in chunk:
5252
num_samples_3 += 1
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
"""Here we show that we can use push_sample to send and pull_chunk to receive a sample."""
2+
import time
3+
from pylsl import StreamInlet, resolve_stream
4+
from time import sleep
5+
6+
# first resolve an EEG stream on the lab network
7+
print("looking for an EEG stream...")
8+
streams = resolve_stream('type', 'FOCUS')
9+
10+
# create a new inlet to read from the stream
11+
inlet = StreamInlet(streams[0])
12+
duration = 5
13+
14+
sleep(1)
15+
16+
def testLSLSamplingRate():
17+
start = time.time()
18+
totalNumSamples = 0
19+
validSamples = 0
20+
numChunks = 0
21+
print( "Testing Sampling Rates..." )
22+
23+
while time.time() <= start + duration:
24+
# print(time.time())
25+
# get chunks of samples
26+
sample, timestamp = inlet.pull_chunk()
27+
if sample:
28+
print(sample)
29+
validSamples += 1
30+
31+
#print( "Number of Chunks and Samples == {} , {}".format(numChunks, totalNumSamples) )
32+
#print( "Valid Samples and Duration == {} / {}".format(validSamples, duration) )
33+
print( "Avg Sampling Rate == {}".format(validSamples / duration) )
34+
35+
36+
testLSLSamplingRate()
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#N canvas -1158 177 945 588 12;
2+
#X obj 179 241 netreceive -u -b;
3+
#X msg 179 179 listen 0;
4+
#X obj 179 270 oscparse;
5+
#X obj 262 148 bng 19 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000;
6+
#X obj 179 149 bng 19 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000;
7+
#X msg 262 179 listen 12345;
8+
#X obj 179 343 route openbci;
9+
#X obj 179 302 list trim;
10+
#X obj 354 250 bng 19 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000;
11+
#X obj 354 311 list prepend symbol;
12+
#X obj 354 340 list trim;
13+
#X text 423 126 Enter the address you'd like to receive here. This is the same as the Address textfield in the GUI. Example: accelerometer, f 23;
14+
#X text 437 213 Clicking the bang would change the routing address to the new value., f 21;
15+
#X text 437 339 After data is routed \, we are left with a list of floats that can be unpacked., f 21;
16+
#X text 149 508 Happy Hacking! We're excited to see what our global Community can continue to create using OpenBCI hardware and software! -RW, f 62;
17+
#X text 48 256 PureData adds the "list" selector after our binary data is parsed., f 16;
18+
#X text 152 107 Turn off netreceive, f 10;
19+
#X text 249 107 Start recieving on named port, f 16;
20+
#X text 647 22 Example Incoming OSC Packet;
21+
#X obj 179 376 route time-series-raw;
22+
#X msg 354 283 time-series-raw;
23+
#X obj 52 427 print rawmsg;
24+
#X obj 179 419 route ch0 ch1 ch2 ch3;
25+
#X obj 179 461 print channel0;
26+
#X text 40 61 openbci time-series-raw ch0 -3.92592 -3.88553 -3.26396 -3.62399 -2.70645 -1.6476 -0.789745 0.749153 1.55314 3.081, f 114;
27+
#X text 32 18 OpenBCI OSC Reciever Example June 21 \, 2023 Richard Waltman, f 31;
28+
#X connect 0 0 2 0;
29+
#X connect 1 0 0 0;
30+
#X connect 2 0 7 0;
31+
#X connect 3 0 5 0;
32+
#X connect 4 0 1 0;
33+
#X connect 5 0 0 0;
34+
#X connect 6 0 19 0;
35+
#X connect 7 0 6 0;
36+
#X connect 7 0 21 0;
37+
#X connect 8 0 20 0;
38+
#X connect 9 0 10 0;
39+
#X connect 10 0 19 1;
40+
#X connect 19 0 22 0;
41+
#X connect 20 0 9 0;
42+
#X connect 22 0 23 0;
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#N canvas 3103 183 661 588 12;
2+
#X obj 179 241 netreceive -u -b;
3+
#X msg 179 179 listen 0;
4+
#X obj 179 270 oscparse;
5+
#X obj 262 148 bng 19 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000;
6+
#X obj 179 149 bng 19 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000;
7+
#X msg 262 179 listen 12345;
8+
#X obj 179 343 route openbci;
9+
#X obj 179 302 list trim;
10+
#X obj 354 250 bng 19 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000;
11+
#X obj 354 311 list prepend symbol;
12+
#X obj 354 340 list trim;
13+
#X obj 69 389 print data;
14+
#X text 423 126 Enter the address you'd like to receive here. This is the same as the Address textfield in the GUI. Example: accelerometer, f 23;
15+
#X text 437 213 Clicking the bang would change the routing address to the new value., f 21;
16+
#X text 437 339 After data is routed \, we are left with a list of floats that can be unpacked., f 21;
17+
#X text 149 508 Happy Hacking! We're excited to see what our global Community can continue to create using OpenBCI hardware and software! -RW, f 62;
18+
#X text 48 256 PureData adds the "list" selector after our binary data is parsed., f 16;
19+
#X text 152 107 Turn off netreceive, f 10;
20+
#X text 249 107 Start recieving on named port, f 16;
21+
#X text 34 25 OpenBCI OSC Reciever Example June 14 \, 2023 Richard Waltman, f 31;
22+
#X obj 179 383 route accelerometer;
23+
#X msg 354 283 accelerometer;
24+
#X obj 179 421 route x y z, f 21;
25+
#X floatatom 179 466 5 0 0 0 - - - 0;
26+
#X floatatom 275 466 5 0 0 0 - - - 0;
27+
#X floatatom 227 466 5 0 0 0 - - - 0;
28+
#X text 394 19 Example Incoming OSC Packet;
29+
#X text 359 41 openbci accelerometer x 0.986508;
30+
#X connect 0 0 2 0;
31+
#X connect 1 0 0 0;
32+
#X connect 2 0 7 0;
33+
#X connect 3 0 5 0;
34+
#X connect 4 0 1 0;
35+
#X connect 5 0 0 0;
36+
#X connect 6 0 20 0;
37+
#X connect 7 0 6 0;
38+
#X connect 7 0 11 0;
39+
#X connect 8 0 21 0;
40+
#X connect 9 0 10 0;
41+
#X connect 10 0 20 1;
42+
#X connect 20 0 22 0;
43+
#X connect 21 0 9 0;
44+
#X connect 22 0 23 0;
45+
#X connect 22 1 25 0;
46+
#X connect 22 2 24 0;

Networking-Test-Kit/OSC/osc_receive.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def close_file(*args):
5656
# Set up necessary parameters from command line
5757
dispatcher = dispatcher.Dispatcher()
5858
if args.option=="print":
59-
dispatcher.map("/openbci", print_message)
59+
dispatcher.map(args.address, print_message)
6060
signal.signal(signal.SIGINT, exit_print)
6161

6262
elif args.option=="record":
@@ -68,7 +68,7 @@ def close_file(*args):
6868
textfile.write("time,address,messages\n")
6969
textfile.write("-------------------------\n")
7070
print("Recording to %s" % filename)
71-
dispatcher.map("/openbci", record_to_file)
71+
dispatcher.map(args.address, record_to_file)
7272
signal.signal(signal.SIGINT, close_file)
7373

7474
# Display server attributes
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import socket
2+
import sys
3+
import time
4+
import argparse
5+
import signal
6+
import struct
7+
import os
8+
import json
9+
10+
numSamples = 0
11+
12+
# Print received message to console
13+
def print_message(*args):
14+
try:
15+
# print(args[0]) #added to see raw data
16+
obj = json.loads(args[0].decode())
17+
print(obj.get('data'))
18+
numSamplesInChannelOne = len(obj.get('data')[0])
19+
global numSamples
20+
print("NumSamplesInPacket_ChannelOne == " + str(numSamplesInChannelOne))
21+
numSamples += numSamplesInChannelOne
22+
if obj:
23+
return True
24+
else:
25+
return False
26+
except BaseException as e:
27+
print(e)
28+
return False
29+
# print("(%s) RECEIVED MESSAGE: " % time.time() +
30+
# ''.join(str(struct.unpack('>%df' % int(length), args[0]))))
31+
32+
# Clean exit from print mode
33+
def exit_print(signal, frame):
34+
print("Closing listener")
35+
sys.exit(0)
36+
37+
# Record received message in text file
38+
def record_to_file(*args):
39+
textfile.write(str(time.time()) + ",")
40+
#textfile.write(args[0])
41+
obj = json.loads(args[0].decode())
42+
#print(obj.get('data'))
43+
textfile.write(json.dumps(obj))
44+
textfile.write("\n")
45+
46+
# Save recording, clean exit from record mode
47+
def close_file(*args):
48+
print("\nFILE SAVED")
49+
textfile.close()
50+
sys.exit(0)
51+
52+
if __name__ == "__main__":
53+
# Collect command line arguments
54+
parser = argparse.ArgumentParser()
55+
parser.add_argument("--ip",
56+
default="127.0.0.1", help="The ip to listen on")
57+
parser.add_argument("--port",
58+
type=int, default=12345, help="The port to listen on")
59+
parser.add_argument("--address",default="/openbci", help="address to listen to")
60+
parser.add_argument("--option",default="print",help="Debugger option")
61+
parser.add_argument("--len",default=9,help="Debugger option")
62+
args = parser.parse_args()
63+
64+
# Set up necessary parameters from command line
65+
length = int(args.len)
66+
if args.option=="print":
67+
signal.signal(signal.SIGINT, exit_print)
68+
elif args.option=="record":
69+
i = 0
70+
while os.path.exists("udp_test%s.txt" % i):
71+
i += 1
72+
filename = "udp_test%i.txt" % i
73+
textfile = open(filename, "w")
74+
textfile.write("time,address,messages\n")
75+
textfile.write("-------------------------\n")
76+
print("Recording to %s" % filename)
77+
signal.signal(signal.SIGINT, close_file)
78+
79+
# Connect to socket
80+
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
81+
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
82+
server_address = (args.ip, args.port)
83+
sock.bind(server_address)
84+
85+
# Display socket attributes
86+
print('--------------------')
87+
print("-- UDP LISTENER -- ")
88+
print('--------------------')
89+
print("IP:", args.ip)
90+
print("PORT:", args.port)
91+
print('--------------------')
92+
print("%s option selected" % args.option)
93+
94+
# Receive messages
95+
print("Listening...")
96+
start = time.time()
97+
98+
duration = 10
99+
while time.time() <= start + duration:
100+
data, addr = sock.recvfrom(20000) # buffer size is 20000 bytes
101+
if args.option=="print":
102+
print_message(data)
103+
# numSamples += 1
104+
elif args.option=="record":
105+
record_to_file(data)
106+
numSamples += 1
107+
108+
print( "Samples == {}".format(numSamples) )
109+
print( "Duration == {}".format(duration) )
110+
print( "Avg Sampling Rate == {}".format(numSamples / duration) )

OpenBCI_GUI/OpenBCI_GUI.pde

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,12 @@ import java.awt.AWTException;
5050
import netP5.*; // for OSC
5151
import oscP5.*; // for OSC
5252
import hypermedia.net.*; //for UDP
53-
import java.nio.ByteBuffer; //for UDP
53+
import java.nio.ByteBuffer; //for BDF file writing
5454
import edu.ucsd.sccn.LSL; //for LSL
5555
import com.fazecast.jSerialComm.*; //Helps distinguish serial ports on Windows
5656
import org.apache.commons.lang3.time.StopWatch;
5757
import http.requests.*;
58+
import java.util.concurrent.atomic.AtomicBoolean;
5859

5960

6061
//------------------------------------------------------------------------
@@ -417,6 +418,7 @@ void setup() {
417418
if (isMac()) {
418419
checkIsMacFullDetail();
419420
}
421+
println("JVM Version: " + System.getProperty("java.version"));
420422
println("Welcome to the Processing-based OpenBCI GUI!"); //Welcome line.
421423
println("For more information, please visit: https://docs.openbci.com/Software/OpenBCISoftware/GUIDocs/");
422424

@@ -518,6 +520,9 @@ synchronized void draw() {
518520
initSystem();
519521
reinitRequested = false;
520522
}
523+
if (systemMode == SYSTEMMODE_POSTINIT) {
524+
w_networking.compareAndSetNetworkingFrameLocks();
525+
}
521526
} else if (systemMode == SYSTEMMODE_INTROANIMATION) {
522527
if (settings.introAnimationInit == 0) {
523528
settings.introAnimationInit = millis();

0 commit comments

Comments
 (0)