Skip to content

Commit 1eabf92

Browse files
committed
Merge remote-tracking branch 'origin/master' into DEV-620
2 parents 263abf6 + f3a5646 commit 1eabf92

17 files changed

Lines changed: 1008 additions & 22 deletions

ShimmerDriver/src/main/java/com/shimmerresearch/bluetooth/ShimmerBluetooth.java

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -715,7 +715,7 @@ else if((mCurrentCommand==GET_FW_VERSION_COMMAND)
715715
}
716716
threadSleep((int)((Math.random()+.1)*100.0));
717717
writeBytes(insBytes);
718-
printLogDataForDebugging("Command Transmitted: \t\t\t" + btCommandToString(mCurrentCommand) + " " + UtilShimmer.bytesToHexStringWithSpacesFormatted(insBytes));
718+
printLogDataForDebugging("Command Transmitted: \t\t\t" + btCommandToString(mCurrentCommand) + ", len=" + insBytes.length + " " + UtilShimmer.bytesToHexStringWithSpacesFormatted(insBytes));
719719

720720
//TODO: are the two stops needed here? better to wait for ack from Shimmer
721721
if(mCurrentCommand==STOP_STREAMING_COMMAND
@@ -880,7 +880,7 @@ private void processNotStreamingWaitForResp() {
880880
mWaitForResponse=false;
881881
mTransactionCompleted=true;
882882
setInstructionStackLock(false);
883-
printLogDataForDebugging("Response Received:\t\t\t" + btCommandToString(responseCommand));
883+
printLogDataForDebugging("Response Received:\t\t\t" + btCommandToString(responseCommand) + ", len=" + byteBuffer.length + " " + UtilShimmer.bytesToHexStringWithSpacesFormatted(byteBuffer));
884884

885885
// Special case for FW_VERSION_RESPONSE because it
886886
// needs to initialize the Shimmer after releasing
@@ -939,7 +939,7 @@ protected void processPacket() {
939939
&& bufferTemp[getPacketSizeWithCrc()+1]==DATA_PACKET){
940940

941941
if (mBtCommsCrcModeCurrent != BT_CRC_MODE.OFF && !checkCrc(bufferTemp, getPacketSize() + 1)) {
942-
discardFirstBufferByte();
942+
discardBufferBytesToNextPacket();
943943
return;
944944
}
945945

@@ -1002,17 +1002,19 @@ else if(isSupportedInStreamCmds() && bufferTemp[getPacketSizeWithCrc()+2]==INSTR
10021002
}
10031003
}
10041004
if(mByteArrayOutputStream.size()>getPacketSizeWithCrc()+2){
1005-
printLogDataForDebugging("Unknown packet error (check with JC):\tExpected: " + (getPacketSizeWithCrc()+2) + "bytes but buffer contains " + mByteArrayOutputStream.size() + "bytes");
1006-
discardFirstBufferByte(); //throw the first byte away
1005+
printLogDataForDebugging("Unknown packet error: \tExpected: " + (getPacketSizeWithCrc()+2) + "bytes but buffer contains " + mByteArrayOutputStream.size() + "bytes");
1006+
discardBufferBytesToNextPacket(); // Skip to start of next packet
10071007
}
10081008

10091009
}
10101010
//TODO: ACK in bufferTemp[0] not handled
10111011
//else if
10121012
else {
1013-
printLogDataForDebugging("Packet syncing problem:\tExpected: " + (getPacketSizeWithCrc()+2) + "bytes. Buffer contains " + mByteArrayOutputStream.size() + "bytes"
1014-
+ "\nBuffer = " + UtilShimmer.bytesToHexStringWithSpacesFormatted(mByteArrayOutputStream.toByteArray()));
1015-
discardFirstBufferByte(); //throw the first byte away
1013+
printLogDataForDebugging("Unexpected packet header bytes. Expected size: " + getPacketSizeWithCrc()
1014+
+ ", Packet 1 header: " + UtilShimmer.byteToHexStringFormatted(bufferTemp[0])
1015+
+ ", Packet 2 header: " + UtilShimmer.byteToHexStringFormatted(bufferTemp[getPacketSizeWithCrc() + 1])
1016+
+ "\nBuffer: " + UtilShimmer.bytesToHexStringWithSpacesFormatted(mByteArrayOutputStream.toByteArray()));
1017+
discardBufferBytesToNextPacket(); // Skip to start of next packet
10161018
}
10171019
}
10181020

