V3.1.9 - quite a few changes - see Changelog.md

This commit is contained in:
Graham Jones
2019-06-22 11:41:58 +01:00
parent 54ce96aabb
commit 238b3c504f
16 changed files with 435 additions and 169 deletions

View File

@@ -63,8 +63,6 @@ import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.utils.ValueFormatter;
import com.rohitss.uceh.UCEHandler;
import static java.util.Objects.isNull;
public class MainActivity extends AppCompatActivity {
static final String TAG = "MainActivity";
private int okColour = Color.BLUE;
@@ -435,15 +433,18 @@ public class MainActivity extends AppCompatActivity {
tv = (TextView) findViewById(R.id.pebbleTv);
if (mConnection.mSdServer.mSdData.mHRAlarmActive) {
tv.setText("HR = " + mConnection.mSdServer.mSdData.mHR);
if (!mConnection.mSdServer.mSdData.mHRAlarmStanding) {
tv.setBackgroundColor(okColour);
tv.setTextColor(okTextColour);
} else {
if (mConnection.mSdServer.mSdData.mHRAlarmStanding) {
tv.setBackgroundColor(alarmColour);
tv.setTextColor(alarmTextColour);
} else if (mConnection.mSdServer.mSdData.mHRFaultStanding) {
tv.setBackgroundColor(warnColour);
tv.setTextColor(warnTextColour);
} else {
tv.setBackgroundColor(okColour);
tv.setTextColor(okTextColour);
}
} else {
if (mConnection.mSdServer.mSdData.pebbleConnected) {
if (mConnection.mSdServer.mSdData.watchConnected) {
tv.setText("HR Alarm OFF");
tv.setBackgroundColor(okColour);
tv.setTextColor(okTextColour);
@@ -455,7 +456,7 @@ public class MainActivity extends AppCompatActivity {
}
}
tv = (TextView) findViewById(R.id.appTv);
if (mConnection.mSdServer.mSdData.pebbleAppRunning) {
if (mConnection.mSdServer.mSdData.watchAppRunning) {
tv.setText("Watch App OK");
tv.setBackgroundColor(okColour);
tv.setTextColor(okTextColour);

View File

@@ -96,6 +96,7 @@ public class OsdUtil implements ActivityCompat.OnRequestPermissionsResultCallbac
private final String[] SMS_PERMISSIONS = {
Manifest.permission.SEND_SMS,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.READ_PHONE_STATE,
};

View 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);
}
}

View File

@@ -29,10 +29,6 @@ import android.os.Parcel;
import android.text.format.Time;
import android.util.Log;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
import org.json.JSONObject;
import org.json.JSONArray;
@@ -82,11 +78,12 @@ public class SdData implements Parcelable {
public long roiPower;
public String alarmPhrase;
public int simpleSpec[];
public boolean pebbleConnected = false;
public boolean pebbleAppRunning = false;
public boolean watchConnected = false;
public boolean watchAppRunning = false;
public boolean serverOK = false;
public boolean mHRAlarmStanding = false;
public boolean mHRFaultStanding = false;
public double mHR = 0;
public SdData() {
@@ -116,8 +113,8 @@ public class SdData implements Parcelable {
specPower = jo.optInt("specPower");
roiPower = jo.optInt("roiPower");
batteryPc = jo.optInt("batteryPc");
pebbleConnected = jo.optBoolean("pebbleConnected");
pebbleAppRunning = jo.optBoolean("pebbleAppRunning");
watchConnected = jo.optBoolean("watchConnected");
watchAppRunning = jo.optBoolean("watchAppRunning");
alarmState = jo.optInt("alarmState");
alarmPhrase = jo.optString("alarmPhrase");
alarmThresh = jo.optInt("alarmThresh");
@@ -159,8 +156,8 @@ public class SdData implements Parcelable {
jsonObj.put("specPower", specPower);
jsonObj.put("roiPower", roiPower);
jsonObj.put("batteryPc", batteryPc);
jsonObj.put("pebbleConnected", pebbleConnected);
jsonObj.put("pebbleAppRunning", pebbleAppRunning);
jsonObj.put("watchConnected", watchConnected);
jsonObj.put("watchAppRunning", watchAppRunning);
jsonObj.put("haveSettings", haveSettings);
jsonObj.put("alarmState", alarmState);
jsonObj.put("alarmPhrase", alarmPhrase);

View File

@@ -683,8 +683,8 @@ public class SdDataSourceAw extends SdDataSource {
tdiff = (tnow.toMillis(false) - mStatusTime.toMillis(false));
Log.v(TAG, "getStatus() - mWatchAppRunningCheck=" + mWatchAppRunningCheck + " tdiff=" + tdiff);
// Check we are actually connected to the pebble.
mSdData.pebbleConnected = PebbleKit.isWatchConnected(mContext);
if (!mSdData.pebbleConnected) mWatchAppRunningCheck = false;
mSdData.watchConnected = PebbleKit.isWatchConnected(mContext);
if (!mSdData.watchConnected) mWatchAppRunningCheck = false;
// And is the pebble_sd app running?
// set mWatchAppRunningCheck has been false for more than 10 seconds
// the app is not talking to us
@@ -692,7 +692,7 @@ public class SdDataSourceAw extends SdDataSource {
if (!mWatchAppRunningCheck &&
(tdiff > (mDataUpdatePeriod + mAppRestartTimeout) * 1000)) {
Log.v(TAG, "getStatus() - tdiff = " + tdiff);
mSdData.pebbleAppRunning = false;
mSdData.watchAppRunning = false;
//Log.v(TAG, "getStatus() - Pebble App Not Running - Attempting to Re-Start");
//mUtil.writeToSysLogFile("SdDataSourceAw.getStatus() - Pebble App not Running - Attempting to Re-Start");
//startWatchApp();
@@ -709,7 +709,7 @@ public class SdDataSourceAw extends SdDataSource {
Log.v(TAG, "getStatus() - Waiting for mFaultTimerPeriod before issuing audible warning...");
}
} else {
mSdData.pebbleAppRunning = true;
mSdData.watchAppRunning = true;
}
// if we have confirmation that the app is running, reset the

View File

@@ -28,32 +28,22 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.os.BatteryManager;
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 org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
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.Timer;
import java.util.TimerTask;
import java.util.UUID;
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 Timer mStatusTimer;
private Timer mSettingsTimer;
private Timer mAlarmCheckTimer;
private Timer mFaultCheckTimer;
private Time mDataStatusTime;
private boolean mWatchAppRunningCheck = false;
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.");
mUtil.writeToSysLogFile("SdDataSourceGarmin.start() - status timer already running??");
}
if (mAlarmCheckTimer == null) {
if (mFaultCheckTimer == null) {
Log.v(TAG, "start(): starting alarm check timer");
mUtil.writeToSysLogFile("SdDataSourceGarmin.start() - starting alarm check timer");
mAlarmCheckTimer = new Timer();
mAlarmCheckTimer.schedule(new TimerTask() {
mFaultCheckTimer = new Timer();
mFaultCheckTimer.schedule(new TimerTask() {
@Override
public void run() {
alarmCheck();
faultCheck();
}
}, 0, 1000);
} else {
@@ -206,12 +196,12 @@ public class SdDataSourceGarmin extends SdDataSource {
mSettingsTimer = null;
}
// Stop the alarm check timer
if (mAlarmCheckTimer != null) {
if (mFaultCheckTimer != null) {
Log.v(TAG, "stop(): cancelling alarm check timer");
mUtil.writeToSysLogFile("SdDataSourceGarmin.stop() - cancelling alarm check timer");
mAlarmCheckTimer.cancel();
mAlarmCheckTimer.purge();
mAlarmCheckTimer = null;
mFaultCheckTimer.cancel();
mFaultCheckTimer.purge();
mFaultCheckTimer = null;
}
} catch (Exception e) {
@@ -467,7 +457,10 @@ public class SdDataSourceGarmin extends SdDataSource {
fft[2*i+1] = 0.;
}
}
//Log.v(TAG,"specPower = "+specPower);
//specPower = specPower/(mSdData.mNsamp/2);
specPower = specPower/mSdData.mNsamp/2;
//Log.v(TAG,"specPower = "+specPower);
// Calculate the Region of Interest power and power ratio.
double roiPower = 0;
@@ -489,8 +482,6 @@ public class SdDataSourceGarmin extends SdDataSource {
simpleSpec[ifreq] = simpleSpec[ifreq] / (binMax-binMin);
}
checkFall();
// Populate the mSdData structure to communicate with the main SdServer service.
mDataStatusTime.setToNow();
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.
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.
}
/****************************************************************
* 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.
* Called from clock_tick_handler()
*/
public void checkFall() {
public void fallCheck() {
int i,j;
double minAcc, maxAcc;
@@ -575,7 +653,7 @@ public class SdDataSourceGarmin extends SdDataSource {
Log.v(TAG, "getStatus() - mWatchAppRunningCheck=" + mWatchAppRunningCheck + " tdiff=" + tdiff);
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?
// set mWatchAppRunningCheck has been false for more than 10 seconds
// the app is not talking to us
@@ -583,7 +661,7 @@ public class SdDataSourceGarmin extends SdDataSource {
if (!mWatchAppRunningCheck &&
(tdiff > (mDataUpdatePeriod + mAppRestartTimeout) * 1000)) {
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.
if (tdiff > (mDataUpdatePeriod + mFaultTimerPeriod) * 1000) {
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...");
}
} else {
mSdData.pebbleAppRunning = true;
mSdData.watchAppRunning = true;
}
// 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() {
boolean inAlarm;
private void faultCheck() {
Time tnow = new Time(Time.getCurrentTimezone());
long tdiff;
tnow.setToNow();
// get time since the last data was received from the watch.
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);
if (!mWatchAppRunningCheck &&
(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;
} 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;
}
}
}

View File

@@ -2,8 +2,6 @@ package uk.org.openseizuredetector;
import android.content.Context;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.AsyncTask;
import android.os.Handler;
import android.preference.PreferenceManager;
@@ -128,8 +126,8 @@ public class SdDataSourceNetwork extends SdDataSource {
if (result.startsWith("Unable to retrieve web page")) {
Log.v(TAG,"doInBackground() - Unable to retrieve data");
sdData.serverOK = false;
sdData.pebbleConnected = false;
sdData.pebbleAppRunning = false;
sdData.watchConnected = false;
sdData.watchAppRunning = false;
sdData.alarmState = ALARM_STATE_NETFAULT;
sdData.alarmPhrase = "Warning - No Connection to Server";
Log.v(TAG,"doInBackground(): No Connection to Server - sdData = "+sdData.toString());
@@ -147,8 +145,8 @@ public class SdDataSourceNetwork extends SdDataSource {
} catch (IOException e) {
sdData.serverOK = false;
sdData.pebbleConnected = false;
sdData.pebbleAppRunning = false;
sdData.watchConnected = false;
sdData.watchAppRunning = false;
sdData.alarmState = ALARM_STATE_NETFAULT;
sdData.alarmPhrase = "Warning - No Connection to Server";
Log.v(TAG,"doInBackground(): IOException - "+e.toString());

View File

@@ -37,11 +37,6 @@ 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;
@@ -679,8 +674,8 @@ public class SdDataSourcePebble extends SdDataSource {
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;
mSdData.watchConnected = PebbleKit.isWatchConnected(mContext);
if (!mSdData.watchConnected) 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
@@ -688,7 +683,7 @@ public class SdDataSourcePebble extends SdDataSource {
if (!mPebbleAppRunningCheck &&
(tdiff > (mDataUpdatePeriod + mAppRestartTimeout) * 1000)) {
Log.v(TAG, "getStatus() - tdiff = " + tdiff);
mSdData.pebbleAppRunning = false;
mSdData.watchAppRunning = false;
//Log.v(TAG, "getStatus() - Pebble App Not Running - Attempting to Re-Start");
//mUtil.writeToSysLogFile("SdDataSourcePebble.getStatus() - Pebble App not Running - Attempting to Re-Start");
//startWatchApp();
@@ -705,7 +700,7 @@ public class SdDataSourcePebble extends SdDataSource {
Log.v(TAG, "getStatus() - Waiting for mFaultTimerPeriod before issuing audible warning...");
}
} else {
mSdData.pebbleAppRunning = true;
mSdData.watchAppRunning = true;
}
// if we have confirmation that the app is running, reset the

View File

@@ -629,7 +629,7 @@ public class SdServer extends Service implements SdDataReceiver {
}
// Fault
if ((sdData.alarmState) == 4 || (sdData.alarmState == 7)) {
if ((sdData.alarmState) == 4 || (sdData.alarmState == 7) || (sdData.mHRFaultStanding)) {
sdData.alarmPhrase = "FAULT";
writeAlarmToSD();
faultWarningBeep();

View File

@@ -101,7 +101,7 @@ public class SdServiceConnection implements ServiceConnection {
public boolean pebbleConnected() {
if (mSdServer!=null) {
if (mSdServer.mSdData!=null) {
if (mSdServer.mSdData.pebbleConnected) {
if (mSdServer.mSdData.watchConnected) {
return true;
}
}
@@ -116,7 +116,7 @@ public class SdServiceConnection implements ServiceConnection {
public boolean pebbleAppRunning() {
if (mSdServer!=null) {
if (mSdServer.mSdData!=null) {
if (mSdServer.mSdData.pebbleAppRunning) {
if (mSdServer.mSdData.watchAppRunning) {
return true;
}
}

View File

@@ -340,7 +340,7 @@ public class StartupActivity extends Activity {
// Is Pebble Watch App Running?
tv = (TextView) findViewById(R.id.textItem4);
pb = (ProgressBar) findViewById(R.id.progressBar4);
if (mConnection.pebbleAppRunning()) {
if (mConnection.watchAppRunning()) {
tv.setText("Watch App Running OK");
tv.setBackgroundColor(okColour);
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.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.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...
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.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.9 - Fixed issue with Garmin Seizure Detector not producing warnings. Added faut pips for missing heart rate data if heart rate alarm active"
+ "\n "
);
// This makes the links display as links, but they do not respond to clicks for some reason...