Started on Network(Passive) datasource for use with esp8266 based seizure detector.

This commit is contained in:
Graham Jones
2017-09-01 22:10:37 +01:00
parent 87774a10ef
commit fc1683ad36
10 changed files with 968 additions and 36 deletions

View File

@@ -1,11 +1,14 @@
OpenSeizureDetector Android App - Change Log OpenSeizureDetector Android App - Change Log
============================================ ============================================
V2.5.2 - 09 May 2016 V2.6.0 - 01 Sep 2017
Added Support for Wifi data source (initially to be used for ESP8266_SD)
V2.5.2 - 09 May 2017
Added support for Pebble App V2.5 which includes a multi-ROI mode to improve sensitivity. Added support for Pebble App V2.5 which includes a multi-ROI mode to improve sensitivity.
V2.5.1 - 07 May 2016 V2.5.1 - 07 May 2017
- Improved alarm annunciation for short duration seizures - setting - Improved alarm annunciation for short duration seizures - setting
Latch Alarms will result in alarms sounding for at least Latch Alarm Latch Alarms will result in alarms sounding for at least Latch Alarm
Timer Duration seconds before resetting. Timer Duration seconds before resetting.

View File

@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="uk.org.openseizuredetector" package="uk.org.openseizuredetector"
android:versionCode="36" android:versionCode="37"
android:versionName="2.5.2"> android:versionName="2.6.0">
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

View File

@@ -0,0 +1,772 @@
/*
Android_Pebble_sd - Android alarm client for openseizuredetector..
See http://openseizuredetector.org for more information.
Copyright Graham Jones, 2015, 2016
This file is part of pebble_sd.
Android_Pebble_sd is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Android_Pebble_sd is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Android_pebble_sd. If not, see <http://www.gnu.org/licenses/>.
*/
package uk.org.openseizuredetector;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.text.format.Time;
import android.util.Log;
import android.widget.Toast;
import com.getpebble.android.kit.PebbleKit;
import com.getpebble.android.kit.util.PebbleDictionary;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;
/**
* Abstract class for a seizure detector data source. Subclasses include a pebble smart watch data source and a
* network data source.
*/
public class SdDataSourceNetworkPassive extends SdDataSource {
private Handler mHandler = new Handler();
private Timer mSettingsTimer;
private Timer mStatusTimer;
private Time mPebbleStatusTime;
private boolean mPebbleAppRunningCheck = false;
private int mAppRestartTimeout = 10; // Timeout before re-starting watch app (sec) if we have not received
// data after mDataUpdatePeriod
//private Looper mServiceLooper;
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 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
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_FILTER = 2; // Use digital filter rather than FFT.
private short mDebug;
private short mDisplaySpectrum;
private short mDataUpdatePeriod;
private short mMutePeriod;
private short mManAlarmPeriod;
private short mPebbleSdMode;
private short mSampleFreq;
private short mAlarmFreqMin;
private short mAlarmFreqMax;
private short mSamplePeriod;
private short mWarnTime;
private short mAlarmTime;
private short mAlarmThresh;
private short mAlarmRatioThresh;
private boolean mFallActive;
private short mFallThreshMin;
private short mFallThreshMax;
private short mFallWindow;
// raw data storage for SD_MODE_RAW
private int MAX_RAW_DATA = 500;
private double[] rawData = new double[MAX_RAW_DATA];
private int nRawData = 0;
public SdDataSourceNetworkPassive(Context context, Handler handler,
SdDataReceiver sdDataReceiver) {
super(context, handler, sdDataReceiver);
mName = "NetworkPassive";
// Set default settings from XML files (mContext is set by super().
PreferenceManager.setDefaultValues(mContext,
R.xml.network_passive_datasource_prefs, true);
}
/**
* Start the datasource updating - initialises from sharedpreferences first to
* make sure any changes to preferences are taken into account.
*/
public void start() {
Log.v(TAG, "start()");
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.start()");
updatePrefs();
startServer();
// Start timer to check status of pebble regularly.
mPebbleStatusTime = new Time(Time.getCurrentTimezone());
// use a timer to check the status of the pebble app on the same frequency
// as we get app data.
if (mStatusTimer == null) {
Log.v(TAG, "start(): starting status timer");
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.start() - starting status timer");
mStatusTimer = new Timer();
mStatusTimer.schedule(new TimerTask() {
@Override
public void run() {
getStatus();
}
}, 0, mDataUpdatePeriod * 1000);
} else {
Log.v(TAG, "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.
//getPebbleSdSettings();
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.");getPebbleSdSettings();
}
}, 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??");
}
}
/**
* Stop the datasource from updating
*/
public void stop() {
Log.v(TAG, "stop()");
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.stop()");
try {
// Stop the status timer
if (mStatusTimer != null) {
Log.v(TAG, "stop(): cancelling status timer");
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.stop() - cancelling status timer");
mStatusTimer.cancel();
mStatusTimer.purge();
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) {
Log.v(TAG, "Error in stop() - " + e.toString());
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.stop() - error - "+e.toString());
}
}
/**
* updatePrefs() - update basic settings from the SharedPreferences
* - defined in res/xml/SdDataSourceNetworkPassivePrefs.xml
*/
public void updatePrefs() {
Log.v(TAG, "updatePrefs()");
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.updatePrefs()");
SharedPreferences SP = PreferenceManager
.getDefaultSharedPreferences(mContext);
try {
// Parse the AppRestartTimeout period setting.
try {
String appRestartTimeoutStr = SP.getString("AppRestartTimeout", "10");
mAppRestartTimeout = Integer.parseInt(appRestartTimeoutStr);
Log.v(TAG, "updatePrefs() - mAppRestartTimeout = " + mAppRestartTimeout);
} catch (Exception ex) {
Log.v(TAG, "updatePrefs() - Problem with AppRestartTimeout preference!");
Toast toast = Toast.makeText(mContext, "Problem Parsing AppRestartTimeout Preference", Toast.LENGTH_SHORT);
toast.show();
}
// Parse the FaultTimer period setting.
try {
String faultTimerPeriodStr = SP.getString("FaultTimerPeriod", "30");
mFaultTimerPeriod = Integer.parseInt(faultTimerPeriodStr);
Log.v(TAG, "updatePrefs() - mFaultTimerPeriod = " + mFaultTimerPeriod);
} catch (Exception ex) {
Log.v(TAG, "updatePrefs() - Problem with FaultTimerPeriod preference!");
Toast toast = Toast.makeText(mContext, "Problem Parsing FaultTimerPeriod Preference", Toast.LENGTH_SHORT);
toast.show();
}
// Watch Settings
String prefStr;
prefStr = SP.getString("PebbleDebug", "SET_FROM_XML");
mDebug = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() Debug = " + mDebug);
prefStr = SP.getString("PebbleDisplaySpectrum", "SET_FROM_XML");
mDisplaySpectrum = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() DisplaySpectrum = " + mDisplaySpectrum);
prefStr = SP.getString("PebbleUpdatePeriod", "SET_FROM_XML");
mDataUpdatePeriod = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() DataUpdatePeriod = " + mDataUpdatePeriod);
prefStr = SP.getString("MutePeriod", "SET_FROM_XML");
mMutePeriod = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() MutePeriod = " + mMutePeriod);
prefStr = SP.getString("ManAlarmPeriod", "SET_FROM_XML");
mManAlarmPeriod = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() ManAlarmPeriod = " + mManAlarmPeriod);
prefStr = SP.getString("PebbleSdMode", "SET_FROM_XML");
mPebbleSdMode = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() PebbleSdMode = " + mPebbleSdMode);
prefStr = SP.getString("SampleFreq", "SET_FROM_XML");
mSampleFreq = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() SampleFreq = " + mSampleFreq);
prefStr = SP.getString("SamplePeriod", "SET_FROM_XML");
mSamplePeriod = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() AnalysisPeriod = " + mSamplePeriod);
prefStr = SP.getString("AlarmFreqMin", "SET_FROM_XML");
mAlarmFreqMin = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() AlarmFreqMin = " + mAlarmFreqMin);
prefStr = SP.getString("AlarmFreqMax", "SET_FROM_XML");
mAlarmFreqMax = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() AlarmFreqMax = " + mAlarmFreqMax);
prefStr = SP.getString("WarnTime", "SET_FROM_XML");
mWarnTime = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() WarnTime = " + mWarnTime);
prefStr = SP.getString("AlarmTime", "SET_FROM_XML");
mAlarmTime = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() AlarmTime = " + mAlarmTime);
prefStr = SP.getString("AlarmThresh", "SET_FROM_XML");
mAlarmThresh = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() AlarmThresh = " + mAlarmThresh);
prefStr = SP.getString("AlarmRatioThresh", "SET_FROM_XML");
mAlarmRatioThresh = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() AlarmRatioThresh = " + mAlarmRatioThresh);
mFallActive = SP.getBoolean("FallActive", false);
Log.v(TAG, "updatePrefs() FallActive = " + mFallActive);
prefStr = SP.getString("FallThreshMin", "SET_FROM_XML");
mFallThreshMin = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() FallThreshMin = " + mFallThreshMin);
prefStr = SP.getString("FallThreshMax", "SET_FROM_XML");
mFallThreshMax = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() FallThreshMax = " + mFallThreshMax);
prefStr = SP.getString("FallWindow", "SET_FROM_XML");
mFallWindow = (short) Integer.parseInt(prefStr);
Log.v(TAG, "updatePrefs() FallWindow = " + mFallWindow);
} catch (Exception ex) {
Log.v(TAG, "updatePrefs() - Problem parsing preferences!");
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.updatePrefs() - ERROR "+ex.toString());
Toast toast = Toast.makeText(mContext, "Problem Parsing Preferences - Something won't work - Please go back to Settings and correct it!", Toast.LENGTH_SHORT);
toast.show();
}
}
/**
* Set this server to receive pebble data by registering it as
* A PebbleDataReceiver
*/
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 {
mSdData.analysisPeriod = data.getUnsignedIntegerAsLong(KEY_SAMPLE_PERIOD);
mSdData.alarmFreqMin = data.getUnsignedIntegerAsLong(KEY_ALARM_FREQ_MIN);
mSdData.alarmFreqMax = data.getUnsignedIntegerAsLong(KEY_ALARM_FREQ_MAX);
mSdData.nMin = data.getUnsignedIntegerAsLong(KEY_NMIN);
mSdData.nMax = data.getUnsignedIntegerAsLong(KEY_NMAX);
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");
}
}
//for (AccelData reading : AccelData.fromDataArray(rawDataBytes)) {
// if (nRawData < MAX_RAW_DATA) {
// rawData[nRawData] = reading.getMagnitude();
// nRawData++;
// } else {
// Log.i(TAG, "WARNING - rawData Buffer Full");
// }
// }
}
}
};
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) {
Log.v(TAG, "stopServer() - error " + e.toString());
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.stopServer() - error " + e.toString());
}
}
/**
* Attempt to start the pebble_sd watch app on the pebble watch.
*/
public void startWatchApp() {
Log.v(TAG, "startWatchApp() - closing app first");
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.startWatchApp() - closing app first");
// first close the watch app if it is running.
PebbleKit.closeAppOnPebble(mContext, SD_UUID);
Log.v(TAG, "startWatchApp() - starting watch app after 5 seconds delay...");
// Wait 5 seconds then start the app.
Timer appStartTimer = new Timer();
appStartTimer.schedule(new TimerTask() {
@Override
public void run() {
Log.v(TAG, "startWatchApp() - starting watch app...");
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.startWatchApp() - starting watch app");
PebbleKit.startAppOnPebble(mContext, SD_UUID);
}
}, 5000);
}
/**
* stop the pebble_sd watch app on the pebble watch.
*/
public void stopWatchApp() {
Log.v(TAG, "stopWatchApp()");
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.stopWatchApp()");
PebbleKit.closeAppOnPebble(mContext, SD_UUID);
}
/**
* Send our latest settings to the watch, then request Pebble App to send
* 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, "getPebbleSdSettings() - sending required settings to pebble");
mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.getPebbleSdSettings()");
sendPebbleSdSettings();
//Log.v(TAG, "getPebbleSdSettings() - requesting settings from pebble");
//mUtil.writeToSysLogFile("SdDataSourceNetworkPassive.getPebbleSdSettings() - 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.sendPebbleSdSettings()");
// 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, "sendPebbleSdSettings() - 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.
* If the watch app is not running, it attempts to re-start it.
*/
public void getStatus() {
Time tnow = new Time(Time.getCurrentTimezone());
long tdiff;
tnow.setToNow();
// get time since the last data was received from the Pebble watch.
tdiff = (tnow.toMillis(false) - mPebbleStatusTime.toMillis(false));
Log.v(TAG, "getStatus() - mPebbleAppRunningCheck=" + mPebbleAppRunningCheck + " tdiff=" + tdiff);
// Check we are actually connected to the pebble.
mSdData.pebbleConnected = PebbleKit.isWatchConnected(mContext);
if (!mSdData.pebbleConnected) mPebbleAppRunningCheck = false;
// And is the pebble_sd app running?
// set mPebbleAppRunningCheck has been false for more than 10 seconds
// the app is not talking to us
// mPebbleAppRunningCheck is set to true in the receiveData handler.
if (!mPebbleAppRunningCheck &&
(tdiff > (mDataUpdatePeriod + mAppRestartTimeout) * 1000)) {
Log.v(TAG, "getStatus() - tdiff = " + tdiff);
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.
//getPebbleSdSettings();
// Only make audible warning beep if we have not received data for more than mFaultTimerPeriod seconds.
if (tdiff > (mDataUpdatePeriod + mFaultTimerPeriod) * 1000) {
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.setToNow();
mSdDataReceiver.onSdDataFault(mSdData);
} else {
Log.v(TAG, "getStatus() - Waiting for mFaultTimerPeriod before issuing audible warning...");
}
} else {
mSdData.pebbleAppRunning = true;
}
// if we have confirmation that the app is running, reset the
// status time to now and initiate another check.
if (mPebbleAppRunningCheck) {
mPebbleAppRunningCheck = false;
mPebbleStatusTime.setToNow();
}
if (!mSdData.haveSettings) {
Log.v(TAG, "getStatus() - no settings received yet - requesting");
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()");
}
}

