Skip to content

Commit 3deb1a3

Browse files
committed
Add udp marker receiver to Marker widget
Add python test script to send markers over the default port
1 parent 05371a9 commit 3deb1a3

4 files changed

Lines changed: 162 additions & 22 deletions

File tree

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import socket
2+
import random
3+
import struct
4+
import time
5+
import argparse
6+
7+
if __name__ == "__main__":
8+
9+
test_duration = 10
10+
11+
# Collect command line arguments
12+
parser = argparse.ArgumentParser()
13+
parser.add_argument("--ip", default="127.0.0.1",
14+
help="The ip of the OSC server")
15+
parser.add_argument("--port", type=int, default=12350,
16+
help="The port the OSC server is sending to")
17+
args = parser.parse_args()
18+
19+
# Establish UDP socket
20+
UDP_IP = args.ip
21+
UDP_PORT = args.port
22+
sock = socket.socket(socket.AF_INET, # Internet
23+
socket.SOCK_DGRAM) # UDP
24+
25+
# Display socket attributes
26+
print('---------------------')
27+
print("-- UDP MARKER SEND -- ")
28+
print('---------------------')
29+
print("IP:", args.ip)
30+
print("PORT:", args.port)
31+
print('--------------------=')
32+
33+
# Send test data
34+
start = time.time()
35+
while time.time() <= start + test_duration:
36+
# generate random float
37+
marker = random.uniform(0, 4)
38+
# package as byte array
39+
msg = struct.pack('!d', marker)
40+
# send through socket
41+
sock.sendto(msg, (UDP_IP, UDP_PORT))
42+
time.sleep(.25)

OpenBCI_GUI/Grid.pde

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,4 +145,8 @@ class Grid {
145145
public void setDrawTableInnerLines(boolean b) {
146146
drawTableInnerLines = b;
147147
}
148+
149+
public int getHeight() {
150+
return rowHeight * numRows;
151+
}
148152
}

OpenBCI_GUI/OpenBCI_GUI.pde

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ 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 BDF file writing
53+
import java.nio.ByteBuffer; //for BDF file writing and UDP Marker Receiver
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;

OpenBCI_GUI/W_Marker.pde

