diff --git a/.gitignore b/.gitignore index c4ff668..3813552 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ OpenBCI_GUI/build/source/*.java *.app OpenBCI_GUI/SavedData OpenBCI_GUI/SavedData/EEG_Data/SDconverted-* +OpenBCI_GUI/data/EEG_Data/* diff --git a/CHANGELOG.md b/CHANGELOG.md index 66fdeb7..f3235f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +# 2.2.0 + +### Bug Fixes +* Fix #151 - Incorrect number of channels on playback caused index out of bounds errors. +* Addresses #149 - Allows for proper scaling of channels with four thanks to #151 #157 + +### New Features +* Band power widget #153 (thanks @sunwangshu) +* Closes #138 - Able to drag and drop the electrodes on the head map (thanks @liqwid) +* Closes #142 - GUI needs to pass key strokes to Ganglion + # 2.1.2 ### Bug Fixes diff --git "a/Icon\r" "b/Icon\r" new file mode 100644 index 0000000..e69de29 diff --git a/OpenBCI_GUI/ControlPanel.pde b/OpenBCI_GUI/ControlPanel.pde index 79bd5d1..321e166 100644 --- a/OpenBCI_GUI/ControlPanel.pde +++ b/OpenBCI_GUI/ControlPanel.pde @@ -33,24 +33,6 @@ CallbackListener cb = new CallbackListener() { //used by ControlP5 to clear text } else if (cp5.isMouseOver(cp5.get(Textfield.class, "fileNameGanglion"))){ println("CallbackListener: controlEvent: clearing"); cp5.get(Textfield.class, "fileNameGanglion").clear(); - } else if (cp5.isMouseOver(cp5.get(Textfield.class, "udp_ip"))){ - println("CallbackListener: controlEvent: clearing"); - cp5.get(Textfield.class, "udp_ip").clear(); - } else if (cp5.isMouseOver(cp5.get(Textfield.class, "udp_port"))){ - println("CallbackListener: controlEvent: clearing"); - cp5.get(Textfield.class, "udp_port").clear(); - } else if (cp5.isMouseOver(cp5.get(Textfield.class, "osc_ip"))){ - println("CallbackListener: controlEvent: clearing"); - cp5.get(Textfield.class, "osc_ip").clear(); - } else if (cp5.isMouseOver(cp5.get(Textfield.class, "osc_address"))){ - println("CallbackListener: controlEvent: clearing"); - cp5.get(Textfield.class, "osc_address").clear(); - } else if (cp5.isMouseOver(cp5.get(Textfield.class, "lsl_data"))){ - println("CallbackListener: controlEvent: clearing"); - cp5.get(Textfield.class, "lsl_data").clear(); - } else if (cp5.isMouseOver(cp5.get(Textfield.class, "lsl_aux"))){ - println("CallbackListener: controlEvent: clearing"); - cp5.get(Textfield.class, "lsl_aux").clear(); } } }; @@ -76,8 +58,6 @@ color isSelected_color = color(184, 220, 105); // Button openClosePort; // boolean portButtonPressed; -int networkType = 0; - boolean calledForBLEList = false; Button refreshPort; @@ -115,6 +95,10 @@ Button synthChanButton4; Button synthChanButton8; Button synthChanButton16; +Button playbackChanButton4; +Button playbackChanButton8; +Button playbackChanButton16; + Serial board; ChannelPopup channelPopup; @@ -150,6 +134,9 @@ public void controlEvent(ControlEvent theEvent) { } } else if(newDataSource == DATASOURCE_PLAYBACKFILE){ updateToNChan(8); + playbackChanButton4.color_notPressed = autoFileName.color_notPressed; + playbackChanButton8.color_notPressed = isSelected_color; + playbackChanButton16.color_notPressed = autoFileName.color_notPressed; } else if(newDataSource == DATASOURCE_SYNTHETIC){ updateToNChan(8); synthChanButton4.color_notPressed = autoFileName.color_notPressed; @@ -183,20 +170,6 @@ public void controlEvent(ControlEvent theEvent) { } verbosePrint("SD setting = " + sdSetting); } - if (theEvent.isFrom("networkList")){ - Map bob = ((MenuList)theEvent.getController()).getItem(int(theEvent.getValue())); - String str = (String)bob.get("headline"); - int index = int(theEvent.getValue()); - if (index == 0) { - networkType = 0; - } else if (index ==1){ - networkType = 1; - } else if (index == 2){ - networkType = 2; - } else if (index == 3){ - networkType = 3; - } - } if (theEvent.isFrom("channelList")){ int setChannelInt = int(theEvent.getValue()) + 1; @@ -244,15 +217,10 @@ class ControlPanel { ChannelCountBox channelCountBox; InitBox initBox; SyntheticChannelCountBox synthChannelCountBox; - - NetworkingBox networkingBoxLive; - UDPOptionsBox udpOptionsBox; - OSCOptionsBox oscOptionsBox; - LSLOptionsBox lslOptionsBox; + PlaybackChannelCountBox playbackChannelCountBox; PlaybackFileBox playbackFileBox; SDConverterBox sdConverterBox; - NetworkingBox networkingBoxPlayback; BLEBox bleBox; DataLogBoxGanglion dataLogBoxGanglion; @@ -301,16 +269,11 @@ class ControlPanel { channelCountBox = new ChannelCountBox(x + w, (dataLogBox.y + dataLogBox.h), w, h, globalPadding); synthChannelCountBox = new SyntheticChannelCountBox(x + w, dataSourceBox.y, w, h, globalPadding); sdBox = new SDBox(x + w, (channelCountBox.y + channelCountBox.h), w, h, globalPadding); - networkingBoxLive = new NetworkingBox(x + w, (sdBox.y + sdBox.h), w, 135, globalPadding); - udpOptionsBox = new UDPOptionsBox(networkingBoxLive.x + networkingBoxLive.w, (sdBox.y + sdBox.h), w-30, networkingBoxLive.h, globalPadding); - oscOptionsBox = new OSCOptionsBox(networkingBoxLive.x + networkingBoxLive.w, (sdBox.y + sdBox.h), w-30, networkingBoxLive.h, globalPadding); - lslOptionsBox = new LSLOptionsBox(networkingBoxLive.x + networkingBoxLive.w, (sdBox.y + sdBox.h), w-30, networkingBoxLive.h, globalPadding); - //boxes active when eegDataSource = Playback - playbackFileBox = new PlaybackFileBox(x + w, dataSourceBox.y, w, h, globalPadding); + playbackChannelCountBox = new PlaybackChannelCountBox(x + w, dataSourceBox.y, w, h, globalPadding); + playbackFileBox = new PlaybackFileBox(x + w, (playbackChannelCountBox.y + playbackChannelCountBox.h), w, h, globalPadding); sdConverterBox = new SDConverterBox(x + w, (playbackFileBox.y + playbackFileBox.h), w, h, globalPadding); - //networkingBoxPlayback = new NetworkingBox(x + w, (sdConverterBox.y + sdConverterBox.h), w, h, globalPadding); rcBox = new RadioConfigBox(x+w, y, w, h, globalPadding); channelPopup = new ChannelPopup(x+w, y, w, h, globalPadding); @@ -365,11 +328,10 @@ class ControlPanel { dataLogBox.update(); channelCountBox.update(); synthChannelCountBox.update(); + playbackChannelCountBox.update(); sdBox.update(); rcBox.update(); initBox.update(); - networkingBoxLive.update(); - //networkingBoxPlayback.update(); channelPopup.update(); serialList.updateMenu(); @@ -447,7 +409,6 @@ class ControlPanel { dataLogBox.draw(); channelCountBox.draw(); sdBox.draw(); - networkingBoxLive.draw(); cp5.get(Textfield.class, "fileName").setVisible(true); //make sure the data file field is visible cp5.get(Textfield.class, "fileNameGanglion").setVisible(false); //make sure the data file field is visible @@ -476,74 +437,18 @@ class ControlPanel { cp5.get(MenuList.class, "serialList").setVisible(true); //make sure the serialList menulist is visible cp5.get(MenuList.class, "bleList").setVisible(false); //make sure the serialList menulist is visible cp5.get(MenuList.class, "sdTimes").setVisible(true); //make sure the SD time record options menulist is visible - cp5.get(MenuList.class, "networkList").setVisible(true); //make sure the SD time record options menulist is visible - if (networkType == -1){ - cp5.get(Textfield.class, "udp_ip").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "udp_port").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "osc_ip").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "osc_port").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "osc_address").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "lsl_data").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "lsl_aux").setVisible(false); //make sure the SD time record options menulist is visible - } else if (networkType == 0){ - cp5.get(Textfield.class, "udp_ip").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "udp_port").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "osc_ip").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "osc_port").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "osc_address").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "lsl_data").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "lsl_aux").setVisible(false); //make sure the SD time record options menulist is visible - - } else if (networkType == 1){ - cp5.get(Textfield.class, "udp_ip").setVisible(true); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "udp_port").setVisible(true); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "osc_ip").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "osc_port").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "osc_address").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "lsl_data").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "lsl_aux").setVisible(false); //make sure the SD time record options menulist is visible - udpOptionsBox.draw(); - } else if (networkType == 2){ - cp5.get(Textfield.class, "udp_ip").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "udp_port").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "osc_ip").setVisible(true); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "osc_port").setVisible(true); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "osc_address").setVisible(true); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "lsl_data").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "lsl_aux").setVisible(false); //make sure the SD time record options menulist is visible - - oscOptionsBox.draw(); - } else if (networkType == 3){ - cp5.get(Textfield.class, "udp_ip").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "udp_port").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "osc_ip").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "osc_port").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "osc_address").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "lsl_data").setVisible(true); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "lsl_aux").setVisible(true); //make sure the SD time record options menulist is visible - lslOptionsBox.draw(); - } } else if (eegDataSource == DATASOURCE_PLAYBACKFILE) { //when data source is from playback file // hideAllBoxes(); //clear lists, so they don't appear + playbackChannelCountBox.draw(); playbackFileBox.draw(); sdConverterBox.draw(); - //networkingBoxPlayback.draw(); //set other CP5 controllers invisible // cp5.get(Textfield.class, "fileName").setVisible(false); //make sure the data file field is visible // cp5.get(Textfield.class, "fileNameGanglion").setVisible(false); //make sure the data file field is visible cp5.get(MenuList.class, "serialList").setVisible(false); cp5.get(MenuList.class, "sdTimes").setVisible(false); - cp5.get(MenuList.class, "networkList").setVisible(false); - cp5.get(Textfield.class, "udp_ip").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "udp_port").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "osc_ip").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "osc_port").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "osc_address").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "lsl_data").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "lsl_aux").setVisible(false); //make sure the SD time record options menulist is visible - cp5Popup.get(MenuList.class, "channelList").setVisible(false); cp5Popup.get(MenuList.class, "pollList").setVisible(false); @@ -612,14 +517,6 @@ class ControlPanel { cp5.get(MenuList.class, "serialList").setVisible(false); cp5.get(MenuList.class, "bleList").setVisible(false); cp5.get(MenuList.class, "sdTimes").setVisible(false); - cp5.get(MenuList.class, "networkList").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "udp_ip").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "udp_port").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "osc_ip").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "osc_port").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "osc_address").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "lsl_data").setVisible(false); //make sure the SD time record options menulist is visible - cp5.get(Textfield.class, "lsl_aux").setVisible(false); //make sure the SD time record options menulist is visible cp5Popup.get(MenuList.class, "channelList").setVisible(false); cp5Popup.get(MenuList.class, "pollList").setVisible(false); } @@ -784,6 +681,30 @@ class ControlPanel { selectSDFile.setIsActive(true); selectSDFile.wasPressed = true; } + + if (playbackChanButton4.isMouseHere()) { + playbackChanButton4.setIsActive(true); + playbackChanButton4.wasPressed = true; + playbackChanButton4.color_notPressed = isSelected_color; + playbackChanButton8.color_notPressed = autoFileName.color_notPressed; //default color of button + playbackChanButton16.color_notPressed = autoFileName.color_notPressed; //default color of button + } + + if (playbackChanButton8.isMouseHere()) { + playbackChanButton8.setIsActive(true); + playbackChanButton8.wasPressed = true; + playbackChanButton8.color_notPressed = isSelected_color; + playbackChanButton4.color_notPressed = autoFileName.color_notPressed; //default color of button + playbackChanButton16.color_notPressed = autoFileName.color_notPressed; //default color of button + } + + if (playbackChanButton16.isMouseHere()) { + playbackChanButton16.setIsActive(true); + playbackChanButton16.wasPressed = true; + playbackChanButton16.color_notPressed = isSelected_color; + playbackChanButton4.color_notPressed = autoFileName.color_notPressed; //default color of button + playbackChanButton8.color_notPressed = autoFileName.color_notPressed; //default color of button + } } //active buttons during DATASOURCE_PLAYBACKFILE @@ -1002,6 +923,18 @@ class ControlPanel { updateToNChan(16); } + if (playbackChanButton4.isMouseHere() && playbackChanButton4.wasPressed) { + updateToNChan(4); + } + + if (playbackChanButton8.isMouseHere() && playbackChanButton8.wasPressed) { + updateToNChan(8); + } + + if (playbackChanButton16.isMouseHere() && playbackChanButton16.wasPressed) { + updateToNChan(16); + } + if (synthChanButton4.isMouseHere() && synthChanButton4.wasPressed) { updateToNChan(4); } @@ -1052,6 +985,12 @@ class ControlPanel { synthChanButton8.wasPressed = false; synthChanButton16.setIsActive(false); synthChanButton16.wasPressed = false; + playbackChanButton4.setIsActive(false); + playbackChanButton4.wasPressed = false; + playbackChanButton8.setIsActive(false); + playbackChanButton8.wasPressed = false; + playbackChanButton16.setIsActive(false); + playbackChanButton16.wasPressed = false; chanButton16.setIsActive(false); chanButton16.wasPressed = false; selectPlaybackFile.setIsActive(false); @@ -1108,24 +1047,6 @@ public void initButtonPressed(){ //do nothing } } - - //Network Protocol Initiation -- based on Gabe's Code - if (networkType == 1){ - ip = cp5.get(Textfield.class, "udp_ip").getText(); - port = int(cp5.get(Textfield.class, "udp_port").getText()); - println(port); - udp = new UDPSend(port, ip); - } else if (networkType == 2){ - ip = cp5.get(Textfield.class, "osc_ip").getText(); - port = int(cp5.get(Textfield.class, "osc_port").getText()); - address = cp5.get(Textfield.class, "osc_address").getText(); - osc = new OSCSend(port, ip, address); - } else if (networkType == 3){ - data_stream = cp5.get(Textfield.class, "lsl_data").getText(); - aux_stream = cp5.get(Textfield.class, "lsl_aux").getText(); - lsl = new LSLSend(data_stream, aux_stream); - } - if(eegDataSource == DATASOURCE_GANGLION){ fileName = cp5.get(Textfield.class, "fileNameGanglion").getText(); // store the current text field value of "File Name" to be passed along to dataFiles } else if(eegDataSource == DATASOURCE_NORMAL_W_AUX){ @@ -1567,6 +1488,52 @@ class SyntheticChannelCountBox { } }; +class PlaybackChannelCountBox { + int x, y, w, h, padding; //size and position + + boolean isSystemInitialized; + // button for init/halt system + + PlaybackChannelCountBox(int _x, int _y, int _w, int _h, int _padding) { + x = _x; + y = _y; + w = _w; + h = 73; + padding = _padding; + + playbackChanButton4 = new Button (x + padding, y + padding*2 + 18, (w-padding*4)/3, 24, "4 chan", fontInfo.buttonLabel_size); + if (nchan == 4) playbackChanButton4.color_notPressed = isSelected_color; //make it appear like this one is already selected + playbackChanButton8 = new Button (x + padding*2 + (w-padding*4)/3, y + padding*2 + 18, (w-padding*4)/3, 24, "8 chan", fontInfo.buttonLabel_size); + if (nchan == 8) playbackChanButton8.color_notPressed = isSelected_color; //make it appear like this one is already selected + playbackChanButton16 = new Button (x + padding*3 + ((w-padding*4)/3)*2, y + padding*2 + 18, (w-padding*4)/3, 24, "16 chan", fontInfo.buttonLabel_size); + if (nchan == 16) playbackChanButton16.color_notPressed = isSelected_color; //make it appear like this one is already selected + } + + public void update() { + } + + public void draw() { + pushStyle(); + fill(boxColor); + stroke(boxStrokeColor); + strokeWeight(1); + rect(x, y, w, h); + fill(bgColor); + textFont(h3, 16); + textAlign(LEFT, TOP); + text("CHANNEL COUNT", x + padding, y + padding); + fill(bgColor); //set color to green + textFont(h3, 16); + textAlign(LEFT, TOP); + text(" (" + str(nchan) + ")", x + padding + 142, y + padding); // print the channel count in green next to the box title + popStyle(); + + playbackChanButton4.draw(); + playbackChanButton8.draw(); + playbackChanButton16.draw(); + } +}; + class PlaybackFileBox { int x, y, w, h, padding; //size and position @@ -1648,48 +1615,6 @@ class SDBox { } }; -class NetworkingBox{ - int x, y, w, h, padding; //size and position - MenuList networkList; - - //boolean initButtonPressed; //default false - - //boolean isSystemInitialized; - NetworkingBox(int _x, int _y, int _w, int _h, int _padding){ - x = _x; - y = _y; - w = _w; - h = _h; - padding = _padding; - networkList = new MenuList(cp5, "networkList", w - padding*2, 96, p4); - networkList.setPosition(x + padding, y+padding+20); - networkList.addItem(makeItem("None")); - networkList.addItem(makeItem("UDP")); - networkList.addItem(makeItem("OSC")); - networkList.addItem(makeItem("LabStreamingLayer (LSL)")); - networkList.scrollerLength = 0; - networkList.activeItem = 0; - } - public void update() { - } - - public void draw() { - pushStyle(); - fill(boxColor); - stroke(boxStrokeColor); - strokeWeight(1); - rect(x, y, w, h); - fill(bgColor); - textFont(h3, 16); - textAlign(LEFT, TOP); - text("NETWORK PROTOCOLS", x + padding, y + padding); - fill(bgColor); //set color to green - textFont(h3, 16); - textAlign(LEFT, TOP); - popStyle(); - } -}; - class RadioConfigBox { int x, y, w, h, padding; //size and position @@ -1781,254 +1706,6 @@ class RadioConfigBox { } }; - - -class UDPOptionsBox { - int x, y, w, h, padding; //size and position - - UDPOptionsBox(int _x, int _y, int _w, int _h, int _padding){ - x = _x; - y = _y; - w = _w; - h = _h; - padding = _padding; - - cp5.addTextfield("udp_ip") - .setPosition(x + 60,y + 50) - .setCaptionLabel("") - .setSize(100,26) - .setFont(f2) - .setFocus(false) - .setColor(color(26,26,26)) - .setColorBackground(color(255,255,255)) // text field bg color - .setColorValueLabel(color(0,0,0)) // text color - .setColorForeground(isSelected_color) // border color when not selected - .setColorActive(isSelected_color) // border color when selected - .setColorCursor(color(26,26,26)) - .setText("localhost") - .align(5, 10, 20, 40) - .onDoublePress(cb) - .setVisible(false) - .setAutoClear(true) - ; - - cp5.addTextfield("udp_port") - .setPosition(x + 60,y + 82) - .setCaptionLabel("") - .setSize(100,26) - .setFont(f2) - .setFocus(false) - .setColor(color(26,26,26)) - .setColorBackground(color(255,255,255)) // text field bg color - .setColorValueLabel(color(0,0,0)) // text color - .setColorForeground(isSelected_color) // border color when not selected - .setColorActive(isSelected_color) // border color when selected - .setColorCursor(color(26,26,26)) - .setText("12345") - .align(5, 10, 20, 40) - .onDoublePress(cb) - .setVisible(false) - .setAutoClear(true) - ; - } - public void update(){ - } - public void draw(){ - pushStyle(); - fill(boxColor); - stroke(boxStrokeColor); - strokeWeight(1); - rect(x, y, w, h); - fill(bgColor); - textFont(h3, 16); - textAlign(LEFT, TOP); - text("Options", x + padding, y + padding); - pushStyle(); - fill(boxColor); - stroke(boxStrokeColor); - strokeWeight(1); - rect(x, y, w, h); - fill(bgColor); - text("UDP OPTIONS", x + padding, y + padding); - textFont(h3, 16); - textAlign(LEFT, TOP); - text("IP", x + padding, y + 50 + padding); - textFont(p4, 14);; - text("Port", x + padding, y + 82 + padding); - popStyle(); - } -}; - -class OSCOptionsBox{ - int x, y, w, h, padding; //size and position - - OSCOptionsBox(int _x, int _y, int _w, int _h, int _padding){ - x = _x; - y = _y; - w = _w; - h = _h; - padding = _padding; - - cp5.addTextfield("osc_ip") - .setPosition(x + 80,y + 35) - .setCaptionLabel("") - .setSize(100,26) - .setFont(f2) - .setFocus(false) - .setColor(color(26,26,26)) - .setColorBackground(color(255,255,255)) // text field bg color - .setColorValueLabel(color(0,0,0)) // text color - .setColorForeground(isSelected_color) // border color when not selected - .setColorActive(isSelected_color) // border color when selected - .setColorCursor(color(26,26,26)) - .setText("localhost") - .align(5, 10, 20, 40) - .onDoublePress(cb) - .setVisible(false) - .setAutoClear(true) - ; - cp5.addTextfield("osc_port") - .setPosition(x + 80,y + 67) - .setCaptionLabel("") - .setSize(100,26) - .setFont(f2) - .setFocus(false) - .setColor(color(26,26,26)) - .setColorBackground(color(255,255,255)) // text field bg color - .setColorValueLabel(color(0,0,0)) // text color - .setColorForeground(isSelected_color) // border color when not selected - .setColorActive(isSelected_color) // border color when selected - .setColorCursor(color(26,26,26)) - .setText("12345") - .align(5, 10, 20, 40) - .onDoublePress(cb) - .setVisible(false) - .setAutoClear(true) - ; - cp5.addTextfield("osc_address") - .setPosition(x + 80,y + 99) - .setCaptionLabel("") - .setSize(100,26) - .setFont(f2) - .setFocus(false) - .setColor(color(26,26,26)) - .setColorBackground(color(255,255,255)) // text field bg color - .setColorValueLabel(color(0,0,0)) // text color - .setColorForeground(isSelected_color) // border color when not selected - .setColorActive(isSelected_color) // border color when selected - .setColorCursor(color(26,26,26)) - .setText("/openbci") - .align(5, 10, 20, 40) - .onDoublePress(cb) - .setVisible(false) - .setAutoClear(true) - ; - } - public void update(){ - } - public void draw(){ - pushStyle(); - fill(boxColor); - stroke(boxStrokeColor); - strokeWeight(1); - rect(x, y, w, h); - fill(bgColor); - textFont(h3, 16); - textAlign(LEFT, TOP); - text("Options", x + padding, y + padding); - pushStyle(); - fill(boxColor); - stroke(boxStrokeColor); - strokeWeight(1); - rect(x, y, w, h); - fill(bgColor); - text("OSC OPTIONS", x + padding, y + padding); - textFont(h3, 16); - textAlign(LEFT, TOP); - text("IP", x + padding, y + 35 + padding); - textFont(p4, 14);; - text("Port", x + padding, y + 67 + padding); - text("Address", x + padding, y + 99 + padding); - popStyle(); - } -}; - -class LSLOptionsBox { - int x, y, w, h, padding; //size and position - - LSLOptionsBox(int _x, int _y, int _w, int _h, int _padding){ - x = _x; - y = _y; - w = _w; - h = _h; - padding = _padding; - - cp5.addTextfield("lsl_data") - .setPosition(x + 115,y + 50) - .setCaptionLabel("") - .setSize(100,26) - .setFont(f2) - .setFocus(false) - .setColor(color(26,26,26)) - .setColorBackground(color(255,255,255)) // text field bg color - .setColorValueLabel(color(0,0,0)) // text color - .setColorForeground(isSelected_color) // border color when not selected - .setColorActive(isSelected_color) // border color when selected - .setColorCursor(color(26,26,26)) - .setText("openbci_data") - .align(5, 10, 20, 40) - .onDoublePress(cb) - .setVisible(false) - .setAutoClear(true) - ; - - cp5.addTextfield("lsl_aux") - .setPosition(x + 115,y + 82) - .setCaptionLabel("") - .setSize(100,26) - .setFont(f2) - .setFocus(false) - .setColor(color(26,26,26)) - .setColorBackground(color(255,255,255)) // text field bg color - .setColorValueLabel(color(0,0,0)) // text color - .setColorForeground(isSelected_color) // border color when not selected - .setColorActive(isSelected_color) // border color when selected - .setColorCursor(color(26,26,26)) - .setText("openbci_aux") - .align(5, 10, 20, 40) - .onDoublePress(cb) - .setVisible(false) - .setAutoClear(true) - ; - } - public void update(){ - } - public void draw(){ - pushStyle(); - fill(boxColor); - stroke(boxStrokeColor); - strokeWeight(1); - rect(x, y, w, h); - fill(bgColor); - textFont(h3, 16); - textAlign(LEFT, TOP); - text("Options", x + padding, y + padding); - pushStyle(); - fill(boxColor); - stroke(boxStrokeColor); - strokeWeight(1); - rect(x, y, w, h); - fill(bgColor); - text("LSL OPTIONS", x + padding, y + padding); - textFont(h3, 16); - textAlign(LEFT, TOP); - text("Data Stream", x + padding, y + 50 + padding); - textFont(p4, 14);; - text("Aux Stream", x + padding, y + 82 + padding); - popStyle(); - } -}; - class SDConverterBox { int x, y, w, h, padding; //size and position diff --git a/OpenBCI_GUI/DataLogging.pde b/OpenBCI_GUI/DataLogging.pde index f89371d..0fc4830 100644 --- a/OpenBCI_GUI/DataLogging.pde +++ b/OpenBCI_GUI/DataLogging.pde @@ -1475,4 +1475,4 @@ public void convertSDFile() { dataWriter.println(); } } -} \ No newline at end of file +} diff --git a/OpenBCI_GUI/DataProcessing.pde b/OpenBCI_GUI/DataProcessing.pde index 6415b20..f246059 100644 --- a/OpenBCI_GUI/DataProcessing.pde +++ b/OpenBCI_GUI/DataProcessing.pde @@ -11,6 +11,14 @@ HashMap processed_file; HashMap index_of_times; HashMap index_of_times_rev; +// indexs +final int DELTA = 0; // 1-4 Hz +final int THETA = 1; // 4-8 Hz +final int ALPHA = 2; // 8-13 Hz +final int BETA = 3; // 13-30 Hz +final int GAMMA = 4; // 30-55 Hz + + //------------------------------------------------------------------------ // Global Functions //------------------------------------------------------------------------ @@ -109,6 +117,8 @@ int getDataIfAvailable(int pointCounter) { //if (eegDataSource==DATASOURCE_PLAYBACKFILE) println("OpenBCI_GUI: getDataIfAvailable: currentTableRowIndex = " + currentTableRowIndex); //println("OpenBCI_GUI: getDataIfAvailable: pointCounter = " + pointCounter); } // close "has enough time passed" + else{ + } } return pointCounter; } @@ -154,6 +164,7 @@ void processNewData() { // w_openbionics.process(); dataProcessing_user.process(yLittleBuff_uV, dataBuffY_uV, dataBuffY_filtY_uV, fftBuff); + dataProcessing.newDataToSend = true; //look to see if the latest data is railed so that we can notify the user on the GUI for (int Ichan=0; Ichan < nchan; Ichan++) is_railed[Ichan].update(dataPacketBuff[lastReadDataPacketInd].values[Ichan]); @@ -330,12 +341,14 @@ int getPlaybackDataFromTable(Table datatable, int currentTableRowIndex, float sc if(!isRunning){ try{ - if(!isOldData) row.getString(nchan+4); - else row.getString(nchan+3); + row.getString(nchan+3); - nchan = 16; + // nchan = 16; AJK 5/31/17 see issue #151 + } + catch (ArrayIndexOutOfBoundsException e){ + println(e); + println("8 Channel"); } - catch (ArrayIndexOutOfBoundsException e){ println("8 Channel");} } } @@ -357,14 +370,26 @@ class DataProcessing { private int currentNotch_ind = 0; // set to 0 to default to 60Hz, set to 1 to default to 50Hz float data_std_uV[]; float polarity[]; - + boolean newDataToSend; + private String[] binNames; + final int[] processing_band_low_Hz = { + 1, 4, 8, 13, 30 + }; //lower bound for each frequency band of interest (2D classifier only) + final int[] processing_band_high_Hz = { + 4, 8, 13, 30, 55 + }; //upper bound for each frequency band of interest + float avgPowerInBins[][]; + float headWidePower[]; + int numBins; DataProcessing(int NCHAN, float sample_rate_Hz) { nchan = NCHAN; fs_Hz = sample_rate_Hz; data_std_uV = new float[nchan]; polarity = new float[nchan]; - + newDataToSend = false; + avgPowerInBins = new float[nchan][processing_band_low_Hz.length]; + headWidePower = new float[processing_band_low_Hz.length]; //check to make sure the sample rate is acceptable and then define the filters if (abs(fs_Hz-250.0f) < 1.0) { @@ -650,8 +675,15 @@ class DataProcessing { //convert to uV_per_bin...still need to confirm the accuracy of this code. //Do we need to account for the power lost in the windowing function? CHIP 2014-10-24 - for (int I=0; I < fftBuff[Ichan].specSize(); I++) { //loop over each FFT bin - fftBuff[Ichan].setBand(I, (float)(fftBuff[Ichan].getBand(I) / fftBuff[Ichan].specSize())); + + // FFT ref: https://www.mathworks.com/help/matlab/ref/fft.html + // first calculate double-sided FFT amplitude spectrum + for (int I=0; I <= Nfft/2; I++) { + fftBuff[Ichan].setBand(I, (float)(fftBuff[Ichan].getBand(I) / Nfft)); + } + // then convert into single-sided FFT spectrum: DC & Nyquist (i=0 & i=N/2) remain the same, others multiply by two. + for (int I=1; I < Nfft/2; I++) { + fftBuff[Ichan].setBand(I, (float)(fftBuff[Ichan].getBand(I) * 2)); } //average the FFT with previous FFT data so that it makes it smoother in time @@ -674,9 +706,47 @@ class DataProcessing { foo = java.lang.Math.sqrt(foo); } fftBuff[Ichan].setBand(I, (float)foo); //put the smoothed data back into the fftBuff data holder for use by everyone else + // fftBuff[Ichan].setBand(I, 1.0f); // test } //end loop over FFT bins + + // calculate single-sided psd by single-sided FFT amplitude spectrum + // PSD ref: https://www.mathworks.com/help/dsp/ug/estimate-the-power-spectral-density-in-matlab.html + // when i = 1 ~ (N/2-1), psd = (N / fs) * mag(i)^2 / 4 + // when i = 0 or i = N/2, psd = (N / fs) * mag(i)^2 + + for (int i = 0; i < processing_band_low_Hz.length; i++) { + float sum = 0; + // int binNum = 0; + for (int Ibin = 0; Ibin <= Nfft/2; Ibin ++) { // loop over FFT bins + float FFT_freq_Hz = fftBuff[Ichan].indexToFreq(Ibin); // center frequency of this bin + float psdx = 0; + // if the frequency matches a band + if (FFT_freq_Hz >= processing_band_low_Hz[i] && FFT_freq_Hz < processing_band_high_Hz[i]) { + if (Ibin != 0 && Ibin != Nfft/2) { + psdx = fftBuff[Ichan].getBand(Ibin) * fftBuff[Ichan].getBand(Ibin) * Nfft/get_fs_Hz_safe() / 4; + } + else { + psdx = fftBuff[Ichan].getBand(Ibin) * fftBuff[Ichan].getBand(Ibin) * Nfft/get_fs_Hz_safe(); + } + sum += psdx; + // binNum ++; + } + } + avgPowerInBins[Ichan][i] = sum; // total power in a band + // println(i, binNum, sum); + } } //end the loop over channels. + for (int i = 0; i < processing_band_low_Hz.length; i++) { + float sum = 0; + + for (int j = 0; j < nchan; j++) { + sum += avgPowerInBins[j][i]; + } + headWidePower[i] = sum/nchan; // averaging power over all channels + } + //delta in channel 2 ... avgPowerInBins[1][DELTA]; + //headwide beta ... headWidePower[BETA]; //find strongest channel int refChanInd = findMax(data_std_uV); @@ -696,5 +766,12 @@ class DataProcessing { polarity[Ichan]=-1.0; } } + + // println("Brain Wide DELTA = " + headWidePower[DELTA]); + // println("Brain Wide THETA = " + headWidePower[THETA]); + // println("Brain Wide ALPHA = " + headWidePower[ALPHA]); + // println("Brain Wide BETA = " + headWidePower[BETA]); + // println("Brain Wide GAMMA = " + headWidePower[GAMMA]); + } } diff --git a/OpenBCI_GUI/GanglionSync.pde b/OpenBCI_GUI/GanglionSync.pde index c760134..1300ee1 100644 --- a/OpenBCI_GUI/GanglionSync.pde +++ b/OpenBCI_GUI/GanglionSync.pde @@ -419,7 +419,7 @@ class OpenBCI_Ganglion { } } } - + private void processStatus(String msg) { String[] list = split(msg, ','); int code = Integer.parseInt(list[1]); @@ -430,7 +430,7 @@ class OpenBCI_Ganglion { if (code == RESP_ERROR_BAD_NOBLE_START) { println("OpenBCI_Ganglion: processStatus: Problem in the Hub"); output("Problem starting Ganglion Hub. Please make sure compatible USB is configured, then restart this GUI."); - } else { + } else { println("OpenBCI_Ganglion: processStatus: Started Successfully"); } } @@ -611,6 +611,15 @@ class OpenBCI_Ganglion { safeTCPWrite(TCP_CMD_COMMAND + "," + command_stop + TCP_STOP); } + + /** + * @description Sends a command to ganglion board + */ + public void passthroughCommand(char c) { + println("OpenBCI_Ganglion: passthroughCommand(): sending \'" + c); + safeTCPWrite(TCP_CMD_COMMAND + "," + c + TCP_STOP); + } + /** * @description Write to TCP server * @params out {String} - The string message to write to the server. @@ -718,4 +727,4 @@ class OpenBCI_Ganglion { controlPanel.open(); output("Ganglion now in bootloader mode! Enjoy!"); } -}; \ No newline at end of file +}; diff --git a/OpenBCI_GUI/HardwareSync.pde b/OpenBCI_GUI/HardwareSync.pde index f588511..a85b7d6 100644 --- a/OpenBCI_GUI/HardwareSync.pde +++ b/OpenBCI_GUI/HardwareSync.pde @@ -98,14 +98,6 @@ void serialEvent(Serial port){ numPacketsDropped = 0; } - //If networking enabled --> send data every sample if 8 channels or every other sample if 16 channels - if (networkType !=0) { - if (nchan==8) { - sendRawData_dataPacket(dataPacketBuff[curDataPacketInd], openBCI.get_scale_fac_uVolts_per_count(), openBCI.get_scale_fac_accel_G_per_count()); - } else if ((nchan==16) && ((dataPacketBuff[curDataPacketInd].sampleIndex %2)!=1)) { - sendRawData_dataPacket(dataPacketBuff[curDataPacketInd], openBCI.get_scale_fac_uVolts_per_count(), openBCI.get_scale_fac_accel_G_per_count()); - } - } switch (outputDataSource) { case OUTPUT_SOURCE_ODF: fileoutput_odf.writeRawData_dataPacket(dataPacketBuff[curDataPacketInd], openBCI.get_scale_fac_uVolts_per_count(), openBCI.get_scale_fac_accel_G_per_count()); diff --git a/OpenBCI_GUI/Interactivity.pde b/OpenBCI_GUI/Interactivity.pde index 664dcf2..5414411 100644 --- a/OpenBCI_GUI/Interactivity.pde +++ b/OpenBCI_GUI/Interactivity.pde @@ -236,6 +236,7 @@ void parseKey(char val) { case 's': println("case s..."); stopRunning(); + // stopButtonWasPressed(); break; case 'b': @@ -319,12 +320,14 @@ void parseKey(char val) { break; default: - println("OpenBCI_GUI: '" + key + "' Pressed...sending to OpenBCI..."); - // if (openBCI.serial_openBCI != null) openBCI.serial_openBCI.write(key);//send the value as ascii with a newline character - //if (openBCI.serial_openBCI != null) openBCI.serial_openBCI.write(key);//send the value as ascii with a newline character - openBCI.sendChar(key); - - break; + if (eegDataSource == DATASOURCE_NORMAL_W_AUX) { + println("Interactivity: '" + key + "' Pressed...sending to Cyton..."); + openBCI.sendChar(key); + } else if (eegDataSource == DATASOURCE_GANGLION) { + println("Interactivity: '" + key + "' Pressed...sending to Ganglion..."); + ganglion.passthroughCommand(key); + } + break; } } @@ -443,7 +446,16 @@ void parseKeycode(int val) { } } +void mouseDragged() { + if (systemMode >= SYSTEMMODE_POSTINIT) { + + //calling mouse dragged inly outside of Control Panel + if (controlPanel.isOpen == false) { + wm.mouseDragged(); + } + } +} //swtich yard if a click is detected void mousePressed() { diff --git a/OpenBCI_GUI/Networking.pde b/OpenBCI_GUI/Networking.pde deleted file mode 100644 index f8569bb..0000000 --- a/OpenBCI_GUI/Networking.pde +++ /dev/null @@ -1,228 +0,0 @@ -////////////////////////////////////////////////////////////////////////// -// -// Networking -// - responsible for sending data over a Network -// - Three types of networks are available: -// - UDP -// - OSC -// - LSL -// - In control panel, specify the network and parameters (port, ip, etc). -// Then, you can receive the streamed data in a variety of different -// programs, given that you specify the correct parameters to receive -// the data stream in those networks. -// -////////////////////////////////////////////////////////////////////////// - -float[] data_to_send; -float[] aux_to_send; -float[] full_message; - -public void sendRawData_dataPacket(DataPacket_ADS1299 data, float scale_to_uV, float scale_for_aux) { - data_to_send = writeValues(data.values,scale_to_uV); - aux_to_send = writeValues(data.auxValues,scale_for_aux); - - full_message = compressArray(data); //Collect packet into full_message array - - //send to appropriate network type - if (networkType == 1){ - udp.send_message(data_to_send); //Send full message to udp - }else if (networkType == 2){ - osc.send_message(data_to_send); //Send full message to osc - }else if (networkType == 3){ - lsl.send_message(data_to_send,aux_to_send); //Send - } -} -// Convert counts to scientific values (uV or G) -private float[] writeValues(int[] values, float scale_fac) { - int nVal = values.length; - float[] temp_buffer = new float[nVal]; - for (int Ival = 0; Ival < nVal; Ival++) { - temp_buffer[Ival] = scale_fac * float(values[Ival]); - } - return temp_buffer; -} - -//Package all data into one array (full_message) for UDP and OSC -private float[] compressArray(DataPacket_ADS1299 data){ - full_message = new float[1 + data_to_send.length + aux_to_send.length]; - full_message[0] = data.sampleIndex; - for (int i=0;i// + /////////////////////////////////////////////////////////////////////////////// // // GUI for controlling the ADS1299-based OpenBCI @@ -24,9 +24,6 @@ import java.util.*; //for Array.copyOfRange() import java.util.Map.Entry; import processing.serial.*; //for serial communication to Arduino/OpenBCI import java.awt.event.*; //to allow for event listener on screen resize -import netP5.*; //for OSC networking -import oscP5.*; //for OSC networking -import hypermedia.net.*; //for UDP networking import processing.net.*; // For TCP networking import grafica.*; import java.lang.reflect.*; // For callbacks @@ -37,6 +34,12 @@ import java.lang.Process; import java.util.Random; import java.awt.Robot; //used for simulating mouse clicks import java.awt.AWTException; +import netP5.*; // for OSC +import oscP5.*; // for OSC +import hypermedia.net.*; //for UDP +import java.nio.ByteBuffer; //for UDP +import edu.ucsd.sccn.LSL; //for LSL + import gifAnimation.*; @@ -60,7 +63,7 @@ final int NCHAN_CYTON = 8; final int NCHAN_CYTON_DAISY = 16; final int NCHAN_GANGLION = 4; -boolean hasIntroAnimation = true; +boolean hasIntroAnimation = false; PImage cog; Gif loadingGIF; Gif loadingGIF_blue; @@ -146,16 +149,6 @@ final int OUTPUT_SOURCE_BDF = 2; // The BDF data format http://www.biosemi.com/f public int outputDataSource = OUTPUT_SOURCE_ODF; // public int outputDataSource = OUTPUT_SOURCE_BDF; -//variables for Networking -int port = 0; -String ip = ""; -String address = ""; -String data_stream = ""; -String aux_stream = ""; -UDPSend udp; -OSCSend osc; -LSLSend lsl; - // Serial output String serial_output_portName = "/dev/tty.usbmodem1411"; //must edit this based on the name of the serial/COM port Serial serial_output; @@ -244,6 +237,8 @@ int hubPid = 0; String nodeHubName = "GanglionHub"; Robot rob3115; +PApplet ourApplet; + //-----------------------------------------1------------------------------- // Global Functions //------------------------------------------------------------------------ @@ -269,6 +264,7 @@ void setup() { println("For more information about how to work with this code base, please visit: http://docs.openbci.com/OpenBCI%20Software/"); //open window size(1024, 768, P2D); + ourApplet = this; frameRate(60); //refresh rate ... this will slow automatically, if your processor can't handle the specified rate smooth(); //turn this off if it's too slow @@ -336,14 +332,14 @@ void setup() { playground = new Playground(navBarHeight); //attempt to open a serial port for "output" - try { - verbosePrint("OpenBCI_GUI.pde: attempting to open serial/COM port for data output = " + serial_output_portName); - serial_output = new Serial(this, serial_output_portName, serial_output_baud); //open the com port - serial_output.clear(); // clear anything in the com port's buffer - } - catch (RuntimeException e) { - verbosePrint("OpenBCI_GUI.pde: could not open " + serial_output_portName); - } + // try { + // verbosePrint("OpenBCI_GUI.pde: attempting to open serial/COM port for data output = " + serial_output_portName); + // serial_output = new Serial(this, serial_output_portName, serial_output_baud); //open the com port + // serial_output.clear(); // clear anything in the com port's buffer + // } + // catch (RuntimeException e) { + // verbosePrint("OpenBCI_GUI.pde: could not open " + serial_output_portName); + // } // println("OpenBCI_GUI: setup: hub is running " + ganglion.isHubRunning()); buttonHelpText = new ButtonHelpText(); @@ -707,6 +703,8 @@ void haltSystem() { ganglion_portName = ""; controlPanel.resetListItems(); + // w_networking.clearCP5(); //closes all networking controllers + // stopDataTransfer(); // make sure to stop data transfer, if data is streaming and being drawn if (eegDataSource == DATASOURCE_NORMAL_W_AUX) { @@ -809,6 +807,7 @@ void systemUpdate() { // for updating data values and variables //re-initialize GUI if screen has been resized and it's been more than 1/2 seccond (to prevent reinitialization of GUI from happening too often) if (screenHasBeenResized) { // GUIWidgets_screenResized(width, height); + ourApplet = this; //reset PApplet... topNav.screenHasBeenResized(width, height); wm.screenResized(); } @@ -979,7 +978,7 @@ void introAnimation() { textLeading(24); fill(31, 69, 110, transparency); textAlign(CENTER, CENTER); - text("OpenBCI GUI v2.1.2\nJanuary 2017", width/2, height/2 + width/9); + text("OpenBCI GUI v2.2.0\nJune 2017", width/2, height/2 + width/9); } //exit intro animation at t2 diff --git a/OpenBCI_GUI/SavedData/OpenBCI-2017-01-17_19-04-34.jpg b/OpenBCI_GUI/SavedData/OpenBCI-2017-01-17_19-04-34.jpg new file mode 100644 index 0000000..fe7f339 Binary files /dev/null and b/OpenBCI_GUI/SavedData/OpenBCI-2017-01-17_19-04-34.jpg differ diff --git a/OpenBCI_GUI/SavedData/OpenBCI-2017-01-17_19-04-36.jpg b/OpenBCI_GUI/SavedData/OpenBCI-2017-01-17_19-04-36.jpg new file mode 100644 index 0000000..ada3994 Binary files /dev/null and b/OpenBCI_GUI/SavedData/OpenBCI-2017-01-17_19-04-36.jpg differ diff --git a/OpenBCI_GUI/SavedData/OpenBCI-2017-01-17_19-04-37.jpg b/OpenBCI_GUI/SavedData/OpenBCI-2017-01-17_19-04-37.jpg new file mode 100644 index 0000000..8007858 Binary files /dev/null and b/OpenBCI_GUI/SavedData/OpenBCI-2017-01-17_19-04-37.jpg differ diff --git a/OpenBCI_GUI/SavedData/OpenBCI-2017-01-17_19-04-38.jpg b/OpenBCI_GUI/SavedData/OpenBCI-2017-01-17_19-04-38.jpg new file mode 100644 index 0000000..4840e7d Binary files /dev/null and b/OpenBCI_GUI/SavedData/OpenBCI-2017-01-17_19-04-38.jpg differ diff --git a/OpenBCI_GUI/SavedData/OpenBCI-2017-01-17_19-04-40.jpg b/OpenBCI_GUI/SavedData/OpenBCI-2017-01-17_19-04-40.jpg new file mode 100644 index 0000000..cba94bf Binary files /dev/null and b/OpenBCI_GUI/SavedData/OpenBCI-2017-01-17_19-04-40.jpg differ diff --git a/OpenBCI_GUI/SavedData/OpenBCI-2017-01-22_10-18-48.jpg b/OpenBCI_GUI/SavedData/OpenBCI-2017-01-22_10-18-48.jpg new file mode 100644 index 0000000..92061db Binary files /dev/null and b/OpenBCI_GUI/SavedData/OpenBCI-2017-01-22_10-18-48.jpg differ diff --git a/OpenBCI_GUI/SavedData/OpenBCI-2017-01-22_10-18-52.jpg b/OpenBCI_GUI/SavedData/OpenBCI-2017-01-22_10-18-52.jpg new file mode 100644 index 0000000..9632468 Binary files /dev/null and b/OpenBCI_GUI/SavedData/OpenBCI-2017-01-22_10-18-52.jpg differ diff --git a/OpenBCI_GUI/SavedData/OpenBCI-2017-01-22_10-19-15.jpg b/OpenBCI_GUI/SavedData/OpenBCI-2017-01-22_10-19-15.jpg new file mode 100644 index 0000000..a9a0aff Binary files /dev/null and b/OpenBCI_GUI/SavedData/OpenBCI-2017-01-22_10-19-15.jpg differ diff --git a/OpenBCI_GUI/SavedData/OpenBCI-2017-01-27_13-41-32.jpg b/OpenBCI_GUI/SavedData/OpenBCI-2017-01-27_13-41-32.jpg new file mode 100644 index 0000000..8dd40cc Binary files /dev/null and b/OpenBCI_GUI/SavedData/OpenBCI-2017-01-27_13-41-32.jpg differ diff --git a/OpenBCI_GUI/SavedData/OpenBCI-2017-01-27_13-41-55.jpg b/OpenBCI_GUI/SavedData/OpenBCI-2017-01-27_13-41-55.jpg new file mode 100644 index 0000000..91e40df Binary files /dev/null and b/OpenBCI_GUI/SavedData/OpenBCI-2017-01-27_13-41-55.jpg differ diff --git a/OpenBCI_GUI/SavedData/OpenBCI-2017-01-27_13-42-06.jpg b/OpenBCI_GUI/SavedData/OpenBCI-2017-01-27_13-42-06.jpg new file mode 100644 index 0000000..5b73daa Binary files /dev/null and b/OpenBCI_GUI/SavedData/OpenBCI-2017-01-27_13-42-06.jpg differ diff --git a/OpenBCI_GUI/SavedData/OpenBCI-2017-01-27_13-42-26.jpg b/OpenBCI_GUI/SavedData/OpenBCI-2017-01-27_13-42-26.jpg new file mode 100644 index 0000000..ec45a19 Binary files /dev/null and b/OpenBCI_GUI/SavedData/OpenBCI-2017-01-27_13-42-26.jpg differ diff --git a/OpenBCI_GUI/SavedData/OpenBCI-2017-01-27_13-42-29.jpg b/OpenBCI_GUI/SavedData/OpenBCI-2017-01-27_13-42-29.jpg new file mode 100644 index 0000000..4adf779 Binary files /dev/null and b/OpenBCI_GUI/SavedData/OpenBCI-2017-01-27_13-42-29.jpg differ diff --git a/OpenBCI_GUI/SavedData/OpenBCI-2017-01-27_13-42-31.jpg b/OpenBCI_GUI/SavedData/OpenBCI-2017-01-27_13-42-31.jpg new file mode 100644 index 0000000..1407532 Binary files /dev/null and b/OpenBCI_GUI/SavedData/OpenBCI-2017-01-27_13-42-31.jpg differ diff --git a/OpenBCI_GUI/SavedData/OpenBCI-2017-01-27_13-42-33.jpg b/OpenBCI_GUI/SavedData/OpenBCI-2017-01-27_13-42-33.jpg new file mode 100644 index 0000000..5d8bbdf Binary files /dev/null and b/OpenBCI_GUI/SavedData/OpenBCI-2017-01-27_13-42-33.jpg differ diff --git a/OpenBCI_GUI/SavedData/OpenBCI-2017-01-27_13-42-34.jpg b/OpenBCI_GUI/SavedData/OpenBCI-2017-01-27_13-42-34.jpg new file mode 100644 index 0000000..21d57ab Binary files /dev/null and b/OpenBCI_GUI/SavedData/OpenBCI-2017-01-27_13-42-34.jpg differ diff --git a/OpenBCI_GUI/SavedData/OpenBCI-2017-02-02_23-06-29.jpg b/OpenBCI_GUI/SavedData/OpenBCI-2017-02-02_23-06-29.jpg new file mode 100644 index 0000000..dc90d1f Binary files /dev/null and b/OpenBCI_GUI/SavedData/OpenBCI-2017-02-02_23-06-29.jpg differ diff --git a/OpenBCI_GUI/SavedData/OpenBCI-2017-02-02_23-06-30.jpg b/OpenBCI_GUI/SavedData/OpenBCI-2017-02-02_23-06-30.jpg new file mode 100644 index 0000000..bcbeb06 Binary files /dev/null and b/OpenBCI_GUI/SavedData/OpenBCI-2017-02-02_23-06-30.jpg differ diff --git a/OpenBCI_GUI/SavedData/OpenBCI-2017-02-02_23-06-34.jpg b/OpenBCI_GUI/SavedData/OpenBCI-2017-02-02_23-06-34.jpg new file mode 100644 index 0000000..e8be588 Binary files /dev/null and b/OpenBCI_GUI/SavedData/OpenBCI-2017-02-02_23-06-34.jpg differ diff --git a/OpenBCI_GUI/SavedData/OpenBCI-2017-02-02_23-06-35.jpg b/OpenBCI_GUI/SavedData/OpenBCI-2017-02-02_23-06-35.jpg new file mode 100644 index 0000000..3636f83 Binary files /dev/null and b/OpenBCI_GUI/SavedData/OpenBCI-2017-02-02_23-06-35.jpg differ diff --git a/OpenBCI_GUI/SavedData/OpenBCI-2017-02-02_23-06-36.jpg b/OpenBCI_GUI/SavedData/OpenBCI-2017-02-02_23-06-36.jpg new file mode 100644 index 0000000..691dc4a Binary files /dev/null and b/OpenBCI_GUI/SavedData/OpenBCI-2017-02-02_23-06-36.jpg differ diff --git a/OpenBCI_GUI/SavedData/OpenBCI-2017-03-04_02-26-27.jpg b/OpenBCI_GUI/SavedData/OpenBCI-2017-03-04_02-26-27.jpg new file mode 100644 index 0000000..c7ec8d5 Binary files /dev/null and b/OpenBCI_GUI/SavedData/OpenBCI-2017-03-04_02-26-27.jpg differ diff --git a/OpenBCI_GUI/SavedData/OpenBCI-2017-03-04_02-26-29.jpg b/OpenBCI_GUI/SavedData/OpenBCI-2017-03-04_02-26-29.jpg new file mode 100644 index 0000000..e7b0f54 Binary files /dev/null and b/OpenBCI_GUI/SavedData/OpenBCI-2017-03-04_02-26-29.jpg differ diff --git a/OpenBCI_GUI/SavedData/OpenBCI-2017-03-04_02-26-32.jpg b/OpenBCI_GUI/SavedData/OpenBCI-2017-03-04_02-26-32.jpg new file mode 100644 index 0000000..8563c67 Binary files /dev/null and b/OpenBCI_GUI/SavedData/OpenBCI-2017-03-04_02-26-32.jpg differ diff --git a/OpenBCI_GUI/W_BandPower.pde b/OpenBCI_GUI/W_BandPower.pde new file mode 100644 index 0000000..0e8a5da --- /dev/null +++ b/OpenBCI_GUI/W_BandPower.pde @@ -0,0 +1,137 @@ + +//////////////////////////////////////////////////// +// +// W_BandPowers.pde +// +// This is a band power visualization widget! +// (Couldn't think up more) +// This is for visualizing the power of each brainwave band: delta, theta, alpha, beta, gamma +// Averaged over all channels +// +// Created by: Wangshu Sun, May 2017 +// +///////////////////////////////////////////////////, + +class W_BandPower extends Widget { + + GPlot plot3; + String bands[] = {"DELTA", "THETA", "ALPHA", "BETA", "GAMMA"}; + + W_BandPower(PApplet _parent){ + super(_parent); //calls the parent CONSTRUCTOR method of Widget (DON'T REMOVE) + + //This is the protocol for setting up dropdowns. + //Note that these 3 dropdowns correspond to the 3 global functions below + //You just need to make sure the "id" (the 1st String) has the same name as the corresponding function + // addDropdown("Dropdown1", "Drop 1", Arrays.asList("A", "B"), 0); + // addDropdown("Dropdown2", "Drop 2", Arrays.asList("C", "D", "E"), 1); + // addDropdown("Dropdown3", "Drop 3", Arrays.asList("F", "G", "H", "I"), 3); + + // Setup for the third plot + plot3 = new GPlot(_parent, x, y-navHeight, w, h+navHeight); + plot3.setPos(x, y); + plot3.setDim(w, h); + plot3.setLogScale("y"); + plot3.setYLim(0.1, 100); + plot3.setXLim(0, 5); + plot3.getYAxis().setNTicks(9); + plot3.getTitle().setTextAlignment(LEFT); + plot3.getTitle().setRelativePos(0); + plot3.getYAxis().getAxisLabel().setText("(uV)^2 / Hz per channel"); + plot3.getYAxis().getAxisLabel().setTextAlignment(RIGHT); + plot3.getYAxis().getAxisLabel().setRelativePos(1); + // plot3.setPoints(points3); + plot3.startHistograms(GPlot.VERTICAL); + plot3.getHistogram().setDrawLabels(true); + //plot3.getHistogram().setRotateLabels(true); + plot3.getHistogram().setBgColors(new color[] { + color(0, 0, 255, 50), color(0, 0, 255, 100), + color(0, 0, 255, 150), color(0, 0, 255, 200) + } + ); + + } + + void update(){ + super.update(); //calls the parent update() method of Widget (DON'T REMOVE) + + GPointsArray points3 = new GPointsArray(dataProcessing.headWidePower.length); + points3.add(DELTA + 0.5, dataProcessing.headWidePower[DELTA], "DELTA"); + points3.add(THETA + 0.5, dataProcessing.headWidePower[THETA], "THETA"); + points3.add(ALPHA + 0.5, dataProcessing.headWidePower[ALPHA], "ALPHA"); + points3.add(BETA + 0.5, dataProcessing.headWidePower[BETA], "BETA"); + points3.add(GAMMA + 0.5, dataProcessing.headWidePower[GAMMA], "GAMMA"); + + plot3.setPoints(points3); + plot3.getTitle().setText("Band Power"); + + } + + void draw(){ + super.draw(); //calls the parent draw() method of Widget (DON'T REMOVE) + + //put your code here... //remember to refer to x,y,w,h which are the positioning variables of the Widget class + // Draw the third plot + plot3.beginDraw(); + plot3.drawBackground(); + plot3.drawBox(); + plot3.drawYAxis(); + plot3.drawTitle(); + plot3.drawHistograms(); + plot3.endDraw(); + + } + + void screenResized(){ + super.screenResized(); //calls the parent screenResized() method of Widget (DON'T REMOVE) + + //put your code here... + plot3.setPos(x, y-navHeight);//update position + plot3.setOuterDim(w, h+navHeight);//update dimensions + + + } + + void mousePressed(){ + super.mousePressed(); //calls the parent mousePressed() method of Widget (DON'T REMOVE) + + //put your code here... + + } + + void mouseReleased(){ + super.mouseReleased(); //calls the parent mouseReleased() method of Widget (DON'T REMOVE) + + //put your code here... + + } + + //add custom functions here + void customFunction(){ + //this is a fake function... replace it with something relevant to this widget + + } + +}; + +// //These functions need to be global! These functions are activated when an item from the corresponding dropdown is selected +// void Dropdown1(int n){ +// println("Item " + (n+1) + " selected from Dropdown 1"); +// if(n==0){ +// //do this +// } else if(n==1){ +// //do this instead +// } +// +// closeAllDropdowns(); // do this at the end of all widget-activated functions to ensure proper widget interactivity ... we want to make sure a click makes the menu close +// } +// +// void Dropdown2(int n){ +// println("Item " + (n+1) + " selected from Dropdown 2"); +// closeAllDropdowns(); +// } +// +// void Dropdown3(int n){ +// println("Item " + (n+1) + " selected from Dropdown 3"); +// closeAllDropdowns(); +// } diff --git a/OpenBCI_GUI/W_headPlot.pde b/OpenBCI_GUI/W_headPlot.pde index 2c2caf5..e27f7a6 100644 --- a/OpenBCI_GUI/W_headPlot.pde +++ b/OpenBCI_GUI/W_headPlot.pde @@ -71,14 +71,21 @@ class W_headPlot extends Widget { super.mousePressed(); //calls the parent mousePressed() method of Widget (DON'T REMOVE) //put your code here... - + headPlot.mousePressed(); } void mouseReleased(){ super.mouseReleased(); //calls the parent mouseReleased() method of Widget (DON'T REMOVE) //put your code here... + headPlot.mouseReleased(); + } + + void mouseDragged(){ + super.mouseDragged(); //calls the parent mouseReleased() method of Widget (DON'T REMOVE) + //put your code here... + headPlot.mouseDragged(); } //add custom class functions here @@ -208,6 +215,9 @@ class HeadPlot { private boolean plot_color_as_log = true; public float smooth_fac = 0.0f; private boolean use_polarity = true; + private int mouse_over_elec_index = -1; + private boolean isDragging = false; + private float drag_x, drag_y; HeadPlot(float x, float y, float w, float h, int win_x, int win_y, int n) { final int n_elec = n; //8 electrodes assumed....or 16 for 16-channel? Change this!!! @@ -1223,6 +1233,38 @@ class HeadPlot { } } + private boolean isMouseOverElectrode(int n){ + float elec_mouse_x_dist = electrode_xy[n][0] - mouseX; + float elec_mouse_y_dist = electrode_xy[n][1] - mouseY; + return elec_mouse_x_dist * elec_mouse_x_dist + elec_mouse_y_dist * elec_mouse_y_dist < elec_diam * elec_diam / 4; + } + + private boolean isDraggedElecInsideHead() { + int dx = mouseX - circ_x; + int dy = mouseY - circ_y; + return dx * dx + dy * dy < (circ_diam - elec_diam) * (circ_diam - elec_diam) / 4; + } + + void mousePressed() { + if (mouse_over_elec_index > -1) { + isDragging = true; + drag_x = mouseX - electrode_xy[mouse_over_elec_index][0]; + drag_y = mouseY - electrode_xy[mouse_over_elec_index][1]; + } else { + isDragging = false; + } + } + + void mouseDragged() { + if (isDragging && mouse_over_elec_index > -1 && isDraggedElecInsideHead()) { + electrode_xy[mouse_over_elec_index][0] = mouseX - drag_x; + electrode_xy[mouse_over_elec_index][1] = mouseY - drag_y; + } + } + + void mouseReleased() { + isDragging = false; + } public boolean isPixelInsideHead(int pixel_x, int pixel_y) { int dx = pixel_x - circ_x; @@ -1275,14 +1317,25 @@ class HeadPlot { } //draw electrodes on the head - strokeWeight(1); + if (!isDragging) { + mouse_over_elec_index = -1; + } for (int Ielec=0; Ielec < electrode_xy.length; Ielec++) { if (drawHeadAsContours) { noFill(); //make transparent to allow color to come through from below } else { fill(electrode_rgb[0][Ielec], electrode_rgb[1][Ielec], electrode_rgb[2][Ielec]); } - ellipse(electrode_xy[Ielec][0], electrode_xy[Ielec][1], elec_diam, elec_diam); //big circle for the head + if (!isDragging && isMouseOverElectrode(Ielec)) { + //electrode with a bigger index gets priority in dragging + mouse_over_elec_index = Ielec; + strokeWeight(2); + } else if (mouse_over_elec_index == Ielec) { + strokeWeight(2); + } else{ + strokeWeight(1); + } + ellipse(electrode_xy[Ielec][0], electrode_xy[Ielec][1], elec_diam, elec_diam); //electrode circle } //add labels to electrodes diff --git a/OpenBCI_GUI/W_networking.pde b/OpenBCI_GUI/W_networking.pde index ae26ea9..ffc62a9 100644 --- a/OpenBCI_GUI/W_networking.pde +++ b/OpenBCI_GUI/W_networking.pde @@ -1,120 +1,1559 @@ - -//////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// +// W_networking.pde (Networking Widget) +// +// This widget provides networking capabilities in the OpenBCI GUI. +// The networking protocols can be used for outputting data +// from the OpenBCI GUI to any program that can receive UDP, OSC, +// or LSL input, such as Matlab, MaxMSP, Python, C/C++, etc. // -// W_template.pde (ie "Widget Template") +// The protocols included are: UDP, OSC, and LSL. // -// This is a Template Widget, intended to be used as a starting point for OpenBCI Community members that want to develop their own custom widgets! -// Good luck! If you embark on this journey, please let us know. Your contributions are valuable to everyone! // -// Created by: Conor Russomanno, November 2016 +// Created by: Gabriel Ibagon (github.com/gabrielibagon), January 2017 // -///////////////////////////////////////////////////, +/////////////////////////////////////////////////////////////////////////////// + class W_networking extends Widget { - //to see all core variables/methods of the Widget class, refer to Widget.pde - //put your custom variables here... - Button widgetTemplateButton; - int protocolMode = 0; + /* Variables for protocol selection */ + int protocolIndex; + String protocolMode; + + /* Widget CP5 */ + ControlP5 cp5_networking; + ControlP5 cp5_networking_dropdowns; + ControlP5 cp5_networking_baudRate; + ControlP5 cp5_networking_portName; + + boolean dataDropdownsShouldBeClosed = false; + // CColor dropdownColors_networking = new CColor(); + + // PApplet ourApplet; + + /* UI Organization */ + /* Widget grid */ + int column0; + int column1; + int column2; + int column3; + int fullColumnWidth; + int twoThirdsWidth; + int row0; + int row1; + int row2; + int row3; + int row4; + int row5; + + /* UI */ + Boolean osc_visible; + Boolean udp_visible; + Boolean lsl_visible; + Boolean serial_visible; + List dataTypes; + Button startButton; + + /* Networking */ + Boolean networkActive; + + /* Streams Objects */ + Stream stream1; + Stream stream2; + Stream stream3; + + List baudRates; + List comPorts; + String defaultBaud; W_networking(PApplet _parent){ - super(_parent); //calls the parent CONSTRUCTOR method of Widget (DON'T REMOVE) + super(_parent); + // ourApplet = _parent; - //This is the protocol for setting up dropdowns. - //Note that these 3 dropdowns correspond to the 3 global functions below - //You just need to make sure the "id" (the 1st String) has the same name as the corresponding function - addDropdown("Protocol", "Drop 1", Arrays.asList("OSC", "UDC", "LSL", "Serial"), protocolMode); - // addDropdown("Dropdown2", "Drop 2", Arrays.asList("C", "D", "E"), 1); - // addDropdown("Dropdown3", "Drop 3", Arrays.asList("F", "G", "H", "I"), 3); + networkActive = false; + stream1 = null; + stream2 = null; + stream3 = null; + dataTypes = Arrays.asList("None", "TimeSeries", "FFT", "EMG", "BandPower", "Widget"); + defaultBaud = "9600"; + baudRates = Arrays.asList("1200", "9600", "57600", "115200"); + protocolMode = "OSC"; //default to OSC + addDropdown("Protocol", "Protocol", Arrays.asList("OSC", "UDP", "LSL", "Serial"), protocolIndex); + comPorts = new ArrayList(Arrays.asList(Serial.list())); + println("comPorts = " + comPorts); - widgetTemplateButton = new Button (x + w/2, y + h/2, 200, navHeight, "Design Your Own Widget!", 12); - widgetTemplateButton.setFont(p4, 14); - widgetTemplateButton.setURL("http://docs.openbci.com/OpenBCI%20Software/"); + + initialize_UI(); + cp5_networking.setAutoDraw(false); + cp5_networking_dropdowns.setAutoDraw(false); + cp5_networking_portName.setAutoDraw(false); + cp5_networking_baudRate.setAutoDraw(false); } + /* ----- USER INTERFACE ----- */ + void update(){ - super.update(); //calls the parent update() method of Widget (DON'T REMOVE) + super.update(); + if(protocolMode.equals("LSL")){ + if(stream1!=null){ + stream1.run(); + } + if(stream2!=null){ + stream2.run(); + } + if(stream2!=null){ + stream2.run(); + } + } //put your code here... + if(dataDropdownsShouldBeClosed){ //this if takes care of the scenario where you select the same widget that is active... + dataDropdownsShouldBeClosed = false; + } else { + if(cp5_networking_dropdowns.get(ScrollableList.class, "dataType1").isOpen()){ + if(!cp5_networking_dropdowns.getController("dataType1").isMouseOver()){ + // println("2"); + cp5_networking_dropdowns.get(ScrollableList.class, "dataType1").close(); + } + } + if(!cp5_networking_dropdowns.get(ScrollableList.class, "dataType1").isOpen()){ + if(cp5_networking_dropdowns.getController("dataType1").isMouseOver()){ + // println("2"); + cp5_networking_dropdowns.get(ScrollableList.class, "dataType1").open(); + } + } + + if(cp5_networking_dropdowns.get(ScrollableList.class, "dataType2").isOpen()){ + if(!cp5_networking_dropdowns.getController("dataType2").isMouseOver()){ + // println("2"); + cp5_networking_dropdowns.get(ScrollableList.class, "dataType2").close(); + } + } + if(!cp5_networking_dropdowns.get(ScrollableList.class, "dataType2").isOpen()){ + if(cp5_networking_dropdowns.getController("dataType2").isMouseOver()){ + // println("2"); + cp5_networking_dropdowns.get(ScrollableList.class, "dataType2").open(); + } + } + + if(cp5_networking_dropdowns.get(ScrollableList.class, "dataType3").isOpen()){ + if(!cp5_networking_dropdowns.getController("dataType3").isMouseOver()){ + // println("2"); + cp5_networking_dropdowns.get(ScrollableList.class, "dataType3").close(); + } + } + if(!cp5_networking_dropdowns.get(ScrollableList.class, "dataType3").isOpen()){ + if(cp5_networking_dropdowns.getController("dataType3").isMouseOver()){ + // println("2"); + cp5_networking_dropdowns.get(ScrollableList.class, "dataType3").open(); + } + } + + if(cp5_networking_baudRate.get(ScrollableList.class, "baud_rate").isOpen()){ + if(!cp5_networking_baudRate.getController("baud_rate").isMouseOver()){ + // println("2"); + cp5_networking_baudRate.get(ScrollableList.class, "baud_rate").close(); + } + } + if(!cp5_networking_baudRate.get(ScrollableList.class, "baud_rate").isOpen() && !cp5_networking_dropdowns.getController("dataType1").isMouseOver()){ + if(cp5_networking_baudRate.getController("baud_rate").isMouseOver()){ + // println("2"); + cp5_networking_baudRate.get(ScrollableList.class, "baud_rate").open(); + } + } + if(cp5_networking_portName.get(ScrollableList.class, "port_name").isOpen()){ + if(!cp5_networking_portName.getController("port_name").isMouseOver()){ + // println("2"); + cp5_networking_portName.get(ScrollableList.class, "port_name").close(); + } + } + if(!cp5_networking_portName.get(ScrollableList.class, "port_name").isOpen() && !cp5_networking_dropdowns.getController("dataType1").isMouseOver() && !cp5_networking_baudRate.getController("baud_rate").isMouseOver()){ + if(cp5_networking_portName.getController("port_name").isMouseOver()){ + // println("2"); + cp5_networking_portName.get(ScrollableList.class, "port_name").open(); + } + } + } } void draw(){ - super.draw(); //calls the parent draw() method of Widget (DON'T REMOVE) + super.draw(); + pushStyle(); + + + + // fill(255,0,0); + // rect(cp5_networking.getController("dataType1").getPosition()[0] - 1, cp5_networking.getController("dataType1").getPosition()[1] - 1, 100 + 2, cp5_networking.get(ScrollableList.class, "dataType1").getHeight()+2); + + showCP5(); - //put your code here... //remember to refer to x,y,w,h which are the positioning variables of the Widget class + cp5_networking.draw(); + + //draw dropdown strokes pushStyle(); + fill(255); + if(!protocolMode.equals("Serial")){ + rect(cp5_networking_dropdowns.getController("dataType1").getPosition()[0] - 1, cp5_networking_dropdowns.getController("dataType1").getPosition()[1] - 1, 100 + 2, cp5_networking_dropdowns.getController("dataType1").getHeight()+2); + rect(cp5_networking_dropdowns.getController("dataType2").getPosition()[0] - 1, cp5_networking_dropdowns.getController("dataType2").getPosition()[1] - 1, 100 + 2, cp5_networking_dropdowns.getController("dataType2").getHeight()+2); + rect(cp5_networking_dropdowns.getController("dataType3").getPosition()[0] - 1, cp5_networking_dropdowns.getController("dataType3").getPosition()[1] - 1, 100 + 2, cp5_networking_dropdowns.getController("dataType3").getHeight()+2); + cp5_networking_dropdowns.draw(); + } + if(protocolMode.equals("Serial")){ + rect(cp5_networking_portName.getController("port_name").getPosition()[0] - 1, cp5_networking_portName.getController("port_name").getPosition()[1] - 1, cp5_networking_portName.getController("port_name").getWidth() + 2, cp5_networking_portName.getController("port_name").getHeight()+2); + cp5_networking_portName.draw(); + rect(cp5_networking_baudRate.getController("baud_rate").getPosition()[0] - 1, cp5_networking_baudRate.getController("baud_rate").getPosition()[1] - 1, cp5_networking_baudRate.getController("baud_rate").getWidth() + 2, cp5_networking_baudRate.getController("baud_rate").getHeight()+2); + cp5_networking_baudRate.draw(); + rect(cp5_networking_dropdowns.getController("dataType1").getPosition()[0] - 1, cp5_networking_dropdowns.getController("dataType1").getPosition()[1] - 1, cp5_networking_dropdowns.getController("dataType1").getWidth() + 2, cp5_networking_dropdowns.getController("dataType1").getHeight()+2); + cp5_networking_dropdowns.draw(); + } + popStyle(); + + + // cp5_networking_dropdowns.draw(); - if(protocolMode == 0){ - fill(255,0,0); - } else if (protocolMode == 1){ - fill(0,255,0); - } else if (protocolMode == 2){ - fill(0,0,255); - } else if (protocolMode == 3){ - fill(0,255,255); + fill(0,0,0);// Background fill: white + textFont(h1,20); + + if(!protocolMode.equals("Serial")){ + // text("Data Type", column0,row1); + text(" Stream 1",column1,row0); + text(" Stream 2",column2,row0); + text(" Stream 3",column3,row0); + } else{ + // text("Data Type", column0,row0+15); } - rect(x, y, w, h); + text("Data Type", column0,row1); + + + startButton.draw(); - widgetTemplateButton.draw(); + // textAlign(RIGHT,TOP); + if(protocolMode.equals("OSC")){ + textFont(f4,40); + text("OSC", x+20,y+h/8+15); + textFont(h1,20); + text("IP", column0,row2); + text("Port", column0,row3); + text("Address",column0,row4); + text("Filters",column0,row5); + }else if (protocolMode.equals("UDP")){ + textFont(f4,40); + text("UDP", x+20,y+h/8+15); + textFont(h1,20); + text("IP", column0,row2); + text("Port", column0,row3); + text("Filters",column0,row4); + }else if (protocolMode.equals("LSL")){ + textFont(f4,40); + text("LSL", x+20,y+h/8+15); + textFont(h1,20); + text("Name", column0,row2); + text("Type", column0,row3); + text("# Chan", column0, row4); + }else if (protocolMode.equals("Serial")){ + textFont(f4,40); + text("Serial", x+20,y+h/8+15); + textFont(h1,20); + text("Baud/Port", column0,row2); + // text("Port Name", column0,row3); + text("Filters",column0,row3); + } popStyle(); } + void initialize_UI(){ + cp5_networking = new ControlP5(pApplet); + cp5_networking_dropdowns = new ControlP5(pApplet); + cp5_networking_baudRate = new ControlP5(pApplet); + cp5_networking_portName = new ControlP5(pApplet); + + /* Textfields */ + // OSC + createTextFields("osc_ip1","127.0.0.1"); + createTextFields("osc_port1","12345"); + createTextFields("osc_address1","/openbci"); + createTextFields("osc_ip2","127.0.0.1"); + createTextFields("osc_port2","12346"); + createTextFields("osc_address2","/openbci"); + createTextFields("osc_ip3","127.0.0.1"); + createTextFields("osc_port3","12347"); + createTextFields("osc_address3","/openbci"); + // UDP + createTextFields("udp_ip1","127.0.0.1"); + createTextFields("udp_port1","12345"); + createTextFields("udp_ip2","127.0.0.1"); + createTextFields("udp_port2","12346"); + createTextFields("udp_ip3","127.0.0.1"); + createTextFields("udp_port3","12347"); + // LSL + createTextFields("lsl_name1","obci_eeg1"); + createTextFields("lsl_type1","EEG"); + createTextFields("lsl_numchan1",Integer.toString(nchan)); + createTextFields("lsl_name2","obci_eeg2"); + createTextFields("lsl_type2","EEG"); + createTextFields("lsl_numchan2",Integer.toString(nchan)); + createTextFields("lsl_name3","obci_eeg3"); + createTextFields("lsl_type3","EEG"); + createTextFields("lsl_numchan3",Integer.toString(nchan)); + + // Serial + //grab list of existing serial port options and store into Arrays.list... + + + + createPortDropdown("port_name", comPorts); + createBaudDropdown("baud_rate", baudRates); + /* General Elements */ + + createRadioButtons("filter1"); + createRadioButtons("filter2"); + createRadioButtons("filter3"); + + createDropdown("dataType1", dataTypes); + createDropdown("dataType2", dataTypes); + createDropdown("dataType3", dataTypes); + + // Start Button + startButton = new Button(x + w/2 - 70,y+h-40,200,20,"Start",14); + startButton.setFont(p4,14); + startButton.setColorNotPressed(color(184,220,105)); + } + + /* Shows and Hides appropriate CP5 elements within widget */ + void showCP5(){ + + + + osc_visible=false; + udp_visible=false; + lsl_visible=false; + serial_visible=false; + + if(protocolMode.equals("OSC")){ + osc_visible = true; + }else if (protocolMode.equals("UDP")){ + udp_visible = true; + }else if (protocolMode.equals("LSL")){ + lsl_visible = true; + }else if (protocolMode.equals("Serial")){ + serial_visible = true; + } + cp5_networking.get(Textfield.class, "osc_ip1").setVisible(osc_visible); + cp5_networking.get(Textfield.class, "osc_port1").setVisible(osc_visible); + cp5_networking.get(Textfield.class, "osc_address1").setVisible(osc_visible); + cp5_networking.get(Textfield.class, "osc_ip2").setVisible(osc_visible); + cp5_networking.get(Textfield.class, "osc_port2").setVisible(osc_visible); + cp5_networking.get(Textfield.class, "osc_address2").setVisible(osc_visible); + cp5_networking.get(Textfield.class, "osc_ip3").setVisible(osc_visible); + cp5_networking.get(Textfield.class, "osc_port3").setVisible(osc_visible); + cp5_networking.get(Textfield.class, "osc_address3").setVisible(osc_visible); + cp5_networking.get(Textfield.class, "udp_ip1").setVisible(udp_visible); + cp5_networking.get(Textfield.class, "udp_port1").setVisible(udp_visible); + cp5_networking.get(Textfield.class, "udp_ip2").setVisible(udp_visible); + cp5_networking.get(Textfield.class, "udp_port2").setVisible(udp_visible); + cp5_networking.get(Textfield.class, "udp_ip3").setVisible(udp_visible); + cp5_networking.get(Textfield.class, "udp_port3").setVisible(udp_visible); + cp5_networking.get(Textfield.class, "lsl_name1").setVisible(lsl_visible); + cp5_networking.get(Textfield.class, "lsl_type1").setVisible(lsl_visible); + cp5_networking.get(Textfield.class, "lsl_numchan1").setVisible(lsl_visible); + cp5_networking.get(Textfield.class, "lsl_name2").setVisible(lsl_visible); + cp5_networking.get(Textfield.class, "lsl_type2").setVisible(lsl_visible); + cp5_networking.get(Textfield.class, "lsl_numchan2").setVisible(lsl_visible); + cp5_networking.get(Textfield.class, "lsl_name3").setVisible(lsl_visible); + cp5_networking.get(Textfield.class, "lsl_type3").setVisible(lsl_visible); + cp5_networking.get(Textfield.class, "lsl_numchan3").setVisible(lsl_visible); + + cp5_networking_portName.get(ScrollableList.class, "port_name").setVisible(serial_visible); + cp5_networking_baudRate.get(ScrollableList.class, "baud_rate").setVisible(serial_visible); + + cp5_networking_dropdowns.get(ScrollableList.class, "dataType1").setVisible(true); + + if(!serial_visible){ + cp5_networking_dropdowns.get(ScrollableList.class, "dataType2").setVisible(true); + cp5_networking_dropdowns.get(ScrollableList.class, "dataType3").setVisible(true); + } else{ + cp5_networking_dropdowns.get(ScrollableList.class, "dataType2").setVisible(false); + cp5_networking_dropdowns.get(ScrollableList.class, "dataType3").setVisible(false); + } + + cp5_networking.get(RadioButton.class, "filter1").setVisible(true); + + if(!serial_visible){ + cp5_networking.get(RadioButton.class, "filter2").setVisible(true); + cp5_networking.get(RadioButton.class, "filter3").setVisible(true); + } else { + cp5_networking.get(RadioButton.class, "filter2").setVisible(false); + cp5_networking.get(RadioButton.class, "filter3").setVisible(false); + } + + } + + /* Create textfields for network parameters */ + void createTextFields(String name, String default_text){ + cp5_networking.addTextfield(name) + .align(10,100,10,100) // Alignment + .setSize(100,20) // Size of textfield + .setFont(f2) + .setFocus(false) // Deselects textfield + .setColor(color(26,26,26)) + .setColorBackground(color(255,255,255)) // text field bg color + .setColorValueLabel(color(0,0,0)) // text color + .setColorForeground(color(26,26,26)) // border color when not selected + .setColorActive(isSelected_color) // border color when selected + .setColorCursor(color(26,26,26)) + .setText(default_text) // Default text in the field + .setCaptionLabel("") // Remove caption label + .setVisible(false) // Initially hidden + .setAutoClear(true) // Autoclear + ; + } + + /* Create radio buttons for filter toggling */ + void createRadioButtons(String name){ + String id = name.substring(name.length()-1); + cp5_networking.addRadioButton(name) + .setSize(10,10) + .setColorForeground(color(120)) + .setColorBackground(color(200,200,200)) // text field bg color + .setColorActive(color(184,220,105)) + .setColorLabel(color(0)) + .setItemsPerRow(2) + .setSpacingColumn(40) + .addItem(id + "-Off", 0) + .addItem(id + "-On", 1) + // .addItem("Off",0) + // .addItem("On",1) + .activate(0) + .setVisible(false) + ; + } + + /* Creating DataType Dropdowns */ + void createDropdown(String name, List _items){ + + cp5_networking_dropdowns.addScrollableList(name) + .setOpen(false) + + .setColorBackground(color(31,69,110)) // text field bg color + .setColorValueLabel(color(255)) // text color + .setColorCaptionLabel(color(255)) + .setColorForeground(color(125)) // border color when not selected + .setColorActive(color(150, 170, 200)) // border color when selected + // .setColorCursor(color(26,26,26)) + + .setSize(100,(_items.size()+1)*(navH-4))// + maxFreqList.size()) + .setBarHeight(navH-4) //height of top/primary bar + .setItemHeight(navH-4) //height of all item/dropdown bars + .addItems(_items) // used to be .addItems(maxFreqList) + .setVisible(false) + ; + cp5_networking_dropdowns.getController(name) + .getCaptionLabel() //the caption label is the text object in the primary bar + .toUpperCase(false) //DO NOT AUTOSET TO UPPERCASE!!! + .setText("None") + .setFont(h4) + .setSize(14) + .getStyle() //need to grab style before affecting the paddingTop + .setPaddingTop(4) + ; + cp5_networking_dropdowns.getController(name) + .getValueLabel() //the value label is connected to the text objects in the dropdown item bars + .toUpperCase(false) //DO NOT AUTOSET TO UPPERCASE!!! + .setText("None") + .setFont(h5) + .setSize(12) //set the font size of the item bars to 14pt + .getStyle() //need to grab style before affecting the paddingTop + .setPaddingTop(3) //4-pixel vertical offset to center text + ; + } + + void createBaudDropdown(String name, List _items){ + cp5_networking_baudRate.addScrollableList(name) + .setOpen(false) + + .setColorBackground(color(31,69,110)) // text field bg color + .setColorValueLabel(color(255)) // text color + .setColorCaptionLabel(color(255)) + .setColorForeground(color(125)) // border color when not selected + .setColorActive(color(150, 170, 200)) // border color when selected + // .setColorCursor(color(26,26,26)) + + .setSize(100,(_items.size()+1)*(navH-4))// + maxFreqList.size()) + .setBarHeight(navH-4) //height of top/primary bar + .setItemHeight(navH-4) //height of all item/dropdown bars + .addItems(_items) // used to be .addItems(maxFreqList) + .setVisible(false) + ; + cp5_networking_baudRate.getController(name) + .getCaptionLabel() //the caption label is the text object in the primary bar + .toUpperCase(false) //DO NOT AUTOSET TO UPPERCASE!!! + .setText(defaultBaud) + .setFont(h4) + .setSize(14) + .getStyle() //need to grab style before affecting the paddingTop + .setPaddingTop(4) + ; + cp5_networking_baudRate.getController(name) + .getValueLabel() //the value label is connected to the text objects in the dropdown item bars + .toUpperCase(false) //DO NOT AUTOSET TO UPPERCASE!!! + .setText("None") + .setFont(h5) + .setSize(12) //set the font size of the item bars to 14pt + .getStyle() //need to grab style before affecting the paddingTop + .setPaddingTop(3) //4-pixel vertical offset to center text + ; + } + + void createPortDropdown(String name, List _items){ + cp5_networking_portName.addScrollableList(name) + .setOpen(false) + + .setColorBackground(color(31,69,110)) // text field bg color + .setColorValueLabel(color(255)) // text color + .setColorCaptionLabel(color(255)) + .setColorForeground(color(125)) // border color when not selected + .setColorActive(color(150, 170, 200)) // border color when selected + // .setColorCursor(color(26,26,26)) + + .setSize(100,(_items.size()+1)*(navH-4))// + maxFreqList.size()) + .setBarHeight(navH-4) //height of top/primary bar + .setItemHeight(navH-4) //height of all item/dropdown bars + .addItems(_items) // used to be .addItems(maxFreqList) + .setVisible(false) + ; + cp5_networking_portName.getController(name) + .getCaptionLabel() //the caption label is the text object in the primary bar + .toUpperCase(false) //DO NOT AUTOSET TO UPPERCASE!!! + .setText("None") + .setFont(h4) + .setSize(14) + .getStyle() //need to grab style before affecting the paddingTop + .setPaddingTop(4) + ; + cp5_networking_portName.getController(name) + .getValueLabel() //the value label is connected to the text objects in the dropdown item bars + .toUpperCase(false) //DO NOT AUTOSET TO UPPERCASE!!! + .setText("None") + .setFont(h5) + .setSize(12) //set the font size of the item bars to 14pt + .getStyle() //need to grab style before affecting the paddingTop + .setPaddingTop(3) //4-pixel vertical offset to center text + ; + } + void screenResized(){ - super.screenResized(); //calls the parent screenResized() method of Widget (DON'T REMOVE) + super.screenResized(); - //put your code here... - widgetTemplateButton.setPos(x + w/2 - widgetTemplateButton.but_dx/2, y + h/2 - widgetTemplateButton.but_dy/2); + cp5_networking.setGraphics(pApplet, 0,0); + cp5_networking_dropdowns.setGraphics(pApplet, 0,0); + cp5_networking_baudRate.setGraphics(pApplet, 0,0); + cp5_networking_portName.setGraphics(pApplet, 0,0); + column0 = x+w/20; + // column1 = x+3*w/10; + // column2 = x+5*w/10; + // column3 = x+7*w/10; + column1 = x+12*w/40; + column2 = x+21*w/40; + column3 = x+30*w/40; + + twoThirdsWidth = (column2+100) - column1; + fullColumnWidth = (column3+100) - column1; + + row0 = y+h/4+10; + row1 = y+4*h/10; + row2 = y+5*h/10; + row3 = y+6*h/10; + row4 = y+7*h/10; + row5 = y+8*h/10; + int offset = 17; + + startButton.setPos(x + w/2 - 70, y + h - 40 ); + cp5_networking.get(Textfield.class, "osc_ip1").setPosition(column1, row2 - offset); + cp5_networking.get(Textfield.class, "osc_port1").setPosition(column1, row3 - offset); + cp5_networking.get(Textfield.class, "osc_address1").setPosition(column1, row4 - offset); + cp5_networking.get(Textfield.class, "osc_ip2").setPosition(column2, row2 - offset); + cp5_networking.get(Textfield.class, "osc_port2").setPosition(column2, row3 - offset); + cp5_networking.get(Textfield.class, "osc_address2").setPosition(column2, row4 - offset); + cp5_networking.get(Textfield.class, "osc_ip3").setPosition(column3, row2 - offset); + cp5_networking.get(Textfield.class, "osc_port3").setPosition(column3, row3 - offset); + cp5_networking.get(Textfield.class, "osc_address3").setPosition(column3, row4 - offset); + cp5_networking.get(Textfield.class, "udp_ip1").setPosition(column1, row2 - offset); + cp5_networking.get(Textfield.class, "udp_port1").setPosition(column1, row3 - offset); + cp5_networking.get(Textfield.class, "udp_ip2").setPosition(column2, row2 - offset); + cp5_networking.get(Textfield.class, "udp_port2").setPosition(column2, row3 - offset); + cp5_networking.get(Textfield.class, "udp_ip3").setPosition(column3, row2 - offset); + cp5_networking.get(Textfield.class, "udp_port3").setPosition(column3, row3 - offset); + cp5_networking.get(Textfield.class, "lsl_name1").setPosition(column1,row2 - offset); + cp5_networking.get(Textfield.class, "lsl_type1").setPosition(column1,row3 - offset); + cp5_networking.get(Textfield.class, "lsl_numchan1").setPosition(column1,row4 - offset); + cp5_networking.get(Textfield.class, "lsl_name2").setPosition(column2,row2 - offset); + cp5_networking.get(Textfield.class, "lsl_type2").setPosition(column2,row3 - offset); + cp5_networking.get(Textfield.class, "lsl_numchan2").setPosition(column2,row4 - offset); + cp5_networking.get(Textfield.class, "lsl_name3").setPosition(column3,row2 - offset); + cp5_networking.get(Textfield.class, "lsl_type3").setPosition(column3,row3 - offset); + cp5_networking.get(Textfield.class, "lsl_numchan3").setPosition(column3,row4 - offset); + + + if (protocolMode.equals("OSC") || protocolMode.equals("LSL")){ + cp5_networking.get(RadioButton.class, "filter1").setPosition(column1, row5 - 10); + cp5_networking.get(RadioButton.class, "filter2").setPosition(column2, row5 - 10); + cp5_networking.get(RadioButton.class, "filter3").setPosition(column3, row5 - 10); + } else if (protocolMode.equals("UDP")){ + cp5_networking.get(RadioButton.class, "filter1").setPosition(column1, row4 - 10); + cp5_networking.get(RadioButton.class, "filter2").setPosition(column2, row4 - 10); + cp5_networking.get(RadioButton.class, "filter3").setPosition(column3, row4 - 10); + } else if (protocolMode.equals("Serial")){ + cp5_networking.get(RadioButton.class, "filter1").setPosition(column1, row3 - 10); + cp5_networking.get(RadioButton.class, "filter2").setPosition(column2, row3 - 10); + cp5_networking.get(RadioButton.class, "filter3").setPosition(column3, row3 - 10); + } + + //Serial Specific + cp5_networking_baudRate.get(ScrollableList.class, "baud_rate").setPosition(column1, row2-offset); + // cp5_networking_portName.get(ScrollableList.class, "port_name").setPosition(column1, row3-offset); + cp5_networking_portName.get(ScrollableList.class, "port_name").setPosition(column2, row2-offset); + cp5_networking_baudRate.get(ScrollableList.class, "baud_rate").setSize(100, (baudRates.size()+1)*(navH-4)); + // cp5_networking_portName.get(ScrollableList.class, "port_name").setSize(fullColumnWidth, (comPorts.size()+1)*(navH-4)); + // cp5_networking_portName.get(ScrollableList.class, "port_name").setSize(fullColumnWidth, (4)*(navH-4)); // + cp5_networking_portName.get(ScrollableList.class, "port_name").setSize(twoThirdsWidth, (5)*(navH-4)); //twoThirdsWidth + + cp5_networking_dropdowns.get(ScrollableList.class, "dataType1").setPosition(column1, row1-offset); + cp5_networking_dropdowns.get(ScrollableList.class, "dataType2").setPosition(column2, row1-offset); + cp5_networking_dropdowns.get(ScrollableList.class, "dataType3").setPosition(column3, row1-offset); } void mousePressed(){ super.mousePressed(); //calls the parent mousePressed() method of Widget (DON'T REMOVE) - - //put your code here... - if(widgetTemplateButton.isMouseHere()){ - widgetTemplateButton.setIsActive(true); + if(startButton.isMouseHere()){ + startButton.setIsActive(true); } + } void mouseReleased(){ super.mouseReleased(); //calls the parent mouseReleased() method of Widget (DON'T REMOVE) - //put your code here... - if(widgetTemplateButton.isActive && widgetTemplateButton.isMouseHere()){ - widgetTemplateButton.goToURL(); + /* If start button was pressed */ + if(startButton.isActive && startButton.isMouseHere()){ + if(!networkActive){ + turnOnButton(); // Change appearance of button + initializeStreams(); // Establish stream + startNetwork(); // Begin streaming + }else{ + turnOffButton(); // Change apppearance of button + stopNetwork(); // Stop streams + } + } + startButton.setIsActive(false); + } + + /* Function call to hide all widget CP5 elements */ + void hideElements(){ + cp5_networking.get(Textfield.class, "osc_ip1").setVisible(false); + cp5_networking.get(Textfield.class, "osc_port1").setVisible(false); + cp5_networking.get(Textfield.class, "osc_address1").setVisible(false); + cp5_networking.get(Textfield.class, "osc_ip2").setVisible(false); + cp5_networking.get(Textfield.class, "osc_port2").setVisible(false); + cp5_networking.get(Textfield.class, "osc_address2").setVisible(false); + cp5_networking.get(Textfield.class, "osc_ip3").setVisible(false); + cp5_networking.get(Textfield.class, "osc_port3").setVisible(false); + cp5_networking.get(Textfield.class, "osc_address3").setVisible(false); + cp5_networking.get(Textfield.class, "udp_ip1").setVisible(false); + cp5_networking.get(Textfield.class, "udp_port1").setVisible(false); + cp5_networking.get(Textfield.class, "udp_ip2").setVisible(false); + cp5_networking.get(Textfield.class, "udp_port2").setVisible(false); + cp5_networking.get(Textfield.class, "udp_ip3").setVisible(false); + cp5_networking.get(Textfield.class, "udp_port3").setVisible(false); + cp5_networking.get(Textfield.class, "lsl_name1").setVisible(false); + cp5_networking.get(Textfield.class, "lsl_type1").setVisible(false); + cp5_networking.get(Textfield.class, "lsl_numchan1").setVisible(false); + cp5_networking.get(Textfield.class, "lsl_name2").setVisible(false); + cp5_networking.get(Textfield.class, "lsl_type2").setVisible(false); + cp5_networking.get(Textfield.class, "lsl_numchan2").setVisible(false); + cp5_networking.get(Textfield.class, "lsl_name3").setVisible(false); + cp5_networking.get(Textfield.class, "lsl_type3").setVisible(false); + cp5_networking.get(Textfield.class, "lsl_numchan3").setVisible(false); + + cp5_networking_dropdowns.get(ScrollableList.class, "dataType1").setVisible(false); + cp5_networking_dropdowns.get(ScrollableList.class, "dataType2").setVisible(false); + cp5_networking_dropdowns.get(ScrollableList.class, "dataType3").setVisible(false); + cp5_networking_portName.get(ScrollableList.class, "port_name").setVisible(false); + cp5_networking_baudRate.get(ScrollableList.class, "baud_rate").setVisible(false); + + cp5_networking.get(RadioButton.class, "filter1").setVisible(false); + cp5_networking.get(RadioButton.class, "filter2").setVisible(false); + cp5_networking.get(RadioButton.class, "filter3").setVisible(false); + //%%%%% + + } + + /* Change appearance of Button to off */ + void turnOffButton(){ + startButton.setColorNotPressed(color(184,220,105)); + startButton.setString("Start"); + } + + void turnOnButton(){ + startButton.setColorNotPressed(color(224, 56, 45)); + startButton.setString("Stop"); + } + + /* Call to shutdown some UI stuff. Called from W_manager, maybe do this differently.. */ + void shutDown(){ + hideElements(); + turnOffButton(); + } + + void initializeStreams(){ + String ip; + int port; + String address; + int filt_pos; + String name; + int nChanLSL; + int baudRate; + String type; + String dt1="None"; + String dt2="None"; + String dt3="None"; + networkActive = true; + switch ((int)cp5_networking_dropdowns.get(ScrollableList.class, "dataType1").getValue()){ + case 0 : dt1 = "None"; + break; + case 1 : dt1 = "TimeSeries"; + break; + case 2 : dt1 = "FFT"; + break; + case 3 : dt1 = "EMG"; + break; + case 4 : dt1 = "BandPower"; + break; + case 5 : dt1 = "Widget"; + break; + } + switch ((int)cp5_networking_dropdowns.get(ScrollableList.class, "dataType2").getValue()){ + case 0 : dt2 = "None"; + break; + case 1 : dt2 = "TimeSeries"; + break; + case 2 : dt2 = "FFT"; + break; + case 3 : dt2 = "EMG"; + break; + case 4 : dt2 = "BandPower"; + break; + case 5 : dt2 = "Widget"; + break; + } + switch ((int)cp5_networking_dropdowns.get(ScrollableList.class, "dataType3").getValue()){ + case 0 : dt3 = "None"; + break; + case 1 : dt3 = "TimeSeries"; + break; + case 2 : dt3 = "FFT"; + break; + case 3 : dt3 = "EMG"; + break; + case 4 : dt3 = "BandPower"; + break; + case 5 : dt3 = "Widget"; + break; + } + + // Establish OSC Streams + if (protocolMode.equals("OSC")){ + if(!dt1.equals("None")){ + ip = cp5_networking.get(Textfield.class, "osc_ip1").getText(); + port = Integer.parseInt(cp5_networking.get(Textfield.class, "osc_port1").getText()); + address = cp5_networking.get(Textfield.class, "osc_address1").getText(); + filt_pos = (int)cp5_networking.get(RadioButton.class, "filter1").getValue(); + stream1 = new Stream(dt1,ip,port,address,filt_pos); + }else{ + stream1 = null; + } + if(!dt2.equals("None")){ + ip = cp5_networking.get(Textfield.class, "osc_ip2").getText(); + port = Integer.parseInt(cp5_networking.get(Textfield.class, "osc_port2").getText()); + address = cp5_networking.get(Textfield.class, "osc_address2").getText(); + filt_pos = (int)cp5_networking.get(RadioButton.class, "filter2").getValue(); + stream2 = new Stream(dt2, ip,port,address,filt_pos); + }else{ + stream2 = null; + } + if(!dt3.equals("None")){ + ip = cp5_networking.get(Textfield.class, "osc_ip3").getText(); + port = Integer.parseInt(cp5_networking.get(Textfield.class, "osc_port3").getText()); + address = cp5_networking.get(Textfield.class, "osc_address3").getText(); + filt_pos = (int)cp5_networking.get(RadioButton.class, "filter3").getValue(); + stream3 = new Stream(dt3, ip,port,address,filt_pos); + }else{ + stream3 = null; + } + + // Establish UDP Streams + }else if (protocolMode.equals("UDP")){ + if(!dt1.equals("None")){ + ip = cp5_networking.get(Textfield.class, "udp_ip1").getText(); + port = Integer.parseInt(cp5_networking.get(Textfield.class, "udp_port1").getText()); + filt_pos = (int)cp5_networking.get(RadioButton.class, "filter1").getValue(); + stream1 = new Stream(dt1,ip,port,filt_pos); + }else{ + stream1 = null; + } + if(!dt2.equals("None")){ + ip = cp5_networking.get(Textfield.class, "udp_ip2").getText(); + port = Integer.parseInt(cp5_networking.get(Textfield.class, "udp_port2").getText()); + filt_pos = (int)cp5_networking.get(RadioButton.class, "filter2").getValue(); + stream2 = new Stream(dt2,ip,port,filt_pos); + }else{ + stream2 = null; + } + if(!dt3.equals("None")){ + ip = cp5_networking.get(Textfield.class, "udp_ip3").getText(); + port = Integer.parseInt(cp5_networking.get(Textfield.class, "udp_port3").getText()); + filt_pos = (int)cp5_networking.get(RadioButton.class, "filter3").getValue(); + stream3 = new Stream(dt3,ip,port,filt_pos); + }else{ + stream3 = null; + } + + // Establish LSL Streams + }else if (protocolMode.equals("LSL")){ + if(!dt1.equals("None")){ + name = cp5_networking.get(Textfield.class, "lsl_name1").getText(); + type = cp5_networking.get(Textfield.class, "lsl_type1").getText(); + nChanLSL = Integer.parseInt(cp5_networking.get(Textfield.class, "lsl_numchan1").getText()); + filt_pos = (int)cp5_networking.get(RadioButton.class, "filter1").getValue(); + stream1 = new Stream(dt1,name,type,nChanLSL,filt_pos); + }else{ + stream1 = null; + } + if(!dt2.equals("None")){ + name = cp5_networking.get(Textfield.class, "lsl_name2").getText(); + type = cp5_networking.get(Textfield.class, "lsl_type2").getText(); + nChanLSL = Integer.parseInt(cp5_networking.get(Textfield.class, "lsl_numchan2").getText()); + filt_pos = (int)cp5_networking.get(RadioButton.class, "filter2").getValue(); + stream2 = new Stream(dt2,name,type,nChanLSL,filt_pos); + }else{ + stream2 = null; + } + if(!dt3.equals("None")){ + name = cp5_networking.get(Textfield.class, "lsl_name3").getText(); + type = cp5_networking.get(Textfield.class, "lsl_type3").getText(); + nChanLSL = Integer.parseInt(cp5_networking.get(Textfield.class, "lsl_numchan3").getText()); + filt_pos = (int)cp5_networking.get(RadioButton.class, "filter3").getValue(); + stream3 = new Stream(dt3,name,type,nChanLSL,filt_pos); + }else{ + stream3 = null; + } + } else if (protocolMode.equals("Serial")){ + // %%%%% + if(!dt1.equals("None")){ + println(comPorts.get((int)(cp5_networking_portName.get(ScrollableList.class, "port_name").getValue()))); + name = comPorts.get((int)(cp5_networking_portName.get(ScrollableList.class, "port_name").getValue())); + // name = cp5_networking_portName.get(ScrollableList.class, "port_name").getItem((int)cp5_networking_portName.get(ScrollableList.class, "port_name").getValue()); + println(Integer.parseInt(baudRates.get((int)(cp5_networking_baudRate.get(ScrollableList.class, "baud_rate").getValue())))); + baudRate = Integer.parseInt(baudRates.get((int)(cp5_networking_baudRate.get(ScrollableList.class, "baud_rate").getValue()))); + + filt_pos = (int)cp5_networking.get(RadioButton.class, "filter1").getValue(); + stream1 = new Stream(dt1,name,baudRate,filt_pos,pApplet); //String dataType, String portName, int baudRate, int filter, PApplet _this + }else{ + stream1 = null; + } } - widgetTemplateButton.setIsActive(false); + } + /* Start networking */ + void startNetwork(){ + if(stream1!=null){ + stream1.start(); + } + if(stream2!=null){ + stream2.start(); + } + if(stream3!=null){ + stream3.start(); + } } - //add custom functions here - void customFunction(){ - //this is a fake function... replace it with something relevant to this widget + /* Stop networking */ + void stopNetwork(){ + networkActive = false; + if (stream1!=null){ + stream1.quit(); + stream1=null; + } + if (stream2!=null){ + stream2.quit(); + stream2=null; + } + if (stream3!=null){ + stream3.quit(); + stream3=null; + } } + void clearCP5(){ + //clears all controllers from ControlP5 instance... + w_networking.cp5_networking.dispose(); + w_networking.cp5_networking_dropdowns.dispose(); + println("clearing cp5_networking..."); + } + + void closeAllDropdowns(){ + dataDropdownsShouldBeClosed = true; + w_networking.cp5_networking_dropdowns.get(ScrollableList.class, "dataType1").close(); + w_networking.cp5_networking_dropdowns.get(ScrollableList.class, "dataType2").close(); + w_networking.cp5_networking_dropdowns.get(ScrollableList.class, "dataType3").close(); + w_networking.cp5_networking_baudRate.get(ScrollableList.class, "baud_rate").close(); + w_networking.cp5_networking_portName.get(ScrollableList.class, "port_name").close(); + } }; -//These functions need to be global! These functions are activated when an item from the corresponding dropdown is selected -void Protocol(int n){ - println("Item " + (n+1) + " selected from Dropdown 1"); - // if(n==0){ - // protcolMode = 0; - // } else if(n==1){ - // protcolMode = 1; - // } else if(n==2){ - // protcolMode = 2; - // } else if(n==3){ - // protcolMode = 3; - // } - w_networking.protocolMode = n; - - closeAllDropdowns(); // do this at the end of all widget-activated functions to ensure proper widget interactivity ... we want to make sure a click makes the menu close +class Stream extends Thread{ + String protocol; + String dataType; + String ip; + int port; + String address; + int filter; + String streamType; + String streamName; + int nChanLSL; + + Boolean isStreaming; + Boolean newData = false; + int numChan = nchan; + // Data buffers + int start = dataBuffY_filtY_uV[0].length-11; + int end = dataBuffY_filtY_uV[0].length-1; + int bufferLen = end-start; + float[] dataToSend = new float[numChan*bufferLen]; + + //OSC Objects + OscP5 osc; + NetAddress netaddress; + OscMessage msg; + //UDP Objects + UDP udp; + ByteBuffer buffer; + // LSL objects + LSL.StreamInfo info_data; + LSL.StreamOutlet outlet_data; + LSL.StreamInfo info_aux; + LSL.StreamOutlet outlet_aux; + + // Serial objects %%%%% + Serial serial_networking; + String portName; + int baudRate; + String serialMessage = ""; + + PApplet pApplet; + + + + /* OSC Stream */ + Stream(String dataType, String ip, int port, String address, int filter){ + this.protocol = "OSC"; + this.dataType = dataType; + this.ip = ip; + this.port = port; + this.address = address; + this.filter = filter; + this.isStreaming = false; + try{ + closeNetwork(); //make sure everything is closed! + }catch (Exception e){ + } + } + /*UDP Stream */ + Stream(String dataType, String ip, int port, int filter){ + this.protocol = "UDP"; + this.dataType = dataType; + this.ip = ip; + this.port = port; + this.filter = filter; + this.isStreaming = false; + if(this.dataType.equals("TimeSeries")){ + buffer = ByteBuffer.allocate(4*numChan); + }else{ + buffer = ByteBuffer.allocate(4*126); + } + try{ + closeNetwork(); //make sure everything is closed! + }catch (Exception e){ + } + } + /* LSL Stream */ + Stream(String dataType, String streamName, String streamType, int nChanLSL, int filter){ + this.protocol = "LSL"; + this.dataType = dataType; + this.streamName = streamName; + this.streamType = streamType; + this.nChanLSL = nChanLSL; + this.filter = filter; + this.isStreaming = false; + try{ + closeNetwork(); //make sure everything is closed! + }catch (Exception e){ + } + } + + // Serial Stream %%%%% + Stream(String dataType, String portName, int baudRate, int filter, PApplet _this){ + // %%%%% + this.protocol = "Serial"; + this.dataType = dataType; + this.portName = portName; + this.baudRate = baudRate; + this.filter = filter; + this.isStreaming = false; + this.pApplet = _this; + if(this.dataType.equals("TimeSeries")){ + buffer = ByteBuffer.allocate(4*numChan); + }else{ + buffer = ByteBuffer.allocate(4*126); + } + + try{ + closeNetwork(); + }catch(Exception e){ + //nothing + } + } + + void start(){ + this.isStreaming = true; + if(!this.protocol.equals("LSL")){ + super.start(); + }else{ + openNetwork(); + } + } + + void run(){ + if (!this.protocol.equals("LSL")){ + openNetwork(); + while(this.isStreaming){ + if(!isRunning){ + try{ + Thread.sleep(1); + }catch (InterruptedException e){ + println(e); + } + }else{ + if (checkForData()){ + if (this.dataType.equals("TimeSeries")){ + sendTimeSeriesData(); + }else if (this.dataType.equals("FFT")){ + sendFFTData(); + }else if (this.dataType.equals("EMG")){ + sendEMGData(); + }else if (this.dataType.equals("BandPower")){ + sendPowerBandData(); + }else if (this.dataType.equals("WIDGET")){ + sendWidgetData(); + } + setDataFalse(); + }else{ + try{ + Thread.sleep(1); + }catch (InterruptedException e){ + println(e); + } + } + } + } + }else if (this.protocol.equals("LSL")){ + if (!isRunning){ + try{ + Thread.sleep(1); + }catch (InterruptedException e){ + println(e); + } + }else{ + if (checkForData()){ + if (this.dataType.equals("TimeSeries")){ + sendTimeSeriesData(); + }else if (this.dataType.equals("FFT")){ + sendFFTData(); + }else if (this.dataType.equals("EMG")){ + sendEMGData(); + }else if (this.dataType.equals("BandPower")){ + sendPowerBandData(); + }else if (this.dataType.equals("WIDGET")){ + sendWidgetData(); + } + setDataFalse(); + // newData = false; + } + } + } + } + + Boolean checkForData(){ + if(this.dataType.equals("TimeSeries")){ + return dataProcessing.newDataToSend; + }else if (this.dataType.equals("FFT")){ + return dataProcessing.newDataToSend; + }else if (this.dataType.equals("EMG")){ + return dataProcessing.newDataToSend; + }else if (this.dataType.equals("BandPower")){ + return dataProcessing.newDataToSend; + }else if (this.dataType.equals("WIDGET")){ + /* ENTER YOUR WIDGET "NEW DATA" RETURN FUNCTION */ + } + return false; + } + + void setDataFalse(){ + if(this.dataType.equals("TimeSeries")){ + dataProcessing.newDataToSend = false; + }else if (this.dataType.equals("FFT")){ + dataProcessing.newDataToSend = false; + }else if (this.dataType.equals("EMG")){ + dataProcessing.newDataToSend = false; + }else if (this.dataType.equals("BandPower")){ + dataProcessing.newDataToSend = false; + }else if (this.dataType.equals("WIDGET")){ + /* ENTER YOUR WIDGET "NEW DATA" RETURN FUNCTION */ + } + } + /* This method contains all of the policies for sending data types */ + void sendTimeSeriesData(){ + // TIME SERIES UNFILTERED + if(filter==0){ + // OSC + if(this.protocol.equals("OSC")){ + for(int i=0;i w){ @@ -48,14 +49,18 @@ void setupWidgets(PApplet _this, ArrayList w){ w_accelerometer.setTitle("Accelerometer"); addWidget(w_accelerometer, w); - // w_networking = new W_networking(_this); - // w_networking.setTitle("Networking"); - // addWidget(w_networking, w); + w_networking = new W_networking(_this); + w_networking.setTitle("Networking"); + addWidget(w_networking, w); w_emg = new W_emg(_this); w_emg.setTitle("EMG"); addWidget(w_emg, w); + w_bandPower = new W_BandPower(_this); + w_bandPower.setTitle("Band Power"); + addWidget(w_bandPower, w); + w_template1 = new W_template(_this); w_template1.setTitle("Widget Template 1"); addWidget(w_template1, w); @@ -162,7 +167,8 @@ class WidgetManager{ } void update(){ - if(visible && updating){ + // if(visible && updating){ + if(visible){ for(int i = 0; i < widgets.size(); i++){ if(widgets.get(i).isActive){ widgets.get(i).update(); @@ -185,6 +191,14 @@ class WidgetManager{ widgets.get(i).draw(); widgets.get(i).drawDropdowns(); popStyle(); + }else{ + if(widgets.get(i).widgetTitle.equals("Networking")){ + try{ + w_networking.shutDown(); + }catch (NullPointerException e){ + println(e); + } + } } } } @@ -213,6 +227,14 @@ class WidgetManager{ } } + void mouseDragged(){ + for(int i = 0; i < widgets.size(); i++){ + if(widgets.get(i).isActive){ + widgets.get(i).mouseDragged(); + } + } + } + void setupLayouts(){ //refer to [PUT_LINK_HERE] for layouts/numbers image //note that the order you create/add these layouts matters... if you reorganize these, the LayoutSelector will be out of order diff --git a/README.md b/README.md index 83862a0..56d926e 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ Project Management Plan: [![Stories in Ready](https://badge.waffle.io/OpenBCI/OpenBCI_GUI_v2.0.svg?label=ready&title=Ready)](http://waffle.io/OpenBCI/OpenBCI_GUI_v2.0) -# OpenBCI_GUI_v2.0 +# OpenBCI_GUI Based on OpenBCI_Processing, OpenBCI_GUI_v2.0 extends the GUI to include additional features, and interfaces with the OpenBCI [Cyton](http://shop.openbci.com/collections/frontpage/products/openbci-32-bit-board-kit?variant=784651699) and [Ganglion](http://shop.openbci.com/collections/frontpage/products/pre-order-ganglion-board?variant=13461804483) hardware systems. Tutorials, and getting started guides can be found on the [OpenBCI Learning Pages](http://docs.openbci.com/Getting%20Started/00-Welcome). For a guide on how to run this code in the Processing IDE, go [to our great docs](http://docs.openbci.com/OpenBCI%20Software/01-OpenBCI_GUI). # IMPORTANT: GANGLION USERS diff --git a/libraries/LSLLink/library/LSLLink.jar b/libraries/LSLLink/library/LSLLink.jar index 39d22a3..dd4412c 100644 Binary files a/libraries/LSLLink/library/LSLLink.jar and b/libraries/LSLLink/library/LSLLink.jar differ diff --git a/libraries/LSLLink/src/main/java/edu/ucsd/sccn/LSL.java b/libraries/LSLLink/src/main/java/edu/ucsd/sccn/LSL.java index f1c2e56..fe44662 100644 --- a/libraries/LSLLink/src/main/java/edu/ucsd/sccn/LSL.java +++ b/libraries/LSLLink/src/main/java/edu/ucsd/sccn/LSL.java @@ -7,19 +7,19 @@ /** * Java API for the lab streaming layer. - * - * The lab streaming layer provides a set of functions to make instrument data accessible - * in real time within a lab network. From there, streams can be picked up by recording programs, + * + * The lab streaming layer provides a set of functions to make instrument data accessible + * in real time within a lab network. From there, streams can be picked up by recording programs, * viewing programs or custom experiment applications that access data streams in real time. * * The API covers two areas: - * - The "push API" allows to create stream outlets and to push data (regular or irregular measurement + * - The "push API" allows to create stream outlets and to push data (regular or irregular measurement * time series, event data, coded audio/video frames, etc.) into them. - * - The "pull API" allows to create stream inlets and read time-synched experiment data from them + * - The "pull API" allows to create stream inlets and read time-synched experiment data from them * (for recording, viewing or experiment control). */ public class LSL { - + /** * Constant to indicate that a stream has variable sampling rate. */ @@ -28,10 +28,10 @@ /** * Constant to indicate that a sample has the next successive time stamp. * This is an optional optimization to transmit less data per sample. - * The stamp is then deduced from the preceding one according to the stream's sampling rate + * The stamp is then deduced from the preceding one according to the stream's sampling rate * (in the case of an irregular rate, the same time stamp as before will is assumed). */ - public static final double DEDUCED_TIMESTAMP = -1.0; + public static final double DEDUCED_TIMESTAMP = -1.0; /** * A very large time duration (> 1 year) for timeout values. @@ -41,31 +41,31 @@ /** * Data format of a channel (each transmitted sample holds an array of channels). - */ + */ public class ChannelFormat { public static final int float32 = 1; /** For up to 24-bit precision measurements in the appropriate physical unit * (e.g., microvolts). Integers from -16777216 to 16777216 are represented accurately. */ - public static final int double64 = 2; /** For universal numeric data as long as permitted by network & disk budget. + public static final int double64 = 2; /** For universal numeric data as long as permitted by network & disk budget. * The largest representable integer is 53-bit. */ public static final int string = 3; /** For variable-length ASCII strings or data blobs, such as video frames, * complex event descriptions, etc. */ - public static final int int32 = 4; /** For high-rate digitized formats that require 32-bit precision. Depends critically on + public static final int int32 = 4; /** For high-rate digitized formats that require 32-bit precision. Depends critically on * meta-data to represent meaningful units. Useful for application event codes or other coded data. */ - public static final int int16 = 5; /** For very high rate signals (40KHz+) or consumer-grade audio + public static final int int16 = 5; /** For very high rate signals (40KHz+) or consumer-grade audio * (for professional audio float is recommended). */ - public static final int int8 = 6; /** For binary signals or other coded data. + public static final int int8 = 6; /** For binary signals or other coded data. * Not recommended for encoding string data. */ - public static final int int64 = 7; /** For now only for future compatibility. Support for this type is not yet exposed in all languages. + public static final int int64 = 7; /** For now only for future compatibility. Support for this type is not yet exposed in all languages. * Also, some builds of liblsl will not be able to send or receive data of this type. */ public static final int undefined = 0; /** Can not be transmitted. */ } - + /** * Protocol version. * The major version is protocol_version() / 100; * The minor version is protocol_version() % 100; - * Clients with different minor versions are protocol-compatible with each other + * Clients with different minor versions are protocol-compatible with each other * while clients with different major versions will refuse to work together. */ public static int protocol_version() { return inst.lsl_protocol_version(); } @@ -79,13 +79,13 @@ /** * Obtain a local system time stamp in seconds. The resolution is better than a millisecond. - * This reading can be used to assign time stamps to samples as they are being acquired. - * If the "age" of a sample is known at a particular time (e.g., from USB transmission - * delays), it can be used as an offset to local_clock() to obtain a better estimate of + * This reading can be used to assign time stamps to samples as they are being acquired. + * If the "age" of a sample is known at a particular time (e.g., from USB transmission + * delays), it can be used as an offset to local_clock() to obtain a better estimate of * when a sample was actually captured. See stream_outlet::push_sample() for a use case. */ public static double local_clock() { return inst.lsl_local_clock(); } - + // ========================== // === Stream Declaration === @@ -98,25 +98,25 @@ * b) core information (stream name, content type, sampling rate) * c) optional meta-data about the stream content (channel labels, measurement units, etc.) * - * Whenever a program wants to provide a new stream on the lab network it will typically first + * Whenever a program wants to provide a new stream on the lab network it will typically first * create a stream_info to describe its properties and then construct a stream_outlet with it to create * the stream on the network. Recipients who discover the outlet can query the stream_info; it is also * written to disk when recording the stream (playing a similar role as a file header). - */ + */ public static class StreamInfo { /** * Construct a new stream_info object. * Core stream information is specified here. Any remaining meta-data can be added later. - * @param name Name of the stream. Describes the device (or product series) that this stream makes available + * @param name Name of the stream. Describes the device (or product series) that this stream makes available * (for use by programs, experimenters or data analysts). Cannot be empty. * @param type Content type of the stream. Please see Table of Content Types in the documentation for naming recommendations. * The content type is the preferred way to find streams (as opposed to searching by name). * @param channel_count Number of channels per sample. This stays constant for the lifetime of the stream. * @param nominal_srate The sampling rate (in Hz) as advertised by the data source, if regular (otherwise set to IRREGULAR_RATE). - * @param channel_format Format/type of each channel. If your channels have different formats, consider supplying + * @param channel_format Format/type of each channel. If your channels have different formats, consider supplying * multiple streams or use the largest type that can hold them all (such as cf_double64). - * @param source_id Unique identifier of the device or source of the data, if available (such as the serial number). - * This is critical for system robustness since it allows recipients to recover from failure even after the + * @param source_id Unique identifier of the device or source of the data, if available (such as the serial number). + * This is critical for system robustness since it allows recipients to recover from failure even after the * serving app, device or computer crashes (just by finding a stream with the same source id on the network again). * Therefore, it is highly recommended to always try to provide whatever information can uniquely identify the data source itself. */ @@ -126,16 +126,16 @@ public StreamInfo(String name, String type, int channel_count) { obj = inst.lsl_create_streaminfo(name, type, channel_count, IRREGULAR_RATE, ChannelFormat.float32, ""); } public StreamInfo(String name, String type) { obj = inst.lsl_create_streaminfo(name, type, 1, IRREGULAR_RATE, ChannelFormat.float32, ""); } public StreamInfo(Pointer handle) { obj = handle; } - + /** Destroy a previously created StreamInfo object. */ public void destroy() { inst.lsl_destroy_streaminfo(obj); } - + // ======================== // === Core Information === // ======================== // (these fields are assigned at construction) - + /** * Name of the stream. This is a human-readable name. For streams * offered by device modules, it refers to the type of device or product @@ -191,13 +191,13 @@ * online. */ public String source_id() { return inst.lsl_get_source_id(obj); } - - + + // ====================================== // === Additional Hosting Information === // ====================================== // (these fields are implicitly assigned once bound to an outlet/inlet) - + /** * Protocol version used to deliver the stream. */ @@ -232,20 +232,20 @@ /** * Hostname of the providing machine. */ - public String hostname() { return inst.lsl_get_hostname(obj); } - + public String hostname() { return inst.lsl_get_hostname(obj); } + // ======================== // === Data Description === // ======================== /** * Extended description of the stream. - * It is highly recommended that at least the channel labels are described here. - * See code examples in the documentation. Other information, such as amplifier settings, - * measurement units if deviating from defaults, setup information, subject information, etc., + * It is highly recommended that at least the channel labels are described here. + * See code examples in the documentation. Other information, such as amplifier settings, + * measurement units if deviating from defaults, setup information, subject information, etc., * can be specified here, as well. See Meta-Data Recommendations in the docs. * - * Important: if you use a stream content type for which meta-data recommendations exist, please + * Important: if you use a stream content type for which meta-data recommendations exist, please * try to lay out your meta-data in agreement with these recommendations for compatibility with other applications. */ public XMLElement desc() { return new XMLElement(inst.lsl_get_desc(obj)); } @@ -264,15 +264,15 @@ * Get access to the underlying native handle. */ public Pointer handle() { return obj; } - + private Pointer obj; } - - + + // ======================= // ==== Stream Outlet ==== // ======================= - + /** * A stream outlet. * Outlets are used to make streaming data (and the meta-data) available on the lab network. @@ -281,10 +281,10 @@ /** * Establish a new stream outlet. This makes the stream discoverable. * @param info The stream information to use for creating this stream. Stays constant over the lifetime of the outlet. - * @param chunk_size Optionally the desired chunk granularity (in samples) for transmission. If unspecified, + * @param chunk_size Optionally the desired chunk granularity (in samples) for transmission. If unspecified, * each push operation yields one chunk. Inlets can override this setting. - * @param max_buffered Optionally the maximum amount of data to buffer (in seconds if there is a nominal - * sampling rate, otherwise x100 in samples). The default is 6 minutes of data. + * @param max_buffered Optionally the maximum amount of data to buffer (in seconds if there is a nominal + * sampling rate, otherwise x100 in samples). The default is 6 minutes of data. */ public StreamOutlet(StreamInfo info, int chunk_size, int max_buffered) { obj = inst.lsl_create_outlet(info.handle(), chunk_size, max_buffered); } public StreamOutlet(StreamInfo info, int chunk_size) { obj = inst.lsl_create_outlet(info.handle(), chunk_size, 360); } @@ -293,16 +293,16 @@ /** * Close the outlet. * The stream will no longer be discoverable after closure and all paired inlets will stop delivering data. - */ + */ public void close() { inst.lsl_destroy_outlet(obj); } - - + + // ======================================== // === Pushing a sample into the outlet === // ======================================== /** - * Push an array of values as a sample into the outlet. + * Push an array of values as a sample into the outlet. * Each entry in the vector corresponds to one channel. * @param data An array of values to push (one for each channel). * @param timestamp Optionally the capture time of the sample, in agreement with local_clock(); if omitted, the current time is used. @@ -326,8 +326,8 @@ public void push_sample(byte[] data) { inst.lsl_push_sample_ctp(obj, data, 0.0, 1); } public void push_sample(String[] data, double timestamp, boolean pushthrough) { inst.lsl_push_sample_strtp(obj, data, timestamp, pushthrough ? 1 : 0); } public void push_sample(String[] data, double timestamp) { inst.lsl_push_sample_strtp(obj, data, timestamp, 1); } - public void push_sample(String[] data) { inst.lsl_push_sample_strtp(obj, data, 0.0, 1); } - + public void push_sample(String[] data) { inst.lsl_push_sample_strtp(obj, data, 0.0, 1); } + // =============================================================== // === Pushing an chunk of multiplexed samples into the outlet === @@ -377,7 +377,7 @@ public void push_chunk(short[] data, double[] timestamps) { inst.lsl_push_chunk_stnp(obj, data, (long)data.length, timestamps, 1); } public void push_chunk(byte[] data, double[] timestamps, boolean pushthrough) { inst.lsl_push_chunk_ctnp(obj, data, (long)data.length, timestamps, pushthrough ? 1 : 0); } public void push_chunk(byte[] data, double[] timestamps) { inst.lsl_push_chunk_ctnp(obj, data, (long)data.length, timestamps, 1); } - public void push_chunk(String[] data, double[] timestamps, boolean pushthrough) { inst.lsl_push_chunk_strtnp(obj, data, (long)data.length, timestamps, pushthrough ? 1 : 0); } + public void push_chunk(String[] data, double[] timestamps, boolean pushthrough) { inst.lsl_push_chunk_strtnp(obj, data, (long)data.length, timestamps, pushthrough ? 1 : 0); } public void push_chunk(String[] data, double[] timestamps) { inst.lsl_push_chunk_strtnp(obj, data, (long)data.length, timestamps, 1); } @@ -400,13 +400,13 @@ /** * Retrieve the stream info provided by this outlet. * This is what was used to create the stream (and also has the Additional Network Information fields assigned). - */ + */ public StreamInfo info() { return new StreamInfo(inst.lsl_get_info(obj)); } - + private Pointer obj; } - - + + // =========================== // ==== Resolve Functions ==== // =========================== @@ -414,15 +414,15 @@ /** * Resolve all streams on the network. * This function returns all currently available streams from any outlet on the network. - * The network is usually the subnet specified at the local router, but may also include + * The network is usually the subnet specified at the local router, but may also include * a multicast group of machines (given that the network supports it), or list of hostnames. - * These details may optionally be customized by the experimenter in a configuration file + * These details may optionally be customized by the experimenter in a configuration file * (see Configuration File in the documentation). * This is the default mechanism used by the browsing programs and the recording program. * @param wait_time The waiting time for the operation, in seconds, to search for streams. - * Warning: If this is too short (less than 0.5s) only a subset (or none) of the + * Warning: If this is too short (less than 0.5s) only a subset (or none) of the * outlets that are present on the network may be returned. - * @return An array of stream info objects (excluding their desc field), any of which can + * @return An array of stream info objects (excluding their desc field), any of which can * subsequently be used to open an inlet. The full info can be retrieve from the inlet. */ public static StreamInfo[] resolve_streams(double wait_time) @@ -443,7 +443,7 @@ * @param minimum Optionally return at least this number of streams. * @param timeout Optionally a timeout of the operation, in seconds (default: no timeout). * If the timeout expires, less than the desired number of streams (possibly none) will be returned. - * @return An array of matching stream info objects (excluding their meta-data), any of + * @return An array of matching stream info objects (excluding their meta-data), any of * which can subsequently be used to open an inlet. */ public static StreamInfo[] resolve_stream(String prop, String value, int minimum, double timeout) @@ -459,13 +459,13 @@ /** * Resolve all streams that match a given predicate. - * Advanced query that allows to impose more conditions on the retrieved streams; the given String is an XPath 1.0 + * Advanced query that allows to impose more conditions on the retrieved streams; the given String is an XPath 1.0 * predicate for the node (omitting the surrounding []'s), see also http://en.wikipedia.org/w/index.php?title=XPath_1.0&oldid=474981951. * @param pred The predicate String, e.g. "name='BioSemi'" or "type='EEG' and starts-with(name,'BioSemi') and count(info/desc/channel)=32" * @param minimum Return at least this number of streams. * @param timeout Optionally a timeout of the operation, in seconds (default: no timeout). * If the timeout expires, less than the desired number of streams (possibly none) will be returned. - * @return An array of matching stream info objects (excluding their meta-data), any of + * @return An array of matching stream info objects (excluding their meta-data), any of * which can subsequently be used to open an inlet. */ public static StreamInfo[] resolve_stream(String pred, int minimum, double timeout) @@ -478,8 +478,8 @@ } public static StreamInfo[] resolve_stream(String pred, int minimum) { return resolve_stream(pred, minimum, FOREVER); } public static StreamInfo[] resolve_stream(String pred) { return resolve_stream(pred, 1, FOREVER); } - - + + // ====================== // ==== Stream Inlet ==== // ====================== @@ -487,26 +487,26 @@ /** * A stream inlet. * Inlets are used to receive streaming data (and meta-data) from the lab network. - */ + */ public static class StreamInlet { /** * Construct a new stream inlet from a resolved stream info. * @param info A resolved stream info object (as coming from one of the resolver functions). - * Note: the stream_inlet may also be constructed with a fully-specified stream_info, - * if the desired channel format and count is already known up-front, but this is - * strongly discouraged and should only ever be done if there is no time to resolve the + * Note: the stream_inlet may also be constructed with a fully-specified stream_info, + * if the desired channel format and count is already known up-front, but this is + * strongly discouraged and should only ever be done if there is no time to resolve the * stream up-front (e.g., due to limitations in the client program). - * @param max_buflen Optionally the maximum amount of data to buffer (in seconds if there is a nominal - * sampling rate, otherwise x100 in samples). Recording applications want to use a fairly - * large buffer size here, while real-time applications would only buffer as much as + * @param max_buflen Optionally the maximum amount of data to buffer (in seconds if there is a nominal + * sampling rate, otherwise x100 in samples). Recording applications want to use a fairly + * large buffer size here, while real-time applications would only buffer as much as * they need to perform their next calculation. - * @param max_chunklen Optionally the maximum size, in samples, at which chunks are transmitted + * @param max_chunklen Optionally the maximum size, in samples, at which chunks are transmitted * (the default corresponds to the chunk sizes used by the sender). - * Recording applications can use a generous size here (leaving it to the network how + * Recording applications can use a generous size here (leaving it to the network how * to pack things), while real-time applications may want a finer (perhaps 1-sample) granularity. * If left unspecified (=0), the sender determines the chunk granularity. - * @param recover Try to silently recover lost streams that are recoverable (=those that that have a source_id set). - * In all other cases (recover is false or the stream is not recoverable) functions may throw a + * @param recover Try to silently recover lost streams that are recoverable (=those that that have a source_id set). + * In all other cases (recover is false or the stream is not recoverable) functions may throw a * LostException if the stream's source is lost (e.g., due to an app or computer crash). */ public StreamInlet(StreamInfo info, int max_buflen, int max_chunklen, boolean recover) { obj = inst.lsl_create_inlet(info.handle(), max_buflen, max_chunklen, recover?1:0); } @@ -514,7 +514,7 @@ public StreamInlet(StreamInfo info, int max_buflen) { obj = inst.lsl_create_inlet(info.handle(), max_buflen, 0, 1); } public StreamInlet(StreamInfo info) { obj = inst.lsl_create_inlet(info.handle(), 360, 0, 1); } - /** + /** * Disconnect and close the inlet. */ public void close() { inst.lsl_destroy_inlet(obj); } @@ -530,21 +530,21 @@ /** * Subscribe to the data stream. - * All samples pushed in at the other end from this moment onwards will be queued and - * eventually be delivered in response to pull_sample() or pull_chunk() calls. + * All samples pushed in at the other end from this moment onwards will be queued and + * eventually be delivered in response to pull_sample() or pull_chunk() calls. * Pulling a sample without some preceding open_stream is permitted (the stream will then be opened implicitly). * @param timeout Optional timeout of the operation (default: no timeout). * @throws TimeoutException (if the timeout expires), or LostException (if the stream source has been lost). */ public void open_stream(double timeout) throws Exception { int[] ec = {0}; inst.lsl_open_stream(obj, timeout, ec); check_error(ec); } public void open_stream() throws Exception { open_stream(FOREVER); } - + /** * Drop the current data stream. - * All samples that are still buffered or in flight will be dropped and transmission - * and buffering of data for this inlet will be stopped. If an application stops being - * interested in data from a source (temporarily or not) but keeps the outlet alive, - * it should call close_stream() to not waste unnecessary system and network + * All samples that are still buffered or in flight will be dropped and transmission + * and buffering of data for this inlet will be stopped. If an application stops being + * interested in data from a source (temporarily or not) but keeps the outlet alive, + * it should call close_stream() to not waste unnecessary system and network * resources. */ public void close_stream() { inst.lsl_close_stream(obj); } @@ -555,13 +555,13 @@ * Subsequent calls are instantaneous (and rely on periodic background updates). * The precision of these estimates should be below 1 ms (empirically within +/-0.2 ms). * @timeout Timeout to acquire the first time-correction estimate (default: no timeout). - * @return The time correction estimate. This is the number that needs to be added to a time stamp + * @return The time correction estimate. This is the number that needs to be added to a time stamp * that was remotely generated via lsl_local_clock() to map it into the local clock domain of this machine. * @throws TimeoutException (if the timeout expires), or LostException (if the stream source has been lost). */ public double time_correction(double timeout) throws Exception { int[] ec = {0}; double res = inst.lsl_time_correction(obj, timeout, ec); check_error(ec); return res; } public double time_correction() throws Exception { return time_correction(FOREVER); } - + // ======================================= // === Pulling a sample from the inlet === // ======================================= @@ -571,12 +571,12 @@ * Handles type checking & conversion. * @param sample An array to hold the resulting values. * @param timeout The timeout for this operation, if any. Use 0.0 to make the function non-blocking. - * @return The capture time of the sample on the remote machine, or 0.0 if no new sample was available. - * To remap this time stamp to the local clock, add the value returned by .time_correction() to it. + * @return The capture time of the sample on the remote machine, or 0.0 if no new sample was available. + * To remap this time stamp to the local clock, add the value returned by .time_correction() to it. * @throws LostException (if the stream source has been lost). */ public double pull_sample(float[] sample, double timeout) throws Exception { int[] ec = {0}; double res = inst.lsl_pull_sample_f(obj, sample, sample.length, timeout, ec); check_error(ec); return res; } - public double pull_sample(float[] sample) throws Exception { return pull_sample(sample, FOREVER); } + public double pull_sample(float[] sample) throws Exception { return pull_sample(sample, FOREVER); } public double pull_sample(double[] sample, double timeout) throws Exception { int[] ec = {0}; double res = inst.lsl_pull_sample_d(obj, sample, sample.length, timeout, ec); check_error(ec); return res; } public double pull_sample(double[] sample) throws Exception { return pull_sample(sample, FOREVER); } public double pull_sample(int[] sample, double timeout) throws Exception { int[] ec = {0}; double res = inst.lsl_pull_sample_i(obj, sample, sample.length, timeout, ec); check_error(ec); return res; } @@ -587,7 +587,7 @@ public double pull_sample(byte[] sample) throws Exception { return pull_sample(sample, FOREVER); } public double pull_sample(String[] sample, double timeout) throws Exception { int[] ec = {0}; double res = inst.lsl_pull_sample_str(obj, sample, sample.length, timeout, ec); check_error(ec); return res; } public double pull_sample(String[] sample) throws Exception { return pull_sample(sample, FOREVER); } - + // ============================================================= @@ -597,14 +597,14 @@ /** * Pull a chunk of data from the inlet. * @param data_buffer A pre-allocated buffer where the channel data shall be stored. - * @param timestamp_buffer A pre-allocated buffer where time stamps shall be stored. - * @param timeout Optionally the timeout for this operation, if any. When the timeout expires, the function - * may return before the entire buffer is filled. The default value of 0.0 will retrieve only + * @param timestamp_buffer A pre-allocated buffer where time stamps shall be stored. + * @param timeout Optionally the timeout for this operation, if any. When the timeout expires, the function + * may return before the entire buffer is filled. The default value of 0.0 will retrieve only * data available for immediate pickup. * @return samples_written Number of samples written to the data and timestamp buffers. * @throws LostException (if the stream source has been lost). */ - public int pull_chunk(float[] data_buffer, double[] timestamp_buffer, double timeout) throws Exception { int[] ec = {0}; long res = inst.lsl_pull_chunk_f(obj, data_buffer, timestamp_buffer, (long)data_buffer.length, (long)timestamp_buffer.length, timeout, ec); check_error(ec); return (int)res; } + public int pull_chunk(float[] data_buffer, double[] timestamp_buffer, double timeout) throws Exception { int[] ec = {0}; long res = inst.lsl_pull_chunk_f(obj, data_buffer, timestamp_buffer, (long)data_buffer.length, (long)timestamp_buffer.length, timeout, ec); check_error(ec); return (int)res; } public int pull_chunk(float[] data_buffer, double[] timestamp_buffer) throws Exception { return pull_chunk(data_buffer, timestamp_buffer, 0.0); } public int pull_chunk(double[] data_buffer, double[] timestamp_buffer, double timeout) throws Exception { int[] ec = {0}; long res = inst.lsl_pull_chunk_d(obj, data_buffer, timestamp_buffer, (long)data_buffer.length, (long)timestamp_buffer.length, timeout, ec); check_error(ec); return (int)res; } public int pull_chunk(double[] data_buffer, double[] timestamp_buffer) throws Exception { return pull_chunk(data_buffer, timestamp_buffer, 0.0); } @@ -619,24 +619,24 @@ /** * Query whether samples are currently available for immediate pickup. - * Note that it is not a good idea to use samples_available() to determine whether + * Note that it is not a good idea to use samples_available() to determine whether * a pull_*() call would block: to be sure, set the pull timeout to 0.0 or an acceptably - * low value. If the underlying implementation supports it, the value will be the number of + * low value. If the underlying implementation supports it, the value will be the number of * samples available (otherwise it will be 1 or 0). */ public int samples_available() { return (int)inst.lsl_samples_available(obj); } /** * Query whether the clock was potentially reset since the last call to was_clock_reset(). - * This is a rarely-used function that is only useful to applications that combine multiple time_correction - * values to estimate precise clock drift; it allows to tolerate cases where the source machine was + * This is a rarely-used function that is only useful to applications that combine multiple time_correction + * values to estimate precise clock drift; it allows to tolerate cases where the source machine was * hot-swapped or restarted in between two measurements. */ public boolean was_clock_reset() { return (int)inst.lsl_was_clock_reset(obj)!=0; } - + private Pointer obj; } - + // ===================== // ==== XML Element ==== @@ -748,23 +748,23 @@ /** Remove a specified child element. */ public void remove_child(XMLElement e) { inst.lsl_remove_child(obj, e.obj); } - + private Pointer obj; } - - + + // =========================== // === Continuous Resolver === // =========================== - /** - * A convenience class that resolves streams continuously in the background throughout - * its lifetime and which can be queried at any time for the set of streams that are currently + /** + * A convenience class that resolves streams continuously in the background throughout + * its lifetime and which can be queried at any time for the set of streams that are currently * visible on the network. */ public static class ContinuousResolver { /** - * Construct a new continuous_resolver that resolves all streams on the network. + * Construct a new continuous_resolver that resolves all streams on the network. * This is analogous to the functionality offered by the free function resolve_streams(). * @param forget_after When a stream is no longer visible on the network (e.g., because it was shut down), * this is the time in seconds after which it is no longer reported by the resolver. @@ -793,31 +793,31 @@ public ContinuousResolver(String pred, double forget_after) { obj = inst.lsl_create_continuous_resolver_bypred(pred, forget_after); } public ContinuousResolver(String pred) { obj = inst.lsl_create_continuous_resolver_bypred(pred, 5.0); } - /** + /** * Close the resolver and stop sending queries. - * It is recommended to close a resolver once not needed any more to avoid spamming + * It is recommended to close a resolver once not needed any more to avoid spamming * the network with resolve queries. */ void close() { inst.lsl_destroy_continuous_resolver(obj); } - + /** * Obtain the set of currently present streams on the network (i.e. resolve result). - * @return An array of matching stream info objects (excluding their meta-data), any of + * @return An array of matching stream info objects (excluding their meta-data), any of * which can subsequently be used to open an inlet. */ public StreamInfo[] results() { - Pointer[] buf = new Pointer[1024]; + Pointer[] buf = new Pointer[1024]; int num = inst.lsl_resolver_results(obj,buf,buf.length); StreamInfo[] res = new StreamInfo[num]; for (int k = 0; k < num; k++) res[k] = new StreamInfo(buf[k]); return res; } - + private Pointer obj; // the underlying native handle } - - + + // ======================= // === Exception Types === // ======================= @@ -828,7 +828,7 @@ public static class TimeoutException extends Exception { public TimeoutException(String message) { super(message); } } - + /** * Exception class that indicates that a stream inlet's source has been irrecoverably lost. */ @@ -842,14 +842,14 @@ public static class ArgumentException extends Exception { public ArgumentException(String message) { super(message); } } - + /** * Exception class that indicates that an internal error has occurred inside liblsl. */ public static class InternalException extends Exception { public InternalException(String message) { super(message); } } - + /** * Check an error condition and throw an exception if appropriate. */ @@ -864,10 +864,10 @@ static void check_error(int[] ec) throws Exception { } } - - /** + + /** * Internal: C library interface. - */ + */ public interface dll extends Library { int lsl_protocol_version(); int lsl_library_version(); @@ -898,7 +898,7 @@ static void check_error(int[] ec) throws Exception { int lsl_push_sample_buftp(Pointer obj, byte[][] data, int[] lengths, double timestamp, int pushthrough); int lsl_push_chunk_ftp(Pointer obj, float[] data, long data_elements, double timestamp, int pushthrough); int lsl_push_chunk_ftnp(Pointer obj, float[] data, long data_elements, double[] timestamps, int pushthrough); - int lsl_push_chunk_dtp(Pointer obj, double[] data, long data_elements, double timestamp, int pushthrough); + int lsl_push_chunk_dtp(Pointer obj, double[] data, long data_elements, double timestamp, int pushthrough); int lsl_push_chunk_dtnp(Pointer obj, double[] data, long data_elements, double[] timestamps, int pushthrough); int lsl_push_chunk_itp(Pointer obj, int[] data, long data_elements, double timestamp, int pushthrough); int lsl_push_chunk_itnp(Pointer obj, int[] data, long data_elements, double[] timestamps, int pushthrough); @@ -908,8 +908,8 @@ static void check_error(int[] ec) throws Exception { int lsl_push_chunk_ctnp(Pointer obj, byte[] data, long data_elements, double[] timestamps, int pushthrough); int lsl_push_chunk_strtp(Pointer obj, String[] data, long data_elements, double timestamp, int pushthrough); int lsl_push_chunk_strtnp(Pointer obj, String[] data, long data_elements, double[] timestamps, int pushthrough); - int lsl_push_chunk_buftp(Pointer obj, byte[][] data, long[] lengths, long data_elements, double timestamp, int pushthrough); - int lsl_push_chunk_buftnp(Pointer obj, byte[][] data, long[] lengths, long data_elements, double[] timestamps, int pushthrough); + int lsl_push_chunk_buftp(Pointer obj, byte[][] data, long[] lengths, long data_elements, double timestamp, int pushthrough); + int lsl_push_chunk_buftnp(Pointer obj, byte[][] data, long[] lengths, long data_elements, double[] timestamps, int pushthrough); int lsl_have_consumers(Pointer obj); int lsl_wait_for_consumers(Pointer obj); Pointer lsl_get_info(Pointer obj); @@ -928,7 +928,7 @@ static void check_error(int[] ec) throws Exception { double lsl_pull_sample_s(Pointer obj, short[] buffer, int buffer_elements, double timeout, int[] ec); double lsl_pull_sample_c(Pointer obj, byte[] buffer, int buffer_elements, double timeout, int[] ec); double lsl_pull_sample_str(Pointer obj, String[] buffer, int buffer_elements, double timeout, int[] ec); - double lsl_pull_sample_buf(Pointer obj, byte[][] buffer, long[] buffer_lengths, int buffer_elements, double timeout, int[] ec); + double lsl_pull_sample_buf(Pointer obj, byte[][] buffer, long[] buffer_lengths, int buffer_elements, double timeout, int[] ec); long lsl_pull_chunk_f(Pointer obj, float[] data_buffer, double[] timestamp_buffer, long data_buffer_elements, long timestamp_buffer_elements, double timeout, int[] ec); long lsl_pull_chunk_d(Pointer obj, double[] data_buffer, double[] timestamp_buffer, long data_buffer_elements, long timestamp_buffer_elements, double timeout, int[] ec); long lsl_pull_chunk_i(Pointer obj, int[] data_buffer, double[] timestamp_buffer, long data_buffer_elements, long timestamp_buffer_elements, double timeout, int[] ec); @@ -968,11 +968,11 @@ static void check_error(int[] ec) throws Exception { Pointer lsl_create_continuous_resolver_bypred(String pred, double forget_after); int lsl_resolver_results(Pointer obj, Pointer[] buffer, int buffer_elements); void lsl_destroy_continuous_resolver(Pointer obj); - + } - + static dll inst; - static { + static { switch (Platform.getOSType()) { case Platform.WINDOWS: inst = (dll)Native.loadLibrary((Platform.is64Bit() ? "liblsl64.dll" : "liblsl32.dll"),dll.class); @@ -993,8 +993,8 @@ static void check_error(int[] ec) throws Exception { static { String libname; if (Platform.isWindows()) { - + } else { } }*/ -} \ No newline at end of file +} diff --git a/libraries/LSLLink/src/main/resources/liblsl32.dylib b/libraries/LSLLink/src/main/resources/darwin/liblsl32.dylib similarity index 100% rename from libraries/LSLLink/src/main/resources/liblsl32.dylib rename to libraries/LSLLink/src/main/resources/darwin/liblsl32.dylib diff --git a/libraries/LSLLink/src/main/resources/liblsl64.dylib b/libraries/LSLLink/src/main/resources/darwin/liblsl64.dylib similarity index 100% rename from libraries/LSLLink/src/main/resources/liblsl64.dylib rename to libraries/LSLLink/src/main/resources/darwin/liblsl64.dylib diff --git a/libraries/LSLLink/src/main/resources/linux-x86-64/liblsl64.so b/libraries/LSLLink/src/main/resources/linux-x86-64/liblsl64.so new file mode 100644 index 0000000..cb503d3 Binary files /dev/null and b/libraries/LSLLink/src/main/resources/linux-x86-64/liblsl64.so differ diff --git a/libraries/LSLLink/src/main/resources/liblsl32.dll b/libraries/LSLLink/src/main/resources/win32-amd64/liblsl32.dll similarity index 100% rename from libraries/LSLLink/src/main/resources/liblsl32.dll rename to libraries/LSLLink/src/main/resources/win32-amd64/liblsl32.dll diff --git a/libraries/LSLLink/src/main/resources/liblsl64.dll b/libraries/LSLLink/src/main/resources/win32-amd64/liblsl64.dll similarity index 100% rename from libraries/LSLLink/src/main/resources/liblsl64.dll rename to libraries/LSLLink/src/main/resources/win32-amd64/liblsl64.dll diff --git a/libraries/LSLLink/src/main/resources/win32-x86-64/liblsl32.dll b/libraries/LSLLink/src/main/resources/win32-x86-64/liblsl32.dll new file mode 100644 index 0000000..ed3e9e7 Binary files /dev/null and b/libraries/LSLLink/src/main/resources/win32-x86-64/liblsl32.dll differ diff --git a/libraries/LSLLink/src/main/resources/win32-x86-64/liblsl64.dll b/libraries/LSLLink/src/main/resources/win32-x86-64/liblsl64.dll new file mode 100644 index 0000000..611e75c Binary files /dev/null and b/libraries/LSLLink/src/main/resources/win32-x86-64/liblsl64.dll differ diff --git a/libraries/controlP5/src/controlP5/ControllerGroup.java b/libraries/controlP5/src/controlP5/ControllerGroup.java index ea4dc13..5712892 100644 --- a/libraries/controlP5/src/controlP5/ControllerGroup.java +++ b/libraries/controlP5/src/controlP5/ControllerGroup.java @@ -1,10 +1,10 @@ -package controlP5; + package controlP5; /** * controlP5 is a processing gui library. - * + * * 2006-2015 by Andreas Schlegel - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 @@ -13,16 +13,16 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General * Public License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307 USA - * + * * @author Andreas Schlegel (http://www.sojamo.de) * @modified 04/14/2016 * @version 2.2.6 - * + * */ import java.util.ArrayList; @@ -35,7 +35,7 @@ /** * ControllerGroup is an abstract class and is extended by class ControlGroup, Tab, or the ListBox. - * + * */ public abstract class ControllerGroup< T > implements ControllerInterface< T > , ControlP5Constants , ControlListener { @@ -924,7 +924,7 @@ public String getInfo( ) { /** * convenience method to fill a float array in favor of theArray[0] = 1.2; etc. - * takes a float array and fills it (starting from index 0) with arguments starting from index 1. + * takes a float array and fills it (starting from index 0) with arguments starting from index 1. */ static public float[] set( float[] theArray , float ... theValues ) { if ( theValues.length > theArray.length ) { diff --git a/libraries/controlP5/src/controlP5/RadioButton.java b/libraries/controlP5/src/controlP5/RadioButton.java index bfba4aa..84c4345 100644 --- a/libraries/controlP5/src/controlP5/RadioButton.java +++ b/libraries/controlP5/src/controlP5/RadioButton.java @@ -2,9 +2,9 @@ /** * controlP5 is a processing gui library. - * + * * 2006-2015 by Andreas Schlegel - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 @@ -13,16 +13,16 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General * Public License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307 USA - * + * * @author Andreas Schlegel (http://www.sojamo.de) * @modified 04/14/2016 * @version 2.2.6 - * + * */ import java.lang.reflect.InvocationTargetException; @@ -36,13 +36,13 @@ * A radioButton is a list of toggles that can be turned on or off. radioButton is of type * ControllerGroup, therefore a controllerPlug can't be set. this means that an event from a * radioButton can't be forwarded to a method other than controlEvent in a sketch. - * + * * a radioButton has 2 sets of values. radioButton.getValue() returns the value of the active * radioButton item. radioButton.getArrayValue() returns a float array that represents the active * (1) and inactive (0) items of a radioButton. - * + * * ControlP5 CheckBox Toggle - * + * * @example controllers/ControlP5radioButton * * @nosuperclasses Controller Controller @@ -68,7 +68,7 @@ /** * Convenience constructor to extend RadioButton. - * + * * @example use/ControlP5extendController * @param theControlP5 * @param theName @@ -189,7 +189,7 @@ public RadioButton setLabelPadding( int thePaddingX , int thePaddingY ) { } /** - * + * * @param theDefaultImage * @param theOverImage * @param theActiveImage @@ -241,7 +241,7 @@ public RadioButton setSize( int theWidth , int theHeight ) { * set the height of a radioButton/checkBox item. by default the height is 11px. in order to * recognize a custom height, the itemHeight has to be set before adding items to a * radioButton/checkBox. - * + * * @param theItemHeight */ public RadioButton setItemHeight( int theItemHeight ) { @@ -257,7 +257,7 @@ public RadioButton setItemHeight( int theItemHeight ) { * set the width of a radioButton/checkBox item. by default the width is 11px. in order to * recognize a custom width, the itemWidth has to be set before adding items to a * radioButton/checkBox. - * + * * @param theItemWidth */ public RadioButton setItemWidth( int theItemWidth ) { @@ -271,7 +271,7 @@ public RadioButton setItemWidth( int theItemWidth ) { /** * Gets a radio button item by index. - * + * * @param theIndex * @return Toggle */ @@ -294,7 +294,7 @@ public Toggle getItem( String theName ) { /** * Gets the state of an item - this can be true (for on) or false (for off) - by index. - * + * * @param theIndex * @return boolean */ @@ -307,7 +307,7 @@ public boolean getState( int theIndex ) { /** * Gets the state of an item - this can be true (for on) or false (for off) - by name. - * + * * @param theName * @return */ @@ -350,7 +350,7 @@ public void updateLayout( ) { /** * Items of a radioButton or a checkBox are organized in columns and rows. SetItemsPerRow sets * the limit of items per row. items exceeding the limit will be pushed to the next row. - * + * * @param theValue */ public RadioButton setItemsPerRow( final int theValue ) { @@ -361,7 +361,7 @@ public RadioButton setItemsPerRow( final int theValue ) { /** * Sets the spacing in pixels between columns. - * + * * @param theSpacing */ public RadioButton setSpacingColumn( final int theSpacing ) { @@ -372,7 +372,7 @@ public RadioButton setSpacingColumn( final int theSpacing ) { /** * Sets the spacing in pixels between rows. - * + * * @param theSpacing */ public RadioButton setSpacingRow( final int theSpacing ) { @@ -398,7 +398,7 @@ public RadioButton deactivateAll( ) { * Deactivates all active RadioButton items and only activates the item corresponding to * theIndex. * TODO does not trigger function or value when called by code, fix! - * + * * @param theIndex */ public RadioButton activate( int theIndex ) { @@ -434,7 +434,7 @@ public RadioButton deactivate( int theIndex ) { /** * Actives an item of the Radio button by name. - * + * * @param theName */ public RadioButton activate( String theName ) { @@ -452,7 +452,7 @@ public RadioButton activate( String theName ) { /** * Deactivates a RadioButton by name and sets the value of the RadioButton to the default value * -1. - * + * * @param theName */ public RadioButton deactivate( String theName ) { @@ -491,7 +491,7 @@ public RadioButton toggle( int theIndex ) { /** * {@inheritDoc} - * + * * @exclude */ @ControlP5.Invisible @Override public void controlEvent( ControlEvent theEvent ) { @@ -572,7 +572,7 @@ protected void updateValues( boolean theBroadcastFlag ) { /** * In order to always have 1 item selected, use setNoneSelectedAllowed(false), by default this * is true. setNoneSelectedAllowed does not apply when in multipleChoice mode. - * + * * @param theValue */ public RadioButton setNoneSelectedAllowed( boolean theValue ) {