V3.1.9 - quite a few changes - see Changelog.md
This commit is contained in:
@@ -4,6 +4,11 @@
|
|||||||
V3.2.0 - (NEXT VERSION!)
|
V3.2.0 - (NEXT VERSION!)
|
||||||
- Added neural network based data analysis.
|
- Added neural network based data analysis.
|
||||||
|
|
||||||
|
V3.1.9 - 14jun2019
|
||||||
|
- Now requests READ_PHONE_STATE along with SMS permissions (required for some phones to send SMS messages)
|
||||||
|
- Fixed issue with Garmin Seizure Detector not producing warnings.
|
||||||
|
- Added faut pips for missing heart rate data if heart rate alarm active
|
||||||
|
|
||||||
V3.1.8 - 06jun2019
|
V3.1.8 - 06jun2019
|
||||||
- Added READ_PHONE_STATE permission which seems to be needed for some phones to send SMS (but not many).
|
- Added READ_PHONE_STATE permission which seems to be needed for some phones to send SMS (but not many).
|
||||||
|
|
||||||
|
|||||||
@@ -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="62"
|
android:versionCode="63"
|
||||||
android:versionName="3.1.8"
|
android:versionName="3.1.9"
|
||||||
>
|
>
|
||||||
<!--android:allowBackup="false"-->
|
<!--android:allowBackup="false"-->
|
||||||
|
|
||||||
|
|||||||
@@ -63,8 +63,6 @@ import com.github.mikephil.charting.data.BarEntry;
|
|||||||
import com.github.mikephil.charting.utils.ValueFormatter;
|
import com.github.mikephil.charting.utils.ValueFormatter;
|
||||||
import com.rohitss.uceh.UCEHandler;
|
import com.rohitss.uceh.UCEHandler;
|
||||||
|
|
||||||
import static java.util.Objects.isNull;
|
|
||||||
|
|
||||||
public class MainActivity extends AppCompatActivity {
|
public class MainActivity extends AppCompatActivity {
|
||||||
static final String TAG = "MainActivity";
|
static final String TAG = "MainActivity";
|
||||||
private int okColour = Color.BLUE;
|
private int okColour = Color.BLUE;
|
||||||
@@ -435,15 +433,18 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
tv = (TextView) findViewById(R.id.pebbleTv);
|
tv = (TextView) findViewById(R.id.pebbleTv);
|
||||||
if (mConnection.mSdServer.mSdData.mHRAlarmActive) {
|
if (mConnection.mSdServer.mSdData.mHRAlarmActive) {
|
||||||
tv.setText("HR = " + mConnection.mSdServer.mSdData.mHR);
|
tv.setText("HR = " + mConnection.mSdServer.mSdData.mHR);
|
||||||
if (!mConnection.mSdServer.mSdData.mHRAlarmStanding) {
|
if (mConnection.mSdServer.mSdData.mHRAlarmStanding) {
|
||||||
tv.setBackgroundColor(okColour);
|
|
||||||
tv.setTextColor(okTextColour);
|
|
||||||
} else {
|
|
||||||
tv.setBackgroundColor(alarmColour);
|
tv.setBackgroundColor(alarmColour);
|
||||||
tv.setTextColor(alarmTextColour);
|
tv.setTextColor(alarmTextColour);
|
||||||
|
} else if (mConnection.mSdServer.mSdData.mHRFaultStanding) {
|
||||||
|
tv.setBackgroundColor(warnColour);
|
||||||
|
tv.setTextColor(warnTextColour);
|
||||||
|
} else {
|
||||||
|
tv.setBackgroundColor(okColour);
|
||||||
|
tv.setTextColor(okTextColour);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (mConnection.mSdServer.mSdData.pebbleConnected) {
|
if (mConnection.mSdServer.mSdData.watchConnected) {
|
||||||
tv.setText("HR Alarm OFF");
|
tv.setText("HR Alarm OFF");
|
||||||
tv.setBackgroundColor(okColour);
|
tv.setBackgroundColor(okColour);
|
||||||
tv.setTextColor(okTextColour);
|
tv.setTextColor(okTextColour);
|
||||||
@@ -455,7 +456,7 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
tv = (TextView) findViewById(R.id.appTv);
|
tv = (TextView) findViewById(R.id.appTv);
|
||||||
if (mConnection.mSdServer.mSdData.pebbleAppRunning) {
|
if (mConnection.mSdServer.mSdData.watchAppRunning) {
|
||||||
tv.setText("Watch App OK");
|
tv.setText("Watch App OK");
|
||||||
tv.setBackgroundColor(okColour);
|
tv.setBackgroundColor(okColour);
|
||||||
tv.setTextColor(okTextColour);
|
tv.setTextColor(okTextColour);
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ public class OsdUtil implements ActivityCompat.OnRequestPermissionsResultCallbac
|
|||||||
private final String[] SMS_PERMISSIONS = {
|
private final String[] SMS_PERMISSIONS = {
|
||||||
Manifest.permission.SEND_SMS,
|
Manifest.permission.SEND_SMS,
|
||||||
Manifest.permission.ACCESS_FINE_LOCATION,
|
Manifest.permission.ACCESS_FINE_LOCATION,
|
||||||
|
Manifest.permission.READ_PHONE_STATE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
195
app/src/main/java/uk/org/openseizuredetector/SdAnalyser.java
Normal file
195
app/src/main/java/uk/org/openseizuredetector/SdAnalyser.java
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
Android_Pebble_SD - a simple accelerometer based seizure detector that runs on a
|
||||||
|
Pebble smart watch (http://getpebble.com).
|
||||||
|
|
||||||
|
See http://openseizuredetector.org for more information.
|
||||||
|
|
||||||
|
Copyright Graham Jones, 2015, 2016, 2017, 2018, 2019.
|
||||||
|
|
||||||
|
This file is part of android_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.util.Log;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import org.jtransforms.fft.DoubleFFT_1D;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SdAnalyser implements the seizure detection algorithm on an Android Phone - it is used by SdDatasourceGarmin
|
||||||
|
*/
|
||||||
|
public class SdAnalyser {
|
||||||
|
private String TAG = "SdAnalyser";
|
||||||
|
private double mSampleFreq;
|
||||||
|
private double mAlarmFreqMin;
|
||||||
|
private double mAlarmFreqMax;
|
||||||
|
private double mSamplePeriod;
|
||||||
|
private double mWarnTime;
|
||||||
|
private double mAlarmTime;
|
||||||
|
private double mAlarmThresh;
|
||||||
|
private double mAlarmRatioThresh;
|
||||||
|
private double mFreqRes;
|
||||||
|
private int mAlarmCount;
|
||||||
|
private double mFreqCutoff;
|
||||||
|
private int mNSamp;
|
||||||
|
|
||||||
|
double roiPower;
|
||||||
|
double specPower;
|
||||||
|
double roiRatio;
|
||||||
|
|
||||||
|
SdAnalyser(double sampleFreq,
|
||||||
|
double alarmFreqMin,
|
||||||
|
double alarmFreqMax,
|
||||||
|
double samplePeriod,
|
||||||
|
double warnTime,
|
||||||
|
double alarmThresh,
|
||||||
|
double alarmRatioThresh) {
|
||||||
|
mSampleFreq = sampleFreq;
|
||||||
|
mAlarmFreqMin = alarmFreqMin;
|
||||||
|
mAlarmFreqMax = alarmFreqMax;
|
||||||
|
mSamplePeriod = samplePeriod;
|
||||||
|
mWarnTime = warnTime;
|
||||||
|
mAlarmThresh = alarmThresh;
|
||||||
|
mAlarmRatioThresh = alarmRatioThresh;
|
||||||
|
|
||||||
|
mFreqRes = 1.0 / mSamplePeriod;
|
||||||
|
mFreqCutoff = mSampleFreq / 2.0;
|
||||||
|
mNSamp = (int)(mSamplePeriod * mSampleFreq);
|
||||||
|
}
|
||||||
|
|
||||||
|
int freq2fftBin(double freq) {
|
||||||
|
int n = (int)(freq/mFreqRes);
|
||||||
|
return(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* doAnalysis() - analyse the data if the accelerometer data array mAccData
|
||||||
|
* and populate the output data structure mSdData
|
||||||
|
*/
|
||||||
|
void calculateSpectralPowers(double[] rawData) {
|
||||||
|
// Set the frequency bounds for the analysis in fft output bin numbers.
|
||||||
|
int nMin = freq2fftBin(mAlarmFreqMin);
|
||||||
|
int nMax = freq2fftBin(mAlarmFreqMax);
|
||||||
|
int nFreqCutoff = freq2fftBin(mFreqCutoff);
|
||||||
|
|
||||||
|
DoubleFFT_1D fftDo = new DoubleFFT_1D(mNSamp);
|
||||||
|
double[] fft = new double[mNSamp * 2];
|
||||||
|
System.arraycopy(rawData, 0, fft, 0, mNSamp);
|
||||||
|
fftDo.realForward(fft);
|
||||||
|
|
||||||
|
// Calculate the whole spectrum power (well a value equivalent to it that avoids square root calculations
|
||||||
|
// and zero any readings that are above the frequency cutoff.
|
||||||
|
double specPower = 0;
|
||||||
|
for (int i = 1; i < mNSamp / 2; i++) {
|
||||||
|
if (i <= nFreqCutoff) {
|
||||||
|
specPower = specPower + getMagnitude(fft, i);
|
||||||
|
} else {
|
||||||
|
fft[2 * i] = 0.;
|
||||||
|
fft[2 * i + 1] = 0.;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
specPower = specPower / (mNSamp / 2);
|
||||||
|
|
||||||
|
// Calculate the Region of Interest power and power ratio.
|
||||||
|
double roiPower = 0;
|
||||||
|
for (int i = nMin; i < nMax; i++) {
|
||||||
|
roiPower = roiPower + getMagnitude(fft, i);
|
||||||
|
}
|
||||||
|
roiPower = roiPower / (nMax - nMin);
|
||||||
|
double roiRatio = 10 * roiPower / specPower;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the magnitude of entry i in the fft array fft
|
||||||
|
*
|
||||||
|
* @param fft
|
||||||
|
* @param i
|
||||||
|
* @return magnitude ( Re*Re + Im*Im )
|
||||||
|
*/
|
||||||
|
double getMagnitude(double[] fft, int i) {
|
||||||
|
double mag;
|
||||||
|
mag = (fft[2 * i] * fft[2 * i] + fft[2 * i + 1] * fft[2 * i + 1]);
|
||||||
|
return mag;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Force the data stored in this datasource to update in line with the JSON string encoded data provided.
|
||||||
|
// Used by webServer to update the GarminDatasource.
|
||||||
|
// Returns a message string that is passed back to the watch.
|
||||||
|
public String updateFromJSON(String jsonStr) {
|
||||||
|
String retVal = "undefined";
|
||||||
|
Log.v(TAG,"updateFromJSON - "+jsonStr);
|
||||||
|
|
||||||
|
try {
|
||||||
|
JSONObject mainObject = new JSONObject(jsonStr);
|
||||||
|
//JSONObject dataObject = mainObject.getJSONObject("dataObj");
|
||||||
|
JSONObject dataObject = mainObject;
|
||||||
|
String dataTypeStr = dataObject.getString("dataType");
|
||||||
|
Log.v(TAG,"updateFromJSON - dataType="+dataTypeStr);
|
||||||
|
if (dataTypeStr.equals("raw")) {
|
||||||
|
Log.v(TAG,"updateFromJSON - processing raw data");
|
||||||
|
try {
|
||||||
|
mSdData.mHR = dataObject.getDouble("HR");
|
||||||
|
} catch (JSONException e) {
|
||||||
|
// if we get 'null' HR (For example if the heart rate is not working)
|
||||||
|
mSdData.mHR = -1;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
mMute = dataObject.getInt("Mute");
|
||||||
|
} catch (JSONException e) {
|
||||||
|
// if we get 'null' HR (For example if the heart rate is not working)
|
||||||
|
mMute = 0;
|
||||||
|
}
|
||||||
|
JSONArray accelVals = dataObject.getJSONArray("data");
|
||||||
|
Log.v(TAG, "Received " + accelVals.length() + " acceleration values");
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < accelVals.length(); i++) {
|
||||||
|
mSdData.rawData[i] = accelVals.getInt(i);
|
||||||
|
}
|
||||||
|
mSdData.mNsamp = accelVals.length();
|
||||||
|
//mNSamp = accelVals.length();
|
||||||
|
mWatchAppRunningCheck = true;
|
||||||
|
doAnalysis();
|
||||||
|
if (mSdData.haveSettings == false) {
|
||||||
|
retVal = "sendSettings";
|
||||||
|
} else {
|
||||||
|
retVal = "OK";
|
||||||
|
}
|
||||||
|
} else if (dataTypeStr.equals("settings")){
|
||||||
|
Log.v(TAG,"updateFromJSON - processing settings");
|
||||||
|
mSamplePeriod = (short)dataObject.getInt("analysisPeriod");
|
||||||
|
mSampleFreq = (short)dataObject.getInt("sampleFreq");
|
||||||
|
mSdData.batteryPc = (short)dataObject.getInt("battery");
|
||||||
|
Log.v(TAG,"updateFromJSON - mSamplePeriod="+mSamplePeriod+" mSampleFreq="+mSampleFreq);
|
||||||
|
mSdData.haveSettings = true;
|
||||||
|
mSdData.mSampleFreq = mSampleFreq;
|
||||||
|
mWatchAppRunningCheck = true;
|
||||||
|
retVal = "OK";
|
||||||
|
} else {
|
||||||
|
Log.e(TAG,"updateFromJSON - unrecognised dataType "+dataTypeStr);
|
||||||
|
retVal = "ERROR";
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG,"updateFromJSON - Error Parsing JSON String - "+e.toString());
|
||||||
|
e.printStackTrace();
|
||||||
|
retVal = "ERROR";
|
||||||
|
}
|
||||||
|
return(retVal);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,10 +29,6 @@ import android.os.Parcel;
|
|||||||
import android.text.format.Time;
|
import android.text.format.Time;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
|
|
||||||
@@ -82,11 +78,12 @@ public class SdData implements Parcelable {
|
|||||||
public long roiPower;
|
public long roiPower;
|
||||||
public String alarmPhrase;
|
public String alarmPhrase;
|
||||||
public int simpleSpec[];
|
public int simpleSpec[];
|
||||||
public boolean pebbleConnected = false;
|
public boolean watchConnected = false;
|
||||||
public boolean pebbleAppRunning = false;
|
public boolean watchAppRunning = false;
|
||||||
public boolean serverOK = false;
|
public boolean serverOK = false;
|
||||||
|
|
||||||
public boolean mHRAlarmStanding = false;
|
public boolean mHRAlarmStanding = false;
|
||||||
|
public boolean mHRFaultStanding = false;
|
||||||
public double mHR = 0;
|
public double mHR = 0;
|
||||||
|
|
||||||
public SdData() {
|
public SdData() {
|
||||||
@@ -116,8 +113,8 @@ public class SdData implements Parcelable {
|
|||||||
specPower = jo.optInt("specPower");
|
specPower = jo.optInt("specPower");
|
||||||
roiPower = jo.optInt("roiPower");
|
roiPower = jo.optInt("roiPower");
|
||||||
batteryPc = jo.optInt("batteryPc");
|
batteryPc = jo.optInt("batteryPc");
|
||||||
pebbleConnected = jo.optBoolean("pebbleConnected");
|
watchConnected = jo.optBoolean("watchConnected");
|
||||||
pebbleAppRunning = jo.optBoolean("pebbleAppRunning");
|
watchAppRunning = jo.optBoolean("watchAppRunning");
|
||||||
alarmState = jo.optInt("alarmState");
|
alarmState = jo.optInt("alarmState");
|
||||||
alarmPhrase = jo.optString("alarmPhrase");
|
alarmPhrase = jo.optString("alarmPhrase");
|
||||||
alarmThresh = jo.optInt("alarmThresh");
|
alarmThresh = jo.optInt("alarmThresh");
|
||||||
@@ -159,8 +156,8 @@ public class SdData implements Parcelable {
|
|||||||
jsonObj.put("specPower", specPower);
|
jsonObj.put("specPower", specPower);
|
||||||
jsonObj.put("roiPower", roiPower);
|
jsonObj.put("roiPower", roiPower);
|
||||||
jsonObj.put("batteryPc", batteryPc);
|
jsonObj.put("batteryPc", batteryPc);
|
||||||
jsonObj.put("pebbleConnected", pebbleConnected);
|
jsonObj.put("watchConnected", watchConnected);
|
||||||
jsonObj.put("pebbleAppRunning", pebbleAppRunning);
|
jsonObj.put("watchAppRunning", watchAppRunning);
|
||||||
jsonObj.put("haveSettings", haveSettings);
|
jsonObj.put("haveSettings", haveSettings);
|
||||||
jsonObj.put("alarmState", alarmState);
|
jsonObj.put("alarmState", alarmState);
|
||||||
jsonObj.put("alarmPhrase", alarmPhrase);
|
jsonObj.put("alarmPhrase", alarmPhrase);
|
||||||
|
|||||||
@@ -683,8 +683,8 @@ public class SdDataSourceAw extends SdDataSource {
|
|||||||
tdiff = (tnow.toMillis(false) - mStatusTime.toMillis(false));
|
tdiff = (tnow.toMillis(false) - mStatusTime.toMillis(false));
|
||||||
Log.v(TAG, "getStatus() - mWatchAppRunningCheck=" + mWatchAppRunningCheck + " tdiff=" + tdiff);
|
Log.v(TAG, "getStatus() - mWatchAppRunningCheck=" + mWatchAppRunningCheck + " tdiff=" + tdiff);
|
||||||
// Check we are actually connected to the pebble.
|
// Check we are actually connected to the pebble.
|
||||||
mSdData.pebbleConnected = PebbleKit.isWatchConnected(mContext);
|
mSdData.watchConnected = PebbleKit.isWatchConnected(mContext);
|
||||||
if (!mSdData.pebbleConnected) mWatchAppRunningCheck = false;
|
if (!mSdData.watchConnected) mWatchAppRunningCheck = false;
|
||||||
// And is the pebble_sd app running?
|
// And is the pebble_sd app running?
|
||||||
// set mWatchAppRunningCheck has been false for more than 10 seconds
|
// set mWatchAppRunningCheck has been false for more than 10 seconds
|
||||||
// the app is not talking to us
|
// the app is not talking to us
|
||||||
@@ -692,7 +692,7 @@ public class SdDataSourceAw extends SdDataSource {
|
|||||||
if (!mWatchAppRunningCheck &&
|
if (!mWatchAppRunningCheck &&
|
||||||
(tdiff > (mDataUpdatePeriod + mAppRestartTimeout) * 1000)) {
|
(tdiff > (mDataUpdatePeriod + mAppRestartTimeout) * 1000)) {
|
||||||
Log.v(TAG, "getStatus() - tdiff = " + tdiff);
|
Log.v(TAG, "getStatus() - tdiff = " + tdiff);
|
||||||
mSdData.pebbleAppRunning = false;
|
mSdData.watchAppRunning = false;
|
||||||
//Log.v(TAG, "getStatus() - Pebble App Not Running - Attempting to Re-Start");
|
//Log.v(TAG, "getStatus() - Pebble App Not Running - Attempting to Re-Start");
|
||||||
//mUtil.writeToSysLogFile("SdDataSourceAw.getStatus() - Pebble App not Running - Attempting to Re-Start");
|
//mUtil.writeToSysLogFile("SdDataSourceAw.getStatus() - Pebble App not Running - Attempting to Re-Start");
|
||||||
//startWatchApp();
|
//startWatchApp();
|
||||||
@@ -709,7 +709,7 @@ public class SdDataSourceAw extends SdDataSource {
|
|||||||
Log.v(TAG, "getStatus() - Waiting for mFaultTimerPeriod before issuing audible warning...");
|
Log.v(TAG, "getStatus() - Waiting for mFaultTimerPeriod before issuing audible warning...");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mSdData.pebbleAppRunning = true;
|
mSdData.watchAppRunning = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we have confirmation that the app is running, reset the
|
// if we have confirmation that the app is running, reset the
|
||||||
|
|||||||
@@ -28,32 +28,22 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.net.ConnectivityManager;
|
|
||||||
import android.os.BatteryManager;
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.text.format.Time;
|
import android.text.format.Time;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.getpebble.android.kit.PebbleKit;
|
|
||||||
import com.getpebble.android.kit.util.PebbleDictionary;
|
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import org.jtransforms.fft.DoubleFFT_1D;
|
import org.jtransforms.fft.DoubleFFT_1D;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.ByteOrder;
|
|
||||||
import java.nio.IntBuffer;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import static java.lang.Long.parseLong;
|
import static java.lang.Long.parseLong;
|
||||||
import static java.lang.Math.sqrt;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -66,7 +56,7 @@ public class SdDataSourceGarmin extends SdDataSource {
|
|||||||
private Handler mHandler = new Handler();
|
private Handler mHandler = new Handler();
|
||||||
private Timer mStatusTimer;
|
private Timer mStatusTimer;
|
||||||
private Timer mSettingsTimer;
|
private Timer mSettingsTimer;
|
||||||
private Timer mAlarmCheckTimer;
|
private Timer mFaultCheckTimer;
|
||||||
private Time mDataStatusTime;
|
private Time mDataStatusTime;
|
||||||
private boolean mWatchAppRunningCheck = false;
|
private boolean mWatchAppRunningCheck = false;
|
||||||
private int mAppRestartTimeout = 10; // Timeout before re-starting watch app (sec) if we have not received
|
private int mAppRestartTimeout = 10; // Timeout before re-starting watch app (sec) if we have not received
|
||||||
@@ -145,14 +135,14 @@ public class SdDataSourceGarmin extends SdDataSource {
|
|||||||
Log.v(TAG, "start(): status timer already running.");
|
Log.v(TAG, "start(): status timer already running.");
|
||||||
mUtil.writeToSysLogFile("SdDataSourceGarmin.start() - status timer already running??");
|
mUtil.writeToSysLogFile("SdDataSourceGarmin.start() - status timer already running??");
|
||||||
}
|
}
|
||||||
if (mAlarmCheckTimer == null) {
|
if (mFaultCheckTimer == null) {
|
||||||
Log.v(TAG, "start(): starting alarm check timer");
|
Log.v(TAG, "start(): starting alarm check timer");
|
||||||
mUtil.writeToSysLogFile("SdDataSourceGarmin.start() - starting alarm check timer");
|
mUtil.writeToSysLogFile("SdDataSourceGarmin.start() - starting alarm check timer");
|
||||||
mAlarmCheckTimer = new Timer();
|
mFaultCheckTimer = new Timer();
|
||||||
mAlarmCheckTimer.schedule(new TimerTask() {
|
mFaultCheckTimer.schedule(new TimerTask() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
alarmCheck();
|
faultCheck();
|
||||||
}
|
}
|
||||||
}, 0, 1000);
|
}, 0, 1000);
|
||||||
} else {
|
} else {
|
||||||
@@ -206,12 +196,12 @@ public class SdDataSourceGarmin extends SdDataSource {
|
|||||||
mSettingsTimer = null;
|
mSettingsTimer = null;
|
||||||
}
|
}
|
||||||
// Stop the alarm check timer
|
// Stop the alarm check timer
|
||||||
if (mAlarmCheckTimer != null) {
|
if (mFaultCheckTimer != null) {
|
||||||
Log.v(TAG, "stop(): cancelling alarm check timer");
|
Log.v(TAG, "stop(): cancelling alarm check timer");
|
||||||
mUtil.writeToSysLogFile("SdDataSourceGarmin.stop() - cancelling alarm check timer");
|
mUtil.writeToSysLogFile("SdDataSourceGarmin.stop() - cancelling alarm check timer");
|
||||||
mAlarmCheckTimer.cancel();
|
mFaultCheckTimer.cancel();
|
||||||
mAlarmCheckTimer.purge();
|
mFaultCheckTimer.purge();
|
||||||
mAlarmCheckTimer = null;
|
mFaultCheckTimer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -467,7 +457,10 @@ public class SdDataSourceGarmin extends SdDataSource {
|
|||||||
fft[2*i+1] = 0.;
|
fft[2*i+1] = 0.;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//Log.v(TAG,"specPower = "+specPower);
|
||||||
|
//specPower = specPower/(mSdData.mNsamp/2);
|
||||||
specPower = specPower/mSdData.mNsamp/2;
|
specPower = specPower/mSdData.mNsamp/2;
|
||||||
|
//Log.v(TAG,"specPower = "+specPower);
|
||||||
|
|
||||||
// Calculate the Region of Interest power and power ratio.
|
// Calculate the Region of Interest power and power ratio.
|
||||||
double roiPower = 0;
|
double roiPower = 0;
|
||||||
@@ -489,8 +482,6 @@ public class SdDataSourceGarmin extends SdDataSource {
|
|||||||
simpleSpec[ifreq] = simpleSpec[ifreq] / (binMax-binMin);
|
simpleSpec[ifreq] = simpleSpec[ifreq] / (binMax-binMin);
|
||||||
}
|
}
|
||||||
|
|
||||||
checkFall();
|
|
||||||
|
|
||||||
// Populate the mSdData structure to communicate with the main SdServer service.
|
// Populate the mSdData structure to communicate with the main SdServer service.
|
||||||
mDataStatusTime.setToNow();
|
mDataStatusTime.setToNow();
|
||||||
mSdData.specPower = (long)specPower / ACCEL_SCALE_FACTOR;
|
mSdData.specPower = (long)specPower / ACCEL_SCALE_FACTOR;
|
||||||
@@ -512,15 +503,102 @@ public class SdDataSourceGarmin extends SdDataSource {
|
|||||||
|
|
||||||
// Because we have received data, set flag to show watch app running.
|
// Because we have received data, set flag to show watch app running.
|
||||||
mWatchAppRunningCheck = true;
|
mWatchAppRunningCheck = true;
|
||||||
|
|
||||||
|
// Check this data to see if it represents an alarm state.
|
||||||
|
alarmCheck();
|
||||||
|
hrCheck();
|
||||||
|
fallCheck();
|
||||||
|
muteCheck();
|
||||||
|
|
||||||
mSdDataReceiver.onSdDataReceived(mSdData); // and tell SdServer we have received data.
|
mSdDataReceiver.onSdDataReceived(mSdData); // and tell SdServer we have received data.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************
|
||||||
|
* checkAlarm() - checks the current accelerometer data and uses
|
||||||
|
* historical data to determine if we are in a fault, warning or ok
|
||||||
|
* state.
|
||||||
|
* Sets mSdData.alarmState and mSdData.hrAlarmStanding
|
||||||
|
*/
|
||||||
|
private void alarmCheck() {
|
||||||
|
boolean inAlarm;
|
||||||
|
Log.v(TAG, "alarmCheck()");
|
||||||
|
// Is the current set of data representing an alarm state?
|
||||||
|
if ((mSdData.roiPower > mAlarmThresh) && (10 * (mSdData.roiPower / mSdData.specPower) > mAlarmRatioThresh)) {
|
||||||
|
inAlarm = true;
|
||||||
|
} else {
|
||||||
|
inAlarm = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the alarmState to Alarm, Warning or OK, depending on the current state and previous ones.
|
||||||
|
if (inAlarm) {
|
||||||
|
mAlarmCount += mSamplePeriod;
|
||||||
|
if (mAlarmCount > mAlarmTime) {
|
||||||
|
// full alarm
|
||||||
|
mSdData.alarmState = 2;
|
||||||
|
} else if (mAlarmCount > mWarnTime) {
|
||||||
|
// warning
|
||||||
|
mSdData.alarmState = 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If we are not in an ALARM state, revert back to WARNING, otherwise
|
||||||
|
// revert back to OK.
|
||||||
|
if (mSdData.alarmState == 2) {
|
||||||
|
// revert to warning
|
||||||
|
mSdData.alarmState = 1;
|
||||||
|
mAlarmCount = mWarnTime + 1; // pretend we have only just entered warning state.
|
||||||
|
} else {
|
||||||
|
// revert to OK
|
||||||
|
mSdData.alarmState = 0;
|
||||||
|
mAlarmCount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.v(TAG, "alarmCheck(): inAlarm=" + inAlarm + ", alarmState = " + mSdData.alarmState + " alarmCount=" + mAlarmCount + " mAlarmTime=" + mAlarmTime);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void muteCheck() {
|
||||||
|
if (mMute != 0) {
|
||||||
|
Log.v(TAG, "Mute Active - setting alarms to mute");
|
||||||
|
mSdData.alarmState = 6;
|
||||||
|
mSdData.alarmPhrase = "MUTE";
|
||||||
|
mSdData.mHRAlarmStanding = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hrCheck - check the Heart rate data in mSdData to see if it represents an alarm condition.
|
||||||
|
* Sets mSdData.mHRAlarmStanding
|
||||||
|
*/
|
||||||
|
public void hrCheck() {
|
||||||
|
Log.v(TAG, "hrCheck()");
|
||||||
|
/* Check Heart Rate against alarm settings */
|
||||||
|
if (mSdData.mHRAlarmActive) {
|
||||||
|
if (mSdData.mHR < 0) {
|
||||||
|
Log.i(TAG,"Heart Rate Fault (HR<0)");
|
||||||
|
mSdData.mHRFaultStanding = true;
|
||||||
|
mSdData.mHRAlarmStanding = false;
|
||||||
|
}
|
||||||
|
else if ((mSdData.mHR > mSdData.mHRTreshMax) || (mSdData.mHR < mSdData.mHRThreshMin)) {
|
||||||
|
Log.i(TAG, "Heart Rate Abnormal - " + mSdData.mHR + " bpm");
|
||||||
|
mSdData.mHRFaultStanding = false;
|
||||||
|
mSdData.mHRAlarmStanding = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mSdData.mHRFaultStanding = false;
|
||||||
|
mSdData.mHRAlarmStanding = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************
|
/****************************************************************
|
||||||
* Simple threshold analysis to chech for fall.
|
* Simple threshold analysis to chech for fall.
|
||||||
* Called from clock_tick_handler()
|
* Called from clock_tick_handler()
|
||||||
*/
|
*/
|
||||||
public void checkFall() {
|
public void fallCheck() {
|
||||||
int i,j;
|
int i,j;
|
||||||
double minAcc, maxAcc;
|
double minAcc, maxAcc;
|
||||||
|
|
||||||
@@ -575,7 +653,7 @@ public class SdDataSourceGarmin extends SdDataSource {
|
|||||||
Log.v(TAG, "getStatus() - mWatchAppRunningCheck=" + mWatchAppRunningCheck + " tdiff=" + tdiff);
|
Log.v(TAG, "getStatus() - mWatchAppRunningCheck=" + mWatchAppRunningCheck + " tdiff=" + tdiff);
|
||||||
Log.v(TAG,"getStatus() - tdiff="+tdiff+", mDataUpatePeriod="+mDataUpdatePeriod+", mAppRestartTimeout="+mAppRestartTimeout);
|
Log.v(TAG,"getStatus() - tdiff="+tdiff+", mDataUpatePeriod="+mDataUpdatePeriod+", mAppRestartTimeout="+mAppRestartTimeout);
|
||||||
|
|
||||||
mSdData.pebbleConnected = true; // We can't check connection for passive network connection, so set it to true to avoid errors.
|
mSdData.watchConnected = true; // We can't check connection for passive network connection, so set it to true to avoid errors.
|
||||||
// And is the watch app running?
|
// And is the watch app running?
|
||||||
// set mWatchAppRunningCheck has been false for more than 10 seconds
|
// set mWatchAppRunningCheck has been false for more than 10 seconds
|
||||||
// the app is not talking to us
|
// the app is not talking to us
|
||||||
@@ -583,7 +661,7 @@ public class SdDataSourceGarmin extends SdDataSource {
|
|||||||
if (!mWatchAppRunningCheck &&
|
if (!mWatchAppRunningCheck &&
|
||||||
(tdiff > (mDataUpdatePeriod + mAppRestartTimeout) * 1000)) {
|
(tdiff > (mDataUpdatePeriod + mAppRestartTimeout) * 1000)) {
|
||||||
Log.v(TAG, "getStatus() - tdiff = " + tdiff);
|
Log.v(TAG, "getStatus() - tdiff = " + tdiff);
|
||||||
mSdData.pebbleAppRunning = false;
|
mSdData.watchAppRunning = false;
|
||||||
// Only make audible warning beep if we have not received data for more than mFaultTimerPeriod seconds.
|
// Only make audible warning beep if we have not received data for more than mFaultTimerPeriod seconds.
|
||||||
if (tdiff > (mDataUpdatePeriod + mFaultTimerPeriod) * 1000) {
|
if (tdiff > (mDataUpdatePeriod + mFaultTimerPeriod) * 1000) {
|
||||||
Log.v(TAG, "getStatus() - Watch App Not Running");
|
Log.v(TAG, "getStatus() - Watch App Not Running");
|
||||||
@@ -596,7 +674,7 @@ public class SdDataSourceGarmin extends SdDataSource {
|
|||||||
Log.v(TAG, "getStatus() - Waiting for mFaultTimerPeriod before issuing audible warning...");
|
Log.v(TAG, "getStatus() - Waiting for mFaultTimerPeriod before issuing audible warning...");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mSdData.pebbleAppRunning = true;
|
mSdData.watchAppRunning = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we have confirmation that the app is running, reset the
|
// if we have confirmation that the app is running, reset the
|
||||||
@@ -612,71 +690,21 @@ public class SdDataSourceGarmin extends SdDataSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* alarmCheck - determines alarm state based on seizure detector data SdData. Called every second.
|
* faultCheck - determines alarm state based on seizure detector data SdData. Called every second.
|
||||||
*/
|
*/
|
||||||
private void alarmCheck() {
|
private void faultCheck() {
|
||||||
boolean inAlarm;
|
|
||||||
Time tnow = new Time(Time.getCurrentTimezone());
|
Time tnow = new Time(Time.getCurrentTimezone());
|
||||||
long tdiff;
|
long tdiff;
|
||||||
tnow.setToNow();
|
tnow.setToNow();
|
||||||
|
|
||||||
// get time since the last data was received from the watch.
|
// get time since the last data was received from the watch.
|
||||||
tdiff = (tnow.toMillis(false) - mDataStatusTime.toMillis(false));
|
tdiff = (tnow.toMillis(false) - mDataStatusTime.toMillis(false));
|
||||||
Log.v(TAG, "alarmCheck() - tdiff=" + tdiff + ", mDataUpatePeriod=" + mDataUpdatePeriod + ", mAppRestartTimeout=" + mAppRestartTimeout
|
Log.v(TAG, "faultCheck() - tdiff=" + tdiff + ", mDataUpatePeriod=" + mDataUpdatePeriod + ", mAppRestartTimeout=" + mAppRestartTimeout
|
||||||
+ ", combined = " + (mDataUpdatePeriod + mAppRestartTimeout) * 1000);
|
+ ", combined = " + (mDataUpdatePeriod + mAppRestartTimeout) * 1000);
|
||||||
if (!mWatchAppRunningCheck &&
|
if (!mWatchAppRunningCheck &&
|
||||||
(tdiff > (mDataUpdatePeriod + mAppRestartTimeout) * 1000)) {
|
(tdiff > (mDataUpdatePeriod + mAppRestartTimeout) * 1000)) {
|
||||||
Log.v(TAG, "alarmCheck() - watch app not running so not doing anything");
|
Log.v(TAG, "faultCheck() - watch app not running so not doing anything");
|
||||||
mAlarmCount = 0;
|
mAlarmCount = 0;
|
||||||
} else {
|
|
||||||
Log.v(TAG, "alarmCheck()");
|
|
||||||
if ((mSdData.roiPower > mAlarmThresh) && (10 * (mSdData.roiPower / mSdData.specPower) > mAlarmRatioThresh)) {
|
|
||||||
inAlarm = true;
|
|
||||||
} else {
|
|
||||||
inAlarm = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inAlarm) {
|
|
||||||
mAlarmCount += mSamplePeriod;
|
|
||||||
if (mAlarmCount > mAlarmTime) {
|
|
||||||
// full alarm
|
|
||||||
mSdData.alarmState = 2;
|
|
||||||
} else if (mAlarmCount > mWarnTime) {
|
|
||||||
// warning
|
|
||||||
mSdData.alarmState = 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If we are not in an ALARM state, revert back to WARNING, otherwise
|
|
||||||
// revert back to OK.
|
|
||||||
if (mSdData.alarmState == 2) {
|
|
||||||
// revert to warning
|
|
||||||
mSdData.alarmState = 1;
|
|
||||||
mAlarmCount = mWarnTime + 1; // pretend we have only just entered warning state.
|
|
||||||
} else {
|
|
||||||
// revert to OK
|
|
||||||
mSdData.alarmState = 0;
|
|
||||||
mAlarmCount = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.v(TAG, "inAlarm=" + inAlarm + ", alarmState = " + mSdData.alarmState + " alarmCount=" + mAlarmCount + " mAlarmTime=" + mAlarmTime);
|
|
||||||
|
|
||||||
/* Check Heart Rate against alarm settings */
|
|
||||||
if (mSdData.mHRAlarmActive) {
|
|
||||||
Log.v(TAG,"Checking HR Alarm");
|
|
||||||
if ((mSdData.mHR > mSdData.mHRTreshMax) || (mSdData.mHR < mSdData.mHRThreshMin)) {
|
|
||||||
Log.i(TAG, "Heart Rate Abnormal - " + mSdData.mHR + " bpm");
|
|
||||||
mSdData.mHRAlarmStanding = true;
|
|
||||||
} else {
|
|
||||||
mSdData.mHRAlarmStanding = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (mMute != 0) {
|
|
||||||
Log.v(TAG,"Mute Active - setting alarms to mute");
|
|
||||||
mSdData.alarmState = 6;
|
|
||||||
mSdData.alarmPhrase = "MUTE";
|
|
||||||
mSdData.mHRAlarmStanding = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ package uk.org.openseizuredetector;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.net.ConnectivityManager;
|
|
||||||
import android.net.NetworkInfo;
|
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
@@ -128,8 +126,8 @@ public class SdDataSourceNetwork extends SdDataSource {
|
|||||||
if (result.startsWith("Unable to retrieve web page")) {
|
if (result.startsWith("Unable to retrieve web page")) {
|
||||||
Log.v(TAG,"doInBackground() - Unable to retrieve data");
|
Log.v(TAG,"doInBackground() - Unable to retrieve data");
|
||||||
sdData.serverOK = false;
|
sdData.serverOK = false;
|
||||||
sdData.pebbleConnected = false;
|
sdData.watchConnected = false;
|
||||||
sdData.pebbleAppRunning = false;
|
sdData.watchAppRunning = false;
|
||||||
sdData.alarmState = ALARM_STATE_NETFAULT;
|
sdData.alarmState = ALARM_STATE_NETFAULT;
|
||||||
sdData.alarmPhrase = "Warning - No Connection to Server";
|
sdData.alarmPhrase = "Warning - No Connection to Server";
|
||||||
Log.v(TAG,"doInBackground(): No Connection to Server - sdData = "+sdData.toString());
|
Log.v(TAG,"doInBackground(): No Connection to Server - sdData = "+sdData.toString());
|
||||||
@@ -147,8 +145,8 @@ public class SdDataSourceNetwork extends SdDataSource {
|
|||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
sdData.serverOK = false;
|
sdData.serverOK = false;
|
||||||
sdData.pebbleConnected = false;
|
sdData.watchConnected = false;
|
||||||
sdData.pebbleAppRunning = false;
|
sdData.watchAppRunning = false;
|
||||||
sdData.alarmState = ALARM_STATE_NETFAULT;
|
sdData.alarmState = ALARM_STATE_NETFAULT;
|
||||||
sdData.alarmPhrase = "Warning - No Connection to Server";
|
sdData.alarmPhrase = "Warning - No Connection to Server";
|
||||||
Log.v(TAG,"doInBackground(): IOException - "+e.toString());
|
Log.v(TAG,"doInBackground(): IOException - "+e.toString());
|
||||||
|
|||||||
@@ -37,11 +37,6 @@ import android.widget.Toast;
|
|||||||
import com.getpebble.android.kit.PebbleKit;
|
import com.getpebble.android.kit.PebbleKit;
|
||||||
import com.getpebble.android.kit.util.PebbleDictionary;
|
import com.getpebble.android.kit.util.PebbleDictionary;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
import java.nio.IntBuffer;
|
import java.nio.IntBuffer;
|
||||||
@@ -679,8 +674,8 @@ public class SdDataSourcePebble extends SdDataSource {
|
|||||||
tdiff = (tnow.toMillis(false) - mPebbleStatusTime.toMillis(false));
|
tdiff = (tnow.toMillis(false) - mPebbleStatusTime.toMillis(false));
|
||||||
Log.v(TAG, "getStatus() - 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.watchConnected = PebbleKit.isWatchConnected(mContext);
|
||||||
if (!mSdData.pebbleConnected) mPebbleAppRunningCheck = false;
|
if (!mSdData.watchConnected) mPebbleAppRunningCheck = false;
|
||||||
// And is the pebble_sd app running?
|
// And is the pebble_sd app running?
|
||||||
// set mPebbleAppRunningCheck has been false for more than 10 seconds
|
// set mPebbleAppRunningCheck has been false for more than 10 seconds
|
||||||
// the app is not talking to us
|
// the app is not talking to us
|
||||||
@@ -688,7 +683,7 @@ public class SdDataSourcePebble extends SdDataSource {
|
|||||||
if (!mPebbleAppRunningCheck &&
|
if (!mPebbleAppRunningCheck &&
|
||||||
(tdiff > (mDataUpdatePeriod + mAppRestartTimeout) * 1000)) {
|
(tdiff > (mDataUpdatePeriod + mAppRestartTimeout) * 1000)) {
|
||||||
Log.v(TAG, "getStatus() - tdiff = " + tdiff);
|
Log.v(TAG, "getStatus() - tdiff = " + tdiff);
|
||||||
mSdData.pebbleAppRunning = false;
|
mSdData.watchAppRunning = false;
|
||||||
//Log.v(TAG, "getStatus() - Pebble App Not Running - Attempting to Re-Start");
|
//Log.v(TAG, "getStatus() - Pebble App Not Running - Attempting to Re-Start");
|
||||||
//mUtil.writeToSysLogFile("SdDataSourcePebble.getStatus() - Pebble App not Running - Attempting to Re-Start");
|
//mUtil.writeToSysLogFile("SdDataSourcePebble.getStatus() - Pebble App not Running - Attempting to Re-Start");
|
||||||
//startWatchApp();
|
//startWatchApp();
|
||||||
@@ -705,7 +700,7 @@ public class SdDataSourcePebble extends SdDataSource {
|
|||||||
Log.v(TAG, "getStatus() - Waiting for mFaultTimerPeriod before issuing audible warning...");
|
Log.v(TAG, "getStatus() - Waiting for mFaultTimerPeriod before issuing audible warning...");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mSdData.pebbleAppRunning = true;
|
mSdData.watchAppRunning = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we have confirmation that the app is running, reset the
|
// if we have confirmation that the app is running, reset the
|
||||||
|
|||||||
@@ -629,7 +629,7 @@ public class SdServer extends Service implements SdDataReceiver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fault
|
// Fault
|
||||||
if ((sdData.alarmState) == 4 || (sdData.alarmState == 7)) {
|
if ((sdData.alarmState) == 4 || (sdData.alarmState == 7) || (sdData.mHRFaultStanding)) {
|
||||||
sdData.alarmPhrase = "FAULT";
|
sdData.alarmPhrase = "FAULT";
|
||||||
writeAlarmToSD();
|
writeAlarmToSD();
|
||||||
faultWarningBeep();
|
faultWarningBeep();
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ public class SdServiceConnection implements ServiceConnection {
|
|||||||
public boolean pebbleConnected() {
|
public boolean pebbleConnected() {
|
||||||
if (mSdServer!=null) {
|
if (mSdServer!=null) {
|
||||||
if (mSdServer.mSdData!=null) {
|
if (mSdServer.mSdData!=null) {
|
||||||
if (mSdServer.mSdData.pebbleConnected) {
|
if (mSdServer.mSdData.watchConnected) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -116,7 +116,7 @@ public class SdServiceConnection implements ServiceConnection {
|
|||||||
public boolean pebbleAppRunning() {
|
public boolean pebbleAppRunning() {
|
||||||
if (mSdServer!=null) {
|
if (mSdServer!=null) {
|
||||||
if (mSdServer.mSdData!=null) {
|
if (mSdServer.mSdData!=null) {
|
||||||
if (mSdServer.mSdData.pebbleAppRunning) {
|
if (mSdServer.mSdData.watchAppRunning) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -340,7 +340,7 @@ public class StartupActivity extends Activity {
|
|||||||
// Is Pebble Watch App Running?
|
// Is Pebble Watch App Running?
|
||||||
tv = (TextView) findViewById(R.id.textItem4);
|
tv = (TextView) findViewById(R.id.textItem4);
|
||||||
pb = (ProgressBar) findViewById(R.id.progressBar4);
|
pb = (ProgressBar) findViewById(R.id.progressBar4);
|
||||||
if (mConnection.pebbleAppRunning()) {
|
if (mConnection.watchAppRunning()) {
|
||||||
tv.setText("Watch App Running OK");
|
tv.setText("Watch App Running OK");
|
||||||
tv.setBackgroundColor(okColour);
|
tv.setBackgroundColor(okColour);
|
||||||
tv.setTextColor(okTextColour);
|
tv.setTextColor(okTextColour);
|
||||||
@@ -506,6 +506,7 @@ public class StartupActivity extends Activity {
|
|||||||
+ "\n V3.1.5 - Added repeat alarm beeps during SMS delay to alert user.."
|
+ "\n V3.1.5 - Added repeat alarm beeps during SMS delay to alert user.."
|
||||||
+ "\n V3.1.6 - Made Cancel Audible button inhibit sending SMS alarms as well as audible beeps"
|
+ "\n V3.1.6 - Made Cancel Audible button inhibit sending SMS alarms as well as audible beeps"
|
||||||
+ "\n V3.1.8 - Added READ_PHONE_STATE permission, which seems to be needed for some phones"
|
+ "\n V3.1.8 - Added READ_PHONE_STATE permission, which seems to be needed for some phones"
|
||||||
|
+ "\n V3.1.9 - Fixed issue with Garmin Seizure Detector not producing warnings. Added faut pips for missing heart rate data if heart rate alarm active"
|
||||||
);
|
);
|
||||||
// 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);
|
||||||
@@ -540,6 +541,7 @@ public class StartupActivity extends Activity {
|
|||||||
+ "\n V3.1.5 - Added repeat alarm beeps during SMS delay to alert user.."
|
+ "\n V3.1.5 - Added repeat alarm beeps during SMS delay to alert user.."
|
||||||
+ "\n V3.1.6 - Made Cancel Audible button inhibit sending SMS alarms as well as audible beeps"
|
+ "\n V3.1.6 - Made Cancel Audible button inhibit sending SMS alarms as well as audible beeps"
|
||||||
+ "\n V3.1.8 - Added READ_PHONE_STATE permission, which seems to be needed for some phones"
|
+ "\n V3.1.8 - Added READ_PHONE_STATE permission, which seems to be needed for some phones"
|
||||||
|
+ "\n V3.1.9 - Fixed issue with Garmin Seizure Detector not producing warnings. Added faut pips for missing heart rate data if heart rate alarm active"
|
||||||
+ "\n "
|
+ "\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...
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
package uk.org.openseizuredetector;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.util.EventLog;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
|
||||||
import android.test.mock.MockContext;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.mockito.internal.exceptions.ExceptionIncludingMockitoWarnings;
|
|
||||||
|
|
||||||
import uk.org.openseizuredetector.EventLogManager.EventLogManager;
|
|
||||||
import uk.org.openseizuredetector.EventLogManager.LogEntryModel;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by graham on 12/05/16.
|
|
||||||
*/
|
|
||||||
public class EventLogManagerTest extends TestCase {
|
|
||||||
private final static String TAG = "EventLogManagerTest";
|
|
||||||
Context mContext;
|
|
||||||
|
|
||||||
protected void setUp() throws Exception {
|
|
||||||
super.setUp();
|
|
||||||
Log.v(TAG,"setUp()");
|
|
||||||
mContext = new MockContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testOpenDb() throws Exception {
|
|
||||||
Log.v(TAG,"testOpenDb()");
|
|
||||||
EventLogManager em = new EventLogManager(mContext);
|
|
||||||
assertNotNull(em);
|
|
||||||
|
|
||||||
|
|
||||||
LogEntryModel lem = new LogEntryModel();
|
|
||||||
//lem.setDate(new Date());
|
|
||||||
lem.setNote("Test Entry");
|
|
||||||
lem.setDataJSON("[]");
|
|
||||||
lem.setAlarmState(1);
|
|
||||||
|
|
||||||
em.addRow(lem);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package uk.org.openseizuredetector;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
public class SdAnalyserTest {
|
||||||
|
public SdAnalyser sda;
|
||||||
|
|
||||||
|
public String alarmJSON = "{ dataType: 'raw', " +
|
||||||
|
"data: [" +
|
||||||
|
"1644, 1316, 1144, 1332, 1716, 1716, 1392, 1148, 1276, 1660, " +
|
||||||
|
"1716, 1496, 1196, 1232, 1572, 1684, 1552, 1236, 1228, 1528, " +
|
||||||
|
"1648, 1572, 1268, 1208, 1492, 1680, 1596, 1272, 1192, 1424, " +
|
||||||
|
"1668, 1636, 1300, 1200, 1356, 1652, 1684, 1420, 1208, 1304, " +
|
||||||
|
"1620, 1672, 1448, 1232, 1248, 1536, 1676, 1540, 1256, 1244, " +
|
||||||
|
"1544, 1644, 1512, 1252, 1236, 1504, 1684, 1540, 1252, 1200, " +
|
||||||
|
"1436, 1664, 1624, 1344, 1204, 1396, 1616, 1596, 1344, 1216, " +
|
||||||
|
"1368, 1648, 1660, 1388, 1220, 1316, 1588, 1672, 1460, 1232, " +
|
||||||
|
"1256, 1580, 1672, 1500, 1256, 1288, 1540, 1688, 1516, 1252, " +
|
||||||
|
"1212, 1464, 1684, 1584, 1288, 1224, 1468, 1692, 1616, 1316, " +
|
||||||
|
"1188, 1360, 1680, 1724, 1424, 1192, 1224, 1556, 1744, 1588, " +
|
||||||
|
"1260, 1220, 1472, 1692, 1608, 1328, 1192, 1412, 1668, 1656, " +
|
||||||
|
"1356, 1216, 1304, 1636, 1712], " +
|
||||||
|
"HR:54, " +
|
||||||
|
"Mute:0 " +
|
||||||
|
"}";
|
||||||
|
|
||||||
|
private String okJSON = "{ " +
|
||||||
|
"dataType: 'raw', " +
|
||||||
|
"data: [" +
|
||||||
|
"1140, 1188, 1144, 1172, 1228, 1212, 1236, 1236, 1256, 1320, " +
|
||||||
|
"1316, 1280, 1240, 1280, 1324, 1284, 1292, 1268, 1284, 1276, " +
|
||||||
|
"1296, 1324, 1308, 1288, 1304, 1276, 1304, 1304, 1276, 1296, " +
|
||||||
|
"1280, 1284, 1296, 1300, 1284, 1288, 1296, 1284, 1300, 1280, " +
|
||||||
|
"1300, 1292, 1276, 1304, 1276, 1316, 1280, 1288, 1296, 1280, " +
|
||||||
|
"1284, 1272, 1300, 1284, 1288, 1292, 1276, 1296, 1276, 1292, " +
|
||||||
|
"1280, 1284, 1284, 1284, 1284, 1284, 1288, 1284, 1304, 1284, " +
|
||||||
|
"1288, 1280, 1296, 1284, 1292, 1296, 1280, 1276, 1288, 1296, " +
|
||||||
|
"1276, 1292, 1288, 1276, 1288, 1276, 1272, 1272, 1292, 1284, " +
|
||||||
|
"1292, 1288, 1280, 1284, 1284, 1268, 1288, 1268, 1276, 1300, " +
|
||||||
|
"1268, 1292, 1292, 1304, 1288, 1284, 1280, 1276, 1288, 1280, " +
|
||||||
|
"1300, 1288, 1320, 1268, 1288, 1280, 1304, 1280, 1280, 1288, " +
|
||||||
|
"1292, 1308, 1268, 1292, 1280], " +
|
||||||
|
"HR:57, " +
|
||||||
|
"Mute:0 " +
|
||||||
|
"}";
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
sda = new SdAnalyser(25.0,
|
||||||
|
3.0,
|
||||||
|
8.0,
|
||||||
|
5.0,
|
||||||
|
5.0,
|
||||||
|
100.0,
|
||||||
|
54.0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void freq2fftBin() {
|
||||||
|
int n;
|
||||||
|
n = sda.freq2fftBin(0.0);
|
||||||
|
assertEquals(0,n);
|
||||||
|
n = sda.freq2fftBin(5.0);
|
||||||
|
assertEquals(25,n);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getMagnitude() {
|
||||||
|
double[] fft = {1, 1,
|
||||||
|
2, 1,
|
||||||
|
2, 2};
|
||||||
|
double m;
|
||||||
|
m = sda.getMagnitude(fft,0);
|
||||||
|
assertEquals(2.0, m, m * 1e-4);
|
||||||
|
m = sda.getMagnitude(fft,1);
|
||||||
|
assertEquals(5.0, m, m * 1e-4);
|
||||||
|
m = sda.getMagnitude(fft,2);
|
||||||
|
assertEquals(8.0, m, m * 1e-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -9,7 +9,7 @@ buildscript {
|
|||||||
google()
|
google()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.4.0'
|
classpath 'com.android.tools.build:gradle:3.4.1'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
allprojects {
|
allprojects {
|
||||||
|
|||||||
Reference in New Issue
Block a user