Progressing with raw analysis in networkPassiveDataSource - not working yet.
This commit is contained in:
@@ -39,6 +39,7 @@ dependencies {
|
|||||||
// google play services used for location finding for SMS alerts.
|
// google play services used for location finding for SMS alerts.
|
||||||
compile 'com.google.android.gms:play-services-location:10.0.0'
|
compile 'com.google.android.gms:play-services-location:10.0.0'
|
||||||
compile 'com.google.android.gms:play-services:10.0.1'
|
compile 'com.google.android.gms:play-services:10.0.1'
|
||||||
|
compile 'com.github.wendykierp:JTransforms:3.0'
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,9 +25,9 @@ package uk.org.openseizuredetector;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.pm.PackageManager;
|
import android.os.BatteryManager;
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.text.format.Time;
|
import android.text.format.Time;
|
||||||
@@ -37,11 +37,10 @@ import android.widget.Toast;
|
|||||||
import com.getpebble.android.kit.PebbleKit;
|
import com.getpebble.android.kit.PebbleKit;
|
||||||
import com.getpebble.android.kit.util.PebbleDictionary;
|
import com.getpebble.android.kit.util.PebbleDictionary;
|
||||||
|
|
||||||
import java.io.File;
|
import org.json.JSONArray;
|
||||||
import java.io.FileOutputStream;
|
import org.json.JSONObject;
|
||||||
import java.io.IOException;
|
import org.jtransforms.fft.DoubleFFT_1D;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
import java.nio.IntBuffer;
|
import java.nio.IntBuffer;
|
||||||
@@ -56,73 +55,23 @@ import java.util.UUID;
|
|||||||
*/
|
*/
|
||||||
public class SdDataSourceNetworkPassive extends SdDataSource {
|
public class SdDataSourceNetworkPassive extends SdDataSource {
|
||||||
private Handler mHandler = new Handler();
|
private Handler mHandler = new Handler();
|
||||||
private Timer mSettingsTimer;
|
|
||||||
private Timer mStatusTimer;
|
private Timer mStatusTimer;
|
||||||
private Time mPebbleStatusTime;
|
private Time mDataStatusTime;
|
||||||
private boolean mPebbleAppRunningCheck = false;
|
private boolean mWatchAppRunningCheck = false;
|
||||||
private int mAppRestartTimeout = 10; // Timeout before re-starting watch app (sec) if we have not received
|
private int mAppRestartTimeout = 10; // Timeout before re-starting watch app (sec) if we have not received
|
||||||
// data after mDataUpdatePeriod
|
// data after mDataUpdatePeriod
|
||||||
//private Looper mServiceLooper;
|
|
||||||
private int mFaultTimerPeriod = 30; // Fault Timer Period in sec
|
private int mFaultTimerPeriod = 30; // Fault Timer Period in sec
|
||||||
private int mSettingsPeriod = 60; // period between requesting settings in seconds.
|
|
||||||
private PebbleKit.PebbleDataReceiver msgDataHandler = null;
|
|
||||||
|
|
||||||
|
|
||||||
private String TAG = "SdDataSourceNetPassive";
|
private String TAG = "SdDataSourceNetPassive";
|
||||||
|
|
||||||
private UUID SD_UUID = UUID.fromString("03930f26-377a-4a3d-aa3e-f3b19e421c9d");
|
|
||||||
private int NSAMP = 512; // Number of samples in fft input dataset.
|
|
||||||
|
|
||||||
private int KEY_DATA_TYPE = 1;
|
|
||||||
private int KEY_ALARMSTATE = 2;
|
|
||||||
private int KEY_MAXVAL = 3;
|
|
||||||
private int KEY_MAXFREQ = 4;
|
|
||||||
private int KEY_SPECPOWER = 5;
|
|
||||||
private int KEY_SETTINGS = 6;
|
|
||||||
private int KEY_ALARM_FREQ_MIN = 7;
|
|
||||||
private int KEY_ALARM_FREQ_MAX = 8;
|
|
||||||
private int KEY_WARN_TIME = 9;
|
|
||||||
private int KEY_ALARM_TIME = 10;
|
|
||||||
private int KEY_ALARM_THRESH = 11;
|
|
||||||
private int KEY_POS_MIN = 12; // position of first data point in array
|
|
||||||
private int KEY_POS_MAX = 13; // position of last data point in array.
|
|
||||||
private int KEY_SPEC_DATA = 14; // Spectrum data
|
|
||||||
private int KEY_ROIPOWER = 15;
|
|
||||||
private int KEY_NMIN = 16;
|
|
||||||
private int KEY_NMAX = 17;
|
|
||||||
private int KEY_ALARM_RATIO_THRESH = 18;
|
|
||||||
private int KEY_BATTERY_PC = 19;
|
|
||||||
//private int KEY_SET_SETTINGS =20; // Phone is asking us to update watch app settings.
|
|
||||||
private int KEY_FALL_THRESH_MIN = 21;
|
|
||||||
private int KEY_FALL_THRESH_MAX = 22;
|
|
||||||
private int KEY_FALL_WINDOW = 23;
|
|
||||||
private int KEY_FALL_ACTIVE = 24;
|
|
||||||
private int KEY_DATA_UPDATE_PERIOD = 25;
|
|
||||||
private int KEY_MUTE_PERIOD = 26;
|
|
||||||
private int KEY_MAN_ALARM_PERIOD = 27;
|
|
||||||
private int KEY_SD_MODE = 28;
|
|
||||||
private int KEY_SAMPLE_FREQ = 29;
|
|
||||||
private int KEY_RAW_DATA = 30;
|
|
||||||
private int KEY_NUM_RAW_DATA = 31;
|
|
||||||
private int KEY_DEBUG = 32;
|
|
||||||
private int KEY_DISPLAY_SPECTRUM = 33;
|
|
||||||
private int KEY_SAMPLE_PERIOD = 34;
|
|
||||||
private int KEY_VERSION_MAJOR = 35;
|
|
||||||
private int KEY_VERSION_MINOR = 36;
|
|
||||||
private int KEY_FREQ_CUTOFF = 37;
|
|
||||||
|
|
||||||
// Values of the KEY_DATA_TYPE entry in a message
|
|
||||||
private int DATA_TYPE_RESULTS = 1; // Analysis Results
|
|
||||||
private int DATA_TYPE_SETTINGS = 2; // Settings
|
|
||||||
private int DATA_TYPE_SPEC = 3; // FFT Spectrum (or part of a spectrum)
|
|
||||||
private int DATA_TYPE_RAW = 4; // raw accelerometer data.
|
|
||||||
|
|
||||||
// Values for SD_MODE
|
// Values for SD_MODE
|
||||||
private int SD_MODE_FFT = 0; // The original OpenSeizureDetector mode (FFT based)
|
private int SD_MODE_FFT = 0; // The original OpenSeizureDetector mode (FFT based)
|
||||||
private int SD_MODE_RAW = 1; // Send raw, unprocessed data to the phone.
|
private int SD_MODE_RAW = 1; // Send raw, unprocessed data to the phone.
|
||||||
private int SD_MODE_FILTER = 2; // Use digital filter rather than FFT.
|
private int SD_MODE_FILTER = 2; // Use digital filter rather than FFT.
|
||||||
|
private int SIMPLE_SPEC_FMAX = 10;
|
||||||
|
|
||||||
private short mDebug;
|
private short mDebug;
|
||||||
|
private short mFreqCutoff = 12;
|
||||||
private short mDisplaySpectrum;
|
private short mDisplaySpectrum;
|
||||||
private short mDataUpdatePeriod;
|
private short mDataUpdatePeriod;
|
||||||
private short mMutePeriod;
|
private short mMutePeriod;
|
||||||
@@ -143,8 +92,9 @@ public class SdDataSourceNetworkPassive extends SdDataSource {
|
|||||||
|
|
||||||
// raw data storage for SD_MODE_RAW
|
// raw data storage for SD_MODE_RAW
|
||||||
private int MAX_RAW_DATA = 500;
|
private int MAX_RAW_DATA = 500;
|
||||||
private double[] rawData = new double[MAX_RAW_DATA];
|
public double[] mAccData = new double[MAX_RAW_DATA];
|
||||||
private int nRawData = 0;
|
int mNSamp = 0;
|
||||||
|
|
||||||
|
|
||||||
public SdDataSourceNetworkPassive(Context context, Handler handler,
|
public SdDataSourceNetworkPassive(Context context, Handler handler,
|
||||||
SdDataReceiver sdDataReceiver) {
|
SdDataReceiver sdDataReceiver) {
|
||||||
@@ -164,9 +114,8 @@ public class SdDataSourceNetworkPassive extends SdDataSource {
|
|||||||
Log.v(TAG, "start()");
|
Log.v(TAG, "start()");
|
||||||
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.start()");
|
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.start()");
|
||||||
updatePrefs();
|
updatePrefs();
|
||||||
startServer();
|
// Start timer to check status of watch regularly.
|
||||||
// Start timer to check status of pebble regularly.
|
mDataStatusTime = new Time(Time.getCurrentTimezone());
|
||||||
mPebbleStatusTime = new Time(Time.getCurrentTimezone());
|
|
||||||
// use a timer to check the status of the pebble app on the same frequency
|
// use a timer to check the status of the pebble app on the same frequency
|
||||||
// as we get app data.
|
// as we get app data.
|
||||||
if (mStatusTimer == null) {
|
if (mStatusTimer == null) {
|
||||||
@@ -183,24 +132,6 @@ public class SdDataSourceNetworkPassive extends SdDataSource {
|
|||||||
Log.v(TAG, "start(): status timer already running.");
|
Log.v(TAG, "start(): status timer already running.");
|
||||||
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.start() - status timer already running??");
|
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.start() - status timer already running??");
|
||||||
}
|
}
|
||||||
// make sure we get some data when we first start.
|
|
||||||
//getData();
|
|
||||||
// Start timer to retrieve pebble settings regularly.
|
|
||||||
//getWatchSdSettings();
|
|
||||||
if (mSettingsTimer == null) {
|
|
||||||
Log.v(TAG, "start(): starting settings timer");
|
|
||||||
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.start() - starting settings timer");
|
|
||||||
mSettingsTimer = new Timer();
|
|
||||||
mSettingsTimer.schedule(new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
//mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.mSettingsTimer timed out.");getWatchSdSettings();
|
|
||||||
}
|
|
||||||
}, 0, 1000 * mSettingsPeriod); // ask for settings less frequently than we get data
|
|
||||||
} else {
|
|
||||||
Log.v(TAG, "start(): settings timer already running.");
|
|
||||||
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.start() - settings timer already running??");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -218,19 +149,6 @@ public class SdDataSourceNetworkPassive extends SdDataSource {
|
|||||||
mStatusTimer.purge();
|
mStatusTimer.purge();
|
||||||
mStatusTimer = null;
|
mStatusTimer = null;
|
||||||
}
|
}
|
||||||
// Stop the settings timer
|
|
||||||
if (mSettingsTimer != null) {
|
|
||||||
Log.v(TAG, "stop(): cancelling settings timer");
|
|
||||||
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.stop() - cancelling settings timer");
|
|
||||||
mSettingsTimer.cancel();
|
|
||||||
mSettingsTimer.purge();
|
|
||||||
mSettingsTimer = null;
|
|
||||||
}
|
|
||||||
// Stop pebble message handler.
|
|
||||||
Log.v(TAG, "stop(): stopping NetworkPassive server");
|
|
||||||
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.stop() - stopping pebble server");
|
|
||||||
stopServer();
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.v(TAG, "Error in stop() - " + e.toString());
|
Log.v(TAG, "Error in stop() - " + e.toString());
|
||||||
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.stop() - error - "+e.toString());
|
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.stop() - error - "+e.toString());
|
||||||
@@ -353,346 +271,129 @@ public class SdDataSourceNetworkPassive extends SdDataSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
// Force the data stored in this datasource to update in line with the JSON string encoded data provided.
|
||||||
* Set this server to receive pebble data by registering it as
|
// Used by webServer to update the NetworkPassiveDatasource
|
||||||
* A PebbleDataReceiver
|
public void updateFromJSON(String jsonStr) {
|
||||||
*/
|
Log.v(TAG,"updateFromJSON - "+jsonStr);
|
||||||
private void startServer() {
|
|
||||||
Log.v(TAG, "StartPebbleServer()");
|
|
||||||
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.startServer()");
|
|
||||||
final Handler handler = new Handler();
|
|
||||||
msgDataHandler = new PebbleKit.PebbleDataReceiver(SD_UUID) {
|
|
||||||
@Override
|
|
||||||
public void receiveData(final Context context,
|
|
||||||
final int transactionId,
|
|
||||||
final PebbleDictionary data) {
|
|
||||||
Log.v(TAG, "Received message from Pebble - data type="
|
|
||||||
+ data.getUnsignedIntegerAsLong(KEY_DATA_TYPE));
|
|
||||||
// If we have a message, the app must be running
|
|
||||||
Log.v(TAG, "Setting mPebbleAppRunningCheck to true");
|
|
||||||
mPebbleAppRunningCheck = true;
|
|
||||||
PebbleKit.sendAckToPebble(context, transactionId);
|
|
||||||
//Log.v(TAG,"Message is: "+data.toJsonString());
|
|
||||||
if (data.getUnsignedIntegerAsLong(KEY_DATA_TYPE)
|
|
||||||
== DATA_TYPE_RESULTS) {
|
|
||||||
Log.v(TAG, "DATA_TYPE = Results");
|
|
||||||
mSdData.dataTime.setToNow();
|
|
||||||
Log.v(TAG, "mSdData.dataTime=" + mSdData.dataTime);
|
|
||||||
|
|
||||||
mSdData.alarmState = data.getUnsignedIntegerAsLong(
|
|
||||||
KEY_ALARMSTATE);
|
|
||||||
mSdData.maxVal = data.getUnsignedIntegerAsLong(KEY_MAXVAL);
|
|
||||||
mSdData.maxFreq = data.getUnsignedIntegerAsLong(KEY_MAXFREQ);
|
|
||||||
mSdData.specPower = data.getUnsignedIntegerAsLong(KEY_SPECPOWER);
|
|
||||||
mSdData.roiPower = data.getUnsignedIntegerAsLong(KEY_ROIPOWER);
|
|
||||||
mSdData.alarmPhrase = "Unknown";
|
|
||||||
mSdData.haveData = true;
|
|
||||||
mSdDataReceiver.onSdDataReceived(mSdData);
|
|
||||||
|
|
||||||
|
|
||||||
// Read the data that has been sent, and convert it into
|
|
||||||
// an integer array.
|
|
||||||
byte[] byteArr = data.getBytes(KEY_SPEC_DATA);
|
|
||||||
if ((byteArr != null) && (byteArr.length != 0)) {
|
|
||||||
IntBuffer intBuf = ByteBuffer.wrap(byteArr)
|
|
||||||
.order(ByteOrder.LITTLE_ENDIAN)
|
|
||||||
.asIntBuffer();
|
|
||||||
int[] intArray = new int[intBuf.remaining()];
|
|
||||||
intBuf.get(intArray);
|
|
||||||
for (int i = 0; i < intArray.length; i++) {
|
|
||||||
mSdData.simpleSpec[i] = intArray[i];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.v(TAG, "***** zero length spectrum received - error!!!!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.getUnsignedIntegerAsLong(KEY_DATA_TYPE)
|
|
||||||
== DATA_TYPE_SETTINGS) {
|
|
||||||
Log.v(TAG, "DATA_TYPE = Settings");
|
|
||||||
try {
|
try {
|
||||||
mSdData.analysisPeriod = data.getUnsignedIntegerAsLong(KEY_SAMPLE_PERIOD);
|
JSONObject mainObject = new JSONObject(jsonStr);
|
||||||
mSdData.alarmFreqMin = data.getUnsignedIntegerAsLong(KEY_ALARM_FREQ_MIN);
|
JSONObject dataObject = mainObject.getJSONObject("dataObj");
|
||||||
mSdData.alarmFreqMax = data.getUnsignedIntegerAsLong(KEY_ALARM_FREQ_MAX);
|
String dataTypeStr = dataObject.getString("dataType");
|
||||||
mSdData.nMin = data.getUnsignedIntegerAsLong(KEY_NMIN);
|
Log.v(TAG,"updateFromJSON - dataType="+dataTypeStr);
|
||||||
mSdData.nMax = data.getUnsignedIntegerAsLong(KEY_NMAX);
|
JSONArray accelVals = dataObject.getJSONArray("data");
|
||||||
mSdData.warnTime = data.getUnsignedIntegerAsLong(KEY_WARN_TIME);
|
|
||||||
mSdData.alarmTime = data.getUnsignedIntegerAsLong(KEY_ALARM_TIME);
|
|
||||||
mSdData.alarmThresh = data.getUnsignedIntegerAsLong(KEY_ALARM_THRESH);
|
|
||||||
mSdData.alarmRatioThresh = data.getUnsignedIntegerAsLong(KEY_ALARM_RATIO_THRESH);
|
|
||||||
mSdData.batteryPc = data.getUnsignedIntegerAsLong(KEY_BATTERY_PC);
|
|
||||||
mSdData.haveSettings = true;
|
|
||||||
} catch (Exception ex) {
|
|
||||||
mUtil.showToast("*** Error interpreting settings sent from watch - Please check you have "
|
|
||||||
+ "the latest version of the watch app installed by using the OpenSeizureDetector "
|
|
||||||
+ "menu to install the Watch App");
|
|
||||||
mUtil.writeToSysLogFile("Error interpreting settings received from watch - wrong version "
|
|
||||||
+ "of watch app installed?");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (data.getUnsignedIntegerAsLong(KEY_DATA_TYPE)
|
|
||||||
== DATA_TYPE_RAW) {
|
|
||||||
Log.v(TAG, "DATA_TYPE = Raw");
|
|
||||||
long numSamples;
|
|
||||||
numSamples = data.getUnsignedIntegerAsLong(KEY_NUM_RAW_DATA);
|
|
||||||
Log.v(TAG, "numSamples = " + numSamples);
|
|
||||||
byte[] rawDataBytes = data.getBytes(KEY_RAW_DATA);
|
|
||||||
for (int i = 0; i < rawDataBytes.length - 4; i += 4) { // 4 bytes per sample
|
|
||||||
int x = (rawDataBytes[i]);
|
|
||||||
//int y = (rawDataBytes[i+2] & 0xff) | (rawDataBytes[i+3] << 8);
|
|
||||||
//int z = (rawDataBytes[i+4] & 0xff) | (rawDataBytes[i+5] << 8);
|
|
||||||
//Log.v(TAG,"x="+x+", y="+y+", z="+z);
|
|
||||||
Log.v(TAG,"x="+x);
|
|
||||||
if (nRawData < MAX_RAW_DATA) {
|
|
||||||
rawData[nRawData] = (int)Math.sqrt(x);
|
|
||||||
} else {
|
|
||||||
Log.i(TAG, "WARNING - rawData Buffer Full");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
Log.v(TAG,"Received " + accelVals.length() + " acceleration values");
|
||||||
|
|
||||||
|
|
||||||
//for (AccelData reading : AccelData.fromDataArray(rawDataBytes)) {
|
|
||||||
// if (nRawData < MAX_RAW_DATA) {
|
|
||||||
// rawData[nRawData] = reading.getMagnitude();
|
|
||||||
// nRawData++;
|
|
||||||
// } else {
|
|
||||||
// Log.i(TAG, "WARNING - rawData Buffer Full");
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i=0;i<accelVals.length();i++)
|
||||||
|
{
|
||||||
|
mAccData[i] = accelVals.getInt(i);
|
||||||
}
|
}
|
||||||
}
|
mNSamp = accelVals.length();
|
||||||
};
|
doAnalysis();
|
||||||
PebbleKit.registerReceivedDataHandler(mContext, msgDataHandler);
|
|
||||||
// We struggle to connect to pebble time if app is already running,
|
|
||||||
// so stop app so we can re-connect to it.
|
|
||||||
//stopWatchApp();
|
|
||||||
startWatchApp();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* De-register this server from receiving pebble data
|
|
||||||
*/
|
|
||||||
public void stopServer() {
|
|
||||||
Log.v(TAG, "stopServer(): Stopping Pebble Server");
|
|
||||||
Log.v(TAG, "stopServer(): msgDataHandler = " + msgDataHandler.toString());
|
|
||||||
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.stopServer()");
|
|
||||||
try {
|
|
||||||
mContext.unregisterReceiver(msgDataHandler);
|
|
||||||
stopWatchApp();
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.v(TAG, "stopServer() - error " + e.toString());
|
Log.v(TAG,"Error Parsing JSON String - "+e.toString());
|
||||||
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.stopServer() - error " + e.toString());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempt to start the pebble_sd watch app on the pebble watch.
|
* doAnalysis() - analyse the data if the accelerometer data array mAccData
|
||||||
|
* and populate the output data structure mSdData
|
||||||
*/
|
*/
|
||||||
public void startWatchApp() {
|
private void doAnalysis() {
|
||||||
Log.v(TAG, "startWatchApp() - closing app first");
|
double freqRes = 1.0*mSampleFreq/mNSamp;
|
||||||
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.startWatchApp() - closing app first");
|
Log.v(TAG,"doAnalysis(): mSampleFreq="+mSampleFreq+" mNSamp="+mNSamp+": freqRes="+freqRes);
|
||||||
// first close the watch app if it is running.
|
// Set the frequency bounds for the analysis in fft output bin numbers.
|
||||||
PebbleKit.closeAppOnPebble(mContext, SD_UUID);
|
int nMin = (int)(mAlarmFreqMin/freqRes);
|
||||||
Log.v(TAG, "startWatchApp() - starting watch app after 5 seconds delay...");
|
int nMax = (int)(mAlarmFreqMax /freqRes);
|
||||||
// Wait 5 seconds then start the app.
|
Log.v(TAG,"doAnalysis(): mAlarmFreqMin="+mAlarmFreqMin+", nMin="+nMin
|
||||||
Timer appStartTimer = new Timer();
|
+", mAlarmFreqMax="+mAlarmFreqMax+", nMax="+nMax);
|
||||||
appStartTimer.schedule(new TimerTask() {
|
// Calculate the bin number of the cutoff frequency
|
||||||
@Override
|
int nFreqCutoff = (int)(mFreqCutoff /freqRes);
|
||||||
public void run() {
|
Log.v(TAG,"mFreqCutoff = "+mFreqCutoff+", nFreqCutoff="+nFreqCutoff);
|
||||||
Log.v(TAG, "startWatchApp() - starting watch app...");
|
|
||||||
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.startWatchApp() - starting watch app");
|
DoubleFFT_1D fftDo = new DoubleFFT_1D(mNSamp);
|
||||||
PebbleKit.startAppOnPebble(mContext, SD_UUID);
|
double[] fft = new double[mNSamp * 2];
|
||||||
|
System.arraycopy(mAccData, 0, fft, 0, mNSamp);
|
||||||
|
fftDo.realForwardFull(fft);
|
||||||
|
|
||||||
|
// Calculate the whole spectrum power (well a value equivalent to it that avoids suare root calculations
|
||||||
|
// and zero any readings that are above the frequency cutoff.
|
||||||
|
double specPower = 0;
|
||||||
|
for (int i = 1; i < mNSamp / 2; i++) {
|
||||||
|
if (i <= nFreqCutoff) {
|
||||||
|
specPower = specPower + fft[2 * i] + fft[2*i] + fft[2*i +1] * fft[2*i+1];
|
||||||
|
|
||||||
|
} else {
|
||||||
|
fft[2*i] = 0.;
|
||||||
|
fft[2*i+1] = 0.;
|
||||||
}
|
}
|
||||||
}, 5000);
|
}
|
||||||
|
specPower = specPower/mNSamp/2;
|
||||||
|
|
||||||
|
// Calculate the Region of Interest power and power ratio.
|
||||||
|
double roiPower = 0;
|
||||||
|
for (int i=nMin;i<nMax;i++) {
|
||||||
|
roiPower = roiPower + fft[2 * i] + fft[2*i] + fft[2*i +1] * fft[2*i+1];
|
||||||
|
}
|
||||||
|
roiPower = roiPower/(nMax - nMin);
|
||||||
|
double roiRatio = 10 * roiPower / specPower;
|
||||||
|
|
||||||
|
// Calculate the simplified spectrum - power in 1Hz bins.
|
||||||
|
double[] simpleSpec = new double[SIMPLE_SPEC_FMAX+1];
|
||||||
|
for (int ifreq=0;ifreq<SIMPLE_SPEC_FMAX;ifreq++) {
|
||||||
|
int binMin = (int)(1 + ifreq/freqRes); // add 1 to loose dc component
|
||||||
|
int binMax = (int)(1 + (ifreq+1)/freqRes);
|
||||||
|
simpleSpec[ifreq]=0;
|
||||||
|
for (int i=binMin;i<binMax;i++) {
|
||||||
|
simpleSpec[ifreq] = simpleSpec[ifreq] + fft[2 * i] + fft[2*i] + fft[2*i +1] * fft[2*i+1];
|
||||||
|
}
|
||||||
|
simpleSpec[ifreq] = simpleSpec[ifreq] / (binMax-binMin);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Populate the mSdData structure to communicate with the main SdServer service.
|
||||||
* stop the pebble_sd watch app on the pebble watch.
|
mDataStatusTime.setToNow();
|
||||||
*/
|
mSdData.specPower = (long)specPower;
|
||||||
public void stopWatchApp() {
|
mSdData.roiPower = (long)roiPower;
|
||||||
Log.v(TAG, "stopWatchApp()");
|
mSdData.dataTime.setToNow();
|
||||||
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.stopWatchApp()");
|
mSdData.maxVal = 0; // not used
|
||||||
PebbleKit.closeAppOnPebble(mContext, SD_UUID);
|
mSdData.maxFreq = 0; // not used
|
||||||
|
mSdData.haveData = true;
|
||||||
|
mSdData.alarmThresh = mAlarmThresh;
|
||||||
|
mSdData.alarmRatioThresh = mAlarmRatioThresh;
|
||||||
|
mSdData.batteryPc = 50; // FIXME we should get the watch to send us battery status.
|
||||||
|
for(int i=0;i<SIMPLE_SPEC_FMAX;i++) {
|
||||||
|
mSdData.simpleSpec[i] = (int)simpleSpec[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send our latest settings to the watch, then request Pebble App to send
|
* Checks the status of the connection to the watch,
|
||||||
* us its latest settings so we can check it has been set up correctly..
|
|
||||||
* Will be received as a message by the receiveData handler
|
|
||||||
*/
|
|
||||||
public void getPebbleSdSettings() {
|
|
||||||
Log.v(TAG, "getWatchSdSettings() - sending required settings to pebble");
|
|
||||||
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.getWatchSdSettings()");
|
|
||||||
sendPebbleSdSettings();
|
|
||||||
//Log.v(TAG, "getWatchSdSettings() - requesting settings from pebble");
|
|
||||||
//mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.getWatchSdSettings() - and request settings from pebble");
|
|
||||||
PebbleDictionary data = new PebbleDictionary();
|
|
||||||
data.addUint8(KEY_SETTINGS, (byte) 1);
|
|
||||||
PebbleKit.sendDataToPebble(
|
|
||||||
mContext,
|
|
||||||
SD_UUID,
|
|
||||||
data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send the pebble watch settings that are stored as class member
|
|
||||||
* variables to the watch.
|
|
||||||
*/
|
|
||||||
public void sendPebbleSdSettings() {
|
|
||||||
Log.v(TAG, "sendPebblSdSettings() - preparing settings dictionary.. mSampleFreq=" + mSampleFreq);
|
|
||||||
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.sendWatchSdSettings()");
|
|
||||||
|
|
||||||
// Watch Settings
|
|
||||||
final PebbleDictionary setDict = new PebbleDictionary();
|
|
||||||
setDict.addInt16(KEY_DEBUG, mDebug);
|
|
||||||
setDict.addInt16(KEY_DISPLAY_SPECTRUM, mDisplaySpectrum);
|
|
||||||
setDict.addInt16(KEY_DATA_UPDATE_PERIOD, mDataUpdatePeriod);
|
|
||||||
setDict.addInt16(KEY_MUTE_PERIOD, mMutePeriod);
|
|
||||||
setDict.addInt16(KEY_MAN_ALARM_PERIOD, mManAlarmPeriod);
|
|
||||||
setDict.addInt16(KEY_SD_MODE, mPebbleSdMode);
|
|
||||||
setDict.addInt16(KEY_SAMPLE_FREQ, mSampleFreq);
|
|
||||||
setDict.addInt16(KEY_SAMPLE_PERIOD, mSamplePeriod);
|
|
||||||
setDict.addInt16(KEY_ALARM_FREQ_MIN, mAlarmFreqMin);
|
|
||||||
setDict.addInt16(KEY_ALARM_FREQ_MAX, mAlarmFreqMax);
|
|
||||||
setDict.addUint16(KEY_WARN_TIME, mWarnTime);
|
|
||||||
setDict.addUint16(KEY_ALARM_TIME, mAlarmTime);
|
|
||||||
setDict.addUint16(KEY_ALARM_THRESH, mAlarmThresh);
|
|
||||||
setDict.addUint16(KEY_ALARM_RATIO_THRESH, mAlarmRatioThresh);
|
|
||||||
if (mFallActive)
|
|
||||||
setDict.addUint16(KEY_FALL_ACTIVE, (short) 1);
|
|
||||||
else
|
|
||||||
setDict.addUint16(KEY_FALL_ACTIVE, (short) 0);
|
|
||||||
setDict.addUint16(KEY_FALL_THRESH_MIN, mFallThreshMin);
|
|
||||||
setDict.addUint16(KEY_FALL_THRESH_MAX, mFallThreshMax);
|
|
||||||
setDict.addUint16(KEY_FALL_WINDOW, mFallWindow);
|
|
||||||
|
|
||||||
// Send Watch Settings to Pebble
|
|
||||||
Log.v(TAG, "sendWatchSdSettings() - setDict = " + setDict.toJsonString());
|
|
||||||
PebbleKit.sendDataToPebble(mContext, SD_UUID, setDict);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compares the watch settings retrieved from the watch (stored in mSdData)
|
|
||||||
* to the required settings stored as member variables to this class.
|
|
||||||
*
|
|
||||||
* @return true if they are all the same, or false if there are discrepancies.
|
|
||||||
*/
|
|
||||||
public boolean checkWatchSettings() {
|
|
||||||
boolean settingsOk = true;
|
|
||||||
if (mDataUpdatePeriod != mSdData.mDataUpdatePeriod) {
|
|
||||||
Log.v(TAG, "checkWatchSettings - mDataUpdatePeriod Wrong");
|
|
||||||
settingsOk = false;
|
|
||||||
}
|
|
||||||
if (mMutePeriod != mSdData.mMutePeriod) {
|
|
||||||
Log.v(TAG, "checkWatchSettings - mMutePeriod Wrong");
|
|
||||||
settingsOk = false;
|
|
||||||
}
|
|
||||||
if (mManAlarmPeriod != mSdData.mManAlarmPeriod) {
|
|
||||||
Log.v(TAG, "checkWatchSettings - mManAlarmPeriod Wrong");
|
|
||||||
settingsOk = false;
|
|
||||||
}
|
|
||||||
if (mSamplePeriod != mSdData.analysisPeriod) {
|
|
||||||
Log.v(TAG, "checkWatchSettings - mSamplePeriod Wrong");
|
|
||||||
settingsOk = false;
|
|
||||||
}
|
|
||||||
if (mAlarmFreqMin != mSdData.alarmFreqMin) {
|
|
||||||
Log.v(TAG, "checkWatchSettings - mAlarmFreqMin Wrong");
|
|
||||||
settingsOk = false;
|
|
||||||
}
|
|
||||||
if (mAlarmFreqMax != mSdData.alarmFreqMax) {
|
|
||||||
Log.v(TAG, "checkWatchSettings - mAlarmFreqMax Wrong");
|
|
||||||
settingsOk = false;
|
|
||||||
}
|
|
||||||
if (mWarnTime != mSdData.warnTime) {
|
|
||||||
Log.v(TAG, "checkWatchSettings - mWarnTime Wrong");
|
|
||||||
settingsOk = false;
|
|
||||||
}
|
|
||||||
if (mAlarmTime != mSdData.alarmTime) {
|
|
||||||
Log.v(TAG, "checkWatchSettings - mAlarmTime Wrong");
|
|
||||||
settingsOk = false;
|
|
||||||
}
|
|
||||||
if (mAlarmThresh != mSdData.alarmThresh) {
|
|
||||||
Log.v(TAG, "checkWatchSettings - mAlarmThresh Wrong");
|
|
||||||
settingsOk = false;
|
|
||||||
}
|
|
||||||
if (mAlarmRatioThresh != mSdData.alarmRatioThresh) {
|
|
||||||
Log.v(TAG, "checkWatchSettings - mAlarmRatioThresh Wrong");
|
|
||||||
settingsOk = false;
|
|
||||||
}
|
|
||||||
if (mFallActive != mSdData.mFallActive) {
|
|
||||||
Log.v(TAG, "checkWatchSettings - mFallActive Wrong");
|
|
||||||
settingsOk = false;
|
|
||||||
}
|
|
||||||
if (mFallThreshMin != mSdData.mFallThreshMin) {
|
|
||||||
Log.v(TAG, "checkWatchSettings - mFallThreshMin Wrong");
|
|
||||||
settingsOk = false;
|
|
||||||
}
|
|
||||||
if (mFallThreshMax != mSdData.mFallThreshMax) {
|
|
||||||
Log.v(TAG, "checkWatchSettings - mFallThreshMax Wrong");
|
|
||||||
settingsOk = false;
|
|
||||||
}
|
|
||||||
if (mFallWindow != mSdData.mFallWindow) {
|
|
||||||
Log.v(TAG, "checkWatchSettings - mFallWindow Wrong");
|
|
||||||
settingsOk = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return settingsOk;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Request Pebble App to send us its latest data.
|
|
||||||
* Will be received as a message by the receiveData handler
|
|
||||||
*/
|
|
||||||
public void getData() {
|
|
||||||
Log.v(TAG, "getData() - requesting data from pebble");
|
|
||||||
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.getData() - requesting data from pebble");
|
|
||||||
//PebbleDictionary data = new PebbleDictionary();
|
|
||||||
//data.addUint8(KEY_DATA_TYPE, (byte) 1);
|
|
||||||
//PebbleKit.sendDataToPebble(
|
|
||||||
// mContext,
|
|
||||||
// SD_UUID,
|
|
||||||
// data);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks the status of the connection to the pebble watch,
|
|
||||||
* and sets class variables for use by other functions.
|
* and sets class variables for use by other functions.
|
||||||
* If the watch app is not running, it attempts to re-start it.
|
|
||||||
*/
|
*/
|
||||||
public void getStatus() {
|
public void getStatus() {
|
||||||
Time tnow = new Time(Time.getCurrentTimezone());
|
Time tnow = new Time(Time.getCurrentTimezone());
|
||||||
long tdiff;
|
long tdiff;
|
||||||
tnow.setToNow();
|
tnow.setToNow();
|
||||||
// get time since the last data was received from the Pebble watch.
|
// get time since the last data was received from the Pebble watch.
|
||||||
tdiff = (tnow.toMillis(false) - mPebbleStatusTime.toMillis(false));
|
tdiff = (tnow.toMillis(false) - mDataStatusTime.toMillis(false));
|
||||||
Log.v(TAG, "getStatus() - mPebbleAppRunningCheck=" + mPebbleAppRunningCheck + " tdiff=" + tdiff);
|
Log.v(TAG, "getStatus() - mWatchAppRunningCheck=" + mWatchAppRunningCheck + " tdiff=" + tdiff);
|
||||||
// Check we are actually connected to the pebble.
|
mSdData.pebbleConnected = true; // We can't check connection for passive network connection, so set it to true to avoid errors.
|
||||||
mSdData.pebbleConnected = PebbleKit.isWatchConnected(mContext);
|
// And is the watch app running?
|
||||||
if (!mSdData.pebbleConnected) mPebbleAppRunningCheck = false;
|
// set mWatchAppRunningCheck has been false for more than 10 seconds
|
||||||
// And is the pebble_sd app running?
|
|
||||||
// set mPebbleAppRunningCheck has been false for more than 10 seconds
|
|
||||||
// the app is not talking to us
|
// the app is not talking to us
|
||||||
// mPebbleAppRunningCheck is set to true in the receiveData handler.
|
// mWatchAppRunningCheck is set to true in the receiveData handler.
|
||||||
if (!mPebbleAppRunningCheck &&
|
if (!mWatchAppRunningCheck &&
|
||||||
(tdiff > (mDataUpdatePeriod + mAppRestartTimeout) * 1000)) {
|
(tdiff > (mDataUpdatePeriod + mAppRestartTimeout) * 1000)) {
|
||||||
Log.v(TAG, "getStatus() - tdiff = " + tdiff);
|
Log.v(TAG, "getStatus() - tdiff = " + tdiff);
|
||||||
mSdData.pebbleAppRunning = false;
|
mSdData.pebbleAppRunning = false;
|
||||||
//Log.v(TAG, "getStatus() - Pebble App Not Running - Attempting to Re-Start");
|
|
||||||
//mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.getStatus() - Pebble App not Running - Attempting to Re-Start");
|
|
||||||
//startWatchApp();
|
|
||||||
//mPebbleStatusTime = tnow; // set status time to now so we do not re-start app repeatedly.
|
|
||||||
//getWatchSdSettings();
|
|
||||||
// Only make audible warning beep if we have not received data for more than mFaultTimerPeriod seconds.
|
// Only make audible warning beep if we have not received data for more than mFaultTimerPeriod seconds.
|
||||||
if (tdiff > (mDataUpdatePeriod + mFaultTimerPeriod) * 1000) {
|
if (tdiff > (mDataUpdatePeriod + mFaultTimerPeriod) * 1000) {
|
||||||
Log.v(TAG, "getStatus() - Pebble App Not Running - Attempting to Re-Start");
|
Log.v(TAG, "getStatus() - Watch App Not Running");
|
||||||
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.getStatus() - Pebble App not Running - Attempting to Re-Start");
|
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.getStatus() - Watch App not Running");
|
||||||
startWatchApp();
|
//mDataStatusTime.setToNow();
|
||||||
mPebbleStatusTime.setToNow();
|
|
||||||
mSdDataReceiver.onSdDataFault(mSdData);
|
mSdDataReceiver.onSdDataFault(mSdData);
|
||||||
} else {
|
} else {
|
||||||
Log.v(TAG, "getStatus() - Waiting for mFaultTimerPeriod before issuing audible warning...");
|
Log.v(TAG, "getStatus() - Waiting for mFaultTimerPeriod before issuing audible warning...");
|
||||||
@@ -703,66 +404,16 @@ public class SdDataSourceNetworkPassive extends SdDataSource {
|
|||||||
|
|
||||||
// if we have confirmation that the app is running, reset the
|
// if we have confirmation that the app is running, reset the
|
||||||
// status time to now and initiate another check.
|
// status time to now and initiate another check.
|
||||||
if (mPebbleAppRunningCheck) {
|
if (mWatchAppRunningCheck) {
|
||||||
mPebbleAppRunningCheck = false;
|
mWatchAppRunningCheck = false;
|
||||||
mPebbleStatusTime.setToNow();
|
mDataStatusTime.setToNow();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mSdData.haveSettings) {
|
if (!mSdData.haveSettings) {
|
||||||
Log.v(TAG, "getStatus() - no settings received yet - requesting");
|
Log.v(TAG, "getStatus() - no settings received yet");
|
||||||
getPebbleSdSettings();
|
|
||||||
getData();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mPebbleSdMode == SD_MODE_RAW) {
|
|
||||||
analyseRawData();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* analyseRawData() - called when raw data is received.
|
|
||||||
* FIXME - this does not do anything at the moment so raw data is
|
|
||||||
* ignored!
|
|
||||||
*/
|
|
||||||
private void analyseRawData() {
|
|
||||||
Log.v(TAG,"analyserawData()");
|
|
||||||
//DoubleFFT_1D fft = new DoubleFFT_1D(MAX_RAW_DATA);
|
|
||||||
//fft.realForward(rawData);
|
|
||||||
// FIXME - rawData should really be a circular buffer.
|
|
||||||
nRawData = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Install the wach app that is bundled in the 'assets' folder of this
|
|
||||||
* phone app.
|
|
||||||
* from https://github.com/pebble-examples/pebblekit-android-example/blob/master/android/Eclipse/src/com/getpebble/pebblekitexample/MainActivity.java#L148
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void installWatchApp() {
|
|
||||||
Log.v(TAG, "SdDataSourceNetworkPassive.installWatchApp()");
|
|
||||||
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.installWatchApp()");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Install the OpenSeizureDetector watch app onto the watch from Pebble AppStore
|
|
||||||
* based on https://forums.getpebble.com/discussion/13128/install-watch-app-pebble-store-from-android-companion-app
|
|
||||||
*/
|
|
||||||
public void installWatchAppFromPebbleAppStore() {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Open Pebble or Pebble Time app. If it is not installed, open Play store so the user can install it.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void startPebbleApp() {
|
|
||||||
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.startPebbleApp()");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user