@@ -1052,7 +1054,7 @@ public boolean checkCrc(byte[] bufferTemp, int length) {
10521054
if (mBtCommsCrcModeCurrent == BT_CRC_MODE.TWO_BYTE_CRC) {
10531055
// + 2 as this is the location of the CRC's MSB
10541056
if (bufferTemp[getPacketSize() + 2] != crcCalc[1]) {
1055-
discardFirstBufferByte();
1057+
discardBufferBytesToNextPacket();
10561058
return false;
10571059
}
10581060
}
@@ -1294,16 +1296,38 @@ protected void clearBuffers() {
12941296
}
12951297

12961298
/**
1297-
*
1299+
* Next packet start should begin with DATA_PACKET or ACK_COMMAND_PROCESSED byte so skip to that point
12981300
*/
1299-
protected void discardFirstBufferByte(){
1301+
protected void discardBufferBytesToNextPacket(){
13001302
byte[] bTemp = mByteArrayOutputStream.toByteArray();
1303+
1304+
//Find index of first DATA_PACKET or ACK byte within the buffer
1305+
int offset = findOffsetOfNextZeroOrFF(bTemp);
1306+
//If not found, just skip one byte
1307+
offset = (offset == -1) ? 1 : offset;
1308+
13011309
mByteArrayOutputStream.reset();
1302-
mByteArrayOutputStream.write(bTemp, 1, bTemp.length-1); //this will throw the first byte away
1310+
mByteArrayOutputStream.write(bTemp, offset, bTemp.length-offset); // discard first 'offset' bytes
13031311
if(mEnablePCTimeStamps) {
1304-
mListofPCTimeStamps.remove(0);
1312+
// Remove first `offset` elements from the original list (destructive, modifies same list)
1313+
mListofPCTimeStamps.subList(0, Math.min(offset, mListofPCTimeStamps.size())).clear();
1314+
}
1315+
consolePrintLn("Throw Bytes " + UtilShimmer.bytesToHexStringWithSpacesFormatted(Arrays.copyOfRange(bTemp, 0, offset)));
1316+
}
1317+
1318+
/**
1319+
* Finds the offset/index of the next DATA_PACKET (0x00) or ACK_COMMAND_PROCESSED (0xFF) byte.
1320+
*
1321+
* @param buffer a byte array to search within
1322+
* @return index of the first 0x00 or 0xFF byte found after position 0, or -1 if not found
1323+
*/
1324+
private static int findOffsetOfNextZeroOrFF(byte[] buffer) {
1325+
for (int i = 1; i < buffer.length; i++) {
1326+
byte b = buffer[i];
1327+
if (b == 0 || b == (byte) 0xFF)
1328+
return i;
13051329
}
1306-
consolePrintLn("Throw Byte" + UtilShimmer.bytesToHexStringWithSpacesFormatted(bTemp));
1330+
return -1;
13071331
}
13081332

13091333
/**

ShimmerDriver/src/main/java/com/shimmerresearch/comms/wiredProtocol/ShimmerCrc.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ public class ShimmerCrc {
99
* @param b the byte to calculate the CRC on
1010
* @return the new CRC value
1111
*/
12-
protected static int shimmerUartCrcByte(int crc, byte b) {
12+
public static int shimmerUartCrcByte(int crc, byte b) {
1313
crc &= 0xFFFF;
1414
crc = ((crc & 0xFFFF) >>> 8) | ((crc & 0xFFFF) << 8);
1515
crc ^= (b&0xFF);

ShimmerDriver/src/main/java/com/shimmerresearch/driver/Configuration.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,6 +1084,7 @@ public static class ObjectClusterSensorName{
10841084

10851085
public static String TIMESTAMP = SensorShimmerClock.ObjectClusterSensorName.TIMESTAMP;//"Timestamp";
10861086
public static String REAL_TIME_CLOCK = SensorShimmerClock.ObjectClusterSensorName.REAL_TIME_CLOCK;//"RealTime";
1087+
public static String SHIMMER_CLOCK = SensorShimmerClock.ObjectClusterSensorName.SHIMMER_CLOCK;//"RealTime";
10871088
// public static String REAL_TIME_CLOCK_SYNC = TimeSyncModule.ObjectClusterSensorName.REAL_TIME_CLOCK_SYNC;//"RealTime_Sync";
10881089
// public static String TIMESTAMP_SYNC = TimeSyncModule.ObjectClusterSensorName.TIMESTAMP_SYNC;//"Timestamp_Sync";
10891090
public static String SYSTEM_TIMESTAMP = SensorSystemTimeStamp.ObjectClusterSensorName.SYSTEM_TIMESTAMP;//"System_Timestamp";
@@ -1727,6 +1728,7 @@ public static class CompatibilityInfoForMaps{
17271728
aMap.put(SensorSystemTimeStamp.ObjectClusterSensorName.SYSTEM_TIMESTAMP_PLOT, SensorShimmerClock.channelSystemTimestampPlot);
17281729

17291730
aMap.put(SensorShimmerClock.ObjectClusterSensorName.REAL_TIME_CLOCK, SensorShimmerClock.channelRealTimeClock);
1731+
aMap.put(SensorShimmerClock.ObjectClusterSensorName.SHIMMER_CLOCK, SensorShimmerClock.channelShimmerClock3LSB);
17301732
// aMap.put(ShimmerClock.ObjectClusterSensorName.REAL_TIME_CLOCK, ShimmerClock.channelRealTimeClockSync);
17311733
aMap.put(SensorShimmerClock.ObjectClusterSensorName.TIMESTAMP_OFFSET, SensorShimmerClock.channelShimmerClockOffset);
17321734
// aMap.putAll(ShimmerClock.mChannelMapRef);
@@ -1773,6 +1775,7 @@ public static class CompatibilityInfoForMaps{
17731775
aMap.put(SensorSystemTimeStamp.ObjectClusterSensorName.SYSTEM_TIMESTAMP_PLOT, SensorShimmerClock.channelSystemTimestampPlot);
17741776

17751777
aMap.put(SensorShimmerClock.ObjectClusterSensorName.REAL_TIME_CLOCK, SensorShimmerClock.channelRealTimeClock);
1778+
aMap.put(SensorShimmerClock.ObjectClusterSensorName.SHIMMER_CLOCK, SensorShimmerClock.channelShimmerClock3LSB);
17761779
// aMap.put(ShimmerClock.ObjectClusterSensorName.REAL_TIME_CLOCK, ShimmerClock.channelRealTimeClockSync);
17771780
aMap.put(SensorShimmerClock.ObjectClusterSensorName.TIMESTAMP_OFFSET, SensorShimmerClock.channelShimmerClockOffset);
17781781
// aMap.putAll(ShimmerClock.mChannelMapRef);

ShimmerDriver/src/main/java/com/shimmerresearch/driver/ShimmerDevice.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1402,6 +1402,9 @@ else if(mDockID.contains(HwDriverShimmerDeviceDetails.DEVICE_TYPE.BASE15.getLabe
14021402
else if(mDockID.contains(HwDriverShimmerDeviceDetails.DEVICE_TYPE.BASE6.getLabel())){
14031403
mDockType = DEVICE_TYPE.BASE6;
14041404
}
1405+
else if(mDockID.contains(HwDriverShimmerDeviceDetails.DEVICE_TYPE.SHIMMER3R.getLabel())){
1406+
mDockType = DEVICE_TYPE.SHIMMER3R;
1407+
}
14051408
else {
14061409
mDockType = DEVICE_TYPE.UNKOWN;
14071410
}
@@ -3087,9 +3090,14 @@ public void disableAllAlgorithms(){
30873090
public boolean isECGAlgoEnabled(AbstractAlgorithm abstractAlgorithm){
30883091
SensorDetails ecgSensorDetails = getSensorDetails(Configuration.Shimmer3.SENSOR_ID.HOST_ECG);
30893092
SensorDetails respSensorDetails = getSensorDetails(Configuration.Shimmer3.SENSOR_ID.HOST_EXG_RESPIRATION);
3090-
if((ecgSensorDetails.isEnabled() || respSensorDetails.isEnabled()) && abstractAlgorithm.mAlgorithmName.contains("ECGtoHR")){
3093+
3094+
if (ecgSensorDetails!=null && ecgSensorDetails.isEnabled() && abstractAlgorithm.mAlgorithmName.contains("ECGtoHR")) {
3095+
return true;
3096+
}
3097+
if (respSensorDetails!=null && ecgSensorDetails.isEnabled() && abstractAlgorithm.mAlgorithmName.contains("ECGtoHR")) {
30913098
return true;
30923099
}
3100+
30933101
return false;
30943102
}
30953103

ShimmerDriver/src/main/java/com/shimmerresearch/driver/ShimmerObject.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2804,7 +2804,8 @@ else if (getHardwareVersion()==HW_ID.SHIMMER_2 || getHardwareVersion()==HW_ID.SH
28042804
protected void parseTimestampShimmer3(COMMUNICATION_TYPE fwType, ObjectCluster objectCluster, double[] uncalibratedData, String[] uncalibratedDataUnits, double[] calibratedData, String[] calibratedDataUnits, String[] sensorNames, long[] newPacketInt) {
28052805
int iTimeStamp=getSignalIndex(Configuration.Shimmer3.ObjectClusterSensorName.TIMESTAMP); //find index
28062806
double shimmerTimestampTicks = (double)newPacketInt[iTimeStamp];
2807-
2807+
objectCluster.addDataToMap(Shimmer3.ObjectClusterSensorName.SHIMMER_CLOCK,CHANNEL_TYPE.UNCAL.toString(),CHANNEL_UNITS.CLOCK_UNIT,shimmerTimestampTicks);
2808+
objectCluster.addDataToMap(Shimmer3.ObjectClusterSensorName.SHIMMER_CLOCK,CHANNEL_TYPE.CAL.toString(),CHANNEL_UNITS.CLOCK_UNIT,shimmerTimestampTicks);
28082809
if(mFirstTime && fwType==COMMUNICATION_TYPE.SD){
28092810
//this is to make sure the Raw starts from zero for SD data. See comment for mFirstTsOffsetFromInitialTsTicks.
28102811
mFirstTsOffsetFromInitialTsTicks = shimmerTimestampTicks;
@@ -2822,7 +2823,7 @@ protected void parseTimestampShimmer3(COMMUNICATION_TYPE fwType, ObjectCluster o
28222823

28232824
double timestampUnwrappedTicks = unwrapTimeStamp(shimmerTimestampTicks);
28242825
double timestampUnwrappedMilliSecs = timestampUnwrappedTicks/getRtcClockFreq()*1000; // to convert into mS
2825-
2826+
28262827
incrementPacketsReceivedCounters();
28272828
calculateTrialPacketLoss(timestampUnwrappedMilliSecs);
28282829

ShimmerDriver/src/main/java/com/shimmerresearch/sensors/SensorShimmerClock.java

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ public static class ObjectClusterSensorName{
8383

8484
public static final String TIMESTAMP_DIFFERENCE = "Timestamp Difference";
8585
public static final String REAL_TIME_CLOCK = "RealTime";
86-
86+
public static final String SHIMMER_CLOCK = "Clock 3_LSB";
8787
public static final String TIMESTAMP_OFFSET = "Offset";
8888
}
8989

@@ -93,6 +93,7 @@ public static class DatabaseChannelHandles{
9393
public static final String OFFSET_TIMESTAMP = "OFFSET";//"Offset";
9494

9595
public static final String REAL_TIME_CLOCK = "Real_Time_Clock";
96+
public static final String SHIMMER_CLOCK = "Clock_3_LSB";
9697
}
9798

9899
public static final class DatabaseConfigHandle{
@@ -106,7 +107,8 @@ public static final class DatabaseConfigHandle{
106107
Arrays.asList(SensorShimmerClock.ObjectClusterSensorName.TIMESTAMP,
107108
SensorShimmerClock.ObjectClusterSensorName.TIMESTAMP_DIFFERENCE,
108109
SensorShimmerClock.ObjectClusterSensorName.REAL_TIME_CLOCK,
109-
SensorShimmerClock.ObjectClusterSensorName.TIMESTAMP_OFFSET
110+
SensorShimmerClock.ObjectClusterSensorName.TIMESTAMP_OFFSET,
111+
SensorShimmerClock.ObjectClusterSensorName.SHIMMER_CLOCK
110112
));
111113
{
112114
sensorShimmerClock.mIsApiSensor = true; // Even though TIMESTAMP channel is an API channel, there is no enabledSensor bit for it
@@ -220,6 +222,17 @@ public static final class DatabaseConfigHandle{
220222
channelRealTimeClock.mChannelSource = CHANNEL_SOURCE.API;
221223
}
222224

225+
public static final ChannelDetails channelShimmerClock3LSB = new ChannelDetails(
226+
ObjectClusterSensorName.SHIMMER_CLOCK,
227+
ObjectClusterSensorName.SHIMMER_CLOCK,
228+
DatabaseChannelHandles.SHIMMER_CLOCK,
229+
CHANNEL_UNITS.CLOCK_UNIT,
230+
Arrays.asList(CHANNEL_TYPE.UNCAL ,CHANNEL_TYPE.CAL), false, true);
231+
{
232+
//TODO put into above constructor
233+
channelRealTimeClock.mChannelSource = CHANNEL_SOURCE.API;
234+
}
235+
223236
//TODO: Move to separate class
224237
public static final ChannelDetails channelBattPercentage = new ChannelDetails(
225238
Configuration.Shimmer3.ObjectClusterSensorName.BATT_PERCENTAGE,
@@ -301,9 +314,8 @@ public void generateSensorMap() {
301314
channelMapRef.put(SensorShimmerClock.ObjectClusterSensorName.TIMESTAMP_DIFFERENCE, SensorShimmerClock.channelShimmerTsDiffernce);
302315
channelMapRef.put(SensorShimmerClock.ObjectClusterSensorName.TIMESTAMP_OFFSET, SensorShimmerClock.channelShimmerClockOffset);
303316
channelMapRef.put(SensorShimmerClock.ObjectClusterSensorName.REAL_TIME_CLOCK, SensorShimmerClock.channelRealTimeClock);
304-
317+
channelMapRef.put(SensorShimmerClock.ObjectClusterSensorName.SHIMMER_CLOCK, SensorShimmerClock.channelShimmerClock3LSB);
305318
channelMapRef.put(SensorBattVoltage.ObjectClusterSensorName.BATT_PERCENTAGE, SensorShimmerClock.channelBattPercentage);
306-
307319
channelMapRef.put(ShimmerStreamingProperties.ObjectClusterSensorName.PACKET_RECEPTION_RATE_CURRENT, SensorShimmerClock.channelReceptionRateCurrent);
308320
channelMapRef.put(ShimmerStreamingProperties.ObjectClusterSensorName.PACKET_RECEPTION_RATE_OVERALL, SensorShimmerClock.channelReceptionRateTrial);
309321
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package com.shimmerresearch.shimmer3.communication;
2+
import org.junit.Before;
3+
import org.junit.BeforeClass;
4+
import org.junit.FixMethodOrder;
5+
import org.junit.Test;
6+
import org.junit.runners.MethodSorters;
7+
8+
import com.shimmerresearch.bluetooth.ShimmerBluetooth.BT_STATE;
9+
import com.shimmerresearch.driver.BasicProcessWithCallBack;
10+
import com.shimmerresearch.driver.CallbackObject;
11+
import com.shimmerresearch.driver.ObjectCluster;
12+
import com.shimmerresearch.driver.ShimmerMsg;
13+
import com.shimmerresearch.driver.Configuration.COMMUNICATION_TYPE;
14+
import com.shimmerresearch.driverUtilities.ChannelDetails;
15+
import com.shimmerresearch.driverUtilities.SensorDetails;
16+
import com.shimmerresearch.driverUtilities.ShimmerVerDetails.HW_ID;
17+
import com.shimmerresearch.exceptions.ShimmerException;
18+
import com.shimmerresearch.pcDriver.ShimmerPC;
19+
import com.shimmerresearch.sensors.AbstractSensor;
20+
import com.shimmerresearch.sensors.AbstractSensor.SENSORS;
21+
22+
import bolts.TaskCompletionSource;
23+
24+
import static org.junit.Assert.assertEquals;
25+
26+
import java.util.ArrayList;
27+
import java.util.LinkedHashMap;
28+
import java.util.concurrent.TimeUnit;
29+
@FixMethodOrder(MethodSorters.NAME_ASCENDING) // Test methods will be run in alphabetical order
30+
public class API_0000X_ByteCommunicationShimmer3_Streaming_Contiguous_Check extends BasicProcessWithCallBack{
31+
ShimmerPC mDevice;
32+
TaskCompletionSource<Boolean> mCalibrationTask;
33+
TaskCompletionSource<Boolean> mStreamingTask;
34+
ByteCommunicationSimulatorS3 mByteCommunicationSimulatorS3;
35+
36+
@Before
37+
public void setUp() {
38+
mByteCommunicationSimulatorS3 = new ByteCommunicationSimulatorS3_streaming_timestamp_contiguous_check("COM99");
39+
mDevice = new ShimmerPC("COM99");
40+
mDevice.setTestRadio(mByteCommunicationSimulatorS3);
41+
setWaitForData(mDevice);
42+
}
43+
44+
ArrayList<ObjectCluster> mListOJC;
45+
@Test
46+
public void test001_testStreaming() {
47+
mListOJC = new ArrayList<ObjectCluster>();
48+
mByteCommunicationSimulatorS3.setIsNewBMPSupported(false);
49+
mCalibrationTask = new TaskCompletionSource<Boolean>();
50+
mDevice.connect("","");
51+
52+
mCalibrationTask = new TaskCompletionSource<>();
53+
mStreamingTask = new TaskCompletionSource<Boolean>();
54+
try {
55+
boolean result = mCalibrationTask.getTask().waitForCompletion(5, TimeUnit.SECONDS);
56+
} catch (InterruptedException e) {
57+
// TODO Auto-generated catch block
58+
e.printStackTrace();
59+
}
60+
61+
try {
62+
mDevice.startStreaming();
63+
} catch (ShimmerException e) {
64+
// TODO Auto-generated catch block
65+
e.printStackTrace();
66+
}
67+
try {
68+
mStreamingTask.getTask().waitForCompletion(2, TimeUnit.SECONDS);
69+
if(mListOJC.size()!=2) {//only one is expected because only the first packet is followed which meets ShimmerBluetooth.processPacket requirements
70+
assert(false);
71+
}
72+
} catch (InterruptedException e) {
73+
// TODO Auto-generated catch block
74+
e.printStackTrace();
75+
}
76+
77+
78+
79+
}
80+
81+
82+
@Override
83+
protected void processMsgFromCallback(ShimmerMsg shimmerMSG) {
84+
// TODO Auto-generated method stub
85+
int ind = shimmerMSG.mIdentifier;
86+
87+
Object object = (Object) shimmerMSG.mB;
88+
89+
if (ind == ShimmerPC.MSG_IDENTIFIER_STATE_CHANGE) {
90+
if (ind == ShimmerPC.MSG_IDENTIFIER_STATE_CHANGE) {
91+
CallbackObject callbackObject = (CallbackObject)object;
92+
93+
if (callbackObject.mState == BT_STATE.CONNECTED) {
94+
if (mDevice.isInitialised()) {
95+
try {
96+
Thread.sleep(200);
97+
} catch (InterruptedException e) {
98+
// TODO Auto-generated catch block
99+
e.printStackTrace();
100+
}
101+
102+
}
103+
104+
}
105+
}
106+
} else if (ind == ShimmerPC.MSG_IDENTIFIER_DATA_PACKET) {
107+
System.out.println("Shimmer MSG_IDENTIFIER_DATA_PACKET");
108+
ObjectCluster objc = (ObjectCluster) shimmerMSG.mB;
109+
mListOJC.add(objc);
110+
}
111+
112+
}
113+
114+
}

0 commit comments

Comments
 (0)