Skip to content

Commit 7221615

Browse files
authored
Merge pull request #269 from ShimmerEngineering/DEV-662
DEV-662
2 parents 3734192 + fe9e6be commit 7221615

9 files changed

Lines changed: 263 additions & 7 deletions

File tree

ShimmerBluetoothManager/src/main/java/com/shimmerresearch/managers/bluetoothManager/ShimmerBluetoothManager.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,17 @@ public ShimmerDevice getShimmerDeviceBtConnected(String connectionHandle){
494494
return shimmerDevice;
495495
}
496496

497+
public boolean checkIfAlgoEnabledonAnyConnectedDevice(String algoName) {
498+
for (String comPort:mMapOfBtConnectedShimmers.keySet()) {
499+
ShimmerDevice device = getShimmerDeviceBtConnected(comPort);
500+
boolean algoenabled = device.isAlgorithmEnabled(algoName);
501+
if(algoenabled) {
502+
return true;
503+
}
504+
}
505+
return false;
506+
}
507+
497508
public ShimmerDevice getShimmerDeviceBtConnectedFromMac(String macAddress){
498509
Iterator<ShimmerDevice> iterator = mMapOfBtConnectedShimmers.values().iterator();
499510
while(iterator.hasNext()){

ShimmerDriver/src/main/java/com/shimmerresearch/algorithms/Filter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
44
This is a BlackMan-Windowed-Sinc Filter. Algorithm for calculating
55
filter coefficients from "The Scientist and Engineer's Guide to Digital Signal Processing",
6-
copyright ©1997-1998 by Steven W. Smith.
6+
copyright 1997-1998 by Steven W. Smith.
77
For more information visit the book's website at: www.DSPguide.com.
88
99
* Copyright (c) 2010 - 2014, Shimmer Research, Ltd.
@@ -64,7 +64,7 @@
6464
*
6565
This is a BlackMan-Windowed-Sinc Filter. Algorithm for calculating
6666
filter coefficients from "The Scientist and Engineer's Guide to Digital Signal Processing",
67-
copyright ©1997-1998 by Steven W. Smith.
67+
copyright ©1997-1998 by Steven W. Smith.
6868
For more information visit the book's website at: www.DSPguide.com.
6969
*
7070
*/

ShimmerDriver/src/main/java/com/shimmerresearch/driverUtilities/FftCalculateDetails.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
/** References
1616
*
17-
*[1] Angkoon Phinyomark, Pornchai Phukpattaranont, Chusak Limsakul (2012) Feature Reduction and Selection for EMG Signal Classification Elsevier, Expert Systems with Applications 39, P74207431
17+
*[1] Angkoon Phinyomark, Pornchai Phukpattaranont, Chusak Limsakul (2012) Feature Reduction and Selection for EMG Signal Classification Elsevier, Expert Systems with Applications 39, P7420 7431
1818
*[2] http://luscinia.sourceforge.net/page26/page35/page35.html
1919
* */
2020

ShimmerDriver/src/main/java/com/shimmerresearch/driverUtilities/UtilShimmer.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.util.Map.Entry;
3030
import java.util.Random;
3131
import java.util.TimeZone;
32+
import java.util.regex.Pattern;
3233

3334
import org.apache.commons.lang3.ArrayUtils;
3435

@@ -938,7 +939,19 @@ public int compare(Entry<Double, Double> o1,
938939
}
939940
return new ArrayList<Double>(sortedMap.keySet());
940941
}
941-
942+
// Regex breakdown:
943+
// ^ : Start of string
944+
// [0-9a-fA-F]{2} : Two hex characters
945+
// ( (:[0-9a-fA-F]{2}){5} | ([0-9a-fA-F]{2}){5} ) : Either 5 groups preceded by colons OR 5 groups with nothing
946+
// $ : End of string
947+
private static final String MAC_REGEX = "^([0-9a-fA-F]{2})((:[0-9a-fA-F]{2}){5}|([0-9a-fA-F]{2}){5})$";
948+
private static final Pattern MAC_PATTERN = Pattern.compile(MAC_REGEX);
949+
950+
public static boolean isValidMacAddress(String mac) {
951+
if (mac == null) return false;
952+
return MAC_PATTERN.matcher(mac).matches();
953+
}
954+
942955
public static boolean isValidMac(String mac) {
943956
if(mac==null){
944957
return false;
@@ -954,7 +967,7 @@ public static boolean isValidMac(String mac) {
954967

955968
return true;
956969
}
957-
970+
958971
public static String getDayString(int dayIndex) {
959972
switch (dayIndex) {
960973
case Calendar.SUNDAY:

ShimmerDriver/src/main/java/com/shimmerresearch/sensors/bmpX80/CalibDetailsBmp280.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ public double[] calibratePressureSensorData(double UP, double UT){
122122
double adc_T = UT;
123123
double adc_P = UP;
124124

125-
// Returns temperature in DegC, double precision. Output value of 51.23 equals 51.23 DegC.
125+
// Returns temperature in DegC, double precision. Output value of 51.23 equals 51.23 DegC.
126126
// t_fine carries fine temperature as global value
127127
double var1 = ((adc_T)/16384.0 - dig_T1/1024.0) * dig_T2;
128128
double var2 = (((adc_T)/131072.0 - dig_T1/8192.0) * (adc_T/131072.0 - dig_T1/8192.0)) * dig_T3;
@@ -131,7 +131,7 @@ public double[] calibratePressureSensorData(double UP, double UT){
131131
// double fTemp = T * 1.8 + 32; // Fahrenheit
132132
// T = T/100.0;
133133

134-
// Returns pressure in Pa as double. Output value of 96386.2 equals 96386.2 Pa = 963.862 hPa
134+
// Returns pressure in Pa as double. Output value of 96386.2 equals 96386.2 Pa = 963.862 hPa
135135
var1 = (t_fine/2.0) - 64000.0;
136136
var2 = var1 * var1 * dig_P6 / 32768.0;
137137
var2 = var2 + var1 * dig_P5 * 2.0;
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package com.shimmerresearch.tools;
2+
import java.util.ArrayList;
3+
import java.util.LinkedHashMap;
4+
import java.util.List;
5+
import java.util.Map;
6+
7+
import com.shimmerresearch.driver.Configuration.Shimmer3.DerivedSensorsBitMask;
8+
9+
public class DerivedSensorParser {
10+
private static final Map<Integer, String> SENSOR_MAP = new LinkedHashMap<>();
11+
12+
static {
13+
SENSOR_MAP.put(DerivedSensorsBitMask.RES_AMP, "RES_AMP");
14+
SENSOR_MAP.put(DerivedSensorsBitMask.SKIN_TEMP, "SKIN_TEMP");
15+
SENSOR_MAP.put(DerivedSensorsBitMask.PPG_12_13, "PPG_12_13");
16+
SENSOR_MAP.put(DerivedSensorsBitMask.PPG1_12_13, "PPG1_12_13");
17+
SENSOR_MAP.put(DerivedSensorsBitMask.PPG2_1_14, "PPG2_1_14");
18+
SENSOR_MAP.put(DerivedSensorsBitMask.PPG_TO_HR_12_13, "PPG_TO_HR_12_13");
19+
SENSOR_MAP.put(DerivedSensorsBitMask.PPG_TO_HR1_12_13, "PPG_TO_HR1_12_13");
20+
SENSOR_MAP.put(DerivedSensorsBitMask.PPG_TO_HR2_1_14, "PPG_TO_HR2_1_14");
21+
SENSOR_MAP.put(DerivedSensorsBitMask.ACTIVITY_MODULE, "ACTIVITY_MODULE");
22+
SENSOR_MAP.put(DerivedSensorsBitMask.GSR_METRICS_GENERAL, "GSR_METRICS_GENERAL");
23+
SENSOR_MAP.put(DerivedSensorsBitMask.ECG2HR_HRV_FREQ_DOMAIN, "ECG2HR_HRV_FREQ_DOMAIN");
24+
SENSOR_MAP.put(DerivedSensorsBitMask.ECG2HR_HRV_TIME_DOMAIN, "ECG2HR_HRV_TIME_DOMAIN");
25+
SENSOR_MAP.put(DerivedSensorsBitMask.ECG2HR_CHIP2_CH2, "ECG2HR_CHIP2_CH2");
26+
SENSOR_MAP.put(DerivedSensorsBitMask.ECG2HR_CHIP2_CH1, "ECG2HR_CHIP2_CH1");
27+
SENSOR_MAP.put(DerivedSensorsBitMask.ECG2HR_CHIP1_CH2, "ECG2HR_CHIP1_CH2");
28+
SENSOR_MAP.put(DerivedSensorsBitMask.ECG2HR_CHIP1_CH1, "ECG2HR_CHIP1_CH1");
29+
SENSOR_MAP.put(DerivedSensorsBitMask.ORIENTATION_9DOF_WR_QUAT, "ORIENTATION_9DOF_WR_QUAT");
30+
SENSOR_MAP.put(DerivedSensorsBitMask.ORIENTATION_9DOF_WR_EULER, "ORIENTATION_9DOF_WR_EULER");
31+
SENSOR_MAP.put(DerivedSensorsBitMask.ORIENTATION_6DOF_WR_QUAT, "ORIENTATION_6DOF_WR_QUAT");
32+
SENSOR_MAP.put(DerivedSensorsBitMask.ORIENTATION_6DOF_WR_EULER, "ORIENTATION_6DOF_WR_EULER");
33+
SENSOR_MAP.put(DerivedSensorsBitMask.ORIENTATION_9DOF_LN_QUAT, "ORIENTATION_9DOF_LN_QUAT");
34+
SENSOR_MAP.put(DerivedSensorsBitMask.ORIENTATION_9DOF_LN_EULER, "ORIENTATION_9DOF_LN_EULER");
35+
SENSOR_MAP.put(DerivedSensorsBitMask.ORIENTATION_6DOF_LN_QUAT, "ORIENTATION_6DOF_LN_QUAT");
36+
SENSOR_MAP.put(DerivedSensorsBitMask.ORIENTATION_6DOF_LN_EULER, "ORIENTATION_6DOF_LN_EULER");
37+
SENSOR_MAP.put(DerivedSensorsBitMask.EMG_PROCESSING_CHAN2, "EMG_PROCESSING_CHAN2");
38+
SENSOR_MAP.put(DerivedSensorsBitMask.EMG_PROCESSING_CHAN1, "EMG_PROCESSING_CHAN1");
39+
SENSOR_MAP.put(DerivedSensorsBitMask.GSR_BASELINE, "GSR_BASELINE");
40+
SENSOR_MAP.put(DerivedSensorsBitMask.GSR_METRICS_TREND_PEAK, "GSR_METRICS_TREND_PEAK");
41+
SENSOR_MAP.put(DerivedSensorsBitMask.GAIT_MODULE, "GAIT_MODULE");
42+
SENSOR_MAP.put(DerivedSensorsBitMask.GYRO_ON_THE_FLY_CAL, "GYRO_ON_THE_FLY_CAL");
43+
}
44+
45+
/**
46+
* Parses the hex string and returns a list of enabled sensor names.
47+
* @param hexInput String format "hx:0000000020440000"
48+
*/
49+
public static List<String> parseHex(String hexInput) {
50+
String cleanHex = hexInput.replace("hx:", "");
51+
// Using Long because the input is 64-bit, even though constants are 32-bit
52+
long bitmask = Long.parseUnsignedLong(cleanHex, 16);
53+
54+
List<String> enabledSensors = new ArrayList<>();
55+
56+
for (Map.Entry<Integer, String> entry : SENSOR_MAP.entrySet()) {
57+
// Check if the specific bit is set
58+
if ((bitmask & entry.getKey()) != 0) {
59+
enabledSensors.add(entry.getValue());
60+
}
61+
}
62+
return enabledSensors;
63+
}
64+
65+
public static void main(String[] args) {
66+
// String containing multiple CSV hex values
67+
String csvInput = "hx:0000000000000000,"
68+
+ "hx:0000000000000004,"
69+
+ "hx:0000000020440000,"
70+
+ "hx:0000000020000000,"
71+
+ "hx:0000000020000024,"
72+
+ "hx:0000000000000024,"
73+
+ "hx:000000000000F000,"
74+
+ "hx:0000000000008000,"
75+
+ "hx:0000000020000004,"
76+
+ "hx:0000000008000224,"
77+
+ "hx:0000000001000000,"
78+
+ "hx:0000000020110000";
79+
80+
// Split by comma
81+
String[] hexValues = csvInput.split(",");
82+
83+
System.out.println(String.format("%-25s | %s", "Hex Value", "Enabled Sensors"));
84+
System.out.println("------------------------------------------------------------");
85+
86+
for (String hex : hexValues) {
87+
List<String> results = parseHex(hex);
88+
String sensors = results.isEmpty() ? "None" : String.join(", ", results);
89+
90+
System.out.println(String.format("%-25s | %s", hex.trim(), sensors));
91+
}
92+
}
93+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package com.shimmerresearch.tools;
2+
3+
import java.util.ArrayList;
4+
import java.util.LinkedHashMap;
5+
import java.util.List;
6+
import java.util.Map;
7+
8+
public class EnabledSensorParser {
9+
10+
private static final Map<Integer, String> SENSOR_MAP = new LinkedHashMap<>();
11+
12+
static {
13+
// Motion
14+
SENSOR_MAP.put(0x80, "SENSOR_ACCEL");
15+
SENSOR_MAP.put(0x1000, "SENSOR_DACCEL");
16+
SENSOR_MAP.put(0x40, "SENSOR_GYRO");
17+
SENSOR_MAP.put(0x20, "SENSOR_MAG");
18+
SENSOR_MAP.put(0x400000, "SENSOR_ALT_ACCEL");
19+
SENSOR_MAP.put(0x200000, "SENSOR_ALT_MAG");
20+
21+
// Biopotential / EXG
22+
SENSOR_MAP.put(0x10, "SENSOR_ECG / EXG1_24BIT");
23+
SENSOR_MAP.put(0x08, "SENSOR_EMG / EXG2_24BIT");
24+
SENSOR_MAP.put(0x100000, "SENSOR_EXG1_16BIT");
25+
SENSOR_MAP.put(0x080000, "SENSOR_EXG2_16BIT");
26+
27+
// Analog / ADC
28+
SENSOR_MAP.put(0x02, "SENSOR_EXT_ADC_A7");
29+
SENSOR_MAP.put(0x01, "SENSOR_EXT_ADC_A6");
30+
SENSOR_MAP.put(0x0800, "SENSOR_EXT_ADC_A15");
31+
SENSOR_MAP.put(0x0400, "SENSOR_INT_ADC_A1");
32+
SENSOR_MAP.put(0x0200, "SENSOR_INT_ADC_A12");
33+
SENSOR_MAP.put(0x0100, "SENSOR_INT_ADC_A13");
34+
SENSOR_MAP.put(0x800000, "SENSOR_INT_ADC_A14");
35+
36+
// Other
37+
SENSOR_MAP.put(0x04, "SENSOR_GSR");
38+
SENSOR_MAP.put(0x40000, "SENSOR_BMPX80");
39+
SENSOR_MAP.put(0x8000, "SENSOR_BRIDGE_AMP");
40+
SENSOR_MAP.put(0x4000, "SENSOR_HEART");
41+
SENSOR_MAP.put(0x2000, "SENSOR_BATT");
42+
}
43+
44+
public static List<String> parseHex(String hexInput) {
45+
String cleanHex = hexInput.replace("hx:", "");
46+
long bitmask = Long.parseUnsignedLong(cleanHex, 16);
47+
48+
List<String> enabledSensors = new ArrayList<>();
49+
50+
for (Map.Entry<Integer, String> entry : SENSOR_MAP.entrySet()) {
51+
if ((bitmask & entry.getKey()) != 0) {
52+
enabledSensors.add(entry.getValue());
53+
}
54+
}
55+
return enabledSensors;
56+
}
57+
58+
public static void main(String[] args) {
59+
60+
String csvInput ="hx:0000000000000104,"
61+
+ "hx:0000000000000004,"
62+
+ "hx:00000000000031E4,"
63+
+ "hx:00000000000439E7,"
64+
+ "hx:00000000000010E0,"
65+
+ "hx:0000000000000010,"
66+
+ "hx:0000000000001104,"
67+
+ "hx:0000000000000018,"
68+
+ "hx:0000000000000098,"
69+
+ "hx:00000000000020E0";
70+
71+
String[] hexValues = csvInput.split(",");
72+
73+
System.out.println(String.format("%-25s | %s", "Hex Value", "Enabled Sensors"));
74+
System.out.println("------------------------------------------------------------");
75+
76+
for (String hex : hexValues) {
77+
List<String> results = parseHex(hex);
78+
String sensors = results.isEmpty() ? "None" : String.join(", ", results);
79+
System.out.println(String.format("%-25s | %s", hex.trim(), sensors));
80+
}
81+
}
82+
}

ShimmerDriver/src/test/java/com/shimmerresearch/driverUtilities/API_00007_UtilShimmerTest.java

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,62 @@
66

77
public class API_00007_UtilShimmerTest {
88

9+
@Test
10+
public void testValidMacWithColons() {
11+
// Upper case
12+
assertTrue("Should be valid: Uppercase with colons",
13+
UtilShimmer.isValidMacAddress("00:1A:2B:3C:4D:5E"));
14+
// Lower case
15+
assertTrue("Should be valid: Lowercase with colons",
16+
UtilShimmer.isValidMacAddress("00:1a:2b:3c:4d:5e"));
17+
}
18+
19+
@Test
20+
public void testValidMacWithoutColons() {
21+
// Pure Hex string
22+
assertTrue("Should be valid: Plain hex string",
23+
UtilShimmer.isValidMacAddress("001A2B3C4D5E"));
24+
assertTrue("Should be valid: Lowercase plain hex",
25+
UtilShimmer.isValidMacAddress("001a2b3c4d5e"));
26+
}
27+
28+
@Test
29+
public void testInvalidCharacters() {
30+
// Contains 'G' (non-hex)
31+
assertFalse("Should be invalid: Contains non-hex character G",
32+
UtilShimmer.isValidMacAddress("00:1A:2B:3C:4D:5G"));
33+
// Contains special characters
34+
assertFalse("Should be invalid: Contains symbols",
35+
UtilShimmer.isValidMacAddress("00:1A:2B:3C:4D:5#"));
36+
}
37+
38+
@Test
39+
public void testInvalidLength() {
40+
// Too short
41+
assertFalse("Should be invalid: Too short",
42+
UtilShimmer.isValidMacAddress("00:1A:2B"));
43+
// Too long
44+
assertFalse("Should be invalid: Too long",
45+
UtilShimmer.isValidMacAddress("00:1A:2B:3C:4D:5E:6F"));
46+
}
47+
48+
@Test
49+
public void testMixedFormats() {
50+
// Cannot mix "no-colon" with "colons" halfway through
51+
assertFalse("Should be invalid: Inconsistent colon usage",
52+
UtilShimmer.isValidMacAddress("001A2B:3C:4D:5E"));
53+
}
54+
55+
@Test
56+
public void testEdgeCases() {
57+
assertFalse("Should be invalid: Null input",
58+
UtilShimmer.isValidMacAddress(null));
59+
assertFalse("Should be invalid: Empty string",
60+
UtilShimmer.isValidMacAddress(""));
61+
assertFalse("Should be invalid: Spaces included",
62+
UtilShimmer.isValidMacAddress("00 1A 2B 3C 4D 5E"));
63+
}
64+
965
@Test
1066
public void testRoundZeroDecimalPoints() {
1167
assertTrue(UtilShimmer.round(5.567, 0) == 6.0);

ShimmerDriverPC/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ repositories {
3232
test {
3333
// this test requires a physical Shimmer2r to run
3434
exclude '**/API_00001_ShimmerPC_GeneralBluetoothShimmer2R.class'
35+
exclude '**/API_0000X_ByteCommunicationShimmer3lns0_16_11_w_sd_only.class'
3536
}
3637

3738
publishing {

0 commit comments

Comments
 (0)