Added adaptive and average heart rate data to SdData so that it is logged to the data sharing database.

This commit is contained in:
Graham Jones
2023-06-16 21:56:36 +01:00
parent 968f1bf883
commit 30dd421e7e
8 changed files with 125 additions and 22 deletions

View File

@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:versionCode="121" android:versionCode="122"
android:versionName="4.1.7"> android:versionName="4.1.8">
<!-- android:allowBackup="false" --> <!-- android:allowBackup="false" -->
<uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

View File

@@ -651,10 +651,16 @@ 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) {
if (mConnection.mSdServer.mSdData.mO2Sat > 0) { if (mConnection.mSdServer.mSdData.mO2Sat > 0) {
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"
+ getString(R.string.SpO2)+" = " + mConnection.mSdServer.mSdData.mO2Sat + "%"); +"(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 { } 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)+" = ---%"); + getString(R.string.SpO2)+" = ---%");
} }
if (mConnection.mSdServer.mSdData.mHRAlarmStanding || mConnection.mSdServer.mSdData.mO2SatAlarmStanding) { if (mConnection.mSdServer.mSdData.mHRAlarmStanding || mConnection.mSdServer.mSdData.mO2SatAlarmStanding) {

View File

@@ -111,11 +111,36 @@ public class SdAlgHr {
return(retVal); 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) { private boolean checkAdaptiveHr(double hrVal) {
boolean retVal; boolean retVal;
double hrThreshMin; double hrThreshMin;
double hrThreshMax; double hrThreshMax;
double avHr = mAdaptiveHrBuff.getAverageVal(); double avHr = getAdaptiveHrAverage();
hrThreshMin = avHr - mAdaptiveHrAlarmThresh; hrThreshMin = avHr - mAdaptiveHrAlarmThresh;
hrThreshMax = avHr + mAdaptiveHrAlarmThresh; hrThreshMax = avHr + mAdaptiveHrAlarmThresh;
@@ -133,7 +158,7 @@ public class SdAlgHr {
private boolean checkAverageHr(double hrVal) { private boolean checkAverageHr(double hrVal) {
boolean retVal; boolean retVal;
double avHr = mAdaptiveHrBuff.getAverageVal(); double avHr = getAverageHrAverage();
retVal = false; retVal = false;
if (hrVal < mAverageHrAlarmThreshMin) { if (hrVal < mAverageHrAlarmThreshMin) {

View File

@@ -87,6 +87,18 @@ public class SdData implements Parcelable {
public double rawData[]; public double rawData[];
public double rawData3D[]; 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; int mNsamp = 0;
/* Analysis results */ /* Analysis results */
@@ -106,8 +118,8 @@ public class SdData implements Parcelable {
public boolean mHRAlarmStanding = false; public boolean mHRAlarmStanding = false;
public boolean mHRFaultStanding = false; public boolean mHRFaultStanding = false;
public boolean mAdaptiveHRAlarmStanding = false; public boolean mAdaptiveHrAlarmStanding = false;
public boolean mAverageHRAlarmStanding = false; public boolean mAverageHrAlarmStanding = false;
public double mHR = 0; public double mHR = 0;
public boolean mO2SatAlarmStanding = false; public boolean mO2SatAlarmStanding = false;
@@ -210,6 +222,8 @@ public class SdData implements Parcelable {
jsonObj.put("alarmState", alarmState); jsonObj.put("alarmState", alarmState);
jsonObj.put("alarmPhrase", alarmPhrase); jsonObj.put("alarmPhrase", alarmPhrase);
jsonObj.put("hr", mHR); jsonObj.put("hr", mHR);
jsonObj.put("adaptiveHrAv", mAdaptiveHrAverage);
jsonObj.put("averageHrAv", mAverageHrAverage);
jsonObj.put("o2Sat", mO2Sat); jsonObj.put("o2Sat", mO2Sat);
jsonObj.put("pSeizure", mPseizure); jsonObj.put("pSeizure", mPseizure);
JSONArray arr = new JSONArray(); JSONArray arr = new JSONArray();
@@ -269,6 +283,15 @@ public class SdData implements Parcelable {
jsonObj.put("hrAlarmStanding", mHRAlarmStanding); jsonObj.put("hrAlarmStanding", mHRAlarmStanding);
jsonObj.put("hrThreshMin", mHRThreshMin); jsonObj.put("hrThreshMin", mHRThreshMin);
jsonObj.put("hrThreshMax", mHRThreshMax); 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("o2SatAlarmActive", mO2SatAlarmActive);
jsonObj.put("o2SatAlarmStanding", mO2SatAlarmStanding); jsonObj.put("o2SatAlarmStanding", mO2SatAlarmStanding);
jsonObj.put("o2SatThreshMin", mO2SatThreshMin); jsonObj.put("o2SatThreshMin", mO2SatThreshMin);
@@ -320,8 +343,8 @@ public class SdData implements Parcelable {
jsonObj.put("alarmRatioThresh", alarmRatioThresh); jsonObj.put("alarmRatioThresh", alarmRatioThresh);
jsonObj.put("hrAlarmActive", mHRAlarmActive); jsonObj.put("hrAlarmActive", mHRAlarmActive);
jsonObj.put("hrAlarmStanding", mHRAlarmStanding); jsonObj.put("hrAlarmStanding", mHRAlarmStanding);
jsonObj.put("adaptiveHrAlarmStanding", mAdaptiveHRAlarmStanding); jsonObj.put("adaptiveHrAlarmStanding", mAdaptiveHrAlarmStanding);
jsonObj.put("averageHrAlarmStanding", mAverageHRAlarmStanding); jsonObj.put("averageHrAlarmStanding", mAverageHrAlarmStanding);
jsonObj.put("hrAlarmStanding", mHRAlarmStanding); jsonObj.put("hrAlarmStanding", mHRAlarmStanding);
jsonObj.put("hrThreshMin", mHRThreshMin); jsonObj.put("hrThreshMin", mHRThreshMin);
jsonObj.put("hrThreshMax", mHRThreshMax); jsonObj.put("hrThreshMax", mHRThreshMax);

View File

@@ -592,6 +592,13 @@ public abstract class SdDataSource {
Log.v(TAG, "hrCheck()"); Log.v(TAG, "hrCheck()");
ArrayList<Boolean> checkResults; ArrayList<Boolean> checkResults;
checkResults = mSdAlgHr.checkHr(mSdData.mHR); 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 */ /* Check for heart rate fault condition */
if (mSdData.mHRAlarmActive) { if (mSdData.mHRAlarmActive) {
if (mSdData.mHR < 0) { if (mSdData.mHR < 0) {
@@ -599,30 +606,30 @@ public abstract class SdDataSource {
Log.i(TAG, "Heart Rate Null - Alarming"); Log.i(TAG, "Heart Rate Null - Alarming");
mSdData.mHRFaultStanding = false; mSdData.mHRFaultStanding = false;
mSdData.mHRAlarmStanding = true; mSdData.mHRAlarmStanding = true;
mSdData.mAdaptiveHRAlarmStanding = false; mSdData.mAdaptiveHrAlarmStanding = false;
mSdData.mAverageHRAlarmStanding = false; mSdData.mAverageHrAlarmStanding = false;
} else { } else {
Log.i(TAG, "Heart Rate Fault (HR<0)"); Log.i(TAG, "Heart Rate Fault (HR<0)");
mSdData.mHRFaultStanding = true; mSdData.mHRFaultStanding = true;
mSdData.mHRAlarmStanding = false; mSdData.mHRAlarmStanding = false;
mSdData.mAdaptiveHRAlarmStanding = false; mSdData.mAdaptiveHrAlarmStanding = false;
mSdData.mAverageHRAlarmStanding = false; mSdData.mAverageHrAlarmStanding = false;
} }
} else { } else {
mSdData.mHRFaultStanding = false; mSdData.mHRFaultStanding = false;
mSdData.mHRAlarmStanding = checkResults.get(0); mSdData.mHRAlarmStanding = checkResults.get(0);
mSdData.mAdaptiveHRAlarmStanding = checkResults.get(1); mSdData.mAdaptiveHrAlarmStanding = checkResults.get(1);
mSdData.mAverageHRAlarmStanding = checkResults.get(2); mSdData.mAverageHrAlarmStanding = checkResults.get(2);
// Show an ALARM state if any of the HR alarms is standing. // 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; mSdData.alarmState = 2;
} }
} }
} else { } else {
mSdData.mHRFaultStanding = false; mSdData.mHRFaultStanding = false;
mSdData.mHRAlarmStanding = false; mSdData.mHRAlarmStanding = false;
mSdData.mAdaptiveHRAlarmStanding = false; mSdData.mAdaptiveHrAlarmStanding = false;
mSdData.mAverageHRAlarmStanding = 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 * updatePrefs() - update basic settings from the SharedPreferences
* - defined in res/xml/SdDataSourceNetworkPassivePrefs.xml * - defined in res/xml/SdDataSourceNetworkPassivePrefs.xml
@@ -952,6 +981,23 @@ public abstract class SdDataSource {
Log.v(TAG, "updatePrefs() HRThreshMax = " + mSdData.mHRThreshMax); Log.v(TAG, "updatePrefs() HRThreshMax = " + mSdData.mHRThreshMax);
mUtil.writeToSysLogFile( "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); mSdData.mO2SatAlarmActive = SP.getBoolean("O2SatAlarmActive", false);
Log.v(TAG, "updatePrefs() O2SatAlarmActive = " + mSdData.mO2SatAlarmActive); Log.v(TAG, "updatePrefs() O2SatAlarmActive = " + mSdData.mO2SatAlarmActive);
mUtil.writeToSysLogFile( "updatePrefs() O2SatAlarmActive = " + mSdData.mO2SatAlarmActive); mUtil.writeToSysLogFile( "updatePrefs() O2SatAlarmActive = " + mSdData.mO2SatAlarmActive);

View File

@@ -10,7 +10,7 @@ buildscript {
mavenCentral() mavenCentral()
} }
dependencies { 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' classpath 'com.google.gms:google-services:4.3.15'
} }
} }

View File

@@ -14,3 +14,6 @@
org.gradle.jvmargs=-Xmx1536M -Dkotlin.daemon.jvm.options\="-Xmx1536M" org.gradle.jvmargs=-Xmx1536M -Dkotlin.daemon.jvm.options\="-Xmx1536M"
android.enableJetifier=true android.enableJetifier=true
android.useAndroidX=true android.useAndroidX=true
android.defaults.buildfeatures.buildconfig=true
android.nonTransitiveRClass=false
android.nonFinalResIds=false

View File

@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists 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