diff --git a/ShimmerBluetoothManager/src/main/java/com/shimmerresearch/managers/bluetoothManager/ShimmerBluetoothManager.java b/ShimmerBluetoothManager/src/main/java/com/shimmerresearch/managers/bluetoothManager/ShimmerBluetoothManager.java index 5e9017487..2b379af4b 100644 --- a/ShimmerBluetoothManager/src/main/java/com/shimmerresearch/managers/bluetoothManager/ShimmerBluetoothManager.java +++ b/ShimmerBluetoothManager/src/main/java/com/shimmerresearch/managers/bluetoothManager/ShimmerBluetoothManager.java @@ -55,7 +55,8 @@ public abstract class ShimmerBluetoothManager{ protected static final boolean USE_INFOMEM_CONFIG_METHOD = true; public static final long SLEEP_BETWEEN_GROUP_ACTIONS_MS = 50; public static final String COMPORT_PREFIX = "COM"; - public static final String COMPORT_PREFIX_MAC = "/dev/"; +// public static final String COMPORT_PREFIX_MAC = "/dev/"; //Commented-out as MacOS is relying on BT device name rather than COM PORT prefix + public static final String COMPORT_PREFIX_MAC = "Shimmer"; protected int mSyncTrainingIntervalInSeconds = 15; protected int msDelayBetweenSetCommands = 0; protected BluetoothProgressReportAll mProgressReportAll; @@ -836,7 +837,8 @@ else if(deviceTypeDetected==DEVICE_TYPE.ARDUINO){ if (shimmerDevice!=null && !(shimmerDevice instanceof ShimmerShell)){ printMessage("Connecting to " + shimmerDevice.getClass().getSimpleName() + " with connection handle = " + (connectThroughComPort? comPort:bluetoothAddress)); if(connectThroughComPort){ - if (!comPort.contains(COMPORT_PREFIX) && !comPort.contains(COMPORT_PREFIX_MAC)) { + if (!comPort.contains(COMPORT_PREFIX)) { + //Besides Windows, this is used on MacOS to connect Shimmer over BLE, as MacOS does not use BT Classic connectShimmer3BleGrpc(bluetoothDetails); }else { connectExistingShimmer(shimmerDevice, comPort, bluetoothAddress); diff --git a/ShimmerDriver/build.gradle b/ShimmerDriver/build.gradle index 56603ac89..61ae4a9ae 100644 --- a/ShimmerDriver/build.gradle +++ b/ShimmerDriver/build.gradle @@ -93,7 +93,7 @@ dependencies { api group: 'com.google.protobuf', name: 'protobuf-java', version: '3.4.0' // https://mvnrepository.com/artifact/io.grpc/grpc-all - api group: 'io.grpc', name: 'grpc-all', version: '1.32.1' + api group: 'io.grpc', name: 'grpc-all', version: '1.71.0' // https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient api group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.3.6' @@ -114,7 +114,7 @@ dependencies { // https://mvnrepository.com/artifact/javax.annotation/javax.annotation-api api("javax.annotation:javax.annotation-api:1.3.2") - + // Declare the dependency for your favourite test framework you want to use in your tests. // TestNG is also supported by the Gradle Test task. Just change the // testCompile dependency to testCompile 'org.testng:testng:6.8.1' and add @@ -128,5 +128,11 @@ dependencies { testImplementation group: 'junit', name: 'junit', version: '4.+' api 'com.parse.bolts:bolts-tasks:1.4.0' + + // https://mvnrepository.com/artifact/org.bouncycastle/bcpkix-jdk15on + implementation("org.bouncycastle:bcpkix-jdk15on:1.61") + + // https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on + implementation("org.bouncycastle:bcprov-jdk15on:1.61") } diff --git a/ShimmerDriver/src/main/java/com/shimmerresearch/driverUtilities/BluetoothDeviceDetails.java b/ShimmerDriver/src/main/java/com/shimmerresearch/driverUtilities/BluetoothDeviceDetails.java index a4c762414..b43598893 100644 --- a/ShimmerDriver/src/main/java/com/shimmerresearch/driverUtilities/BluetoothDeviceDetails.java +++ b/ShimmerDriver/src/main/java/com/shimmerresearch/driverUtilities/BluetoothDeviceDetails.java @@ -33,13 +33,18 @@ public BluetoothDeviceDetails(String comPort, String macId, String friendlyName) } public void setMacId(String mac){ - - mac = mac.replace("-", ""); - - if(mac.length()>=12) { - mShimmerMacId = mac.toUpperCase(); - mac = mac.replace(":", "").toUpperCase(); - mShimmerMacIdParsed = mac.substring(8); + if(mac.startsWith("Shimmer") && mac.contains("-")) { + //If using device name (e.g. Shimmer3-6813), then leave as is + mShimmerMacId = mac; + mShimmerMacId = mac; + } else { + mac = mac.replace("-", ""); + + if(mac.length()>=12) { + mShimmerMacId = mac.toUpperCase(); + mac = mac.replace(":", "").toUpperCase(); + mShimmerMacIdParsed = mac.substring(8); + } } } diff --git a/ShimmerDriver/src/main/java/com/shimmerresearch/driverUtilities/UtilShimmer.java b/ShimmerDriver/src/main/java/com/shimmerresearch/driverUtilities/UtilShimmer.java index c34293add..024b1ba44 100644 --- a/ShimmerDriver/src/main/java/com/shimmerresearch/driverUtilities/UtilShimmer.java +++ b/ShimmerDriver/src/main/java/com/shimmerresearch/driverUtilities/UtilShimmer.java @@ -1368,5 +1368,10 @@ public static int getTimeZoneOffset(){ // System.err.println(milliSeconds); // System.err.println(UtilShimmer.bytesToHexStringWithSpacesFormatted(convertMilliSecondsToShimmerRtcDataBytesLSB(milliSeconds))); // } + + public static boolean isOsMac() { + return System.getProperty("os.name").toLowerCase().contains("mac"); + } + } diff --git a/ShimmerDriver/src/main/java/com/shimmerresearch/grpc/GrpcBLERadioByteCommunication.java b/ShimmerDriver/src/main/java/com/shimmerresearch/grpc/GrpcBLERadioByteCommunication.java index af47b88ab..34b47f75e 100644 --- a/ShimmerDriver/src/main/java/com/shimmerresearch/grpc/GrpcBLERadioByteCommunication.java +++ b/ShimmerDriver/src/main/java/com/shimmerresearch/grpc/GrpcBLERadioByteCommunication.java @@ -135,7 +135,7 @@ public void connect() throws ShimmerException { @Override public void onNext(StateStatus value) { // TODO Auto-generated method stub - System.out.println(value.getMessage() + " " + value.getState().toString()); +// System.out.println(value.getMessage() + " " + value.getState().toString()); if (value.getState().equals(BluetoothState.Connected)) { mConnectTask.setResult(true); diff --git a/ShimmerDriver/src/main/java/com/shimmerresearch/grpc/GrpcBLERadioByteTools.java b/ShimmerDriver/src/main/java/com/shimmerresearch/grpc/GrpcBLERadioByteTools.java index 935ed98c3..7a8721f34 100644 --- a/ShimmerDriver/src/main/java/com/shimmerresearch/grpc/GrpcBLERadioByteTools.java +++ b/ShimmerDriver/src/main/java/com/shimmerresearch/grpc/GrpcBLERadioByteTools.java @@ -1,6 +1,7 @@ package com.shimmerresearch.grpc; import java.io.BufferedReader; +import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.net.ServerSocket; @@ -8,6 +9,9 @@ import java.util.List; import javax.swing.JFrame; + +import com.shimmerresearch.driverUtilities.UtilShimmer; + import javax.swing.JButton; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; @@ -15,17 +19,23 @@ public class GrpcBLERadioByteTools { private Process runningProcess; - String mExeName = "ShimmerBLEGrpc.exe"; - String mExePath = "C:\\Github\\Shimmer-C-API\\ShimmerAPI\\ShimmerBLEGrpc\\bin\\Debug\\" + mExeName; // Replace with the path to your .exe file + String mExeNameWindows = "ShimmerBLEGrpc.exe"; + String mExePathWindows = "C:\\Github\\Shimmer-C-API\\ShimmerAPI\\ShimmerBLEGrpc\\bin\\Debug\\" + mExeNameWindows; // Replace with the path to your .exe file //String exePath = "C:\\Users\\JC\\Desktop\\testgrpc\\ShimmerBLEGrpc.exe"; // Replace with the path to your .exe file + //Below used by Consensys MacOS + String mExeNameMac = "ShimmerBLEGrpc"; + String mExePathMac = System.getProperty("user.dir") + "/libs/ShimmerBLEGrpc/Products/usr/local/bin/" + mExeNameMac; + public GrpcBLERadioByteTools() { } public GrpcBLERadioByteTools(String exeName, String exePath) { - mExeName = exeName; - mExePath = exePath; + mExeNameWindows = exeName; + mExeNameMac = exeName; + mExePathWindows = exePath; + mExePathMac = exePath; } @@ -76,8 +86,14 @@ public int startServer() throws Exception { List command = new ArrayList<>(); // Add the command itself - command.add(mExePath); + if(UtilShimmer.isOsMac()) { + command.add(mExePathMac); + command.add("--port"); + } else { + command.add(mExePathWindows); + } command.add(Integer.toString(port)); + ProcessBuilder processBuilder = new ProcessBuilder(command); processBuilder.redirectErrorStream(true); // Redirect standard error to the input stream runningProcess = processBuilder.start(); @@ -85,7 +101,7 @@ public int startServer() throws Exception { try (BufferedReader reader = new BufferedReader(new InputStreamReader(runningProcess.getInputStream()))) { String line; while ((line = reader.readLine()) != null) { - System.out.println(line); + System.out.println("[BLEGrpcServer] " + line); } } catch (IOException e) { // TODO Auto-generated catch block @@ -142,7 +158,7 @@ public void actionPerformed(ActionEvent e) { JButton btnCheck = new JButton("checkServerApp"); btnCheck.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - if (grpcTools.isExeRunning(grpcTools.mExeName)) { + if (grpcTools.isExeRunning(grpcTools.mExeNameWindows)) { System.out.println("EXE RUNNING"); } else { System.out.println("EXE NOT RUNNING"); diff --git a/ShimmerDriverPC/build.gradle b/ShimmerDriverPC/build.gradle index e5bc818b9..ef118cef0 100644 --- a/ShimmerDriverPC/build.gradle +++ b/ShimmerDriverPC/build.gradle @@ -95,4 +95,10 @@ dependencies { // 'test.useTestNG()' to your build script. testImplementation 'junit:junit:4.12' implementation 'com.parse.bolts:bolts-tasks:1.4.0' + + // https://mvnrepository.com/artifact/org.bouncycastle/bcpkix-jdk15on + implementation("org.bouncycastle:bcpkix-jdk15on:1.61") + + // https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on + implementation("org.bouncycastle:bcprov-jdk15on:1.61") } diff --git a/ShimmerDriverPC/src/main/java/com/shimmerresearch/pcDriver/ShimmerGRPC.java b/ShimmerDriverPC/src/main/java/com/shimmerresearch/pcDriver/ShimmerGRPC.java index 3ff0d57a8..a43b46da7 100644 --- a/ShimmerDriverPC/src/main/java/com/shimmerresearch/pcDriver/ShimmerGRPC.java +++ b/ShimmerDriverPC/src/main/java/com/shimmerresearch/pcDriver/ShimmerGRPC.java @@ -22,6 +22,7 @@ import com.shimmerresearch.driverUtilities.AssembleShimmerConfig; import com.shimmerresearch.driverUtilities.SensorDetails; import com.shimmerresearch.driverUtilities.ShimmerVerDetails.HW_ID; +import com.shimmerresearch.driverUtilities.UtilShimmer; import com.shimmerresearch.driverUtilities.ChannelDetails.CHANNEL_TYPE; import com.shimmerresearch.grpc.ShimmerBLEByteServerGrpc; import com.shimmerresearch.grpc.ShimmerBLEGRPC.BluetoothState; @@ -36,6 +37,7 @@ import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; +import io.grpc.StatusRuntimeException; import io.grpc.stub.StreamObserver; import com.shimmerresearch.driver.BasicProcessWithCallBack; @@ -64,31 +66,36 @@ public class ShimmerGRPC extends ShimmerBluetooth implements Serializable{ * */ private static final long serialVersionUID = 5029128107276324956L; - + public ShimmerGRPC(String macAddress, String serverHost, int serverPort) { super(); mServerHost = serverHost; mServerPort = serverPort; mMacAddress = macAddress; + mMyBluetoothAddress = ""; mUseProcessingThread = true; if (channel==null) { InitializeProcess(); } } - + + /** + * This constructor is used for MacOS for BLE where the mFriendlyName is the BT device name (e.g. Shimmer3-6813). + * BT device name is used in place of COM Port which is Classic BT only + */ + public ShimmerGRPC(String macAddress, String mFriendlyName, String serverHost, int serverPort) { + this(mFriendlyName, serverHost, serverPort); + mMyBluetoothAddress = macAddress; + mComPort = mFriendlyName; + } + public void InitializeProcess() { - // Define the server host and port - - // Create a channel to connect to the server - channel = ManagedChannelBuilder.forAddress(mServerHost, mServerPort) + channel = ManagedChannelBuilder.forTarget(mServerHost + ":" + mServerPort) .usePlaintext() // Use plaintext communication (insecure for testing) .build(); + // Create a gRPC client stub blockingStub = ShimmerBLEByteServerGrpc.newBlockingStub(channel); - - - - } @@ -98,8 +105,10 @@ public static void main(String[] args) { JButton btnNewButton = new JButton("Connect"); - final ShimmerGRPC shimmer = new ShimmerGRPC("E8EB1B713E36","localhost",50052); - + final ShimmerGRPC shimmer = new ShimmerGRPC("E8EB1B713E36","localhost",50052); + //Use constructor below instead for MacOS, which uses the BT device name to connect, e.g. Shimmer3-6813 + //final ShimmerGRPC shimmer = new ShimmerGRPC("E8EB1B713E36","Shimmer3-3E36","localhost",50052); + SensorDataReceived sdr = shimmer.new SensorDataReceived(); sdr.setWaitForData(shimmer); @@ -271,11 +280,18 @@ protected void writeBytes(byte[] data) { // Create a request message WriteBytes request = WriteBytes.newBuilder().setAddress(mMacAddress).setByteToWrite(ByteString.copyFrom(data)).build(); - // Call the remote gRPC service method - Reply response = blockingStub.writeBytesShimmer(request); - - // Process the response - System.out.println("Received: " + response.getMessage()); + try { + // Call the remote gRPC service method + Reply response = blockingStub.writeBytesShimmer(request); + + // Process the response + System.out.println("Received: " + response.getMessage()); + } catch(StatusRuntimeException sre) { + // Remote gRPC service is not available, so disconnect Shimmer device + sre.printStackTrace(); + System.out.println("ERROR: Lost connection to GRPC Server"); + connectionLost(); + } } @Override @@ -510,11 +526,15 @@ public void disconnect() throws ShimmerException { // Create a request message Request request = Request.newBuilder().setName(mMacAddress).build(); - // Call the remote gRPC service method - Reply response = blockingStub.disconnectShimmer(request); + try { + // Call the remote gRPC service method + Reply response = blockingStub.disconnectShimmer(request); + // Process the response + System.out.println("Received: " + response.getMessage()); + } catch(Exception e) { + e.printStackTrace(); + } - // Process the response - System.out.println("Received: " + response.getMessage()); closeConnection(); setBluetoothRadioState(BT_STATE.DISCONNECTED); } diff --git a/ShimmerDriverPC/src/main/java/com/shimmerresearch/tools/bluetooth/BasicShimmerBluetoothManagerPc.java b/ShimmerDriverPC/src/main/java/com/shimmerresearch/tools/bluetooth/BasicShimmerBluetoothManagerPc.java index 2faae6f88..07669d4bb 100644 --- a/ShimmerDriverPC/src/main/java/com/shimmerresearch/tools/bluetooth/BasicShimmerBluetoothManagerPc.java +++ b/ShimmerDriverPC/src/main/java/com/shimmerresearch/tools/bluetooth/BasicShimmerBluetoothManagerPc.java @@ -19,6 +19,7 @@ import com.shimmerresearch.driver.Configuration.COMMUNICATION_TYPE; import com.shimmerresearch.driver.shimmer4sdk.Shimmer4sdk; import com.shimmerresearch.driverUtilities.BluetoothDeviceDetails; +import com.shimmerresearch.driverUtilities.UtilShimmer; import com.shimmerresearch.exceptions.ConnectionExceptionListener; import com.shimmerresearch.exceptions.ShimmerException; import com.shimmerresearch.grpc.GrpcBLERadioByteCommunication; @@ -46,8 +47,8 @@ public BasicShimmerBluetoothManagerPc() { startGrpc(); } - public BasicShimmerBluetoothManagerPc(boolean isInternalUse) { - if(isInternalUse) { + public BasicShimmerBluetoothManagerPc(boolean startGrpc) { + if(startGrpc) { startGrpc(); } } @@ -191,19 +192,25 @@ public void connectVerisenseDevice(BluetoothDeviceDetails bdd) { @Override public void connectShimmer3BleGrpc(BluetoothDeviceDetails bdd) { ShimmerGRPC shimmer; + String macId = bdd.mShimmerMacId.replaceAll(":", ""); - if(!shimmer3BleMacIdList.contains(bdd.mShimmerMacId)) { - - shimmer = new ShimmerGRPC(bdd.mShimmerMacId.replace(":", ""),"localhost",mGRPCPort); + if(!shimmer3BleMacIdList.contains(macId)) { + if(UtilShimmer.isOsMac()) { + //Use the mFriendlyName (e.g. Shimmer3-6813), because MacOS doesn't use BT MacID + shimmer = new ShimmerGRPC(macId, bdd.mFriendlyName, "localhost", mGRPCPort); + } else { + shimmer = new ShimmerGRPC(macId, "localhost", mGRPCPort); + } shimmer.setShimmerUserAssignedName(bdd.mFriendlyName); - shimmer.setMacIdFromUart(bdd.mShimmerMacId); + shimmer.setMacIdFromUart(macId); initializeNewShimmerCommon(shimmer); shimmer3BleDeviceList.add(shimmer); - shimmer3BleMacIdList.add(bdd.mShimmerMacId); + shimmer3BleMacIdList.add(macId); } else { - shimmer = shimmer3BleDeviceList.get(shimmer3BleMacIdList.indexOf(bdd.mShimmerMacId)); + shimmer = shimmer3BleDeviceList.get(shimmer3BleMacIdList.indexOf(macId)); + initializeNewShimmerCommon(shimmer); } try { @@ -215,6 +222,7 @@ public void connectShimmer3BleGrpc(BluetoothDeviceDetails bdd) { e.printStackTrace(); } } + @Override public void connectShimmerThroughCommPort(String comPort){ directConnectUnknownShimmer=true; diff --git a/ShimmerPCBasicExamples/src/main/java/com/shimmerresearch/simpleexamples/SensorMapsExample.java b/ShimmerPCBasicExamples/src/main/java/com/shimmerresearch/simpleexamples/SensorMapsExample.java index 41b98690f..f9fbc2656 100644 --- a/ShimmerPCBasicExamples/src/main/java/com/shimmerresearch/simpleexamples/SensorMapsExample.java +++ b/ShimmerPCBasicExamples/src/main/java/com/shimmerresearch/simpleexamples/SensorMapsExample.java @@ -3,6 +3,7 @@ import javax.swing.JFrame; import com.shimmerresearch.bluetooth.ShimmerBluetooth.BT_STATE; +import com.shimmerresearch.comms.radioProtocol.ShimmerLiteProtocolInstructionSet.LiteProtocolInstructionSet.InstructionsGet; import com.shimmerresearch.driver.BasicProcessWithCallBack; import com.shimmerresearch.driver.CallbackObject; import com.shimmerresearch.driver.Configuration; @@ -14,6 +15,7 @@ import com.shimmerresearch.driverUtilities.BluetoothDeviceDetails; import com.shimmerresearch.driverUtilities.SensorDetails; import com.shimmerresearch.driverUtilities.ShimmerVerDetails.HW_ID; +import com.shimmerresearch.driverUtilities.UtilShimmer; import com.shimmerresearch.exceptions.ShimmerException; import com.shimmerresearch.grpc.ShimmerGRPC; import com.shimmerresearch.guiUtilities.configuration.EnableLowPowerModeDialog; @@ -88,13 +90,17 @@ public class SensorMapsExample extends BasicProcessWithCallBack { * @wbp.parser.entryPoint */ public void initialize() { + //Set the default port to 50052, this is used if the software cannot start the gRPC server automatically + BasicShimmerBluetoothManagerPc.mGRPCPort = 50052; + frame = new JFrame("Shimmer SensorMaps Example"); frame.setBounds(100, 100, 1200, 591); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().setLayout(null); - JLabel lblSetComPort = new JLabel("Set COM Port (e.g. COMX or /dev/rfcommX) or Mac Address (e.g. XX:XX:XX:XX:XX:XX , note this requires grpc and BLE)"); - lblSetComPort.setBounds(10, 25, 1000, 23); + JLabel lblSetComPort = new JLabel("Windows: Set COM Port (e.g. COMX or /dev/rfcommX) or Mac Address (e.g. XX:XX:XX:XX:XX:XX , note this requires grpc and BLE)" + + " | MacOS: Set device name (e.g. Shimmer3-XXXX) - gRPC/BLE"); + lblSetComPort.setBounds(10, 25, 1200, 23); frame.getContentPane().add(lblSetComPort); textField = new JTextField(); @@ -108,18 +114,24 @@ public void initialize() { public void actionPerformed(ActionEvent arg0) { btComport = textField.getText(); - if (btComport.length()==17) { + if (btComport.length()==17 || (btComport.startsWith("Shimmer") && btComport.contains("-"))) { + //Mac address or device name (e.g. Shimmer3-6813) if (comboBox.getSelectedItem().equals("Shimmer3")) { - BluetoothDeviceDetails bdd = new BluetoothDeviceDetails("", btComport, "Shimmer3BLE"); - btManager.connectShimmer3BleGrpc(bdd); + if(UtilShimmer.isOsMac()) { //MacOS uses the device name as both com port and friendly name + BluetoothDeviceDetails bdd = new BluetoothDeviceDetails("", btComport, btComport); + btManager.connectShimmer3BleGrpc(bdd); + } else { + BluetoothDeviceDetails bdd = new BluetoothDeviceDetails("", btComport, "Shimmer3BLE"); + btManager.connectShimmer3BleGrpc(bdd); + } } else if (comboBox.getSelectedItem().equals("Verisense")) { BluetoothDeviceDetails bdd = new BluetoothDeviceDetails(btComport, btComport, "ShimmerGRPC"); btManager.connectVerisenseDevice(bdd); } } else { + //COM port btManager.connectShimmerThroughCommPort(btComport); } - } }); btnConnect.setToolTipText("attempt connection to Shimmer device");