Lines changed: 115 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,20 @@ class W_Marker extends Widget {
1717
private final int MARKER_BUTTON_HEIGHT = 20;
1818
private final int MARKER_BUTTON_GRID_CELL_HEIGHT = 30;
1919
private final int MAX_NUMBER_OF_MARKER_BUTTONS = 8;
20+
private final int MARKER_BUTTON_GRID_EXTERIOR_PADDING = 10;
2021
private Button[] markerButtons = new Button[MAX_NUMBER_OF_MARKER_BUTTONS];
2122
private Grid markerButtonGrid;
2223

24+
private Textfield markerReceiveIPTextfield;
25+
private Textfield markerReceivePortTextfield;
26+
private String markerReceiveIP = "127.0.0.1";
27+
private int markerReceivePort = 12350;
28+
private final int MARKER_RECEIVE_TEXTFIELD_WIDTH = 100;
29+
private final int MARKER_RECEIVE_TEXTFIELD_HEIGHT = 20;
30+
private int markerReceiveX, markerReceiveY, markerReceiveW, markerReceiveH;
31+
32+
private hypermedia.net.UDP udpReceiver;
33+
2334
private MarkerBar markerBar;
2435
private int graphX, graphY, graphW, graphH;
2536
private int PAD_FIVE = 5;
@@ -47,11 +58,20 @@ class W_Marker extends Widget {
4758
markerButtonGrid.setDrawTableBorder(true);
4859
markerButtonGrid.setDrawTableInnerLines(true);
4960

61+
udpReceiver = new UDP(_parent, markerReceivePort);
62+
udpReceiver.listen(true);
63+
udpReceiver.log(true);
64+
udpReceiver.setReceiveHandler("receiveMarkerViaUdp");
65+
66+
createMarkerReceiveUI();
67+
5068
//Add all cp5 elements to a list so that they can be checked for overlap
5169
cp5ElementsToCheckForOverlap = new ArrayList<controlP5.Controller>();
5270
for (int i = 0; i < MAX_NUMBER_OF_MARKER_BUTTONS; i++) {
5371
cp5ElementsToCheckForOverlap.add(markerButtons[i]);
5472
}
73+
cp5ElementsToCheckForOverlap.add(markerReceiveIPTextfield);
74+
cp5ElementsToCheckForOverlap.add(markerReceivePortTextfield);
5575
}
5676

5777
public void update(){
@@ -83,6 +103,8 @@ class W_Marker extends Widget {
83103

84104
resizeMarkerButtonGrid();
85105

106+
updateMarkerReceiveUIPosition();
107+
86108
updateGraphDims();
87109
markerBar.screenResized(graphX, graphY, graphW, graphH);
88110

@@ -97,7 +119,7 @@ class W_Marker extends Widget {
97119

98120
private void resizeMarkerButtonGrid() {
99121
int tableX = x + GRAPH_PADDING;
100-
int tableY = y + GRAPH_PADDING;
122+
int tableY = y + MARKER_BUTTON_GRID_EXTERIOR_PADDING;
101123
int tableW = w - GRAPH_PADDING * 2;
102124
int tableH = y - graphY - GRAPH_PADDING * 2;
103125
markerButtonGrid.setDim(tableX, tableY, tableW);
@@ -117,6 +139,20 @@ class W_Marker extends Widget {
117139
}
118140
}
119141

142+
private void updateMarkerReceiveUIPosition() {
143+
final int MARKER_UI_PADDING_Y = 10;
144+
markerReceiveX = x + GRAPH_PADDING;
145+
markerReceiveY = y + MARKER_BUTTON_GRID_EXTERIOR_PADDING * 2 + MARKER_BUTTON_GRID_CELL_HEIGHT * 2;
146+
println(markerReceiveY);
147+
markerReceiveW = w - GRAPH_PADDING * 2;
148+
markerReceiveH = MARKER_RECEIVE_TEXTFIELD_HEIGHT + MARKER_UI_PADDING_Y;
149+
int halfMarkerReceiveW = markerReceiveW / 2;
150+
int markerReceiveUIMiddle = markerReceiveX + halfMarkerReceiveW;
151+
152+
markerReceiveIPTextfield.setPosition(markerReceiveX, markerReceiveY + MARKER_UI_PADDING_Y / 2);
153+
markerReceivePortTextfield.setPosition(markerReceiveUIMiddle, markerReceiveY + MARKER_UI_PADDING_Y / 2);
154+
}
155+
120156
private void createMarkerButtons() {
121157
for (int i = 0; i < MAX_NUMBER_OF_MARKER_BUTTONS; i++) {
122158
//Create marker buttons
@@ -131,7 +167,7 @@ class W_Marker extends Widget {
131167
newButton.setBorderColor(OBJECT_BORDER_GREY);
132168
newButton.onRelease(new CallbackListener() {
133169
public void controlEvent(CallbackEvent theEvent) {
134-
insertMarkerFromKeyboardOrButton(markerNumber);
170+
insertMarker(markerNumber);
135171
}
136172
});
137173
newButton.setDescription("Click to insert marker " + markerNumber + " into the data stream.");
@@ -144,35 +180,61 @@ class W_Marker extends Widget {
144180
public boolean checkForMarkerKeyPress(char keyPress) {
145181
switch (keyPress) {
146182
case 'z':
147-
insertMarkerFromKeyboardOrButton(1);
183+
insertMarker(1);
148184
return true;
149185
case 'x':
150-
insertMarkerFromKeyboardOrButton(2);
186+
insertMarker(2);
151187
return true;
152188
case 'c':
153-
insertMarkerFromKeyboardOrButton(3);
189+
insertMarker(3);
154190
return true;
155191
case 'v':
156-
insertMarkerFromKeyboardOrButton(4);
192+
insertMarker(4);
157193
return true;
158194
case 'Z':
159-
insertMarkerFromKeyboardOrButton(5);
195+
insertMarker(5);
160196
return true;
161197
case 'X':
162-
insertMarkerFromKeyboardOrButton(6);
198+
insertMarker(6);
163199
return true;
164200
case 'C':
165-
insertMarkerFromKeyboardOrButton(7);
201+
insertMarker(7);
166202
return true;
167203
case 'V':
168-
insertMarkerFromKeyboardOrButton(8);
204+
insertMarker(8);
169205
return true;
170206
default:
171207
return false;
172208
}
173209
}
174210

175-
private void insertMarkerFromKeyboardOrButton(int markerNumber) {
211+
private void createMarkerReceiveUI() {
212+
markerReceiveIPTextfield = createTextfield("markerReceiveIPTextfield", markerReceiveIP);
213+
markerReceivePortTextfield = createTextfield("markerReceivePortTextfield", Integer.toString(markerReceivePort));
214+
updateMarkerReceiveUIPosition();
215+
}
216+
217+
/* Create textfields for network parameters */
218+
private Textfield createTextfield(String name, String default_text) {
219+
Textfield myTextfield = localCP5.addTextfield(name).align(10, 100, 10, 100) // Alignment
220+
.setSize(MARKER_RECEIVE_TEXTFIELD_WIDTH, MARKER_RECEIVE_TEXTFIELD_HEIGHT) // Size of textfield
221+
.setFont(f2)
222+
.setFocus(false) // Deselects textfield
223+
.setColor(OPENBCI_DARKBLUE)
224+
.setColorBackground(color(255, 255, 255)) // text field bg color
225+
.setColorValueLabel(OPENBCI_DARKBLUE) // text color
226+
.setColorForeground(OPENBCI_DARKBLUE) // border color when not selected
227+
.setColorActive(isSelected_color) // border color when selected
228+
.setColorCursor(OPENBCI_DARKBLUE)
229+
.setText(default_text) // Default text in the field
230+
.setCaptionLabel("") // Remove caption label
231+
.setVisible(true) // Initially visible
232+
.setAutoClear(true) // Autoclear
233+
;
234+
return myTextfield;
235+
}
236+
237+
private void insertMarker(int markerNumber) {
176238
int markerChannel = ((DataSource)currentBoard).getMarkerChannel();
177239

178240
if (currentBoard instanceof BoardBrainFlow) {
@@ -182,6 +244,16 @@ class W_Marker extends Widget {
182244
}
183245
}
184246

247+
public void insertMarkerFromExternal(float markerValue) {
248+
int markerChannel = ((DataSource)currentBoard).getMarkerChannel();
249+
250+
if (currentBoard instanceof BoardBrainFlow) {
251+
if (markerChannel != -1) {
252+
((Board)currentBoard).insertMarker(markerValue);
253+
}
254+
}
255+
}
256+
185257
public void setMarkerWindow(int n) {
186258
markerWindow = markerWindow.values()[n];
187259
markerBar.adjustTimeAxis(markerWindow.getValue());
@@ -207,16 +279,15 @@ class W_Marker extends Widget {
207279
return markerCount;
208280
}
209281

210-
};
282+
public String getMarkerReceiveIP() {
283+
return getIpAddrFromStr(markerReceiveIPTextfield.getText());
284+
}
211285

212-
//The following global functions are used by the Marker widget dropdowns. This method is the least amount of code.
213-
public void markerWindowDropdown(int n) {
214-
w_marker.setMarkerWindow(n);
215-
}
286+
public String getMarkerReceivePort() {
287+
return dropNonPrintableChars(markerReceivePortTextfield.getText());
288+
}
216289

217-
public void markerCountDropdown(int n) {
218-
w_marker.setMarkerCount(n);
219-
}
290+
}; //end class W_Marker
220291

221292
//This class contains the time series plot for displaying the markers over time
222293
class MarkerBar {
@@ -373,8 +444,7 @@ class MarkerBar {
373444
}
374445
}; //end of class
375446

376-
377-
447+
//Enum for the Marker Window in W_Marker class
378448
public enum MarkerWindow implements IndexingInterface
379449
{
380450
FIVE (0, 5, "5 sec"),
@@ -415,6 +485,7 @@ public enum MarkerWindow implements IndexingInterface
415485
}
416486
}
417487

488+
//Enum for the Marker Count in W_Marker class
418489
public enum MarkerCount implements IndexingInterface
419490
{
420491
FOUR (0, 4, "4"),
@@ -452,4 +523,27 @@ public enum MarkerCount implements IndexingInterface
452523
}
453524
return enumStrings;
454525
}
526+
}
527+
528+
//The following global functions are used by the Marker widget dropdowns. This method is the least amount of code.
529+
public void markerWindowDropdown(int n) {
530+
w_marker.setMarkerWindow(n);
531+
}
532+
533+
public void markerCountDropdown(int n) {
534+
w_marker.setMarkerCount(n);
535+
}
536+
537+
//Custom UDP receive handler for receiving markers from external sources
538+
public void receiveMarkerViaUdp( byte[] data, String ip, int port ) {
539+
float markerValue = convertByteArrayToFloat(data);
540+
String message = Float.toString(markerValue);
541+
542+
//println( "received: \""+message+"\" from "+ip+" on port "+port );
543+
w_marker.insertMarkerFromExternal(markerValue);
544+
}
545+
546+
public float convertByteArrayToFloat(byte[] array) {
547+
ByteBuffer buffer = ByteBuffer.wrap(array);
548+
return buffer.getFloat();
455549
}

0 commit comments

Comments
 (0)