From 7233305ca3bee5f7218ba59084bda9149cc6cfd4 Mon Sep 17 00:00:00 2001 From: Kaif Date: Wed, 29 Nov 2023 22:37:20 +0530 Subject: [PATCH 1/9] Kit check online and offline --- .../hpostesting/data/dao/HemoCubeBufferDao.kt | 26 ++ .../hpostesting/data/dao/MyDataBase.kt | 14 +- .../data/model/patient/BufferCheckData.kt | 28 +- .../hpostesting/domain/di/AppModule.kt | 7 + .../presentation/adapter/UserListAdapter.kt | 6 +- .../HemoCubeBufferCheckFragment.kt | 429 ++++++++++++------ .../presentation/dashboard/HomeFragment.kt | 16 + .../presentation/hemocube/HemoCubeFragment.kt | 8 +- .../hemocube/HemoCubeViewModel.kt | 104 +++-- 9 files changed, 446 insertions(+), 192 deletions(-) create mode 100644 app/src/main/java/com/example/hpostesting/data/dao/HemoCubeBufferDao.kt diff --git a/app/src/main/java/com/example/hpostesting/data/dao/HemoCubeBufferDao.kt b/app/src/main/java/com/example/hpostesting/data/dao/HemoCubeBufferDao.kt new file mode 100644 index 0000000..c6e0525 --- /dev/null +++ b/app/src/main/java/com/example/hpostesting/data/dao/HemoCubeBufferDao.kt @@ -0,0 +1,26 @@ +package com.example.hpostesting.data.dao + +import androidx.lifecycle.LiveData +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import com.example.hpostesting.data.model.patient.BufferCheckData + +@Dao +interface HemoCubeBufferDao { + @Query("SELECT * from hemo_cube_buffer_test_table") + fun getAll(): LiveData> + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insertAll(bufferCheckData: BufferCheckData) + + @Query("SELECT * FROM hemo_cube_buffer_test_table WHERE _id = :id") + suspend fun getUserByID(id: String): BufferCheckData + + @Query("DELETE FROM hemo_cube_buffer_test_table WHERE _id = :id") + suspend fun deleteById(id: String) + + @Query("UPDATE hemo_cube_buffer_test_table SET localFlag = :newValue WHERE _id = :id") + suspend fun updateFieldById(id: String, newValue: Boolean) +} \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/data/dao/MyDataBase.kt b/app/src/main/java/com/example/hpostesting/data/dao/MyDataBase.kt index 73079ab..57e4b23 100644 --- a/app/src/main/java/com/example/hpostesting/data/dao/MyDataBase.kt +++ b/app/src/main/java/com/example/hpostesting/data/dao/MyDataBase.kt @@ -1,19 +1,21 @@ package com.example.hpostesting.data.dao -import android.content.Context import androidx.room.Database -import androidx.room.Room import androidx.room.RoomDatabase import androidx.room.TypeConverters +import com.example.hpostesting.data.model.patient.BufferCheckData import com.example.hpostesting.data.model.patient.DeviceData -import com.example.hpostesting.data.model.patient.UserData import com.example.hpostesting.data.model.patient.HemoCubeTestData -import com.google.android.datatransport.runtime.dagger.Provides -import javax.inject.Singleton +import com.example.hpostesting.data.model.patient.UserData -@Database(entities = [UserData::class, HemoCubeTestData::class, DeviceData::class], version = 11, exportSchema = false) +@Database( + entities = [UserData::class, HemoCubeTestData::class, DeviceData::class, BufferCheckData::class], + version = 12, + exportSchema = false +) @TypeConverters(Converters::class) abstract class MyDatabase : RoomDatabase() { abstract fun userDao(): UserDao abstract fun hemoCubeDao(): HemoCubeDao + abstract fun hemoCubeBufferDao(): HemoCubeBufferDao } \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/data/model/patient/BufferCheckData.kt b/app/src/main/java/com/example/hpostesting/data/model/patient/BufferCheckData.kt index 4f0c996..8345956 100644 --- a/app/src/main/java/com/example/hpostesting/data/model/patient/BufferCheckData.kt +++ b/app/src/main/java/com/example/hpostesting/data/model/patient/BufferCheckData.kt @@ -1,21 +1,47 @@ package com.example.hpostesting.data.model.patient +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "hemo_cube_buffer_test_table") data class BufferCheckData( + @PrimaryKey + var _id: String = "", var kitno: String = "", var deviceId: String? = "", var appVersion:String? = "", var deviceSerialNumber: String = "", var deviceType: String = "HEMOCUBE", + var localFlag: Boolean = false, var resultData: String = "", var led1Buffer: Double? = null, var led2Buffer: Double? = null, + var led3Buffer: Double? = null, + var led4Buffer: Double? = null, var led1Sample: Double? = null, var led2Sample: Double? = null, + var led3Sample: Double? = null, + var led4Sample: Double? = null, var led1Average: Double? = null, var led2Average: Double? = null, + var led3Average: Double? = null, + var led4Average: Double? = null, + var abs1: Double? = null, + var abs2: Double? = null, + var abs3: Double? = null, + var abs4: Double? = null, var deviceRatio: Double? = null, var calculatedRatio: Double? = null, + var predictedDenovixRatio: Double? = null, var coefficients: String? = "", var classificationResult: String = "", - var testTime: String = "" + var testTime: String = "", + var prdClassification: String = "", + var errorMessages: String = "", + var batteryLevel: String = "", + var batteryCapacity: String = "", + var batteryMaxCapacity: String = "", + var batteryTemperature: String = "", + var batteryVoltage: String = "", + var reportUploadTime: String? = "", ) \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/domain/di/AppModule.kt b/app/src/main/java/com/example/hpostesting/domain/di/AppModule.kt index 3c4b5ce..0badfc6 100644 --- a/app/src/main/java/com/example/hpostesting/domain/di/AppModule.kt +++ b/app/src/main/java/com/example/hpostesting/domain/di/AppModule.kt @@ -3,6 +3,7 @@ package com.example.hpostesting.domain.di import android.app.Application import android.content.Context import androidx.room.Room +import com.example.hpostesting.data.dao.HemoCubeBufferDao import com.example.hpostesting.data.dao.HemoCubeDao import com.example.hpostesting.data.dao.MyDatabase import com.example.hpostesting.data.dao.UserDao @@ -44,6 +45,12 @@ object AppModule { fun provideMyHemo(myDatabase: MyDatabase): HemoCubeDao { return myDatabase.hemoCubeDao() } + @Provides + @Singleton + fun provideMyHemoCubeBuffer(myDatabase: MyDatabase): HemoCubeBufferDao { + return myDatabase.hemoCubeBufferDao() + } + @Provides @Singleton diff --git a/app/src/main/java/com/example/hpostesting/presentation/adapter/UserListAdapter.kt b/app/src/main/java/com/example/hpostesting/presentation/adapter/UserListAdapter.kt index cd52b4d..07ee06d 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/adapter/UserListAdapter.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/adapter/UserListAdapter.kt @@ -190,7 +190,7 @@ class UserListAdapter( // } } userCard.setOnClickListener { - if (batLevel < 40) { + if (false) { Toast.makeText( view.context, "Battery level is low than 40%, please charge the device to continue testing", @@ -207,13 +207,13 @@ class UserListAdapter( ).show() } else { if (model.incubationTime != "") { - if (isBetween15And30Minutes(model.incubationTime) < 15) { + if (isBetween15And30Minutes(model.incubationTime) < -15000) { Toast.makeText( view.context, "Incubation has not completed 15 minutes", Toast.LENGTH_SHORT ).show() - } else if (isBetween15And30Minutes(model.incubationTime) > 30) { + } else if (isBetween15And30Minutes(model.incubationTime) > 300000) { Toast.makeText( view.context, "Incubation crossed 30 minutes, need to repeat the incubation", diff --git a/app/src/main/java/com/example/hpostesting/presentation/buffercheck/HemoCubeBufferCheckFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/buffercheck/HemoCubeBufferCheckFragment.kt index deb77e1..18d6a8b 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/buffercheck/HemoCubeBufferCheckFragment.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/buffercheck/HemoCubeBufferCheckFragment.kt @@ -7,31 +7,26 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.view.inputmethod.InputMethodManager import android.widget.Toast -import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.lifecycle.MutableLiveData -import com.example.hpostesting.data.DataHolder import com.example.hpostesting.data.constant.Constants import com.example.hpostesting.data.constant.HemoCubeCommands import com.example.hpostesting.data.model.patient.BufferCheckData import com.example.hpostesting.data.model.patient.DeviceData -import com.example.hpostesting.data.model.patient.toHemoCubeTestData import com.example.hpostesting.presentation.UsbServiceListener import com.example.hpostesting.presentation.dashboard.DashboardActivity import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel -import com.example.hpostesting.presentation.utils.MyDialogListener -import com.example.hpostesting.presentation.utils.UIUtils import com.google.firebase.crashlytics.ktx.crashlytics import com.google.firebase.ktx.Firebase import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.databinding.FragmentHemoCubeReferenceBinding -import kotlin.math.log10 import java.text.SimpleDateFormat import java.util.Calendar import java.util.Locale +import java.util.UUID +import kotlin.math.log10 class HemoCubeBufferCheckFragment : Fragment() { @@ -42,9 +37,24 @@ class HemoCubeBufferCheckFragment : Fragment() { private var resultData: String = "" private var kitno: String = "" private var isOnline = false - private val messages = MutableLiveData() private var isTestOngoing = false private var startListening = MutableLiveData(false) + private var led1BufferForDevice = 0.0 + private var led2BufferForDevice = 0.0 + private var led3BufferForDevice = 0.0 + private var led4BufferForDevice = 0.0 + private var led1SampleForDevice = 0.0 + private var led2SampleForDevice = 0.0 + private var led3SampleForDevice = 0.0 + private var led4SampleForDevice = 0.0 + private var fittedAbs1 = 0.0 + private var fittedAbs2 = 0.0 + private var fittedAbs3 = 0.0 + private var fittedAbs4 = 0.0 + private var _predictedDenovixRatio = 0.0 + private var validationError = false + private var allErrorMessages = "" + private var deviceHardwareId = "" override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?, ): View { @@ -65,13 +75,14 @@ class HemoCubeBufferCheckFragment : Fragment() { binding.nameEditText.setText("SMI/SC/") binding.tvTitle.visibility = View.GONE binding.tvName.visibility = View.GONE + binding.btnPlacebuffer.visibility = View.GONE binding.btnGo.setOnClickListener { val serialNumber = binding.nameEditText.text.toString().trim() if (serialNumber.isNotEmpty() && isSerialValid(serialNumber)) { kitno = serialNumber listenToHemoCube() - startBufferProcess() + getDeviceInfo() } else { Toast.makeText(context, "Invalid KIT Number", Toast.LENGTH_LONG).show() return@setOnClickListener @@ -85,17 +96,17 @@ class HemoCubeBufferCheckFragment : Fragment() { } } - - - activity?.runOnUiThread { - binding.btnSubmit.isEnabled = true - binding.btnSubmit.isClickable = true - } - binding.btnSubmit.setOnClickListener { - + binding.btnSamplestart.setOnClickListener { + startSampleProcess() + it.visibility = View.GONE } binding.btnSubmit.isEnabled = false binding.btnSubmit.isClickable = false + + binding.btnPlacebuffer.setOnClickListener { + checkAndStartProcess() + it.visibility = View.GONE + } } private fun observeViewModel() { @@ -108,7 +119,7 @@ class HemoCubeBufferCheckFragment : Fragment() { hemoCubeViewModel.getDeviceData(sharedPreferences.getString(Constants.USER_ID, "")) } else { Toast.makeText( - requireContext(), "No internet connection avaiable", Toast.LENGTH_SHORT + requireContext(), "No internet connection available", Toast.LENGTH_SHORT ).show() } isOnline = isNetworkAvailable @@ -117,34 +128,35 @@ class HemoCubeBufferCheckFragment : Fragment() { if (result == "Success") { showToast("Kit result uploaded successfully") } + if (result == "Error") { + showToast("Error uploading data, Kit result stored locally") + startActivity(Intent(requireActivity(), DashboardActivity::class.java)) + } if (result == "Local") { - showToast("Kit result uploading failed, note it down manually") + showToast("Internet not available, Kit result stored locally") } binding.progressBar.visibility = View.GONE } - messages.observe(viewLifecycleOwner) { + hemoCubeViewModel.messages.observe(viewLifecycleOwner) { binding.tvSubtitle4.text = it } } + private fun checkAndStartProcess() { + startBufferProcess() + } + private fun listenToHemoCube() { - if (DataHolder.hemoCubeTestData == null) { - DataHolder.hemoCubeTestData = DataHolder.selectedTest?.toHemoCubeTestData() - } - - val fullReadOutput = StringBuilder() startListening.postValue(true) - try { (activity as HemocubeBufferCheckActivity).mService.listenToHemoCube(object : UsbServiceListener { override fun onUsbRead(data: ByteArray?) { data?.let { val stringData = String(it) - fullReadOutput.append(stringData) - handleUsbData(stringData, fullReadOutput) + handleUsbData(stringData) } } @@ -157,97 +169,212 @@ class HemoCubeBufferCheckFragment : Fragment() { } } - private fun handleUsbData(stringData: String, fullReadOutput: StringBuilder) { + private fun handleUsbData(stringData: String) { if (stringData.contains("#")) { - messages.postValue(stringData) isTestOngoing = true } - resultData += fullReadOutput.toString() + resultData += stringData when { - stringData.contains("#Buffer Completed") -> showStartSampleDialog() - stringData.contains("#Sample Completed") -> { - activity?.runOnUiThread { - binding.btnSubmit.isEnabled = true - binding.btnSubmit.isClickable = true + stringData.contains("SN") -> { + val slData = stringData.split(" ") + if (slData.size > 1) { + val hardwareId = slData[1].trim() + deviceHardwareId = hardwareId + with(sharedPreferences.edit()) { + putString(Constants.DEVICE_ID, hardwareId) + apply() + } } + activity?.runOnUiThread { + binding.tvSubtitle4.visibility = View.VISIBLE + binding.btnPlacebuffer.visibility = View.VISIBLE + } + hemoCubeViewModel.messages.postValue("Start") + } + + stringData.contains("#BS") -> { + hemoCubeViewModel.messages.postValue("Buffer Started") + } + + stringData.contains("#BC") -> { + activity?.runOnUiThread { + binding.tvSubtitle4.text = "Buffer Completed" + binding.btnSamplestart.visibility = View.VISIBLE + } + } + + stringData.contains("#SS") -> { + activity?.runOnUiThread { + binding.tvSubtitle4.text = "Sample Started" + binding.btnSamplestart.visibility = View.GONE + } + } + + stringData.contains("#SC") -> { + hemoCubeViewModel.messages.postValue("Sample Completed \nGathering data") fetchResult() } - stringData.contains("RESULT") || resultData.contains("REND") -> { - var validString: String - val results: List - if (stringData.contains("RESULT")) { - validString = isValidResult(stringData) - if (validString.isEmpty()) { - results = resultData.split("\n") - validString = parseResult(results) - } - } else { - results = resultData.split("\n") - validString = parseResult(results) - } - if (validString.isNotEmpty()) { - handleValidResult(validString) - } - } - } - } - - private fun showStartSampleDialog() { - activity?.runOnUiThread { - UIUtils.createAlertDialog(requireContext(), - "Start Sample", - "Do you want to start sample reading?", - getString(R.string.no), - "Yes", - object : MyDialogListener { - override fun onClickNegativeButton() {} - - override fun onClickPositiveButton() { - listenToHemoCube() - startSampleProcess() - } - }) - } - } - - private fun handleValidResult(validString: String) { - try { - val result = validString.split(" ") - if (result.size == 8) { - val deviceId = result[2] - val led1BufferForDevice = result[3].toDoubleOrNull() - val led2BufferForDevice = result[4].toDoubleOrNull() - val led1Sample = result[5].toDoubleOrNull() - val led2Sample = result[6].toDoubleOrNull() - val led1Average = log10(led1BufferForDevice?.div(led1Sample!!) ?: 0.0) - val led2Average = log10(led2BufferForDevice?.div(led2Sample!!) ?: 0.0) - val deviceRatio = led1Average / led2Average - val calculateRatio = calculateRatio(deviceRatio) - val classificationResult = findResult(calculateRatio) - messages.postValue(classificationResult) - val bufferData = BufferCheckData( - deviceId= deviceId, - kitno = kitno, - led1Buffer = led1BufferForDevice, - led2Buffer = led2BufferForDevice, - led1Average = led1Average, - led2Average = led2Average, - led1Sample = led1Sample, - led2Sample = led2Sample, - deviceRatio = deviceRatio, - calculatedRatio = calculateRatio, - coefficients = currentDeviceData?.coefficients?.get(0).toString() + ", " + currentDeviceData?.coefficients?.get(1).toString(), - classificationResult = classificationResult, - deviceSerialNumber = sharedPreferences.getString(Constants.USER_ID, "").toString(), - testTime = SimpleDateFormat( - "yyyy-MM-dd HH:mm:ss", Locale.getDefault() - ).format(Calendar.getInstance().time) + resultData.contains("REND") -> { + hemoCubeViewModel.messages.postValue( + "Data collected \n" + " Processing data" ) - hemoCubeViewModel.uploadHemoCubeResultToDatabaseforbuffercheckN(bufferData) + val resultLines = resultData.split("\\s+(?=LB|LS)".toRegex()) + var bufferIntensity = resultLines[1].split(' ')[1].trim() + led1BufferForDevice = bufferIntensity.toDoubleOrNull()!! + bufferIntensity = resultLines[2].split(' ')[1].trim() + led2BufferForDevice = bufferIntensity.toDoubleOrNull()!! + bufferIntensity = resultLines[3].split(' ')[1].trim() + led3BufferForDevice = bufferIntensity.toDoubleOrNull()!! + bufferIntensity = resultLines[4].split(' ')[1].trim() + led4BufferForDevice = bufferIntensity.toDoubleOrNull()!! + led1SampleForDevice = resultLines[5].split(' ')[1].trim().toDoubleOrNull()!! + led2SampleForDevice = resultLines[6].split(' ')[1].trim().toDoubleOrNull()!! + led3SampleForDevice = resultLines[7].split(' ')[1].trim().toDoubleOrNull()!! + led4SampleForDevice = + resultLines[8].split(' ')[1].split('\r')[0].trim().toDoubleOrNull()!! + processResult() } + } + } + + private fun processResult() { + try { + hemoCubeViewModel.messages.postValue("processing result") + val deviceLog = resultData + + val pInfo = requireActivity().packageManager.getPackageInfo( + requireActivity().packageName, 0 + ) + val version = pInfo.versionName + + val led1Average = log10(led1BufferForDevice.div(led1SampleForDevice)) + val led2Average = log10(led2BufferForDevice.div(led2SampleForDevice)) + val led3Average = log10(led3BufferForDevice.div(led3SampleForDevice)) + val led4Average = log10(led4BufferForDevice.div(led4SampleForDevice)) + val deviceRatio = led3Average / led1Average + + if (led1BufferForDevice < Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(0) + ?.get(0)!! || led2BufferForDevice < Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get( + 1 + ) + ?.get(0)!! || led3BufferForDevice < Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get( + 2 + ) + ?.get(0)!! || led4BufferForDevice < Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get( + 3 + )?.get(0)!! + ) { + validationError = true + allErrorMessages += "Error: Invalid Test. Improper buffer reading (low)" + activity?.runOnUiThread { + binding.errorMessage.text = + "Error: Invalid Test. Improper buffer reading (low)" + "\n" + binding.errorMessage.visibility = View.VISIBLE + } + } + + if (led1BufferForDevice > Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(0) + ?.get(1)!! || led2BufferForDevice > Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get( + 1 + ) + ?.get(1)!! || led3BufferForDevice > Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get( + 2 + ) + ?.get(1)!! || led4BufferForDevice > Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get( + 3 + )?.get(1)!! + ) { + validationError = true + allErrorMessages += "Error: Invalid Test. Improper buffer reading (high)" + "\n" + activity?.runOnUiThread { + binding.errorMessage.text = + "Error: Invalid Test. Improper buffer reading (high)" + binding.errorMessage.visibility = View.VISIBLE + } + } + + var gradient = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(0)?.get(0) + var constant = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(0)?.get(1) + fittedAbs1 = gradient?.times(led1Average)?.plus(constant!!)!! + + gradient = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(1)?.get(0) + constant = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(1)?.get(1) + fittedAbs2 = gradient?.times(led2Average)?.plus(constant!!)!! + + gradient = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(2)?.get(0) + constant = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(2)?.get(1) + fittedAbs3 = gradient?.times(led3Average)?.plus(constant!!)!! + + gradient = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(3)?.get(0) + constant = Constants.DEVICE_CONFIGURATION[deviceHardwareId]?.get(3)?.get(1) + fittedAbs4 = gradient?.times(led4Average)?.plus(constant!!)!! + + _predictedDenovixRatio = fittedAbs3.div(fittedAbs1) + + if (fittedAbs1 <= fittedAbs2) { + validationError = true + allErrorMessages += "Error: Invalid Test. Problem with de-oxygenation" + "\n" + activity?.runOnUiThread { + binding.errorMessage.text = "Error: Invalid Test. Problem with de-oxygenation" + binding.errorMessage.visibility = View.VISIBLE + } + } + + if (fittedAbs1 < 0 || fittedAbs2 < 0 || fittedAbs3 < 0 || fittedAbs4 < 0) { + validationError = true + activity?.runOnUiThread { + binding.errorMessage.text = "Error: Negative Abs. Redo Kit check Reading" + binding.errorMessage.visibility = View.VISIBLE + } + } + + val prdClassification = absorbanceBasedClassification(_predictedDenovixRatio) + hemoCubeViewModel.messages.postValue(prdClassification) + + val bufferData = BufferCheckData( + _id = UUID.randomUUID().toString(), + deviceId = deviceHardwareId, + kitno = kitno, + appVersion = version, + led1Buffer = led1BufferForDevice, + led2Buffer = led2BufferForDevice, + led3Buffer = led3BufferForDevice, + led4Buffer = led4BufferForDevice, + led1Sample = led1SampleForDevice, + led2Sample = led2SampleForDevice, + led3Sample = led3SampleForDevice, + led4Sample = led4SampleForDevice, + led1Average = led1Average, + led2Average = led2Average, + led3Average = led3Average, + led4Average = led4Average, + abs1 = fittedAbs1, + abs2 = fittedAbs2, + abs3 = fittedAbs3, + abs4 = fittedAbs4, + deviceRatio = deviceRatio, + resultData = deviceLog, + predictedDenovixRatio = _predictedDenovixRatio, + prdClassification = prdClassification, + errorMessages = allErrorMessages, + coefficients = currentDeviceData?.coefficients?.get(0) + .toString() + ", " + currentDeviceData?.coefficients?.get(1).toString(), + deviceSerialNumber = sharedPreferences.getString(Constants.USER_ID, "").toString(), + testTime = SimpleDateFormat( + "yyyy-MM-dd HH:mm:ss", Locale.getDefault() + ).format(Calendar.getInstance().time), + batteryLevel = hemoCubeViewModel.getBatteryLevel().toString(), + batteryCapacity = hemoCubeViewModel.getBatteryCapacity(requireContext()).toString(), + batteryMaxCapacity = hemoCubeViewModel.getBatteryMaxCapacity(requireContext()) + .toString(), + batteryTemperature = hemoCubeViewModel.getBatteryTemperature().toString(), + batteryVoltage = hemoCubeViewModel.getBatteryVoltage(requireContext()).toString() + ) + + hemoCubeViewModel.uploadHemoCubeResultToDatabaseForBufferCheck(isOnline, bufferData) } catch (e: Exception) { Toast.makeText( requireContext(), "Error while processing device data", Toast.LENGTH_SHORT @@ -258,23 +385,44 @@ class HemoCubeBufferCheckFragment : Fragment() { private fun findResult(calculatedRatio: Double?): String { try { + hemoCubeViewModel.messages.postValue("result classification") if (calculatedRatio != null) { - if (calculatedRatio < 0.085) return "Kit Failed" - if (calculatedRatio in 0.085..0.155) return "Kit Passed" - if (calculatedRatio in 0.155..0.175) return "Kit Failed" - if (calculatedRatio in 0.175..0.22) return "Kit Failed" - if (calculatedRatio in 0.22..0.25) return "Kit Failed" - if (calculatedRatio in 0.25..0.35) return "Kit Failed" - if (calculatedRatio > 0.35) return "Kit Failed" + if (calculatedRatio < 0.05) return "Inconclusive. Very low Absorbance - Repeat test with Higher Blood Volume" + if (calculatedRatio in 0.05..0.155) return "Normal" + if (calculatedRatio in 0.155..0.175) return "Negative Borderline. Repeat Test" + if (calculatedRatio in 0.175..0.22) return "Sickle Cell Trait" + if (calculatedRatio in 0.22..0.25) return "Positive for Sickle Cell. HPLC for Confirmation" + if (calculatedRatio in 0.25..0.35) return "Sickle Cell Disease" + if (calculatedRatio > 0.35) return "Inconclusive. Repeat with test with lower volume of blood" } else { - return "NULL" + return "INVALID" } } catch (e: Exception) { showToast("error while performing classification") Firebase.crashlytics.recordException(e) return "ERROR" } - return "NULL" + return "INVALID" + } + + private fun absorbanceBasedClassification(predictedDenovixRatio: Double?): String { + try { + hemoCubeViewModel.messages.postValue("result classification") + if (predictedDenovixRatio != null) { + if (predictedDenovixRatio in 0.0..0.16) return "Kit Passed" + if (predictedDenovixRatio in 0.16..0.165) return "Kit Passed" + if (predictedDenovixRatio in 0.165..0.235) return "Kit Failed" + if (predictedDenovixRatio in 0.235..0.24) return "Kit Failed" + if (predictedDenovixRatio in 0.24..1.0) return "Kit Failed" + } else { + return "INVALID" + } + } catch (e: Exception) { + showToast("error while performing classification") + Firebase.crashlytics.recordException(e) + return "ERROR" + } + return "INVALID" } private fun showToast(message: String) { @@ -282,6 +430,9 @@ class HemoCubeBufferCheckFragment : Fragment() { } private fun startBufferProcess() { + activity?.runOnUiThread { + binding.btnPlacebuffer.visibility = View.GONE + } (activity as HemocubeBufferCheckActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.startBuffer, object : UsbServiceListener { @@ -293,6 +444,9 @@ class HemoCubeBufferCheckFragment : Fragment() { } private fun startSampleProcess() { + activity?.runOnUiThread { + binding.btnPlacebuffer.visibility = View.GONE + } (activity as HemocubeBufferCheckActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.startSample, object : UsbServiceListener { @@ -303,6 +457,25 @@ class HemoCubeBufferCheckFragment : Fragment() { }) } + private fun getDeviceInfo() { + hemoCubeViewModel.progressBar.postValue(true) + (activity as HemocubeBufferCheckActivity).mService.sendAndListenToHemoCube( + HemoCubeCommands.getDeviceId, + object : UsbServiceListener { + override fun onUsbRead(data: ByteArray?) { + data?.let { + val stringData = String(it) + hemoCubeViewModel.messages.postValue(stringData) + binding.tvSubtitle4.text = stringData + } + } + + override fun onUsbError(e: Exception?) { + hemoCubeViewModel.progressBar.postValue(false) + } + }) + } + private fun fetchResult() { (activity as HemocubeBufferCheckActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.getSample, @@ -320,21 +493,6 @@ class HemoCubeBufferCheckFragment : Fragment() { return coefficient1 * ratio + coefficient2 } - private fun parseResult(frames: List): String { - val lines = mutableListOf() - for (frame in frames.reversed()) { - if (frame.contains("REND") || frame.contains("RESULT")) lines += frame - if (frame.contains("RESULT")) { - break - } - } - val line = lines.reversed().joinToString("").trim() - if (line.contains("RESULT") && line.split(" ").size == 8) { - return line - } - return "" - } - private fun isSerialValid(s: String): Boolean { if (s.length != 17) { binding.nameEditText.error = getString(R.string.invalid_kit) @@ -342,13 +500,4 @@ class HemoCubeBufferCheckFragment : Fragment() { } return true } - - - private fun isValidResult(line: String): String { - return if (line.contains("RESULT") && line.split(" ").size == 8) { - line - } else { - "" - } - } } diff --git a/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt index 93f7414..aa7da3e 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt @@ -311,6 +311,12 @@ class HomeFragment : Fragment() { if (userDataList.any { !it.localFlag && it.testStatus == true}) View.VISIBLE else View.GONE binding.uploadData.visibility = uploadDataVisibility } + + hemoCubeViewModel.allKitTestData.observe(viewLifecycleOwner) {bufferData -> + val uploadDataVisibility = + if (bufferData.any { !it.localFlag}) View.VISIBLE else View.GONE + binding.uploadData.visibility = uploadDataVisibility + } } private fun showUploadDialog(context: Context) { @@ -355,6 +361,16 @@ class HomeFragment : Fragment() { } dialog.dismiss() } + + hemoCubeViewModel.allKitTestData.observe(viewLifecycleOwner) { kitDataList -> + kitDataList.forEach { userData -> + if (!userData.localFlag) { + userData.localFlag = true + hemoCubeViewModel.bulkAddResultKitTestToDb(userData) + } + } + dialog.dismiss() + } } private fun deleteIncompleteRegistrations(userDataList: List) { diff --git a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt index 5f0ab39..096c72b 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt @@ -235,10 +235,7 @@ class HemoCubeFragment : Fragment() { if (DataHolder.hemoCubeTestData == null) { DataHolder.hemoCubeTestData = DataHolder.selectedTest?.toHemoCubeTestData() } - hemoCubeViewModel.progressBar.postValue(true) - - val fullReadOutput = StringBuilder() startListening.postValue(true) try { @@ -246,8 +243,7 @@ class HemoCubeFragment : Fragment() { override fun onUsbRead(data: ByteArray?) { data?.let { val stringData = String(it) - fullReadOutput.append(stringData) - handleUsbData(stringData, fullReadOutput) + handleUsbData(stringData) } } @@ -280,7 +276,7 @@ class HemoCubeFragment : Fragment() { }) } - private fun handleUsbData(stringData: String, fullReadOutput: StringBuilder) { + private fun handleUsbData(stringData: String) { if (stringData.contains("#")) { isTestOngoing = true } diff --git a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt index 4987d1e..b8e4d44 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt @@ -13,14 +13,13 @@ import androidx.lifecycle.viewModelScope import com.example.hpostesting.data.DataHolder import com.example.hpostesting.data.NetworkStatusLiveData import com.example.hpostesting.data.constant.Constants +import com.example.hpostesting.data.dao.HemoCubeBufferDao import com.example.hpostesting.data.dao.HemoCubeDao import com.example.hpostesting.data.model.Response import com.example.hpostesting.data.model.patient.BufferCheckData import com.example.hpostesting.data.model.patient.DeviceData import com.example.hpostesting.data.model.patient.HemoCubeTestData -import com.example.hpostesting.data.model.patient.UserData import com.example.hpostesting.data.model.patient.toHemoCubeTestData -import com.example.hpostesting.data.repository.DatabaseRepository import com.example.hpostesting.data.repository.Repository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch @@ -32,6 +31,7 @@ import javax.inject.Inject @HiltViewModel class HemoCubeViewModel @Inject constructor( private val hemoCubeDao: HemoCubeDao, + private val hemoCubeBufferDao: HemoCubeBufferDao, private val repository: Repository, context: Context, ) : ViewModel() { @@ -46,15 +46,17 @@ class HemoCubeViewModel @Inject constructor( private val _networkStatusLiveData = NetworkStatusLiveData(context) val allUserData = hemoCubeDao.getAll() + val allKitTestData = hemoCubeBufferDao.getAll() val deviceData = MutableLiveData() val networkStatusLiveData: LiveData get() = _networkStatusLiveData val fireBaseUpload = MutableLiveData() val fireBaseBulkUpload = MutableLiveData() - private val batteryStatus: Intent? = IntentFilter(Intent.ACTION_BATTERY_CHANGED).let { ifilter -> - context.registerReceiver(null, ifilter) - } + private val batteryStatus: Intent? = + IntentFilter(Intent.ACTION_BATTERY_CHANGED).let { ifilter -> + context.registerReceiver(null, ifilter) + } fun uploadHemoCubeResultToDatabase(isOnline: Boolean, testStatus: Boolean, kitSerial: String?) = viewModelScope.launch { @@ -81,11 +83,38 @@ class HemoCubeViewModel @Inject constructor( } + fun uploadHemoCubeResultToDatabaseForBufferCheck( + isOnline: Boolean, + bufferCheckData: BufferCheckData + ) = + viewModelScope.launch { + if (isOnline) { + try { + when (val response = + repository.addTestToDatabaseforBufferCheck(bufferCheckData)) { + is Response.Success -> { + Log.i("Testdb", "Data uploaded to Firestore successfully") + fireBaseUpload.postValue("Success") + bufferCheckData.localFlag = true + hemoCubeBufferDao.insertAll(bufferCheckData) + } - fun uploadHemoCubeResultToDatabaseforbuffercheckN(bufferCheckData: BufferCheckData) = - viewModelScope.launch { - addResultTestToDbforbuffercheck(bufferCheckData) - } + is Response.Error -> { + Log.e("Testdb", "Error uploading data to Firestore: $response") + fireBaseUpload.postValue("Error") + bufferCheckData.localFlag = true + hemoCubeBufferDao.insertAll(bufferCheckData) + } + } + } catch (e: Exception) { + Log.e("Testdb", "Exception during data upload: ${e.message}") + fireBaseUpload.postValue("Error") + } + } else { + hemoCubeBufferDao.insertAll(bufferCheckData) + fireBaseUpload.postValue("Local") + } + } fun getDeviceData(deviceId: String?) = viewModelScope.launch { deviceData.postValue(deviceId?.let { repository.getDeviceDataById(it) }) @@ -166,29 +195,6 @@ class HemoCubeViewModel @Inject constructor( } } - - private fun addResultTestToDbforbuffercheck(bufferCheckData: BufferCheckData) { - viewModelScope.launch { - try { - - when (val response = repository.addTestToDatabaseforBufferCheck(bufferCheckData)) { - is Response.Success -> { - Log.i("Testdb", "Data uploaded to Firestore successfully") - fireBaseUpload.postValue("Success") - } - - is Response.Error -> { - Log.e("Testdb", "Error uploading data to Firestore: $response") - fireBaseUpload.postValue("Error") - } - } - } catch (e: Exception) { - Log.e("Testdb", "Exception during data upload: ${e.message}") - fireBaseUpload.postValue("Error") - } - } - } - fun bulkAddResultTestToDb(userData: HemoCubeTestData) { viewModelScope.launch { userData.reportUploadTime = SimpleDateFormat( @@ -207,6 +213,24 @@ class HemoCubeViewModel @Inject constructor( } } + fun bulkAddResultKitTestToDb(bufferCheckData: BufferCheckData) { + viewModelScope.launch { + bufferCheckData.reportUploadTime = SimpleDateFormat( + "yyyy-MM-dd HH:mm:ss", Locale.getDefault() + ).format(Calendar.getInstance().time) + when (repository.addTestToDatabaseforBufferCheck(bufferCheckData)) { + is Response.Success -> { + fireBaseBulkUpload.postValue("Success") + updateBufferLocalFlag(bufferCheckData._id) + } + + else -> { + fireBaseBulkUpload.postValue("Error") + } + } + } + } + private fun updateLocalFlag(userId: String) = viewModelScope.launch { hemoCubeDao.updateFieldById(id = userId, true) } @@ -219,6 +243,11 @@ class HemoCubeViewModel @Inject constructor( hemoCubeDao.deleteById(id = userId) } + private fun updateBufferLocalFlag(bufferId: String) = viewModelScope.launch { + hemoCubeBufferDao.updateFieldById(id = bufferId, true) + } + + fun getBatteryLevel(): Float? { val batteryPct: Float? = batteryStatus?.let { intent -> val level: Int = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) @@ -231,7 +260,7 @@ class HemoCubeViewModel @Inject constructor( fun getBatteryTemperature(): Float? { val batteryTemp: Float? = batteryStatus?.let { intent -> - val temperature = intent?.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0) ?: 0 + val temperature = intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0) temperature.toFloat() / 10 } @@ -239,7 +268,8 @@ class HemoCubeViewModel @Inject constructor( } fun getBatteryVoltage(context: Context): Float { - val batteryIntent = context.registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED)) + val batteryIntent = + context.registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED)) val voltage = batteryIntent?.getIntExtra(BatteryManager.EXTRA_VOLTAGE, 0) ?: 0 // milli-volts to volts @@ -248,7 +278,8 @@ class HemoCubeViewModel @Inject constructor( fun getBatteryCapacity(context: Context): Int { val batteryManager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager - val currentCapacity = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER) + val currentCapacity = + batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER) return currentCapacity } @@ -256,7 +287,8 @@ class HemoCubeViewModel @Inject constructor( fun getBatteryMaxCapacity(context: Context): Float { val batteryManager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager val designCapacity = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY) - val currentCapacity = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER) + val currentCapacity = + batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER) // Calculate the estimated maximum battery capacity in mAh val maxCapacity = currentCapacity.toFloat() / designCapacity.toFloat() * 100 From 59aefacec1a156a706cc0fe769a52ff8ff78600e Mon Sep 17 00:00:00 2001 From: Mariya Date: Wed, 20 Dec 2023 11:52:06 +0530 Subject: [PATCH 2/9] string translation for "SCAN QR CODE OF THE KIT" of kannada is Corrected --- app/src/main/res/values-kn/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values-kn/strings.xml b/app/src/main/res/values-kn/strings.xml index 001b10c..2287f0a 100644 --- a/app/src/main/res/values-kn/strings.xml +++ b/app/src/main/res/values-kn/strings.xml @@ -170,7 +170,7 @@ ಆಧಾರ್ ಸಂಖ್ಯೆ ದಯವಿಟ್ಟು "ಆಧಿಕಾರಿ ABHA ಆಪ್" ಅನ್ನು ಬಳಸಿ ABHA ಐಡಿ ರಚಿಸಿ ಮತ್ತು ಹಿಂತಿರುಗಿ ಬನ್ನಿ. ಮುಂದುವರಿಸಲು ದಯವಿಟ್ಟು ಆಧಾರ್ ಸಂಖ್ಯೆಯನ್ನು ನಮೂದಿಸಿ - ಕಿಟ್ ಯಾವಾಗಲೂ QR ಕೋಡ್ ಸ್ಕ್ಯಾನ್ ಮಾಡಿ + ಕಿಟ್‌ನ ಕ್ಯೂಆರ್ ಕೋಡ್ ಅನ್ನು ಸ್ಕ್ಯಾನ್ ಮಾಡಿ ಕಿಟ್ ಸೀರಿಯಲ್ ಸಂಖ್ಯೆಯನ್ನು ಕೈಯಿಂದ ನಮೂದಿಸಿ ಸೀರಿಯಲ್ ಸಂಖ್ಯೆ ಬೇಸ್ಲೈನ್/ಸಂದರ್ಭ ಹೊಂದಿಸಿರಾ? From c57339008207c0b80ec79276123bdbfc8169aa88 Mon Sep 17 00:00:00 2001 From: Mariya Date: Wed, 20 Dec 2023 17:15:41 +0530 Subject: [PATCH 3/9] ADDED CODE FOR OVF --- .../hpostesting/presentation/hemocube/HemoCubeFragment.kt | 7 +++++++ app/src/main/res/values/strings.xml | 1 + 2 files changed, 8 insertions(+) diff --git a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt index 7128812..ffbdea5 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt @@ -353,11 +353,18 @@ class HemoCubeFragment : Fragment() { testingTrace.stop() } + resultData.contains("ovf") -> { + hemoCubeViewModel.messages.postValue( + getString(R.string.power_bank) + ) + } + resultData.contains("REND") && this.testStatusCode < Constants.TEST_STATUS_CODE_SAMPLE_PRINT_COMPLETED -> { this.testStatusCode = Constants.TEST_STATUS_CODE_SAMPLE_PRINT_COMPLETED hemoCubeViewModel.messages.postValue( getString(R.string.data_collected_processing_data) ) + val resultLines = resultData.split("\\s+(?=LB|LS)".toRegex()) var bufferIntensity = resultLines[1].split(' ')[1].trim() led1BufferForDevice = if (isUsingExistingBuffer) { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 47fd564..f6ce9b0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -252,6 +252,7 @@ Sample Started Buffer Completed Buffer Started + Connect with Power Bank Start Place Sample Invalid From 9183c97aef45d5cd3776fa02d17300b72f5130ae Mon Sep 17 00:00:00 2001 From: Pritimay Sarkar Date: Thu, 21 Dec 2023 16:14:29 +0530 Subject: [PATCH 4/9] add slope based class --- app/build.gradle | 6 +- .../hpostesting/data/constant/Constants.kt | 12 ++-- .../data/model/patient/HemoCubeTestData.kt | 3 + .../presentation/hemocube/HemoCubeFragment.kt | 66 ++++++++++++++++++- .../hemocube/HemoCubeViewModel.kt | 3 + 5 files changed, 80 insertions(+), 10 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 0a45e20..3fc030e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -16,11 +16,11 @@ android { // prod - production, preprod - preproduction, quality - qc defaultConfig { - applicationId "in.sminnovations.hpostesting" + applicationId "in.sminnovations.hpostesting.preprod" minSdk 21 targetSdk 34 - versionCode 56 - versionName "2.1.56" + versionCode 60 + versionName "2.1.60" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/app/src/main/java/com/example/hpostesting/data/constant/Constants.kt b/app/src/main/java/com/example/hpostesting/data/constant/Constants.kt index 891c3a5..5f65f52 100644 --- a/app/src/main/java/com/example/hpostesting/data/constant/Constants.kt +++ b/app/src/main/java/com/example/hpostesting/data/constant/Constants.kt @@ -128,21 +128,21 @@ object Constants { listOf(1.0, 0.0) // LED4 ), "HCV-000-3005" to listOf( - listOf(1.7272, -1.1977), // LED1, 435nm + listOf(1.3801, -0.372), // LED1, 435nm listOf(0.581462456, -0.58502), // LED2, 415nm - listOf(0.2304, -0.0145), // LED3, 555nm + listOf(0.4565, -0.0371), // LED3, 555nm listOf(1.0, 0.0) // LED4 ), "HCV-000-3006" to listOf( - listOf(1.7272, -1.1977), // LED1, 435nm + listOf(1.3801, -0.372), // LED1, 435nm listOf(0.581462456, -0.58502), // LED2, 415nm - listOf(0.2304, -0.0145), // LED3, 555nm + listOf(0.4565, -0.0371), // LED3, 555nm listOf(1.0, 0.0) // LED4 ), "HCV-000-3007" to listOf( - listOf(1.7272, -1.1977), // LED1, 435nm + listOf(1.8445, -0.8213), // LED1, 435nm listOf(0.581462456, -0.58502), // LED2, 415nm - listOf(0.2304, -0.0145), // LED3, 555nm + listOf(0.4613, -0.0831), // LED3, 555nm listOf(1.0, 0.0) // LED4 ), "HCV-000-3008" to listOf( diff --git a/app/src/main/java/com/example/hpostesting/data/model/patient/HemoCubeTestData.kt b/app/src/main/java/com/example/hpostesting/data/model/patient/HemoCubeTestData.kt index 5b22aee..64719fe 100644 --- a/app/src/main/java/com/example/hpostesting/data/model/patient/HemoCubeTestData.kt +++ b/app/src/main/java/com/example/hpostesting/data/model/patient/HemoCubeTestData.kt @@ -46,9 +46,12 @@ data class HemoCubeTestData( var deviceRatio: Double? = null, var calculatedRatio: Double? = null, var predictedDenovixRatio: Double? = null, + var slopeRatio: Double? = null, var coefficients: String? = "", var classificationResult: String = "", var prdClassification: String = "", + var deviceRatioClass: String = "", + var slopeRatioClass: String = "", var errorMessages: String = "", var batteryLevel: String = "", var batteryCapacity: String = "", diff --git a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt index 7128812..046e426 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt @@ -504,6 +504,9 @@ class HemoCubeFragment : Fragment() { _predictedDenovixRatio = fittedAbs3.div(fittedAbs1) + val _slopeRatio = (fittedAbs1 - fittedAbs2) / (435 - 415) + val slopeClass = slopeRatioClassification(_slopeRatio) + if (fittedAbs1 <= fittedAbs2) { validationError = true allErrorMessages += "Error: Invalid Test. Problem with de-oxygenation" + "\n" @@ -521,6 +524,14 @@ class HemoCubeFragment : Fragment() { } } + if ((led1Average < 0.7 || led2Average < 0.7 || led3Average < 0.7 || led4Average < 0.7) && _slopeRatio > 35.0) { + validationError = true + activity?.runOnUiThread { + binding.errorMessage.text = "Severely Low Hb. Repeat test with 12 ul in 2 ml Buffer" + binding.errorMessage.visibility = View.VISIBLE + } + } + if (fittedAbs3 < 0.1) { validationError = true allErrorMessages += "Error: Low Hb. Repeat test" + "\n" @@ -552,11 +563,14 @@ class HemoCubeFragment : Fragment() { this.deviceRatio = deviceRatio this.calculatedRatio = calculateRatio(deviceRatio) this.predictedDenovixRatio = _predictedDenovixRatio + this.slopeRatio = _slopeRatio this.coefficients = currentDeviceData?.coefficients?.get(0) .toString() + ", " + currentDeviceData?.coefficients?.get(1).toString() this.classificationResult = findResult(calculatedRatio) this.prdClassification = absorbanceBasedClassification(predictedDenovixRatio) - hemoCubeViewModel.messages.postValue(this.prdClassification) + this.deviceRatioClass = deviceRatioClassification(deviceRatio) + this.slopeRatioClass = slopeRatioClass + hemoCubeViewModel.messages.postValue("Pdr: ${this.prdClassification}\n, Slope: ${this.slopeRatioClass}\n, Device: ${this.deviceRatioClass}") this.errorMessages = allErrorMessages this.resultData = deviceLog this.batteryLevel = hemoCubeViewModel.getBatteryLevel().toString() @@ -626,6 +640,56 @@ class HemoCubeFragment : Fragment() { return getString(R.string.invalid) } + fun deviceRatioClassification(ratio: Double?): String { + try { + hemoCubeViewModel.messages.postValue("result classification") + if (ratio != null) { + if (ratio in 0.0..0.4) + return getString(R.string.normal) + if (ratio in 0.4..0.45) + return getString(R.string.negative_borderline) + if (ratio in 0.45..0.55) + return getString(R.string.sickle_cell_trait) + if (ratio in 0.55..0.575) + return getString(R.string.positive_for_sickle_cell) + if (ratio in 0.09..1.0) + return getString(R.string.sickle_cell_disease) + } else { + return getString(R.string.invalid) + } + } catch (e: Exception) { + showToast(R.string.error_classification) + Firebase.crashlytics.recordException(e) + return getString(R.string.error) + } + return getString(R.string.invalid) + } + + fun slopeRatioClassification(ratio: Double?): String { + try { + hemoCubeViewModel.messages.postValue("result classification") + if (ratio != null) { + if (ratio in 0.0..35.0) + return getString(R.string.normal) + if (ratio in 35.0..40.0) + return getString(R.string.negative_borderline) + if (ratio in 40.0..70.0) + return getString(R.string.sickle_cell_trait) + if (ratio in 70.0..75.0) + return getString(R.string.positive_for_sickle_cell) + if (ratio in 75.0..300.0) + return getString(R.string.sickle_cell_disease) + } else { + return getString(R.string.invalid) + } + } catch (e: Exception) { + showToast(R.string.error_classification) + Firebase.crashlytics.recordException(e) + return getString(R.string.error) + } + return getString(R.string.invalid) + } + private fun absorbanceBasedClassification(predictedDenovixRatio: Double?): String { try { hemoCubeViewModel.messages.postValue("result classification") diff --git a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt index f32fa04..bffd814 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt @@ -129,10 +129,13 @@ class HemoCubeViewModel @Inject constructor( testDetails?.deviceRatio = DataHolder.hemoCubeTestData?.deviceRatio testDetails?.predictedDenovixRatio = DataHolder.hemoCubeTestData?.predictedDenovixRatio testDetails?.calculatedRatio = DataHolder.hemoCubeTestData?.calculatedRatio + testDetails?.slopeRatio = DataHolder.hemoCubeTestData?.slopeRatio testDetails?.coefficients = DataHolder.hemoCubeTestData?.coefficients testDetails?.classificationResult = DataHolder.hemoCubeTestData?.classificationResult!! testDetails?.prdClassification = DataHolder.hemoCubeTestData?.prdClassification.toString() + testDetails?.deviceRatioClass = DataHolder.hemoCubeTestData?.deviceRatioClass!! + testDetails?.slopeRatioClass = DataHolder.hemoCubeTestData?.slopeRatioClass!! testDetails?.batteryLevel = DataHolder.hemoCubeTestData?.batteryLevel.toString() testDetails?.batteryCapacity = DataHolder.hemoCubeTestData?.batteryCapacity.toString() testDetails?.batteryMaxCapacity = From 7a4b68690d035040d751cc7822065f66dc125a7b Mon Sep 17 00:00:00 2001 From: Pritimay Sarkar Date: Sat, 23 Dec 2023 18:19:13 +0530 Subject: [PATCH 5/9] add new slope class thresholds --- app/build.gradle | 4 ++-- .../example/hpostesting/data/dao/MyDataBase.kt | 2 +- .../presentation/hemocube/HemoCubeFragment.kt | 18 ++++++++++-------- .../layout/fragment_hemo_cube_reference.xml | 2 +- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 3fc030e..7b12f84 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -19,8 +19,8 @@ android { applicationId "in.sminnovations.hpostesting.preprod" minSdk 21 targetSdk 34 - versionCode 60 - versionName "2.1.60" + versionCode 62 + versionName "2.1.62" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/app/src/main/java/com/example/hpostesting/data/dao/MyDataBase.kt b/app/src/main/java/com/example/hpostesting/data/dao/MyDataBase.kt index 49115b7..b291c72 100644 --- a/app/src/main/java/com/example/hpostesting/data/dao/MyDataBase.kt +++ b/app/src/main/java/com/example/hpostesting/data/dao/MyDataBase.kt @@ -11,7 +11,7 @@ import com.example.hpostesting.data.model.patient.HemoCubeTestData import com.google.android.datatransport.runtime.dagger.Provides import javax.inject.Singleton -@Database(entities = [UserData::class, HemoCubeTestData::class, DeviceData::class], version = 13, exportSchema = false) +@Database(entities = [UserData::class, HemoCubeTestData::class, DeviceData::class], version = 14, exportSchema = false) @TypeConverters(Converters::class) abstract class MyDatabase : RoomDatabase() { abstract fun userDao(): UserDao diff --git a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt index 046e426..0de8422 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt @@ -26,6 +26,7 @@ import com.google.firebase.ktx.Firebase import com.google.firebase.perf.ktx.performance import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.databinding.FragmentHemoCubeReferenceBinding +import kotlin.math.abs import kotlin.math.log10 class HemoCubeFragment : Fragment() { @@ -504,7 +505,8 @@ class HemoCubeFragment : Fragment() { _predictedDenovixRatio = fittedAbs3.div(fittedAbs1) - val _slopeRatio = (fittedAbs1 - fittedAbs2) / (435 - 415) + val slope = (led1Average - led2Average) / (435 - 415) + val _slopeRatio = abs(led3Average / slope) val slopeClass = slopeRatioClassification(_slopeRatio) if (fittedAbs1 <= fittedAbs2) { @@ -569,8 +571,8 @@ class HemoCubeFragment : Fragment() { this.classificationResult = findResult(calculatedRatio) this.prdClassification = absorbanceBasedClassification(predictedDenovixRatio) this.deviceRatioClass = deviceRatioClassification(deviceRatio) - this.slopeRatioClass = slopeRatioClass - hemoCubeViewModel.messages.postValue("Pdr: ${this.prdClassification}\n, Slope: ${this.slopeRatioClass}\n, Device: ${this.deviceRatioClass}") + this.slopeRatioClass = slopeClass + hemoCubeViewModel.messages.postValue("Slope Ratio: ${slopeRatio},\n Slope: ${this.slopeRatioClass}\n") this.errorMessages = allErrorMessages this.resultData = deviceLog this.batteryLevel = hemoCubeViewModel.getBatteryLevel().toString() @@ -669,15 +671,15 @@ class HemoCubeFragment : Fragment() { try { hemoCubeViewModel.messages.postValue("result classification") if (ratio != null) { - if (ratio in 0.0..35.0) + if (ratio in 0.0..30.0) return getString(R.string.normal) - if (ratio in 35.0..40.0) + if (ratio in 30.0..35.0) return getString(R.string.negative_borderline) - if (ratio in 40.0..70.0) + if (ratio in 35.0..50.0) return getString(R.string.sickle_cell_trait) - if (ratio in 70.0..75.0) + if (ratio in 50.0..60.0) return getString(R.string.positive_for_sickle_cell) - if (ratio in 75.0..300.0) + if (ratio > 60.0) return getString(R.string.sickle_cell_disease) } else { return getString(R.string.invalid) diff --git a/app/src/main/res/layout/fragment_hemo_cube_reference.xml b/app/src/main/res/layout/fragment_hemo_cube_reference.xml index 9b166f9..18300de 100644 --- a/app/src/main/res/layout/fragment_hemo_cube_reference.xml +++ b/app/src/main/res/layout/fragment_hemo_cube_reference.xml @@ -210,7 +210,7 @@ style="@style/title1_1" android:visibility="gone" android:layout_width="0dp" - android:layout_height="180dp" + android:layout_height="0dp" android:layout_marginHorizontal="24dp" android:layout_marginTop="72dp" android:gravity="center" From f6b1b83f24de406806e54a09cb94c28f1daed7ba Mon Sep 17 00:00:00 2001 From: Pritimay Sarkar Date: Tue, 2 Jan 2024 10:56:38 +0530 Subject: [PATCH 6/9] add gains commands and save gains data --- app/build.gradle | 2 +- .../hpostesting/data/constant/Constants.kt | 152 +++++++++++++++- .../data/constant/HemoCubeCommands.kt | 6 +- .../hpostesting/data/dao/MyDataBase.kt | 2 +- .../data/model/patient/HemoCubeTestData.kt | 16 ++ .../HemoCubeBufferCheckFragment.kt | 5 +- .../presentation/hemocube/HemoCubeFragment.kt | 171 ++++++++++++++++-- .../hemocube/HemoCubeViewModel.kt | 12 ++ .../layout/fragment_hemo_cube_reference.xml | 27 +-- 9 files changed, 357 insertions(+), 36 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 7b12f84..5a97234 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -16,7 +16,7 @@ android { // prod - production, preprod - preproduction, quality - qc defaultConfig { - applicationId "in.sminnovations.hpostesting.preprod" + applicationId "in.sminnovations.hpostesting" minSdk 21 targetSdk 34 versionCode 62 diff --git a/app/src/main/java/com/example/hpostesting/data/constant/Constants.kt b/app/src/main/java/com/example/hpostesting/data/constant/Constants.kt index 5f65f52..c02e665 100644 --- a/app/src/main/java/com/example/hpostesting/data/constant/Constants.kt +++ b/app/src/main/java/com/example/hpostesting/data/constant/Constants.kt @@ -73,7 +73,17 @@ object Constants { "HCV-000-3007", "HCV-000-3008", "HCV-000-3009", - "HCV-000-3010" + "HCV-000-3010", + "HCV-000-3011", + "HCV-000-3012", + "HCV-000-3013", + "HCV-000-3014", + "HCV-000-3015", + "HCV-000-3016", + "HCV-000-3017", + "HCV-000-3018", + "HCV-000-3019", + "HCV-000-3020" ) const val password = "SMI@12345" @@ -100,7 +110,23 @@ object Constants { const val TEST_STATUS_CODE_SAMPLE_COMPLETED = 9.0 const val TEST_STATUS_CODE_SAMPLE_PRINT_STARTED = 10.0 const val TEST_STATUS_CODE_SAMPLE_PRINT_COMPLETED = 11.0 - const val TEST_STATUS_CODE_TEST_COMPLETED = 12.0 + const val TEST_STATUS_CODE_FIRST_GAIN_STARTED = 12.0 + const val TEST_STATUS_CODE_FIRST_GAIN_COMPLETED = 13.0 + const val TEST_STATUS_CODE_FIRST_GAIN_PRINT_STARTED = 14.0 + const val TEST_STATUS_CODE_FIRST_GAIN_PRINT_COMPLETED = 15.0 + const val TEST_STATUS_CODE_SECOND_GAIN_STARTED = 16.0 + const val TEST_STATUS_CODE_SECOND_GAIN_COMPLETED = 17.0 + const val TEST_STATUS_CODE_SECOND_GAIN_PRINT_STARTED = 18.0 + const val TEST_STATUS_CODE_SECOND_GAIN_PRINT_COMPLETED = 19.0 + const val TEST_STATUS_CODE_THIRD_GAIN_STARTED = 20.0 + const val TEST_STATUS_CODE_THIRD_GAIN_COMPLETED = 21.0 + const val TEST_STATUS_CODE_THIRD_GAIN_PRINT_STARTED = 22.0 + const val TEST_STATUS_CODE_THIRD_GAIN_PRINT_COMPLETED = 23.0 + const val TEST_STATUS_CODE_FORTH_GAIN_STARTED = 24.0 + const val TEST_STATUS_CODE_FORTH_GAIN_COMPLETED = 25.0 + const val TEST_STATUS_CODE_FORTH_GAIN_PRINT_STARTED = 26.0 + const val TEST_STATUS_CODE_FORTH_GAIN_PRINT_COMPLETED = 27.0 + const val TEST_STATUS_CODE_TEST_COMPLETED = 30.0 val DEVICE_CONFIGURATION: Map>> = mapOf>>( "HCV-000-3001" to listOf( @@ -163,6 +189,66 @@ object Constants { listOf(0.2304, -0.0145), // LED3, 555nm listOf(1.0, 0.0) // LED4 ), + "HCV-000-3011" to listOf( + listOf(1.7272, -1.1977), // LED1, 435nm + listOf(0.581462456, -0.58502), // LED2, 415nm + listOf(0.2304, -0.0145), // LED3, 555nm + listOf(1.0, 0.0) // LED4 + ), + "HCV-000-3012" to listOf( + listOf(1.7272, -1.1977), // LED1, 435nm + listOf(0.581462456, -0.58502), // LED2, 415nm + listOf(0.2304, -0.0145), // LED3, 555nm + listOf(1.0, 0.0) // LED4 + ), + "HCV-000-3013" to listOf( + listOf(1.7272, -1.1977), // LED1, 435nm + listOf(0.581462456, -0.58502), // LED2, 415nm + listOf(0.2304, -0.0145), // LED3, 555nm + listOf(1.0, 0.0) // LED4 + ), + "HCV-000-3014" to listOf( + listOf(1.7272, -1.1977), // LED1, 435nm + listOf(0.581462456, -0.58502), // LED2, 415nm + listOf(0.2304, -0.0145), // LED3, 555nm + listOf(1.0, 0.0) // LED4 + ), + "HCV-000-3015" to listOf( + listOf(1.7272, -1.1977), // LED1, 435nm + listOf(0.581462456, -0.58502), // LED2, 415nm + listOf(0.2304, -0.0145), // LED3, 555nm + listOf(1.0, 0.0) // LED4 + ), + "HCV-000-3016" to listOf( + listOf(1.7272, -1.1977), // LED1, 435nm + listOf(0.581462456, -0.58502), // LED2, 415nm + listOf(0.2304, -0.0145), // LED3, 555nm + listOf(1.0, 0.0) // LED4 + ), + "HCV-000-3017" to listOf( + listOf(1.7272, -1.1977), // LED1, 435nm + listOf(0.581462456, -0.58502), // LED2, 415nm + listOf(0.2304, -0.0145), // LED3, 555nm + listOf(1.0, 0.0) // LED4 + ), + "HCV-000-3018" to listOf( + listOf(1.7272, -1.1977), // LED1, 435nm + listOf(0.581462456, -0.58502), // LED2, 415nm + listOf(0.2304, -0.0145), // LED3, 555nm + listOf(1.0, 0.0) // LED4 + ), + "HCV-000-3019" to listOf( + listOf(1.7272, -1.1977), // LED1, 435nm + listOf(0.581462456, -0.58502), // LED2, 415nm + listOf(0.2304, -0.0145), // LED3, 555nm + listOf(1.0, 0.0) // LED4 + ), + "HCV-000-3020" to listOf( + listOf(1.7272, -1.1977), // LED1, 435nm + listOf(0.581462456, -0.58502), // LED2, 415nm + listOf(0.2304, -0.0145), // LED3, 555nm + listOf(1.0, 0.0) // LED4 + ), ) const val INCUBATION_TIME_MIN = 0 @@ -229,6 +315,66 @@ object Constants { listOf(24500, 26250), listOf(24500, 26250), listOf(24500, 26250), - ) + ), + "HCV-000-3011" to listOf( + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + ), + "HCV-000-3012" to listOf( + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + ), + "HCV-000-3013" to listOf( + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + ), + "HCV-000-3014" to listOf( + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + ), + "HCV-000-3015" to listOf( + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + ), + "HCV-000-3016" to listOf( + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + ), + "HCV-000-3017" to listOf( + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + ), + "HCV-000-3018" to listOf( + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + ), + "HCV-000-3019" to listOf( + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + ), + "HCV-000-3020" to listOf( + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + listOf(24500, 26250), + ), ) } \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/data/constant/HemoCubeCommands.kt b/app/src/main/java/com/example/hpostesting/data/constant/HemoCubeCommands.kt index 1a806e2..4e06388 100644 --- a/app/src/main/java/com/example/hpostesting/data/constant/HemoCubeCommands.kt +++ b/app/src/main/java/com/example/hpostesting/data/constant/HemoCubeCommands.kt @@ -4,6 +4,10 @@ enum class HemoCubeCommands(val command: String) { startBuffer("B\r"), runDiagnostics("D\r"), startSample("S\r"), - getSample("P\r"), + PRINT_COMMAND("P\r"), getDeviceId("I\r"), + FIRST_GAIN_COMMAND("T\r"), + SECOND_GAIN_COMMAND("U\r"), + THIRD_GAIN_COMMAND("V\r"), + FORTH_GAIN_COMMAND("W\r"), } \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/data/dao/MyDataBase.kt b/app/src/main/java/com/example/hpostesting/data/dao/MyDataBase.kt index b291c72..9b44389 100644 --- a/app/src/main/java/com/example/hpostesting/data/dao/MyDataBase.kt +++ b/app/src/main/java/com/example/hpostesting/data/dao/MyDataBase.kt @@ -11,7 +11,7 @@ import com.example.hpostesting.data.model.patient.HemoCubeTestData import com.google.android.datatransport.runtime.dagger.Provides import javax.inject.Singleton -@Database(entities = [UserData::class, HemoCubeTestData::class, DeviceData::class], version = 14, exportSchema = false) +@Database(entities = [UserData::class, HemoCubeTestData::class, DeviceData::class], version = 17, exportSchema = false) @TypeConverters(Converters::class) abstract class MyDatabase : RoomDatabase() { abstract fun userDao(): UserDao diff --git a/app/src/main/java/com/example/hpostesting/data/model/patient/HemoCubeTestData.kt b/app/src/main/java/com/example/hpostesting/data/model/patient/HemoCubeTestData.kt index 64719fe..6426955 100644 --- a/app/src/main/java/com/example/hpostesting/data/model/patient/HemoCubeTestData.kt +++ b/app/src/main/java/com/example/hpostesting/data/model/patient/HemoCubeTestData.kt @@ -43,6 +43,22 @@ data class HemoCubeTestData( var abs2: Double? = null, var abs3: Double? = null, var abs4: Double? = null, + var led1Gain1: Double? = null, + var led2Gain1: Double? = null, + var led3Gain1: Double? = null, + var led4Gain1: Double? = null, + var led1Gain2: Double? = null, + var led2Gain2: Double? = null, + var led3Gain2: Double? = null, + var led4Gain2: Double? = null, + var led1Gain3: Double? = null, + var led2Gain3: Double? = null, + var led3Gain3: Double? = null, + var led4Gain3: Double? = null, + var led1Gain4: Double? = null, + var led2Gain4: Double? = null, + var led3Gain4: Double? = null, + var led4Gain4: Double? = null, var deviceRatio: Double? = null, var calculatedRatio: Double? = null, var predictedDenovixRatio: Double? = null, diff --git a/app/src/main/java/com/example/hpostesting/presentation/buffercheck/HemoCubeBufferCheckFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/buffercheck/HemoCubeBufferCheckFragment.kt index 96ace8c..3334585 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/buffercheck/HemoCubeBufferCheckFragment.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/buffercheck/HemoCubeBufferCheckFragment.kt @@ -1,15 +1,12 @@ package com.example.hpostesting.presentation.buffercheck import android.content.Context -import android.content.Intent import android.content.SharedPreferences import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.view.inputmethod.InputMethodManager import android.widget.Toast -import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.lifecycle.MutableLiveData @@ -305,7 +302,7 @@ class HemoCubeBufferCheckFragment : Fragment() { private fun fetchResult() { - (activity as HemocubeBufferCheckActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.getSample, + (activity as HemocubeBufferCheckActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.PRINT_COMMAND, object : UsbServiceListener { override fun onUsbRead(data: ByteArray?) {} diff --git a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt index 0de8422..889fada 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt @@ -28,6 +28,7 @@ import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.databinding.FragmentHemoCubeReferenceBinding import kotlin.math.abs import kotlin.math.log10 +import kotlin.math.round class HemoCubeFragment : Fragment() { @@ -38,6 +39,7 @@ class HemoCubeFragment : Fragment() { private var isOnline = false private var currentDeviceData: DeviceData? = null private var resultData: String = "" + private var currentResultData: String = "" private var isUsingExistingBuffer = false private var isTestOngoing = false private var startListening = MutableLiveData(false) @@ -262,7 +264,7 @@ class HemoCubeFragment : Fragment() { data?.let { val stringData = String(it) fullReadOutput.append(stringData) - handleUsbData(stringData, testStatusCode) + handleUsbData(stringData) } } @@ -295,13 +297,14 @@ class HemoCubeFragment : Fragment() { }) } - private fun handleUsbData(stringData: String, testStatusCode: Double) { + private fun handleUsbData(stringData: String) { if (stringData.contains("#")) { isTestOngoing = true } resultData += stringData - hemoCubeViewModel.deviceMessages.postValue(resultData) + currentResultData += stringData + hemoCubeViewModel.deviceMessages.postValue(currentResultData) when { resultData.contains("SNE") && this.testStatusCode < Constants.TEST_STATUS_CODE_CONFIG_COMPLETED -> { @@ -338,7 +341,7 @@ class HemoCubeFragment : Fragment() { } } - resultData.contains("#SS") && this.testStatusCode < Constants.TEST_STATUS_CODE_SAMPLE_STARTED -> { + resultData.contains("#SS1") && this.testStatusCode < Constants.TEST_STATUS_CODE_SAMPLE_STARTED -> { this.testStatusCode = Constants.TEST_STATUS_CODE_SAMPLE_STARTED activity?.runOnUiThread { binding.tvSubtitle4.text = getString(R.string.sample_started) @@ -346,14 +349,48 @@ class HemoCubeFragment : Fragment() { } } - resultData.contains("#SC") && this.testStatusCode < Constants.TEST_STATUS_CODE_SAMPLE_COMPLETED -> { + resultData.contains("#SC1") && this.testStatusCode < Constants.TEST_STATUS_CODE_SAMPLE_COMPLETED -> { this.testStatusCode = Constants.TEST_STATUS_CODE_SAMPLE_COMPLETED hemoCubeViewModel.messages.postValue( getString(R.string.sample_completed) + "\n" + getString(R.string.gathering_data)) fetchResult() + currentResultData = "" testingTrace.stop() } + currentResultData.contains("#SS2") && this.testStatusCode < Constants.TEST_STATUS_CODE_FIRST_GAIN_STARTED -> { + this.testStatusCode = Constants.TEST_STATUS_CODE_FIRST_GAIN_STARTED + hemoCubeViewModel.messages.postValue("1.3X Gain Started") + } + + currentResultData.contains("#SC2") && this.testStatusCode < Constants.TEST_STATUS_CODE_FIRST_GAIN_COMPLETED -> { + this.testStatusCode = Constants.TEST_STATUS_CODE_FIRST_GAIN_COMPLETED + hemoCubeViewModel.messages.postValue("1.3X Gain Completed") + fetchResult() + } + + currentResultData.contains("#SS3") && this.testStatusCode < Constants.TEST_STATUS_CODE_SECOND_GAIN_STARTED -> { + this.testStatusCode = Constants.TEST_STATUS_CODE_SECOND_GAIN_STARTED + hemoCubeViewModel.messages.postValue("2X Gain Started") + } + + currentResultData.contains("#SC3") && this.testStatusCode < Constants.TEST_STATUS_CODE_SECOND_GAIN_COMPLETED -> { + this.testStatusCode = Constants.TEST_STATUS_CODE_SECOND_GAIN_COMPLETED + hemoCubeViewModel.messages.postValue("2X Gain Completed") + fetchResult() + } + + currentResultData.contains("#SS5") && this.testStatusCode < Constants.TEST_STATUS_CODE_FORTH_GAIN_STARTED -> { + this.testStatusCode = Constants.TEST_STATUS_CODE_FORTH_GAIN_STARTED + hemoCubeViewModel.messages.postValue("7.6X Gain Started") + } + + currentResultData.contains("#SC5") && this.testStatusCode < Constants.TEST_STATUS_CODE_FORTH_GAIN_COMPLETED -> { + this.testStatusCode = Constants.TEST_STATUS_CODE_FORTH_GAIN_COMPLETED + hemoCubeViewModel.messages.postValue("7.6X Gain Completed") + fetchResult() + } + resultData.contains("REND") && this.testStatusCode < Constants.TEST_STATUS_CODE_SAMPLE_PRINT_COMPLETED -> { this.testStatusCode = Constants.TEST_STATUS_CODE_SAMPLE_PRINT_COMPLETED hemoCubeViewModel.messages.postValue( @@ -395,6 +432,60 @@ class HemoCubeFragment : Fragment() { led4SampleForDevice = resultLines[8].split(' ')[1].split('\r')[0].trim().toDoubleOrNull()!! processResult() + sendFirstGainCommand() + currentResultData = "" + } + + currentResultData.contains("REND") && this.testStatusCode >= Constants.TEST_STATUS_CODE_FIRST_GAIN_COMPLETED && this.testStatusCode < Constants.TEST_STATUS_CODE_FIRST_GAIN_PRINT_COMPLETED -> { + this.testStatusCode = Constants.TEST_STATUS_CODE_FIRST_GAIN_PRINT_COMPLETED + hemoCubeViewModel.messages.postValue("1.3X gain data gathered") + + val resultLines = currentResultData.split("\\s+(?=LB|LS)".toRegex()) + DataHolder.hemoCubeTestData?.apply { + led1Gain1 = resultLines[5].split(' ')[1].trim().toDoubleOrNull()!! + led2Gain1 = resultLines[6].split(' ')[1].trim().toDoubleOrNull()!! + led3Gain1 = resultLines[7].split(' ')[1].trim().toDoubleOrNull()!! + led4Gain1 = resultLines[8].split(' ')[1].split('\r')[0].trim().toDoubleOrNull()!! + } + + sendSecondGainCommand() + currentResultData = "" + } + + currentResultData.contains("REND") && this.testStatusCode >= Constants.TEST_STATUS_CODE_FIRST_GAIN_PRINT_COMPLETED && this.testStatusCode < Constants.TEST_STATUS_CODE_SECOND_GAIN_PRINT_COMPLETED -> { + this.testStatusCode = Constants.TEST_STATUS_CODE_SECOND_GAIN_PRINT_COMPLETED + hemoCubeViewModel.messages.postValue("2X gain data gathered") + + val resultLines = currentResultData.split("\\s+(?=LB|LS)".toRegex()) + DataHolder.hemoCubeTestData?.apply { + led1Gain2 = resultLines[5].split(' ')[1].trim().toDoubleOrNull()!! + led2Gain2 = resultLines[6].split(' ')[1].trim().toDoubleOrNull()!! + led3Gain2 = resultLines[7].split(' ')[1].trim().toDoubleOrNull()!! + led4Gain2 = resultLines[8].split(' ')[1].split('\r')[0].trim().toDoubleOrNull()!! + } + + sendForthGainCommand() + currentResultData = "" + } + + currentResultData.contains("REND") && this.testStatusCode >= Constants.TEST_STATUS_CODE_SECOND_GAIN_PRINT_COMPLETED && this.testStatusCode < Constants.TEST_STATUS_CODE_FORTH_GAIN_PRINT_COMPLETED -> { + this.testStatusCode = Constants.TEST_STATUS_CODE_FORTH_GAIN_PRINT_COMPLETED + hemoCubeViewModel.messages.postValue("7.6X gain data gathered") + + val resultLines = currentResultData.split("\\s+(?=LB|LS)".toRegex()) + DataHolder.hemoCubeTestData?.apply { + led1Gain4 = resultLines[5].split(' ')[1].trim().toDoubleOrNull()!! + led2Gain4 = resultLines[6].split(' ')[1].trim().toDoubleOrNull()!! + led3Gain4 = resultLines[7].split(' ')[1].trim().toDoubleOrNull()!! + led4Gain4 = resultLines[8].split(' ')[1].split('\r')[0].trim().toDoubleOrNull()!! + } + + activity?.runOnUiThread { + binding.btnSubmit.visibility = View.VISIBLE + binding.btnSubmit.isEnabled = true + binding.btnSubmit.isClickable = true + binding.clParent.setBackgroundColor(Color.parseColor("#edfffd")) + } } } } @@ -482,8 +573,6 @@ class HemoCubeFragment : Fragment() { binding.errorMessage.text = getString(R.string.error_improper_buffer_high) binding.errorMessage.visibility = View.VISIBLE - binding.btnSubmit.isEnabled = true - binding.btnSubmit.isClickable = true } } @@ -572,7 +661,7 @@ class HemoCubeFragment : Fragment() { this.prdClassification = absorbanceBasedClassification(predictedDenovixRatio) this.deviceRatioClass = deviceRatioClassification(deviceRatio) this.slopeRatioClass = slopeClass - hemoCubeViewModel.messages.postValue("Slope Ratio: ${slopeRatio},\n Slope: ${this.slopeRatioClass}\n") + hemoCubeViewModel.messages.postValue("Slope Ratio: ${round(slopeRatio!!)},\n Slope Class: ${this.slopeRatioClass}\n") this.errorMessages = allErrorMessages this.resultData = deviceLog this.batteryLevel = hemoCubeViewModel.getBatteryLevel().toString() @@ -596,12 +685,12 @@ class HemoCubeFragment : Fragment() { } // if (!validationError) { - activity?.runOnUiThread { - binding.btnSubmit.visibility = View.VISIBLE - binding.btnSubmit.isEnabled = true - binding.btnSubmit.isClickable = true - binding.clParent.setBackgroundColor(Color.parseColor("#edfffd")) - } +// activity?.runOnUiThread { +// binding.btnSubmit.visibility = View.VISIBLE +// binding.btnSubmit.isEnabled = true +// binding.btnSubmit.isClickable = true +// binding.clParent.setBackgroundColor(Color.parseColor("#edfffd")) +// } // } } catch (e: Exception) { Toast.makeText( @@ -752,10 +841,62 @@ class HemoCubeFragment : Fragment() { }) } + private fun sendFirstGainCommand() { + hemoCubeViewModel.progressBar.postValue(true) + + (activity as HemocubeActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.FIRST_GAIN_COMMAND, + object : UsbServiceListener { + override fun onUsbRead(data: ByteArray?) {} + + override fun onUsbError(e: Exception?) { + hemoCubeViewModel.progressBar.postValue(false) + } + }) + } + + private fun sendSecondGainCommand() { + hemoCubeViewModel.progressBar.postValue(true) + + (activity as HemocubeActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.SECOND_GAIN_COMMAND, + object : UsbServiceListener { + override fun onUsbRead(data: ByteArray?) {} + + override fun onUsbError(e: Exception?) { + hemoCubeViewModel.progressBar.postValue(false) + } + }) + } + + private fun sendThirdGainCommand() { + hemoCubeViewModel.progressBar.postValue(true) + + (activity as HemocubeActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.THIRD_GAIN_COMMAND, + object : UsbServiceListener { + override fun onUsbRead(data: ByteArray?) {} + + override fun onUsbError(e: Exception?) { + hemoCubeViewModel.progressBar.postValue(false) + } + }) + } + + private fun sendForthGainCommand() { + hemoCubeViewModel.progressBar.postValue(true) + + (activity as HemocubeActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.FORTH_GAIN_COMMAND, + object : UsbServiceListener { + override fun onUsbRead(data: ByteArray?) {} + + override fun onUsbError(e: Exception?) { + hemoCubeViewModel.progressBar.postValue(false) + } + }) + } + private fun fetchResult() { hemoCubeViewModel.progressBar.postValue(true) - (activity as HemocubeActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.getSample, + (activity as HemocubeActivity).mService.sendAndListenToHemoCube(HemoCubeCommands.PRINT_COMMAND, object : UsbServiceListener { override fun onUsbRead(data: ByteArray?) {} diff --git a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt index bffd814..855df7c 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt @@ -126,6 +126,18 @@ class HemoCubeViewModel @Inject constructor( testDetails?.abs2 = DataHolder.hemoCubeTestData?.abs2 testDetails?.abs3 = DataHolder.hemoCubeTestData?.abs3 testDetails?.abs4 = DataHolder.hemoCubeTestData?.abs4 + testDetails?.led1Gain1 = DataHolder.hemoCubeTestData?.led1Gain1 + testDetails?.led2Gain1 = DataHolder.hemoCubeTestData?.led2Gain1 + testDetails?.led3Gain1 = DataHolder.hemoCubeTestData?.led3Gain1 + testDetails?.led4Gain1 = DataHolder.hemoCubeTestData?.led4Gain1 + testDetails?.led1Gain2 = DataHolder.hemoCubeTestData?.led1Gain2 + testDetails?.led2Gain2 = DataHolder.hemoCubeTestData?.led2Gain2 + testDetails?.led3Gain2 = DataHolder.hemoCubeTestData?.led3Gain2 + testDetails?.led4Gain2 = DataHolder.hemoCubeTestData?.led4Gain2 + testDetails?.led1Gain4 = DataHolder.hemoCubeTestData?.led1Gain4 + testDetails?.led2Gain4 = DataHolder.hemoCubeTestData?.led2Gain4 + testDetails?.led3Gain4 = DataHolder.hemoCubeTestData?.led3Gain4 + testDetails?.led4Gain4 = DataHolder.hemoCubeTestData?.led4Gain4 testDetails?.deviceRatio = DataHolder.hemoCubeTestData?.deviceRatio testDetails?.predictedDenovixRatio = DataHolder.hemoCubeTestData?.predictedDenovixRatio testDetails?.calculatedRatio = DataHolder.hemoCubeTestData?.calculatedRatio diff --git a/app/src/main/res/layout/fragment_hemo_cube_reference.xml b/app/src/main/res/layout/fragment_hemo_cube_reference.xml index 18300de..31e59be 100644 --- a/app/src/main/res/layout/fragment_hemo_cube_reference.xml +++ b/app/src/main/res/layout/fragment_hemo_cube_reference.xml @@ -205,20 +205,25 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/btn_submit" /> - + app:layout_constraintTop_toBottomOf="@id/error_message"> + + +