Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
6554807
DEV-221 Updates for support for gRPC on MacOS
jyong15 Apr 15, 2025
487f276
DEV-221 DEV-232
jyong15 Apr 28, 2025
27dd481
Merge branch 'master' into DEV-221
jyong15 Apr 28, 2025
04d5d2e
DEV-232 Minor
jyong15 Apr 28, 2025
c953532
DEV-221 DEV-232 Fix imports
jyong15 Apr 28, 2025
50c7223
DEV-221 try fix ShimmerDriverPc build
jyong15 Apr 29, 2025
9d121be
DEV-232 DEV-221 remove log print in GrpcBLERadioByteCommunication
jyong15 Apr 29, 2025
d374fc1
DEV-232 Update constructors in ShimmerGRPC to fix bugs with mac address
jyong15 May 9, 2025
0f135a7
DEV-232 Remove colons from Mac ID when connect Shimmer3BleGrpc
jyong15 May 9, 2025
9b42214
DEV-221 DEV-270 minor update SensorMapsExample & update log print
jyong15 Jun 19, 2025
e29661f
Merge remote-tracking branch 'origin/master' into DEV-221
jyong15 Jun 25, 2025
3352eb1
DEV-221 DEV-325 refactor boolean for clarity
jyong15 Jun 25, 2025
fe77bda
Merge remote-tracking branch 'origin/master' into DEV-221
jyong15 Jul 7, 2025
a78e35f
DEV-344 update path location for BLEGrpc for installed MacOS app
jyong15 Jul 9, 2025
db56074
Merge pull request #213 from ShimmerEngineering/DEV-221
dmariapan-shimmer Jul 9, 2025
7ef23e9
Merge remote-tracking branch 'origin/master' into CON_v2_1
MAzalya Jul 31, 2025
af9888a
Merge branch 'CON_v2_1' into DEV-344
jyong15 Aug 4, 2025
afe4f76
Merge pull request #238 from ShimmerEngineering/DEV-344
dmariapan-shimmer Aug 7, 2025
e944257
Merge branch 'master' into CON_v2_1
jyong15 Aug 26, 2025
676ca7e
DEV-468 make startGrpc() method accessible
jyong15 Aug 26, 2025
951760b
Merge pull request #241 from ShimmerEngineering/DEV-468
dmariapan-shimmer Aug 26, 2025
e230611
DEV-448 WIP implementing check for whether BLE gRPC server is running
jyong15 Sep 18, 2025
5804f97
DEV-448 fix IOThread not stopping
jyong15 Sep 29, 2025
bb3143e
DEV-448 fix typo
jyong15 Sep 29, 2025
2348316
DEV-448 fix checks for running BLE Server
jyong15 Sep 29, 2025
254f8ed
Merge pull request #246 from ShimmerEngineering/DEV-448
dmariapan-shimmer Sep 30, 2025
9e631a2
Update BasicShimmerBluetoothManagerPc.java
JongChern Sep 30, 2025
5991ba1
Merge branch 'CON_v2_1' into DEV-457
JongChern Sep 30, 2025
443f064
Merge pull request #247 from ShimmerEngineering/DEV-457
jyong15 Oct 9, 2025
99c5d54
Merge branch 'master' into CON_v2_1
jyong15 Oct 16, 2025
67ed359
DEV-516 improve logging of BLE Server - add exit code
jyong15 Oct 29, 2025
6c50e11
DEV-516 add shutdown hook to ensure BLE Server closes
jyong15 Oct 30, 2025
6777c07
Merge pull request #251 from ShimmerEngineering/DEV-516
dmariapan-shimmer Oct 31, 2025
a6c754e
Merge branch 'master' into CON_v2_1
jyong15 Nov 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
10 changes: 8 additions & 2 deletions ShimmerDriver/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,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'
Expand All @@ -116,7 +116,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
Expand All @@ -130,5 +130,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")
}

Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,47 @@
package com.shimmerresearch.grpc;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import javax.swing.JFrame;