View File

@@ -477,15 +477,15 @@ public class SdDataSourcePebble extends SdDataSource {
* De-register this server from receiving pebble data * De-register this server from receiving pebble data
*/ */
public void stopPebbleServer() { public void stopPebbleServer() {
Log.v(TAG, "stopPebbleServer(): Stopping Pebble Server"); Log.v(TAG, "stopServer(): Stopping Pebble Server");
Log.v(TAG, "stopPebbleServer(): msgDataHandler = " + msgDataHandler.toString()); Log.v(TAG, "stopServer(): msgDataHandler = " + msgDataHandler.toString());
mUtil.writeToSysLogFile("SdDataSourcePebble.stopPebbleServer()"); mUtil.writeToSysLogFile("SdDataSourcePebble.stopServer()");
try { try {
mContext.unregisterReceiver(msgDataHandler); mContext.unregisterReceiver(msgDataHandler);
stopWatchApp(); stopWatchApp();
} catch (Exception e) { } catch (Exception e) {
Log.v(TAG, "stopPebbleServer() - error " + e.toString()); Log.v(TAG, "stopServer() - error " + e.toString());
mUtil.writeToSysLogFile("SdDataSourcePebble.stopPebbleServer() - error " + e.toString()); mUtil.writeToSysLogFile("SdDataSourcePebble.stopServer() - error " + e.toString());
} }
} }
@@ -650,8 +650,8 @@ public class SdDataSourcePebble extends SdDataSource {
* Will be received as a message by the receiveData handler * Will be received as a message by the receiveData handler
*/ */
public void getPebbleData() { public void getPebbleData() {
Log.v(TAG, "getPebbleData() - requesting data from pebble"); Log.v(TAG, "getData() - requesting data from pebble");
mUtil.writeToSysLogFile("SdDataSourcePebble.getPebbleData() - requesting data from pebble"); mUtil.writeToSysLogFile("SdDataSourcePebble.getData() - requesting data from pebble");
PebbleDictionary data = new PebbleDictionary(); PebbleDictionary data = new PebbleDictionary();
data.addUint8(KEY_DATA_TYPE, (byte) 1); data.addUint8(KEY_DATA_TYPE, (byte) 1);
PebbleKit.sendDataToPebble( PebbleKit.sendDataToPebble(
@@ -672,7 +672,7 @@ public class SdDataSourcePebble extends SdDataSource {
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) - mPebbleStatusTime.toMillis(false));
Log.v(TAG, "getPebbleStatus() - mPebbleAppRunningCheck=" + mPebbleAppRunningCheck + " tdiff=" + tdiff); Log.v(TAG, "getStatus() - mPebbleAppRunningCheck=" + mPebbleAppRunningCheck + " tdiff=" + tdiff);
// Check we are actually connected to the pebble. // Check we are actually connected to the pebble.
mSdData.pebbleConnected = PebbleKit.isWatchConnected(mContext); mSdData.pebbleConnected = PebbleKit.isWatchConnected(mContext);
if (!mSdData.pebbleConnected) mPebbleAppRunningCheck = false; if (!mSdData.pebbleConnected) mPebbleAppRunningCheck = false;
@@ -682,22 +682,22 @@ public class SdDataSourcePebble extends SdDataSource {
// mPebbleAppRunningCheck is set to true in the receiveData handler. // mPebbleAppRunningCheck is set to true in the receiveData handler.
if (!mPebbleAppRunningCheck && if (!mPebbleAppRunningCheck &&
(tdiff > (mDataUpdatePeriod + mAppRestartTimeout) * 1000)) { (tdiff > (mDataUpdatePeriod + mAppRestartTimeout) * 1000)) {
Log.v(TAG, "getPebbleStatus() - tdiff = " + tdiff); Log.v(TAG, "getStatus() - tdiff = " + tdiff);
mSdData.pebbleAppRunning = false; mSdData.pebbleAppRunning = false;
//Log.v(TAG, "getPebbleStatus() - Pebble App Not Running - Attempting to Re-Start"); //Log.v(TAG, "getStatus() - Pebble App Not Running - Attempting to Re-Start");
//mUtil.writeToSysLogFile("SdDataSourcePebble.getPebbleStatus() - Pebble App not Running - Attempting to Re-Start"); //mUtil.writeToSysLogFile("SdDataSourcePebble.getStatus() - Pebble App not Running - Attempting to Re-Start");
//startWatchApp(); //startWatchApp();
//mPebbleStatusTime = tnow; // set status time to now so we do not re-start app repeatedly. //mPebbleStatusTime = tnow; // set status time to now so we do not re-start app repeatedly.
//getPebbleSdSettings(); //getPebbleSdSettings();
// 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, "getPebbleStatus() - Pebble App Not Running - Attempting to Re-Start"); Log.v(TAG, "getStatus() - Pebble App Not Running - Attempting to Re-Start");
mUtil.writeToSysLogFile("SdDataSourcePebble.getPebbleStatus() - Pebble App not Running - Attempting to Re-Start"); mUtil.writeToSysLogFile("SdDataSourcePebble.getStatus() - Pebble App not Running - Attempting to Re-Start");
startWatchApp(); startWatchApp();
mPebbleStatusTime.setToNow(); mPebbleStatusTime.setToNow();
mSdDataReceiver.onSdDataFault(mSdData); mSdDataReceiver.onSdDataFault(mSdData);
} else { } else {
Log.v(TAG, "getPebbleStatus() - Waiting for mFaultTimerPeriod before issuing audible warning..."); Log.v(TAG, "getStatus() - Waiting for mFaultTimerPeriod before issuing audible warning...");
} }
} else { } else {
mSdData.pebbleAppRunning = true; mSdData.pebbleAppRunning = true;
@@ -711,7 +711,7 @@ public class SdDataSourcePebble extends SdDataSource {
} }
if (!mSdData.haveSettings) { if (!mSdData.haveSettings) {
Log.v(TAG, "getPebbleStatus() - no settings received yet - requesting"); Log.v(TAG, "getStatus() - no settings received yet - requesting");
getPebbleSdSettings(); getPebbleSdSettings();
getPebbleData(); getPebbleData();
} }

View File

@@ -204,6 +204,11 @@ public class SdServer extends Service implements SdDataReceiver, SdLocationRecei
mUtil.writeToSysLogFile("SdServer.onStartCommand() - creating SdDataSourceNetwork"); mUtil.writeToSysLogFile("SdServer.onStartCommand() - creating SdDataSourceNetwork");
mSdDataSource = new SdDataSourceNetwork(this.getApplicationContext(), mHandler, this); mSdDataSource = new SdDataSourceNetwork(this.getApplicationContext(), mHandler, this);
break; break;
case "NetworkPassive":
Log.v(TAG, "Selecting Network (Passive) DataSource");
mUtil.writeToSysLogFile("SdServer.onStartCommand() - creating SdDataSourceNetworkPassive");
mSdDataSource = new SdDataSourceNetworkPassive(this.getApplicationContext(), mHandler, this);
break;
default: default:
Log.v(TAG, "Datasource " + mSdDataSourceName + " not recognised - Exiting"); Log.v(TAG, "Datasource " + mSdDataSourceName + " not recognised - Exiting");
mUtil.writeToSysLogFile("SdServer.onStartCommand() - Datasource " + mSdDataSourceName + " not recognised - exiting"); mUtil.writeToSysLogFile("SdServer.onStartCommand() - Datasource " + mSdDataSourceName + " not recognised - exiting");

View File

@@ -11,6 +11,7 @@ import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.StringTokenizer; import java.util.StringTokenizer;
@@ -39,15 +40,29 @@ public class SdWebServer extends NanoHTTPD {
} }
public void setSdData(SdData sdData) { public void setSdData(SdData sdData) {
Log.v(TAG,"setSdData()"); Log.v(TAG, "setSdData()");
mSdData = sdData; mSdData = sdData;
} }
@Override @Override
public Response serve(String uri, Method method, public Response serve(IHTTPSession session) {
Map<String, String> header, String uri;
Map<String, String> parameters, Method method;
Map<String, String> files) { Map<String, String> header;
Map<String, String> parameters;
Map<String, String> files = new HashMap<String, String>();
try {
session.parseBody(files);
} catch (IOException ioe) {
return new Response(Response.Status.INTERNAL_ERROR, MIME_PLAINTEXT, "SERVER INTERNAL ERROR: IOException: " + ioe.getMessage());
} catch (ResponseException re) {
return new Response(re.getStatus(), MIME_PLAINTEXT, re.getMessage());
}
uri = session.getUri();
method = session.getMethod();
header = session.getHeaders();
parameters = session.getParms();
Log.v(TAG, "WebServer.serve() - uri=" + uri + " Method=" + method.toString()); Log.v(TAG, "WebServer.serve() - uri=" + uri + " Method=" + method.toString());
String answer = "Error - you should not see this message! - Something wrong in WebServer.serve()"; String answer = "Error - you should not see this message! - Something wrong in WebServer.serve()";
@@ -61,12 +76,25 @@ public class SdWebServer extends NanoHTTPD {
if (uri.equals("/")) uri = "/index.html"; if (uri.equals("/")) uri = "/index.html";
switch (uri) { switch (uri) {
case "/data": case "/data":
//Log.v(TAG,"WebServer.serve() - Returning data"); switch (method) {
try { case GET:
answer = mSdData.toString(); //Log.v(TAG,"WebServer.serve() - Returning data");
} catch (Exception ex) { try {
Log.v(TAG, "Error Creating Data Object - " + ex.toString()); answer = mSdData.toString();
answer = "Error Creating Data Object"; } catch (Exception ex) {
Log.v(TAG, "Error Creating Data Object - " + ex.toString());
answer = "Error Creating Data Object";
}
break;
case POST:
Log.v(TAG, "WebServer.serve() - POST /data - receiving data from device: parameters=" + parameters.toString());
Log.v(TAG, " header=" + header.toString());
Log.v(TAG, " files=" + files.toString());
String postData = files.get("postData");
Log.v(TAG, " postData=" + postData);
break;
default:
Log.v(TAG, "WebServer.serve() - Unrecognised method - " + method);
} }
break; break;

View File

@@ -461,11 +461,11 @@ public class StartupActivity extends Activity {
+ "http://openseizuredetector.org.uk, or the app Facebook page at https://www.facebook.com/openseizuredetector. " + "http://openseizuredetector.org.uk, or the app Facebook page at https://www.facebook.com/openseizuredetector. "
+ "so I can get in touch if necessary.\nThank you! Graham \ngraham@openseizuredetector.org.uk " + "so I can get in touch if necessary.\nThank you! Graham \ngraham@openseizuredetector.org.uk "
+ "\n\nChanges in this version:" + "\n\nChanges in this version:"
+ "\n- Added an alarm latch automatic reset timer. This means that if you enable 'Latch Alarms'" + "\n- Added support for 'Wifi Datasources' - initially for the experimental ESP8266 based seizure detector."
+ "\n in the alarms settings then an alarm will stay active for a period set by the Latch Alarm" + "\n "
+ "\n Time Duration setting before it re-sets, even if the watch only detects an alarm condition" + "\n "
+ "\n for a short period. This is to make sure a carer is alerted to even a short duration alarm" + "\n "
+ "\n condition. The alarm can be reset manually by pressing the 'Accept Alarm' button." + "\n ."
); );
// This makes the links display as links, but they do not respond to clicks for some reason... // This makes the links display as links, but they do not respond to clicks for some reason...
Linkify.addLinks(s, Linkify.ALL); Linkify.addLinks(s, Linkify.ALL);

View File

@@ -3,10 +3,12 @@
<string-array name="datasource_list"> <string-array name="datasource_list">
<item>"Pebble Watch"</item> <item>"Pebble Watch"</item>
<item>"Network"</item> <item>"Network"</item>
<item>"Network (passive)"</item>
</string-array> </string-array>
<string-array name="datasource_list_values"> <string-array name="datasource_list_values">
<item>"Pebble"</item> <item>"Pebble"</item>
<item>"Network"</item> <item>"Network"</item>
<item>"NetworkPassive"</item>
</string-array> </string-array>
</resources> </resources>

View File

@@ -0,0 +1,122 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- The ListPreference data is defined in pebble_datasource_values.xml -->
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory android:title="User Interface Settings">
<EditTextPreference
android:defaultValue="5"
android:key="PebbleUpdatePeriod"
android:summary="Time period at which data is sent to the phone (does not affect analysis frequency - see Sample Period setting for that)"
android:title="Data Transfer Period (sec)" />
<EditTextPreference
android:defaultValue="300"
android:key="MutePeriod"
android:summary="Time that alarms are muted following a long press of the UP button"
android:title="Mute Period (sec)" />
<EditTextPreference
android:defaultValue="30"
android:key="ManAlarmPeriod"
android:summary="Time that manual alarms sound following a long press of the DOWN button"
android:title="Manual Alarm Period (sec)" />
</PreferenceCategory>
<PreferenceCategory android:title="Seizure Detector Settings">
<EditTextPreference
android:defaultValue="5"
android:key="WarnTime"
android:summary="Time to wait before initiating warning (Default = 5 sec)"
android:title="WarnTime (sec)" />
<EditTextPreference
android:defaultValue="10"
android:key="AlarmTime"
android:summary="Time to wait before initiating alarm (Default = 10 sec)"
android:title="AlarmTime (sec)" />
<EditTextPreference
android:defaultValue="100"
android:key="AlarmThresh"
android:summary="Alarm Threshold (Default = 100)"
android:title="AlarmThresh" />
<EditTextPreference
android:defaultValue="50"
android:key="AlarmRatioThresh"
android:summary="Alarm Ratio Threshold (Default = 50). Increase this value to reduce sensitivity if false alarms are a problem."
android:title="AlarmRatioThresh" />
<EditTextPreference
android:defaultValue="3"
android:key="AlarmFreqMin"
android:summary="Minimum Frequency of ROI (Hz) (Default = 3 Hz)"
android:title="AlarmFreqMin (Hz)" />
<EditTextPreference
android:defaultValue="10"
android:key="AlarmFreqMax"
android:summary="Maximum Frequency of ROI (Hz) (Default = 10 Hz)"
android:title="AlarmFreqMax (Hz)" />
<EditTextPreference
android:defaultValue="5"
android:key="SamplePeriod"
android:summary="Period (in seconds) between data analyses"
android:title="SamplePeriod (sec)" />
<ListPreference
android:key="PebbleSdMode"
android:title="Seizure Detector Mode"
android:summary="Select one of the three available modes of operation."
android:entries="@array/pebble_sd_mode_list"
android:entryValues="@array/pebble_sd_mode_list_values"
android:defaultValue="0"
android:dialogTitle="Select Seizure Detector Mode" />
<ListPreference
android:key="SampleFreq"
android:title="Select Sample Frequency"
android:summary="Higher Frequency is more Accurate, but uses more battery power."
android:entries="@array/pebble_sample_freq_list"
android:entryValues="@array/pebble_sample_freq_list_values"
android:defaultValue="100"
android:dialogTitle="Select Sample Frequency"
android:enabled="true"
/>
</PreferenceCategory>
<PreferenceCategory android:title="Fall Detector Settings">
<CheckBoxPreference
android:defaultValue="false"
android:key="FallActive"
android:summary=""
android:title="Activate Fall Detection Function" />
<EditTextPreference
android:defaultValue="200"
android:key="FallThreshMin"
android:summary=""
android:title="Fall Detection Lower Threshold (milli-g)" />
<EditTextPreference
android:defaultValue="1200"
android:key="FallThreshMax"
android:summary=""
android:title="Fall Detection Upper Threshold (milli-g)" />
<EditTextPreference
android:defaultValue="1500"
android:key="FallWindow"
android:summary=""
android:title="Fall Detection Window (milli-seconds)" />
</PreferenceCategory>
<PreferenceCategory
android:title="Watch Communications Settings">
<ListPreference
android:key="PebbleDebug"
android:title="Seizure Detector Debug Mode"
android:summary="Set Debug mode on or off."
android:entries="@array/pebble_debug_list"
android:entryValues="@array/pebble_debug_values"
android:defaultValue="0"
android:dialogTitle="Select Debug Mode" />
<EditTextPreference
android:defaultValue="10"
android:key="AppRestartTimeout"
android:numeric="integer"
android:summary="Period (seconds) that we wait for data from the watch before assuming the watch app is not running and re-starting it."
android:title="Period (sec) we wait for data before restarting watch app." />
</PreferenceCategory>
</PreferenceScreen>

View File

@@ -4,7 +4,7 @@ buildscript {
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:2.3.1' classpath 'com.android.tools.build:gradle:2.3.3'
} }
} }
allprojects { allprojects {