Started on Network(Passive) datasource for use with esp8266 based seizure detector.
This commit is contained in:
@@ -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.
|
||||||
|
|||||||
@@ -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" />
|
||||||
|
|||||||
@@ -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()");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|||||||
@@ -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,6 +76,8 @@ 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":
|
||||||
|
switch (method) {
|
||||||
|
case GET:
|
||||||
//Log.v(TAG,"WebServer.serve() - Returning data");
|
//Log.v(TAG,"WebServer.serve() - Returning data");
|
||||||
try {
|
try {
|
||||||
answer = mSdData.toString();
|
answer = mSdData.toString();
|
||||||
@@ -69,6 +86,17 @@ public class SdWebServer extends NanoHTTPD {
|
|||||||
answer = "Error Creating Data Object";
|
answer = "Error Creating Data Object";
|
||||||
}
|
}
|
||||||
break;
|
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;
|
||||||
|
|
||||||
case "/settings":
|
case "/settings":
|
||||||
//Log.v(TAG,"WebServer.serve() - Returning settings");
|
//Log.v(TAG,"WebServer.serve() - Returning settings");
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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>
|
||||||
122
app/src/main/res/xml/network_passive_datasource_prefs.xml
Normal file
122
app/src/main/res/xml/network_passive_datasource_prefs.xml
Normal 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>
|
||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user