import com.shimmerresearch.driverUtilities.UtilShimmer;

import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

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

public GrpcBLERadioByteTools() {
//Below used by Consensys MacOS
String userDir = System.getProperty("user.dir").equals("/") ? (getApplicationPath().toString() + "/libs/") : (System.getProperty("user.dir") + "/libs/");
String mExeNameMac = "ShimmerBLEGrpc";
String mExePathMac = userDir + "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;
}


Expand Down Expand Up @@ -67,37 +83,105 @@ public boolean isExeRunning(String exeName) {
return false;
}
}
public int startServer() throws Exception {

public boolean isExeRunningMacOS(String exeName) {
try {
Process process = Runtime.getRuntime().exec(new String[]{"pgrep", "-x", exeName});
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
boolean found = reader.readLine() != null;

if (!process.waitFor(5, TimeUnit.SECONDS)) { // Wait up to 5 seconds
process.destroy(); // Terminate the process if it doesn't exit
System.err.println("pgrep process timed out.");
return false; // Consider it not found or an error
}

return found;
} catch (IOException e) {
System.err.println("Error executing pgrep command: " + e.getMessage());
e.printStackTrace();
return false;
} catch (InterruptedException e) {
System.err.println("Thread interrupted while waiting for pgrep process: " + e.getMessage());
Thread.currentThread().interrupt(); // Restore the interrupted status
return false;
}
}

public boolean isServerRunning() {
if(UtilShimmer.isOsMac()) {
return isExeRunningMacOS(mExeNameMac);
} else {
return isExeRunning(mExeNameWindows);
}
}

public int startServer() throws Exception {
int port = getFreePort();

System.out.println(port + " is free");
List<String> 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();

// Add shutdown hook to ensure server is closed when Java app exits
try {
Runtime.getRuntime().addShutdownHook(shutdownHook);
} catch (IllegalStateException ignored) {
// JVM is already shutting down
}

Thread processThread = new Thread(() -> {
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
e.printStackTrace();
}
});
runningProcess.onExit().thenAccept(p -> {
int code = p.exitValue();
System.err.println("[BLEGrpcServer] exited: code=" + code +
(code >= 128 ? " (likely signal " + (code - 128) + ")" : ""));
});

processThread.start();
return port;
// You can continue with other tasks here

}

private final Thread shutdownHook = new Thread(() -> {
Process p = runningProcess;
if (p == null) return;

try {
// Try graceful termination first
p.destroy(); // sends SIGTERM on Unix, WM_CLOSE/CTRL_BREAK semantics vary on Windows
if (!p.waitFor(3, java.util.concurrent.TimeUnit.SECONDS)) {
// Fall back to force kill
p.destroyForcibly();
p.waitFor(2, java.util.concurrent.TimeUnit.SECONDS);
}
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
} catch (Exception e) {
e.printStackTrace();
}
});

public void stopServer() {
if (runningProcess != null) {
Expand All @@ -107,6 +191,18 @@ public void stopServer() {
System.err.println("No external process is currently running.");
}
}

public static Path getApplicationPath() {
try {
URL codeSourceUrl = GrpcBLERadioByteTools.class.getProtectionDomain().getCodeSource().getLocation();
Path codeSourcePath = Paths.get(codeSourceUrl.toURI());
if (codeSourcePath.toFile().isFile())
return codeSourcePath.getParent();
return codeSourcePath;
} catch (URISyntaxException e) {
throw new IllegalStateException("Failed to determine application path due to a URI syntax error.", e);
}
}

public static void main(String[] args) {

Expand Down Expand Up @@ -142,7 +238,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");
Expand Down
6 changes: 6 additions & 0 deletions ShimmerDriverPC/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,12 @@ 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")
}

// Shadow JAR task to create a runnable JAR with dependencies
Expand Down
Loading
Loading