diff --git a/ShimmerBluetoothManager/build.gradle b/ShimmerBluetoothManager/build.gradle index 74f7f7cba..2bc18533c 100644 --- a/ShimmerBluetoothManager/build.gradle +++ b/ShimmerBluetoothManager/build.gradle @@ -12,6 +12,8 @@ Rev0.2 sourceCompatibility = 1.11 targetCompatibility = 1.11 +//sourceCompatibility = '1.8' // Ensure code is compiled with Java 8 when compiling ShimmerJavaClass for Matlab see ShimmerDriverPC (build.gradle) +//targetCompatibility = '1.8' // Ensure bytecode is compatible with Java 8 when compiling ShimmerJavaClass for Matlab see ShimmerDriverPC (build.gradle) repositories { mavenCentral() diff --git a/ShimmerDriver/build.gradle b/ShimmerDriver/build.gradle index 0c346175b..29e1f4aa3 100644 --- a/ShimmerDriver/build.gradle +++ b/ShimmerDriver/build.gradle @@ -15,6 +15,8 @@ Rev0.2 apply plugin: 'java-library' sourceCompatibility = 1.11 targetCompatibility = 1.11 +//sourceCompatibility = '1.8' // Ensure code is compiled with Java 8 when compiling ShimmerJavaClass for Matlab see ShimmerDriverPC (build.gradle) +//targetCompatibility = '1.8' // Ensure bytecode is compatible with Java 8 when compiling ShimmerJavaClass for Matlab see ShimmerDriverPC (build.gradle) repositories { mavenCentral() diff --git a/ShimmerDriver/src/main/java/com/shimmerresearch/driver/Configuration.java b/ShimmerDriver/src/main/java/com/shimmerresearch/driver/Configuration.java index 834d9669c..8bf461b39 100644 --- a/ShimmerDriver/src/main/java/com/shimmerresearch/driver/Configuration.java +++ b/ShimmerDriver/src/main/java/com/shimmerresearch/driver/Configuration.java @@ -677,7 +677,7 @@ public class SensorBitmap{ * data packets. The firmware also uses the IMU IDs as Sensor IDs in the * IMU/BMP calibration bytes. */ - public class SENSOR_ID{ + public static class SENSOR_ID{ public static final int RESERVED_ANY_SENSOR = -1; public static final int HOST_SHIMMER_STREAMING_PROPERTIES = -100; diff --git a/ShimmerDriver/src/main/java/com/shimmerresearch/driver/ObjectCluster.java b/ShimmerDriver/src/main/java/com/shimmerresearch/driver/ObjectCluster.java index 2b202fae6..29bf516b5 100644 --- a/ShimmerDriver/src/main/java/com/shimmerresearch/driver/ObjectCluster.java +++ b/ShimmerDriver/src/main/java/com/shimmerresearch/driver/ObjectCluster.java @@ -88,6 +88,7 @@ final public class ObjectCluster implements Cloneable,Serializable{ private String mMyName; private String mBluetoothAddress; + private String mComPort; // ------- Old Array approach - Start ----------- public byte[] mRawData; @@ -220,6 +221,13 @@ public void setMacAddress(String macAddress){ mBluetoothAddress = macAddress; } + public void setComPort(String comport) { + mComPort = comport; + } + + public String getComPort() { + return mComPort; + } /** * Takes in a collection of Format Clusters and returns the Format Cluster specified by the string format * @param collectionFormatCluster @@ -247,6 +255,15 @@ public double getFormatClusterValue(ChannelDetails channelDetails, CHANNEL_TYPE return getFormatClusterValue(channelDetails.mObjectClusterName, channelType.toString()); } + public FormatCluster getFormatCluster(String channelName, String format) + { + FormatCluster formatCluster = getLastFormatCluster(channelName, format); + if(formatCluster!=null){ + return formatCluster; + } + return null; + } + // public double getFormatClusterValue(ChannelDetails channelDetails, String format){ // return getFormatClusterValue(channelDetails.mObjectClusterName, format); // } diff --git a/ShimmerDriver/src/main/java/com/shimmerresearch/driver/ShimmerDevice.java b/ShimmerDriver/src/main/java/com/shimmerresearch/driver/ShimmerDevice.java index dfdceacb8..21544fb14 100644 --- a/ShimmerDriver/src/main/java/com/shimmerresearch/driver/ShimmerDevice.java +++ b/ShimmerDriver/src/main/java/com/shimmerresearch/driver/ShimmerDevice.java @@ -4501,6 +4501,13 @@ public String getComPort() { return mComPort; } + /**This method will only return the comport name + * @return + */ + public String getComPortName() { + return mComPort; + } + public boolean isReadyToConnect() { if (mCommsProtocolRadio==null ||mCommsProtocolRadio.mRadioHal==null diff --git a/ShimmerDriver/src/main/java/com/shimmerresearch/driver/ShimmerObject.java b/ShimmerDriver/src/main/java/com/shimmerresearch/driver/ShimmerObject.java index eca0679ed..bb903172f 100644 --- a/ShimmerDriver/src/main/java/com/shimmerresearch/driver/ShimmerObject.java +++ b/ShimmerDriver/src/main/java/com/shimmerresearch/driver/ShimmerObject.java @@ -812,6 +812,7 @@ public ObjectCluster buildMsg(byte[] newPacket, COMMUNICATION_TYPE fwType, boole objectCluster.setShimmerName(mShimmerUserAssignedName); objectCluster.setMacAddress(mMyBluetoothAddress); + objectCluster.setComPort(getComPortName()); objectCluster.mRawData = newPacket; if(fwType!=COMMUNICATION_TYPE.BLUETOOTH && fwType!=COMMUNICATION_TYPE.SD){ diff --git a/ShimmerDriverPC/build.gradle b/ShimmerDriverPC/build.gradle index c031d2bb4..684e55dec 100644 --- a/ShimmerDriverPC/build.gradle +++ b/ShimmerDriverPC/build.gradle @@ -8,13 +8,17 @@ */ // Apply the java plugin to add support for Java -apply plugin: 'java' -apply plugin: 'java-library' -apply plugin: 'eclipse' -apply plugin: 'maven-publish' - +plugins { + id 'java' + id 'java-library' + id 'eclipse' + id 'maven-publish' + id 'com.github.johnrengelman.shadow' version '7.0.0' // Apply the Shadow plugin +} sourceCompatibility = 1.11 - +targetCompatibility = 1.11 +//sourceCompatibility = '1.8' // Ensure code is compiled with Java 8 when compiling ShimmerJavaClass for Matlab see ShimmerDriverPC (build.gradle) +//targetCompatibility = '1.8' // Ensure bytecode is compatible with Java 8 when compiling ShimmerJavaClass for Matlab see ShimmerDriverPC (build.gradle) /* Rev0.2 - switch to using jfrog @@ -96,3 +100,20 @@ dependencies { testImplementation 'junit:junit:4.12' implementation 'com.parse.bolts:bolts-tasks:1.4.0' } + +// Shadow JAR task to create a runnable JAR with dependencies +/* +Change to using the following below for ShimmerDriverPC/ShimmerDriver/ShimmerBluetoothManager +sourceCompatibility = '1.8' // Ensure code is compiled with Java 8 +targetCompatibility = '1.8' // Ensure bytecode is compatible with Java 8 +*/ +shadowJar { + archiveBaseName.set('ShimmerJavaClass') // Use archiveBaseName instead of baseName + archiveClassifier.set('') // Remove classifier so it’s named shimmerjavaclass.jar + + manifest { + attributes 'Main-Class': 'com.shimmerresearch.tools.matlab.ShimmerJavaClass' // Specify the main class + } + + mergeServiceFiles() // Merges service files (if any) +} diff --git a/ShimmerDriverPC/src/main/java/com/shimmerresearch/tools/matlab/ShimmerJavaClass.java b/ShimmerDriverPC/src/main/java/com/shimmerresearch/tools/matlab/ShimmerJavaClass.java new file mode 100644 index 000000000..ad56ab320 --- /dev/null +++ b/ShimmerDriverPC/src/main/java/com/shimmerresearch/tools/matlab/ShimmerJavaClass.java @@ -0,0 +1,254 @@ +package com.shimmerresearch.tools.matlab; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTextField; + +import com.shimmerresearch.bluetooth.ShimmerBluetooth.BT_STATE; +import com.shimmerresearch.driver.BasicProcessWithCallBack; +import com.shimmerresearch.driver.CallbackObject; +import com.shimmerresearch.driver.ObjectCluster; +import com.shimmerresearch.driver.ShimmerMsg; +import com.shimmerresearch.driver.Configuration.COMMUNICATION_TYPE; +import com.shimmerresearch.driver.FormatCluster; +import com.shimmerresearch.driverUtilities.ChannelDetails; +import com.shimmerresearch.exceptions.ShimmerException; +import com.shimmerresearch.pcDriver.ShimmerPC; +import com.shimmerresearch.tools.bluetooth.BasicShimmerBluetoothManagerPc; +import com.shimmerresearch.algorithms.*; + +public class ShimmerJavaClass { + private String comPort; + private SensorDataReceived sdr = new SensorDataReceived(); + private String[] channelNames; + private final ConcurrentLinkedQueue connectedDevices = new ConcurrentLinkedQueue<>(); + private final ConcurrentHashMap> dataQueues = new ConcurrentHashMap<>(); + private List collectedData = new ArrayList<>(); + + + private boolean mDebug = true; + +// private int rowIndex = 0; + Object[] currentData = null; + public static BasicShimmerBluetoothManagerPc mBluetoothManager; + + public ShimmerJavaClass() { + mBluetoothManager = new BasicShimmerBluetoothManagerPc(false); + sdr.setWaitForData(mBluetoothManager.callBackObject); + mBluetoothManager.addCallBack(sdr); + if (mDebug) { + System.out.println("Callback Registered"); + System.out.flush(); + } + } + + public static void main(String[] args) { + ShimmerJavaClass example = new ShimmerJavaClass(); + example.createAndShowGUI(); + } + + public void createAndShowGUI() { + JFrame frame = new JFrame("Shimmer Device Controller"); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setSize(400, 200); + + JPanel panel = new JPanel(); + + JTextField inputComPort = new JTextField("COM3"); + JButton connectButton = new JButton("Connect"); + JButton disconnectButton = new JButton("Disconnect"); + JButton startButton = new JButton("Start Streaming"); + JButton stopButton = new JButton("Stop Streaming"); + + connectButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + comPort = inputComPort.getText(); + mBluetoothManager.connectShimmerThroughCommPort(comPort); + } + }); + + disconnectButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + mBluetoothManager.disconnectShimmer(comPort); + } + }); + + startButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + try { + mBluetoothManager.getShimmerDeviceBtConnected(comPort).startStreaming(); + } catch (ShimmerException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + while(true) { + if (hasDataToRead(comPort)) { + readData(); + } + + } + } + }); + + + + stopButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + try { + mBluetoothManager.getShimmerDeviceBtConnected(comPort).stopStreaming(); + } catch (ShimmerException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + } + }); + + panel.add(inputComPort); + panel.add(connectButton); + panel.add(disconnectButton); + panel.add(startButton); + panel.add(stopButton); + frame.add(panel); + + frame.setVisible(true); + } + + public String[] retrieveSensorChannels() { + LinkedHashMap mapOfAllChannels = mBluetoothManager.getShimmerDeviceBtConnected(comPort).getMapOfAllChannelsForStoringToDB(COMMUNICATION_TYPE.BLUETOOTH, null, false, false); + List listOfChannelDetails = new ArrayList(mapOfAllChannels.values()); + + List channelNamesList = new ArrayList(); + for (ChannelDetails channel : listOfChannelDetails) { + channelNamesList.add(channel.mObjectClusterName); + } + + return channelNamesList.toArray(new String[0]); + } + public boolean hasDataToRead(String comPort) { + Queue queue = dataQueues.get(comPort); + return queue != null && !queue.isEmpty(); + } + private void sendData(String comPort, Object[] data) { + dataQueues.computeIfAbsent(comPort, k -> new LinkedList<>()).add(data); + } + + public void readData() { + for (String comPort : dataQueues.keySet()) { + Object[] data = receiveData(comPort); + if (data != null && mDebug) { + float[][] matrix = (float[][]) data[0]; + String[] signalNames = (String[]) data[1]; + String[] formats = (String[]) data[2]; + String[] units = (String[]) data[3]; + + System.out.println("==== Data from device: " + comPort + " ===="); + for (int i = 0; i < matrix.length; i++) { + System.out.print("Row " + i + ": "); + for (int j = 0; j < matrix[i].length; j++) { + System.out.print(matrix[i][j] + " " + units[j] + " [" + signalNames[j] + "] | "); + } + System.out.println(); + } + } + } + } + + public Object[] receiveData(String comPort) { + Queue queue = dataQueues.get(comPort); + if (queue == null || queue.isEmpty()) return null; + + List deviceData = new ArrayList<>(); + String[] signalNameArray = null, signalFormatArray = null, signalUnitArray = null; + + while (!queue.isEmpty()) { + Object[] data = queue.poll(); + if (data == null) continue; // skip this iteration safely + + float[] values = (float[]) data[1]; + if (values == null) continue; + + signalNameArray = (String[]) data[2]; + signalFormatArray = (String[]) data[3]; + signalUnitArray = (String[]) data[4]; + deviceData.add(values); + } + + float[][] dataMatrix = deviceData.toArray(new float[0][0]); + return new Object[] { dataMatrix, signalNameArray, signalFormatArray, signalUnitArray }; + } + + + public class SensorDataReceived extends BasicProcessWithCallBack { + + @Override + protected void processMsgFromCallback(ShimmerMsg shimmerMSG) { + int ind = shimmerMSG.mIdentifier; + Object object = shimmerMSG.mB; + + if (ind == ShimmerPC.MSG_IDENTIFIER_STATE_CHANGE) { + CallbackObject callbackObject = (CallbackObject) object; + + if (callbackObject.mState == BT_STATE.CONNECTING) { + System.out.println("Device State Change: " + callbackObject.mState); + System.out.flush(); + + } else if (callbackObject.mState == BT_STATE.CONNECTED) { + System.out.println("Device State Change: " + callbackObject.mState); + System.out.flush(); + if (comPort == null) { + comPort = callbackObject.mComPort; + } + channelNames = retrieveSensorChannels(); + if (mDebug) { + for(String channel : channelNames) { + System.out.println(channel); + } + } + } else if (callbackObject.mState == BT_STATE.DISCONNECTED || callbackObject.mState == BT_STATE.CONNECTION_LOST) { + System.out.println("Device State Change: " + callbackObject.mState); + System.out.flush(); + + } + } else if (ind == ShimmerPC.MSG_IDENTIFIER_NOTIFICATION_MESSAGE) { + + } else if (ind == ShimmerPC.MSG_IDENTIFIER_DATA_PACKET) { + ObjectCluster objc = (ObjectCluster) shimmerMSG.mB; + + float[] newData = new float[channelNames.length]; + String[] signalNameArray = new String[channelNames.length]; + String[] signalFormatArray = new String[channelNames.length]; + String[] signalUnitArray = new String[channelNames.length]; + + for (int i = 0; i < channelNames.length; i++) { + FormatCluster formatCluster = objc.getFormatCluster(channelNames[i], "CAL"); + if (formatCluster != null) { + newData[i] = (float) formatCluster.mData; + signalNameArray[i] = channelNames[i]; + signalFormatArray[i] = formatCluster.mFormat; + signalUnitArray[i] = formatCluster.mUnits; + } + } + + String comPort = objc.getComPort(); + Object[] outputData = { comPort, newData, signalNameArray, signalFormatArray, signalUnitArray }; + sendData(comPort, outputData); + } + } + } +} \ No newline at end of file