Added support for different formats of acceleration data
This commit is contained in:
@@ -47,7 +47,10 @@ import org.json.JSONArray;
|
|||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -68,6 +71,7 @@ public class SdDataSourceBLE extends SdDataSource {
|
|||||||
|
|
||||||
private int nRawData = 0;
|
private int nRawData = 0;
|
||||||
private double[] rawData = new double[MAX_RAW_DATA];
|
private double[] rawData = new double[MAX_RAW_DATA];
|
||||||
|
private double[] rawData3d = new double[MAX_RAW_DATA * 3];
|
||||||
private int mAccFmt = 0;
|
private int mAccFmt = 0;
|
||||||
private boolean waitForDescriptorWrite = false;
|
private boolean waitForDescriptorWrite = false;
|
||||||
|
|
||||||
@@ -75,6 +79,7 @@ public class SdDataSourceBLE extends SdDataSource {
|
|||||||
private static final int STATE_CONNECTING = 1;
|
private static final int STATE_CONNECTING = 1;
|
||||||
private static final int STATE_CONNECTED = 2;
|
private static final int STATE_CONNECTED = 2;
|
||||||
|
|
||||||
|
/*
|
||||||
public final static String ACTION_GATT_CONNECTED =
|
public final static String ACTION_GATT_CONNECTED =
|
||||||
"com.example.bluetooth.le.ACTION_GATT_CONNECTED";
|
"com.example.bluetooth.le.ACTION_GATT_CONNECTED";
|
||||||
public final static String ACTION_GATT_DISCONNECTED =
|
public final static String ACTION_GATT_DISCONNECTED =
|
||||||
@@ -85,7 +90,7 @@ public class SdDataSourceBLE extends SdDataSource {
|
|||||||
"com.example.bluetooth.le.ACTION_DATA_AVAILABLE";
|
"com.example.bluetooth.le.ACTION_DATA_AVAILABLE";
|
||||||
public final static String EXTRA_DATA =
|
public final static String EXTRA_DATA =
|
||||||
"com.example.bluetooth.le.EXTRA_DATA";
|
"com.example.bluetooth.le.EXTRA_DATA";
|
||||||
|
*/
|
||||||
|
|
||||||
public static String SERV_DEV_INFO = "0000180a-0000-1000-8000-00805f9b34fb";
|
public static String SERV_DEV_INFO = "0000180a-0000-1000-8000-00805f9b34fb";
|
||||||
public static String SERV_HEART_RATE = "0000180d-0000-1000-8000-00805f9b34fb";
|
public static String SERV_HEART_RATE = "0000180d-0000-1000-8000-00805f9b34fb";
|
||||||
@@ -99,8 +104,12 @@ public class SdDataSourceBLE extends SdDataSource {
|
|||||||
public static String CHAR_OSD_ACC_FMT= "000085e9-0005-1000-8000-00805f9b34fb";
|
public static String CHAR_OSD_ACC_FMT= "000085e9-0005-1000-8000-00805f9b34fb";
|
||||||
// Valid values are 0: 8 bit vector magnitude scaled so 1g=44
|
// Valid values are 0: 8 bit vector magnitude scaled so 1g=44
|
||||||
|
|
||||||
public static String CHAR_MANUF_NAME = "00002a29-0000-1000-8000-00805f9b34fb";
|
public final static int ACC_FMT_8BIT = 0;
|
||||||
public static String CLIENT_CHARACTERISTIC_CONFIG = "00002902-0000-1000-8000-00805f9b34fb";
|
public final static int ACC_FMT_16BIT = 1;
|
||||||
|
public final static int ACC_FMT_3D = 3;
|
||||||
|
|
||||||
|
// public static String CHAR_MANUF_NAME = "00002a29-0000-1000-8000-00805f9b34fb";
|
||||||
|
// public static String CLIENT_CHARACTERISTIC_CONFIG = "00002902-0000-1000-8000-00805f9b34fb";
|
||||||
private BluetoothGatt mGatt;
|
private BluetoothGatt mGatt;
|
||||||
private BluetoothGattCharacteristic mOsdChar;
|
private BluetoothGattCharacteristic mOsdChar;
|
||||||
|
|
||||||
@@ -305,7 +314,7 @@ public class SdDataSourceBLE extends SdDataSource {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* executeReadCharacteristic runs teh bluetoothGatt readCharacteristic command to read the value
|
* executeReadCharacteristic runs the bluetoothGatt readCharacteristic command to read the value
|
||||||
* of a given characteristic.
|
* of a given characteristic.
|
||||||
* Because only one BLE operation can be taking place at a time, it may fail, in which case
|
* Because only one BLE operation can be taking place at a time, it may fail, in which case
|
||||||
* the read is re-tried after a 100ms delay.
|
* the read is re-tried after a 100ms delay.
|
||||||
@@ -344,7 +353,7 @@ public class SdDataSourceBLE extends SdDataSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onDataReceived(BluetoothGattCharacteristic characteristic) {
|
public void onDataReceived(BluetoothGattCharacteristic characteristic) {
|
||||||
/**
|
/*
|
||||||
* onDataReceived - called whenever a BLE characteristic notifies us that its data has changed.
|
* onDataReceived - called whenever a BLE characteristic notifies us that its data has changed.
|
||||||
* If the data is acceleration data, we add it to a buffer - it is analysed once the buffer is full.
|
* If the data is acceleration data, we add it to a buffer - it is analysed once the buffer is full.
|
||||||
* Heart rate data is written directly to sdData to be used in future analysis.
|
* Heart rate data is written directly to sdData to be used in future analysis.
|
||||||
@@ -362,35 +371,64 @@ public class SdDataSourceBLE extends SdDataSource {
|
|||||||
//Log.d(TAG, "onDataReceived(): Heart rate format UINT8.");
|
//Log.d(TAG, "onDataReceived(): Heart rate format UINT8.");
|
||||||
}
|
}
|
||||||
final int heartRate = characteristic.getIntValue(format, 1); // heart rate is second byte
|
final int heartRate = characteristic.getIntValue(format, 1); // heart rate is second byte
|
||||||
//byte[] rawDataBytes = characteristic.getValue();
|
|
||||||
//Log.d(TAG,"onDataReceived - len(rawDataBytes)="+rawDataBytes.length);
|
|
||||||
//for (int i=0;i<rawDataBytes.length;i++) {
|
|
||||||
// Log.d(TAG,"onDataReceived - HR["+i+" = "+rawDataBytes[i]);
|
|
||||||
//}
|
|
||||||
mSdData.mHR = (double) heartRate;
|
mSdData.mHR = (double) heartRate;
|
||||||
Log.d(TAG, String.format("onDataReceived(): CHAR_HEART_RATE_MEASUREMENT: %d", heartRate));
|
Log.d(TAG, String.format("onDataReceived(): CHAR_HEART_RATE_MEASUREMENT: %d", heartRate));
|
||||||
}
|
}
|
||||||
else if (characteristic.getUuid().toString().equals(CHAR_OSD_ACC_DATA)) {
|
else if (characteristic.getUuid().toString().equals(CHAR_OSD_ACC_DATA)) {
|
||||||
//Log.v(TAG,"Received OSD ACC DATA"+characteristic.getValue());
|
//Log.v(TAG,"Received OSD ACC DATA"+characteristic.getValue());
|
||||||
byte[] rawDataBytes = characteristic.getValue();
|
byte[] rawDataBytes = characteristic.getValue();
|
||||||
|
short[] newAccVals = parseDataToAccVals(rawDataBytes);
|
||||||
Log.v(TAG, "onDataReceived(): CHAR_OSD_ACC_DATA: numSamples = " + rawDataBytes.length+" nRawData="+nRawData);
|
Log.v(TAG, "onDataReceived(): CHAR_OSD_ACC_DATA: numSamples = " + rawDataBytes.length+" nRawData="+nRawData);
|
||||||
for (int i = 0; i < rawDataBytes.length;i++) {
|
Log.v(TAG, "onDataReceived() - rawDataBytes="+ Arrays.toString(rawDataBytes));
|
||||||
if (nRawData < MAX_RAW_DATA) {
|
Log.v(TAG, "onDataReceived() - newAccVals="+Arrays.toString(newAccVals));
|
||||||
rawData[nRawData] = 1000 * rawDataBytes[i] / 64; // Scale to mg
|
for (int i = 0; i < newAccVals.length;i++) {
|
||||||
nRawData++;
|
if (nRawData < MAX_RAW_DATA ) {
|
||||||
|
switch (mAccFmt) {
|
||||||
|
case ACC_FMT_8BIT:
|
||||||
|
case ACC_FMT_16BIT:
|
||||||
|
rawData[nRawData] = newAccVals[i];
|
||||||
|
nRawData++;
|
||||||
|
break;
|
||||||
|
case ACC_FMT_3D:
|
||||||
|
// 3d data is x1,y1,z1, x2,y2,z2 ... xn,yn,zn
|
||||||
|
// We only do this every third value, then process x, y and z simultaneously.
|
||||||
|
if (i+2 < newAccVals.length) {
|
||||||
|
if (i % 3 == 0) {
|
||||||
|
short x, y, z;
|
||||||
|
x = newAccVals[i];
|
||||||
|
y = newAccVals[i + 1];
|
||||||
|
z = newAccVals[i + 3];
|
||||||
|
// Calculate vector magnitude
|
||||||
|
rawData[nRawData] = Math.sqrt(x * x + y * y + z * z);
|
||||||
|
// Store 3d values
|
||||||
|
rawData3d[nRawData * 3] = x;
|
||||||
|
rawData3d[nRawData * 3 + 1] = y;
|
||||||
|
rawData3d[nRawData * 3 + 2] = z;
|
||||||
|
nRawData++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Log.e(TAG,"INVALID ACCELERATION FORMAT"+mAccFmt);
|
||||||
|
mUtil.showToast("INVALID ACCELERATION FORMAT "+mAccFmt);
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Log.i(TAG, "onDataReceived(): RawData Buffer Full - processing data");
|
Log.i(TAG, "onDataReceived(): RawData Buffer Full - processing data");
|
||||||
// Re-start collecting raw data.
|
|
||||||
mSdData.watchAppRunning = true;
|
mSdData.watchAppRunning = true;
|
||||||
for (i = 0; i < rawData.length; i++) {
|
for (i = 0; i < rawData.length; i++) {
|
||||||
mSdData.rawData[i] = rawData[i];
|
mSdData.rawData[i] = rawData[i];
|
||||||
|
mSdData.rawData3D[i*3] = rawData3d[i*3];
|
||||||
|
mSdData.rawData3D[i*3 +1] = rawData3d[i*3 +1];
|
||||||
|
mSdData.rawData3D[i*3 +2] = rawData3d[i*3 +2];
|
||||||
//Log.v(TAG,"onDataReceived() i="+i+", "+rawData[i]);
|
//Log.v(TAG,"onDataReceived() i="+i+", "+rawData[i]);
|
||||||
}
|
}
|
||||||
mSdData.mNsamp = rawData.length;
|
mSdData.mNsamp = rawData.length;
|
||||||
//mNSamp = accelVals.length();
|
|
||||||
mWatchAppRunningCheck = true;
|
mWatchAppRunningCheck = true;
|
||||||
mDataStatusTime = new Time(Time.getCurrentTimezone());
|
mDataStatusTime = new Time(Time.getCurrentTimezone());
|
||||||
|
// Process the data to do seizure detection
|
||||||
doAnalysis();
|
doAnalysis();
|
||||||
|
// Re-start collecting raw data.
|
||||||
nRawData = 0;
|
nRawData = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -423,6 +461,32 @@ public class SdDataSourceBLE extends SdDataSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private short[] parseDataToAccVals(byte[] rawDataBytes) {
|
||||||
|
short[] retArr;
|
||||||
|
switch (mAccFmt) {
|
||||||
|
case ACC_FMT_8BIT:
|
||||||
|
retArr = new short[rawDataBytes.length];
|
||||||
|
for (int i = 0; i < rawDataBytes.length;i++) {
|
||||||
|
retArr[i] = (short) (1000 * rawDataBytes[i] / 64); // Scale to mg
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ACC_FMT_16BIT:
|
||||||
|
case ACC_FMT_3D:
|
||||||
|
// from https://stackoverflow.com/questions/5625573/byte-array-to-short-array-and-back-again-in-java
|
||||||
|
retArr = new short[rawDataBytes.length/2];
|
||||||
|
// to turn bytes to shorts as either big endian or little endian.
|
||||||
|
ByteBuffer.wrap(rawDataBytes)
|
||||||
|
.order(ByteOrder.LITTLE_ENDIAN)
|
||||||
|
.asShortBuffer()
|
||||||
|
.get(retArr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Log.e(TAG,"INVALID ACCELERATION FORMAT"+mAccFmt);
|
||||||
|
mUtil.showToast("INVALID ACCELERATION FORMAT "+mAccFmt);
|
||||||
|
retArr = new short[0];
|
||||||
|
}
|
||||||
|
return(retArr);
|
||||||
|
}
|
||||||
@Override
|
@Override
|
||||||
public void onCharacteristicRead(BluetoothGatt gatt,
|
public void onCharacteristicRead(BluetoothGatt gatt,
|
||||||
BluetoothGattCharacteristic characteristic,
|
BluetoothGattCharacteristic characteristic,
|
||||||
|
|||||||
Reference in New Issue
Block a user