From 3e61397eb520148092390ba9a2391bb8ac44bda2 Mon Sep 17 00:00:00 2001 From: Graham Jones Date: Fri, 16 Jun 2023 21:56:36 +0100 Subject: [PATCH] Added adaptive and average heart rate data to SdData so that it is logged to the data sharing database. --- app/src/main/AndroidManifest.xml | 4 +- .../org/openseizuredetector/MainActivity.java | 12 +++- .../uk/org/openseizuredetector/SdAlgHr.java | 29 ++++++++- .../uk/org/openseizuredetector/SdData.java | 33 ++++++++-- .../org/openseizuredetector/SdDataSource.java | 64 ++++++++++++++++--- .../org/openseizuredetector/SdWebServer.java | 4 +- build.gradle | 2 +- gradle.properties | 3 + gradle/wrapper/gradle-wrapper.properties | 2 +- 9 files changed, 130 insertions(+), 23 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 8ca1e0c..482a97c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionCode="122" + android:versionName="4.1.8"> diff --git a/app/src/main/java/uk/org/openseizuredetector/MainActivity.java b/app/src/main/java/uk/org/openseizuredetector/MainActivity.java index ba6132e..1f22dd9 100644 --- a/app/src/main/java/uk/org/openseizuredetector/MainActivity.java +++ b/app/src/main/java/uk/org/openseizuredetector/MainActivity.java @@ -651,10 +651,16 @@ public class MainActivity extends AppCompatActivity { tv = (TextView) findViewById(R.id.pebbleTv); //if (mConnection.mSdServer.mSdData.mHRAlarmActive) { if (mConnection.mSdServer.mSdData.mO2Sat > 0) { - tv.setText(getString(R.string.HR_Equals) + mConnection.mSdServer.mSdData.mHR + " bpm\n" - + getString(R.string.SpO2)+" = " + mConnection.mSdServer.mSdData.mO2Sat + "%"); + tv.setText(getString(R.string.HR_Equals) + Math.round(mConnection.mSdServer.mSdData.mHR) + " bpm\n" + +"(av=" + +Math.round(mConnection.mSdServer.mSdData.mAdaptiveHrAverage)+"," + +Math.round(mConnection.mSdServer.mSdData.mAverageHrAverage)+") bpm\n" + + getString(R.string.SpO2)+" = " + Math.round(mConnection.mSdServer.mSdData.mO2Sat) + "%"); } else { - tv.setText(getString(R.string.HR_Equals) + mConnection.mSdServer.mSdData.mHR + " bpm\n" + tv.setText(getString(R.string.HR_Equals) + Math.round(mConnection.mSdServer.mSdData.mHR) + " bpm\n" + +"(av=" + +Math.round(mConnection.mSdServer.mSdData.mAdaptiveHrAverage)+"," + +Math.round(mConnection.mSdServer.mSdData.mAverageHrAverage)+") bpm\n" + getString(R.string.SpO2)+" = ---%"); } if (mConnection.mSdServer.mSdData.mHRAlarmStanding || mConnection.mSdServer.mSdData.mO2SatAlarmStanding) { diff --git a/app/src/main/java/uk/org/openseizuredetector/SdAlgHr.java b/app/src/main/java/uk/org/openseizuredetector/SdAlgHr.java index 8edf04f..819e908 100644 --- a/app/src/main/java/uk/org/openseizuredetector/SdAlgHr.java +++ b/app/src/main/java/uk/org/openseizuredetector/SdAlgHr.java @@ -111,11 +111,36 @@ public class SdAlgHr { return(retVal); } + /** + * Returns the average heart rate being used by the Adaptive heart rate algorithm + * @return Average Heart reate in bpm. + */ + public double getAdaptiveHrAverage() { + return mAdaptiveHrBuff.getAverageVal(); + } + + public CircBuf getAverageHrBuff() { + return mAverageHrBuff; + } + + public CircBuf getAdaptiveHrBuff() { + return mAdaptiveHrBuff; + } + + /** + * Returns the average heart rate being used by the Average heart rate algorithm + * @return Average Heart rate in bpm. + */ + public double getAverageHrAverage() { + return mAverageHrBuff.getAverageVal(); + } + + private boolean checkAdaptiveHr(double hrVal) { boolean retVal; double hrThreshMin; double hrThreshMax; - double avHr = mAdaptiveHrBuff.getAverageVal(); + double avHr = getAdaptiveHrAverage(); hrThreshMin = avHr - mAdaptiveHrAlarmThresh; hrThreshMax = avHr + mAdaptiveHrAlarmThresh; @@ -133,7 +158,7 @@ public class SdAlgHr { private boolean checkAverageHr(double hrVal) { boolean retVal; - double avHr = mAdaptiveHrBuff.getAverageVal(); + double avHr = getAverageHrAverage(); retVal = false; if (hrVal < mAverageHrAlarmThreshMin) { diff --git a/app/src/main/java/uk/org/openseizuredetector/SdData.java b/app/src/main/java/uk/org/openseizuredetector/SdData.java index 413b2e3..420ca52 100644 --- a/app/src/main/java/uk/org/openseizuredetector/SdData.java +++ b/app/src/main/java/uk/org/openseizuredetector/SdData.java @@ -87,6 +87,18 @@ public class SdData implements Parcelable { public double rawData[]; public double rawData3D[]; + public boolean mAdaptiveHrAlarmActive; + public double mAdaptiveHrAlarmWindowSecs; + public double mAdaptiveHrAlarmThresh; + public boolean mAverageHrAlarmActive; + public double mAverageHrAlarmWindowSecs; + public double mAverageHrAlarmThreshMin; + public double mAverageHrAlarmThreshMax; + public double mAverageHrAverage; + public double mAdaptiveHrAverage; + + public CircBuf mAdaptiveHrBuf; + public CircBuf mAverageHrBuf; int mNsamp = 0; /* Analysis results */ @@ -106,8 +118,8 @@ public class SdData implements Parcelable { public boolean mHRAlarmStanding = false; public boolean mHRFaultStanding = false; - public boolean mAdaptiveHRAlarmStanding = false; - public boolean mAverageHRAlarmStanding = false; + public boolean mAdaptiveHrAlarmStanding = false; + public boolean mAverageHrAlarmStanding = false; public double mHR = 0; public boolean mO2SatAlarmStanding = false; @@ -210,6 +222,8 @@ public class SdData implements Parcelable { jsonObj.put("alarmState", alarmState); jsonObj.put("alarmPhrase", alarmPhrase); jsonObj.put("hr", mHR); + jsonObj.put("adaptiveHrAv", mAdaptiveHrAverage); + jsonObj.put("averageHrAv", mAverageHrAverage); jsonObj.put("o2Sat", mO2Sat); jsonObj.put("pSeizure", mPseizure); JSONArray arr = new JSONArray(); @@ -269,6 +283,15 @@ public class SdData implements Parcelable { jsonObj.put("hrAlarmStanding", mHRAlarmStanding); jsonObj.put("hrThreshMin", mHRThreshMin); jsonObj.put("hrThreshMax", mHRThreshMax); + jsonObj.put("adaptiveHrAlarmActive", mAdaptiveHrAlarmActive); + jsonObj.put("adaptiveHrAlarmStanding", mAdaptiveHrAlarmStanding); + jsonObj.put("adaptiveHrAlarmWindow", mAdaptiveHrAlarmWindowSecs); + jsonObj.put("adaptiveHrAlarmThresh", mAdaptiveHrAlarmThresh); + jsonObj.put("averageHrAlarmActive", mAverageHrAlarmActive); + jsonObj.put("averageHrAlarmStanding", mAverageHrAlarmStanding); + jsonObj.put("averageHrAlarmThreshMin", mAverageHrAlarmThreshMin); + jsonObj.put("averageHrAlarmThreshMax", mAverageHrAlarmThreshMax); + jsonObj.put("o2SatAlarmActive", mO2SatAlarmActive); jsonObj.put("o2SatAlarmStanding", mO2SatAlarmStanding); jsonObj.put("o2SatThreshMin", mO2SatThreshMin); @@ -320,12 +343,14 @@ public class SdData implements Parcelable { jsonObj.put("alarmRatioThresh", alarmRatioThresh); jsonObj.put("hrAlarmActive", mHRAlarmActive); jsonObj.put("hrAlarmStanding", mHRAlarmStanding); - jsonObj.put("adaptiveHrAlarmStanding", mAdaptiveHRAlarmStanding); - jsonObj.put("averageHrAlarmStanding", mAverageHRAlarmStanding); + jsonObj.put("adaptiveHrAlarmStanding", mAdaptiveHrAlarmStanding); + jsonObj.put("averageHrAlarmStanding", mAverageHrAlarmStanding); jsonObj.put("hrAlarmStanding", mHRAlarmStanding); jsonObj.put("hrThreshMin", mHRThreshMin); jsonObj.put("hrThreshMax", mHRThreshMax); jsonObj.put("hr", mHR); + jsonObj.put("adaptiveHrAv", mAdaptiveHrAverage); + jsonObj.put("averageHrAv", mAverageHrAverage); jsonObj.put("o2SatAlarmActive", mO2SatAlarmActive); jsonObj.put("o2SatAlarmStanding", mO2SatAlarmStanding); jsonObj.put("o2SatThreshMin", mO2SatThreshMin); diff --git a/app/src/main/java/uk/org/openseizuredetector/SdDataSource.java b/app/src/main/java/uk/org/openseizuredetector/SdDataSource.java index 34e0dbc..5173abd 100644 --- a/app/src/main/java/uk/org/openseizuredetector/SdDataSource.java +++ b/app/src/main/java/uk/org/openseizuredetector/SdDataSource.java @@ -592,6 +592,13 @@ public abstract class SdDataSource { Log.v(TAG, "hrCheck()"); ArrayList checkResults; checkResults = mSdAlgHr.checkHr(mSdData.mHR); + + // Populate mSdData so that the heart rate data is logged and is accessible to user interface components. + mSdData.mAdaptiveHrAverage = mSdAlgHr.getAdaptiveHrAverage(); + mSdData.mAverageHrAverage = mSdAlgHr.getAverageHrAverage(); + mSdData.mAdaptiveHrBuf = mSdAlgHr.getAdaptiveHrBuff(); + mSdData.mAverageHrBuf = mSdAlgHr.getAverageHrBuff(); + /* Check for heart rate fault condition */ if (mSdData.mHRAlarmActive) { if (mSdData.mHR < 0) { @@ -599,30 +606,30 @@ public abstract class SdDataSource { Log.i(TAG, "Heart Rate Null - Alarming"); mSdData.mHRFaultStanding = false; mSdData.mHRAlarmStanding = true; - mSdData.mAdaptiveHRAlarmStanding = false; - mSdData.mAverageHRAlarmStanding = false; + mSdData.mAdaptiveHrAlarmStanding = false; + mSdData.mAverageHrAlarmStanding = false; } else { Log.i(TAG, "Heart Rate Fault (HR<0)"); mSdData.mHRFaultStanding = true; mSdData.mHRAlarmStanding = false; - mSdData.mAdaptiveHRAlarmStanding = false; - mSdData.mAverageHRAlarmStanding = false; + mSdData.mAdaptiveHrAlarmStanding = false; + mSdData.mAverageHrAlarmStanding = false; } } else { mSdData.mHRFaultStanding = false; mSdData.mHRAlarmStanding = checkResults.get(0); - mSdData.mAdaptiveHRAlarmStanding = checkResults.get(1); - mSdData.mAverageHRAlarmStanding = checkResults.get(2); + mSdData.mAdaptiveHrAlarmStanding = checkResults.get(1); + mSdData.mAverageHrAlarmStanding = checkResults.get(2); // Show an ALARM state if any of the HR alarms is standing. - if (mSdData.mHRAlarmStanding | mSdData.mAdaptiveHRAlarmStanding | mSdData.mAverageHRAlarmStanding) { + if (mSdData.mHRAlarmStanding | mSdData.mAdaptiveHrAlarmStanding | mSdData.mAverageHrAlarmStanding) { mSdData.alarmState = 2; } } } else { mSdData.mHRFaultStanding = false; mSdData.mHRAlarmStanding = false; - mSdData.mAdaptiveHRAlarmStanding = false; - mSdData.mAverageHRAlarmStanding = false; + mSdData.mAdaptiveHrAlarmStanding = false; + mSdData.mAverageHrAlarmStanding = false; } } @@ -787,6 +794,28 @@ public abstract class SdDataSource { } } + /** + * Read a preference value, and return it as a double. + * FIXME - this should be in osdUtil so other classes can use it. + * + * @param SP - Shared Preferences object + * @param prefName - name of preference to read. + * @param defVal - default value if it is not stored. + * @return double value of the stored specified preference, or the default value. + */ + private double readDoublePref(SharedPreferences SP, String prefName, String defVal) { + String prefValStr; + double retVal = -1; + try { + prefValStr = SP.getString(prefName, defVal); + retVal = Double.parseDouble(prefValStr); + } catch (Exception ex) { + Log.v(TAG, "readDoublePref() - Problem with preference!"); + //mUtil.showToast(TAG+":"+mContext.getString(R.string.problem_parsing_preferences)); + } + return retVal; + } + /** * updatePrefs() - update basic settings from the SharedPreferences * - defined in res/xml/SdDataSourceNetworkPassivePrefs.xml @@ -952,6 +981,23 @@ public abstract class SdDataSource { Log.v(TAG, "updatePrefs() HRThreshMax = " + mSdData.mHRThreshMax); mUtil.writeToSysLogFile( "updatePrefs() HRThreshMax = " + mSdData.mHRThreshMax); + mSdData.mAdaptiveHrAlarmActive = SP.getBoolean("HRAdaptiveAlarmActive", false); + mSdData.mAdaptiveHrAlarmWindowSecs = readDoublePref(SP, "HRAdaptiveAlarmWindowSecs", "30"); + mSdData.mAdaptiveHrAlarmThresh = readDoublePref(SP, "HRAdaptiveAlarmThresh", "20"); + Log.d(TAG,"updatePrefs(): mAdaptiveHrAlarmActive="+mSdData.mAdaptiveHrAlarmActive); + Log.d(TAG,"updatePrefs(): mAdaptiveHrWindowSecs="+mSdData.mAdaptiveHrAlarmWindowSecs); + Log.d(TAG,"updatePrefs(): mAdaptiveHrAlarmThresh="+mSdData.mAdaptiveHrAlarmThresh); + + mSdData.mAverageHrAlarmActive = SP.getBoolean("HRAverageAlarmActive", false); + mSdData.mAverageHrAlarmWindowSecs = readDoublePref(SP, "HRAverageAlarmWindowSecs", "120"); + mSdData.mAverageHrAlarmThreshMin = readDoublePref(SP, "HRAverageAlarmThreshMin", "40"); + mSdData.mAverageHrAlarmThreshMax = readDoublePref(SP, "HRAverageAlarmThreshMax", "120"); + Log.d(TAG,"updatePrefs(): mAverageHrAlarmActive="+mSdData.mAverageHrAlarmActive); + Log.d(TAG,"updatePrefs(): mAverageHrAlarmWindowSecs="+mSdData.mAverageHrAlarmWindowSecs); + Log.d(TAG,"updatePrefs(): mAverageHrAlarmThreshMin="+mSdData.mAverageHrAlarmThreshMin); + Log.d(TAG,"updatePrefs(): mAverageHrAlarmThreshMax="+mSdData.mAverageHrAlarmThreshMax); + + mSdData.mO2SatAlarmActive = SP.getBoolean("O2SatAlarmActive", false); Log.v(TAG, "updatePrefs() O2SatAlarmActive = " + mSdData.mO2SatAlarmActive); mUtil.writeToSysLogFile( "updatePrefs() O2SatAlarmActive = " + mSdData.mO2SatAlarmActive); diff --git a/app/src/main/java/uk/org/openseizuredetector/SdWebServer.java b/app/src/main/java/uk/org/openseizuredetector/SdWebServer.java index eadebc1..720eac8 100644 --- a/app/src/main/java/uk/org/openseizuredetector/SdWebServer.java +++ b/app/src/main/java/uk/org/openseizuredetector/SdWebServer.java @@ -128,7 +128,7 @@ public class SdWebServer extends NanoHTTPD { case GET: //Log.v(TAG,"WebServer.serve() - Returning settings"); try { - JSONObject jsonObj = new JSONObject(); + /*JSONObject jsonObj = new JSONObject(); jsonObj.put("alarmFreqMin", mSdData.alarmFreqMin); jsonObj.put("alarmFreqMax", mSdData.alarmFreqMax); jsonObj.put("nMin", mSdData.nMin); @@ -139,6 +139,8 @@ public class SdWebServer extends NanoHTTPD { jsonObj.put("alarmRatioThresh", mSdData.alarmRatioThresh); jsonObj.put("batteryPc", mSdData.batteryPc); answer = jsonObj.toString(); + */ + answer = mSdData.toSettingsJSON(); } catch (Exception ex) { Log.v(TAG, "Error Creating Data Object - " + ex.toString()); answer = "{'msg': 'Error Creating Data Object'}"; diff --git a/build.gradle b/build.gradle index ea68539..fcf4b08 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:7.3.1' + classpath 'com.android.tools.build:gradle:8.0.2' classpath 'com.google.gms:google-services:4.3.15' } } diff --git a/gradle.properties b/gradle.properties index 0c43022..0af9548 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,3 +14,6 @@ org.gradle.jvmargs=-Xmx1536M -Dkotlin.daemon.jvm.options\="-Xmx1536M" android.enableJetifier=true android.useAndroidX=true +android.defaults.buildfeatures.buildconfig=true +android.nonTransitiveRClass=false +android.nonFinalResIds=false diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 6cfefbd..3f8e9a4 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip