diff --git a/mobile/build.gradle b/mobile/build.gradle index a850adb..ee12ffe 100644 --- a/mobile/build.gradle +++ b/mobile/build.gradle @@ -11,8 +11,8 @@ android { applicationId "com.example.samplewearmobileapp" minSdk 28 targetSdk 33 - versionCode 1 - versionName "1.0" + versionCode 2 + versionName "1.1" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/mobile/src/main/java/com/example/samplewearmobileapp/Constants.kt b/mobile/src/main/java/com/example/samplewearmobileapp/Constants.kt index b8421ad..8fa924a 100644 --- a/mobile/src/main/java/com/example/samplewearmobileapp/Constants.kt +++ b/mobile/src/main/java/com/example/samplewearmobileapp/Constants.kt @@ -145,10 +145,15 @@ object Constants { const val MICRO_TO_MILLI_VOLT = .001 /** - * Convert millisecond to seconds. + * Convert milliseconds to seconds. */ const val MS_TO_SEC = .001 + /** + * Convert nanoseconds to milliseconds. + */ + const val NANO_TO_MICRO_SEC = .000001 + /** * Filter coefficients for Butterworth fs=130 low_cutoff=5 high_cutoff=20 */ diff --git a/mobile/src/main/java/com/example/samplewearmobileapp/EcgPlotter.kt b/mobile/src/main/java/com/example/samplewearmobileapp/EcgPlotter.kt index 50140c2..2a2829b 100644 --- a/mobile/src/main/java/com/example/samplewearmobileapp/EcgPlotter.kt +++ b/mobile/src/main/java/com/example/samplewearmobileapp/EcgPlotter.kt @@ -5,6 +5,7 @@ import android.util.Log import com.androidplot.util.PixelUtils import com.androidplot.xy.* import com.example.samplewearmobileapp.Constants.MICRO_TO_MILLI_VOLT +import com.example.samplewearmobileapp.Constants.NANO_TO_MICRO_SEC import com.example.samplewearmobileapp.Constants.N_DOMAIN_LARGE_BOXES import com.example.samplewearmobileapp.Constants.N_ECG_PLOT_POINTS import com.example.samplewearmobileapp.Constants.N_LARGE @@ -179,7 +180,9 @@ class EcgPlotter: PlotterListener { seriesVisible.addLast(dataIndex, MICRO_TO_MILLI_VOLT * ecgDataSample.voltage) // Add the value to the all series as well seriesAll.addLast(dataIndex, MICRO_TO_MILLI_VOLT * ecgDataSample.voltage) - seriesTimestamp.addLast(dataIndex, ecgDataSample.timeStamp) + seriesTimestamp.addLast(dataIndex, + (NANO_TO_MICRO_SEC * ecgDataSample.timeStamp).toLong().adjustEpoch() + ) dataIndex++ } // Reset the domain boundaries @@ -316,5 +319,9 @@ class EcgPlotter: PlotterListener { companion object { private const val TAG = "EcgPlotter" + + private fun Long.adjustEpoch(): Long { + return this + Date(2000 - 1900, 0, 1).time + } } } \ No newline at end of file diff --git a/mobile/src/main/java/com/example/samplewearmobileapp/MainActivity.kt b/mobile/src/main/java/com/example/samplewearmobileapp/MainActivity.kt index 43869c2..a41105a 100644 --- a/mobile/src/main/java/com/example/samplewearmobileapp/MainActivity.kt +++ b/mobile/src/main/java/com/example/samplewearmobileapp/MainActivity.kt @@ -542,27 +542,27 @@ class MainActivity : AppCompatActivity(), GoogleApiClient.ConnectionCallbacks, } return true } else if (id == R.id.save_all) { - saveDataWithNote(SaveType.ALL) + saveDataWithName(SaveType.ALL) return true } else if (id == R.id.save_all_ppg_data) { - saveDataWithNote(SaveType.ALL_PPG) + saveDataWithName(SaveType.ALL_PPG) return true } else if (id == R.id.save_ecg_data) { - saveDataWithNote(SaveType.ECG_DATA) + saveDataWithName(SaveType.ECG_DATA) return true } else if (id == R.id.save_ppg_green_data) { - saveDataWithNote(SaveType.PPG_GREEN_DATA) + saveDataWithName(SaveType.PPG_GREEN_DATA) return true } else if (id == R.id.save_ppg_ir_data) { - saveDataWithNote(SaveType.PPG_IR_DATA) + saveDataWithName(SaveType.PPG_IR_DATA) return true } else if (id == R.id.save_ppg_red_data) { - saveDataWithNote(SaveType.PPG_RED_DATA) + saveDataWithName(SaveType.PPG_RED_DATA) return true } // else if (id == R.id.save_plot) { @@ -1390,12 +1390,11 @@ class MainActivity : AppCompatActivity(), GoogleApiClient.ConnectionCallbacks, /** * Commence saving the current samples as a file. - * Prompts for a note, then calls - * the appropriate save method. - * + * Prompts for a name to used as the file name, + * then calls the appropriate save method. * @param saveType The SaveType. */ - private fun saveDataWithNote(saveType: SaveType) { + private fun saveDataWithName(saveType: SaveType) { val msg: String val state = Environment.getExternalStorageState() if (Environment.MEDIA_MOUNTED != state) { @@ -1404,12 +1403,12 @@ class MainActivity : AppCompatActivity(), GoogleApiClient.ConnectionCallbacks, AppUtils.errMsg(this, msg) return } - // Get a note + // Get file name val dialog = AlertDialog.Builder( this, R.style.InverseTheme ) - dialog.setTitle(R.string.note_dialog_title) + dialog.setTitle(R.string.filename_dialog_title) val viewInflated: View = LayoutInflater.from(applicationContext) .inflate(R.layout.device_id_dialog, null, false) val input = viewInflated.findViewById(R.id.input) @@ -1540,11 +1539,11 @@ class MainActivity : AppCompatActivity(), GoogleApiClient.ConnectionCallbacks, } /** - * Finishes the saveData after getting the note. + * Finishes the saveData after getting the name. * Only saves the ECG recording data. - * @param note The note. + * @param filename The name. */ - private fun saveEcgData(note: String) { + private fun saveEcgData(filename: String) { val prefs = getPreferences(MODE_PRIVATE) val treeUriStr = prefs.getString(PREF_TREE_URI, null) if (treeUriStr == null) { @@ -1555,7 +1554,7 @@ class MainActivity : AppCompatActivity(), GoogleApiClient.ConnectionCallbacks, var msg: String val format = "yyyy-MM-dd_HH-mm" val df = SimpleDateFormat(format, Locale.US) - val fileName = "ECG-" + df.format(stopTime!!) + ".csv" + val fileName = filename + "_ECG_" + df.format(stopTime!!) + ".csv" try { val treeUri = Uri.parse(treeUriStr) val treeDocumentId = DocumentsContract.getTreeDocumentId(treeUri) @@ -1588,7 +1587,7 @@ class MainActivity : AppCompatActivity(), GoogleApiClient.ConnectionCallbacks, ("application=" + "SamplingApp Version: " + AppUtils.getVersion(this)) + "\n" ) - out.write("datatype=ECG") + out.write("datatype=ECG\n") out.write( """ stoptime=${stopTime.toString()} @@ -1610,7 +1609,7 @@ class MainActivity : AppCompatActivity(), GoogleApiClient.ConnectionCallbacks, out.write("deviceid=$deviceId\n") out.write("battery=$deviceBatteryLevel\n") out.write("firmware=$deviceFirmware\n") - out.write("note=$note\n") +// out.write("note=$filename\n") // Write samples for (i in 0 until sampleCount) { @@ -1640,13 +1639,13 @@ class MainActivity : AppCompatActivity(), GoogleApiClient.ConnectionCallbacks, } /** - * Finishes the saveData after getting the note. + * Finishes the saveData after getting the name. * Only saves the PPG recording data that corresponds * to the given PPG Plotter. - * @param note The note. + * @param filename The name. * @param ppgPlotter A PPG Plotter. */ - private fun savePpgData(note: String, ppgPlotter: PpgPlotter) { + private fun savePpgData(filename: String, ppgPlotter: PpgPlotter) { val prefs = getPreferences(MODE_PRIVATE) val treeUriStr = prefs.getString(PREF_TREE_URI, null) if (treeUriStr == null) { @@ -1663,7 +1662,7 @@ class MainActivity : AppCompatActivity(), GoogleApiClient.ConnectionCallbacks, PpgType.PPG_IR -> "PPG IR" PpgType.PPG_RED -> "PPG Red" } - val fileName = ppgTypeString + "-" + df.format(stopTime!!) + ".csv" + val fileName = filename + "-" + ppgTypeString + "-" + df.format(stopTime!!) + ".csv" try { val treeUri = Uri.parse(treeUriStr) val treeDocumentId = DocumentsContract.getTreeDocumentId(treeUri) @@ -1714,7 +1713,7 @@ class MainActivity : AppCompatActivity(), GoogleApiClient.ConnectionCallbacks, """.trimIndent() ) out.write("stopcalculatedhr=$calculatedStopHr\n") - out.write("note=$note\n") +// out.write("note=$filename\n") // Write samples for (i in 0 until sampleCount) { diff --git a/mobile/src/main/java/com/example/samplewearmobileapp/QrsPlotter.kt b/mobile/src/main/java/com/example/samplewearmobileapp/QrsPlotter.kt index c305d7d..1c6988b 100644 --- a/mobile/src/main/java/com/example/samplewearmobileapp/QrsPlotter.kt +++ b/mobile/src/main/java/com/example/samplewearmobileapp/QrsPlotter.kt @@ -5,11 +5,13 @@ import android.util.Log import android.view.View import com.androidplot.util.PixelUtils import com.androidplot.xy.* +import com.example.samplewearmobileapp.Constants.NANO_TO_MICRO_SEC import com.example.samplewearmobileapp.Constants.N_DOMAIN_LARGE_BOXES import com.example.samplewearmobileapp.Constants.N_ECG_PLOT_POINTS import com.example.samplewearmobileapp.Constants.N_LARGE import com.example.samplewearmobileapp.Constants.N_TOTAL_VISIBLE_ECG_POINTS import com.example.samplewearmobileapp.utils.AppUtils +import java.util.Date class QrsPlotter: PlotterListener { private lateinit var parentActivity: MainActivity @@ -245,7 +247,8 @@ class QrsPlotter: PlotterListener { seriesDataScores.addLast(dataIndex, score) } if (timestamp != null) { - seriesTimestamp.addLast(dataIndex, timestamp) + seriesTimestamp.addLast(dataIndex, + (NANO_TO_MICRO_SEC * timestamp).toLong().adjustEpoch()) } dataIndex++ // Reset the domain boundaries @@ -357,5 +360,9 @@ class QrsPlotter: PlotterListener { companion object { private const val TAG = "QrsPlotter" + + private fun Long.adjustEpoch(): Long { + return this + Date(2000 - 1900, 0, 1).time + } } } \ No newline at end of file diff --git a/mobile/src/main/res/values/strings.xml b/mobile/src/main/res/values/strings.xml index 4762835..e19cb09 100644 --- a/mobile/src/main/res/values/strings.xml +++ b/mobile/src/main/res/values/strings.xml @@ -104,6 +104,7 @@ Set Device ID Enter a Note + Enter File Name %1$s\nBattery level: %2$s\nFirmware: %3$s\nID: %4$s\n %1$.1f sec"