diff --git a/app/build.gradle b/app/build.gradle
index 1158de0..b207d3c 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -18,8 +18,8 @@ android {
applicationId "in.sminnovations.hpostesting.prod"
minSdk 21
targetSdk 34
- versionCode 11
- versionName "2.1.13"
+ versionCode 14
+ versionName "2.1.14"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 11d8e5e..3c91302 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -33,6 +33,13 @@
android:parentActivityName="com.example.hpostesting.presentation.MainActivity"
android:theme="@style/Theme.HPOS.NoActionBar"
android:windowSoftInputMode="adjustPan" />
+
+
\ No newline at end of file
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
new file mode 100644
index 0000000..e8fb957
--- /dev/null
+++ b/app/src/main/java/com/example/hpostesting/presentation/buffercheck/HemoCubeBufferCheckFragment.kt
@@ -0,0 +1,310 @@
+package com.example.hpostesting.presentation.buffercheck
+
+import android.content.Context
+import android.content.SharedPreferences
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Toast
+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.DeviceData
+import com.example.hpostesting.data.model.patient.toHemoCubeTestData
+import com.example.hpostesting.presentation.UsbServiceListener
+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
+
+class HemoCubeBufferCheckFragment : Fragment() {
+
+ private lateinit var binding: FragmentHemoCubeReferenceBinding
+ private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels()
+ private lateinit var sharedPreferences: SharedPreferences
+ private var currentDeviceData: DeviceData? = null
+ private var resultData: String = ""
+ private val messages = MutableLiveData()
+ private var isTestOngoing = false
+ private var startListening = MutableLiveData(false)
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
+ ): View {
+ binding = FragmentHemoCubeReferenceBinding.inflate(inflater, container, false)
+ sharedPreferences =
+ requireContext().getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE)
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ initViews()
+ observeViewModel()
+ }
+
+ private fun initViews() {
+ binding.btnKit.visibility = View.GONE
+ binding.btnSubmit.visibility = View.GONE
+ binding.etBloodGroup.visibility = View.GONE
+ listenToHemoCube()
+ startBufferProcess()
+ }
+
+ private fun observeViewModel() {
+
+ hemoCubeViewModel.deviceData.observe(viewLifecycleOwner) {
+ currentDeviceData = it
+ }
+
+ hemoCubeViewModel.networkStatusLiveData.observe(viewLifecycleOwner) { isNetworkAvailable ->
+ if (isNetworkAvailable) {
+ hemoCubeViewModel.getDeviceData(sharedPreferences.getString(Constants.USER_ID, ""))
+ } else {
+ Toast.makeText(
+ requireContext(),
+ "No internet connection avaiable",
+ Toast.LENGTH_SHORT
+ ).show()
+ }
+ }
+
+ messages.observe(viewLifecycleOwner) {
+ binding.tvSubtitle4.text = it
+ }
+ }
+
+ 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)
+ }
+ }
+
+ override fun onUsbError(e: Exception?) {
+ }
+ })
+ } catch (e: Exception) {
+ showToast("test is going on")
+ Firebase.crashlytics.recordException(e)
+ }
+ }
+
+ private fun handleUsbData(stringData: String, fullReadOutput: StringBuilder) {
+ if (stringData.contains("#")) {
+ messages.postValue(stringData)
+ isTestOngoing = true
+ }
+
+ resultData += fullReadOutput.toString()
+
+ when {
+ stringData.contains("ERROR 500") -> showError500Dialog()
+ stringData.contains("ERROR 501") -> showError501Dialog()
+ stringData.contains("#Buffer Completed") -> showStartSampleDialog()
+ stringData.contains("#Sample Completed") -> 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 showError500Dialog() {
+ UIUtils.createAlertDialog(requireContext(),
+ "BUFFER ERROR",
+ "Do you want to continue with existing buffer?",
+ getString(R.string.noo),
+ "Yes",
+ object : MyDialogListener {
+ override fun onClickNegativeButton() {}
+
+ override fun onClickPositiveButton() {
+ listenToHemoCube()
+ startBufferProcess()
+ }
+ })
+ }
+
+
+ private fun showError501Dialog() {
+ UIUtils.createAlertDialog(requireContext(),
+ "SAMPLE ERROR",
+ "Do you want to continue with Sample?",
+ getString(R.string.noo),
+ "Yes",
+ object : MyDialogListener {
+ override fun onClickNegativeButton() {}
+
+ override fun onClickPositiveButton() {
+ listenToHemoCube()
+ startSampleProcess()
+ }
+ })
+ }
+
+ 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 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 calculatedRatio = calculateRatio(deviceRatio)
+ val classificationResult = findResult(calculatedRatio)
+ messages.postValue(classificationResult)
+ }
+ } catch (e: Exception) {
+ Toast.makeText(
+ requireContext(), "Error while processing device data", Toast.LENGTH_SHORT
+ ).show()
+ Firebase.crashlytics.recordException(e)
+ }
+ }
+
+ private fun findResult(calculatedRatio: Double?): String {
+ try {
+ 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"
+ } else {
+ return "NULL"
+ }
+ } catch (e: Exception) {
+ showToast("error while performing classification")
+ Firebase.crashlytics.recordException(e)
+ return "ERROR"
+ }
+ return "NULL"
+ }
+
+ private fun showToast(message: String) {
+ Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
+ }
+
+ private fun startBufferProcess() {
+
+ (activity as HemocubeBufferCheckActivity).mService.sendAndListenToHemoCube(
+ HemoCubeCommands.startBuffer,
+ object : UsbServiceListener {
+ override fun onUsbRead(data: ByteArray?) {}
+
+ override fun onUsbError(e: Exception?) {
+ }
+ })
+ }
+
+ private fun startSampleProcess() {
+
+ (activity as HemocubeBufferCheckActivity).mService.sendAndListenToHemoCube(
+ HemoCubeCommands.startSample,
+ object : UsbServiceListener {
+ override fun onUsbRead(data: ByteArray?) {}
+
+ override fun onUsbError(e: Exception?) {
+ }
+ })
+ }
+
+ private fun fetchResult() {
+
+ (activity as HemocubeBufferCheckActivity).mService.sendAndListenToHemoCube(
+ HemoCubeCommands.getSample,
+ object : UsbServiceListener {
+ override fun onUsbRead(data: ByteArray?) {}
+
+ override fun onUsbError(e: Exception?) {
+ }
+ })
+ }
+
+ private fun calculateRatio(ratio: Double): Double {
+ val coefficient1 = currentDeviceData?.coefficients?.get(0) ?: 0.0
+ val coefficient2 = currentDeviceData?.coefficients?.get(1) ?: 1.0
+ 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 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/buffercheck/HemocubeBufferCheckActivity.kt b/app/src/main/java/com/example/hpostesting/presentation/buffercheck/HemocubeBufferCheckActivity.kt
new file mode 100644
index 0000000..6375d39
--- /dev/null
+++ b/app/src/main/java/com/example/hpostesting/presentation/buffercheck/HemocubeBufferCheckActivity.kt
@@ -0,0 +1,164 @@
+package com.example.hpostesting.presentation.buffercheck
+
+import android.app.PendingIntent
+import android.content.BroadcastReceiver
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.content.ServiceConnection
+import android.hardware.usb.UsbDevice
+import android.hardware.usb.UsbDeviceConnection
+import android.hardware.usb.UsbManager
+import android.os.Bundle
+import android.os.IBinder
+import android.util.Log
+import android.view.Menu
+import android.widget.Toast
+import androidx.activity.viewModels
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.content.ContextCompat
+import androidx.core.view.get
+import com.example.hpostesting.data.DataHolder
+import com.example.hpostesting.data.constant.Constants
+import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
+import com.example.hpostesting.presentation.testRight.UsbService
+import com.hoho.android.usbserial.driver.UsbSerialDriver
+import com.hoho.android.usbserial.driver.UsbSerialProber
+import dagger.hilt.android.AndroidEntryPoint
+import `in`.sminnovations.hpostesting.R
+import `in`.sminnovations.hpostesting.databinding.ActivityHemocubeBinding
+
+@AndroidEntryPoint
+open class HemocubeBufferCheckActivity : AppCompatActivity() {
+ private lateinit var binding: ActivityHemocubeBinding
+ private val viewModel by viewModels()
+ private var myMenu: Menu? = null
+
+ private lateinit var mDriver: UsbSerialDriver
+ private var mConnection: UsbDeviceConnection? = null
+ lateinit var mService: UsbService
+
+ private val TAG = "HemoCube"
+
+ private val broadcastReceiver = object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+
+ synchronized(this) {
+ val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
+
+ if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
+ device?.apply {
+ connectUsb(true)
+ DataHolder.usbConnected.postValue(true)
+ }
+ } else {
+ DataHolder.usbConnected.postValue(true)
+ }
+ }
+
+ }
+ }
+ private val connection = object : ServiceConnection {
+ override fun onServiceConnected(className: ComponentName, service: IBinder) {
+ val binder = service as UsbService.UsbServiceBinder
+ mService = binder.getService()
+ viewModel.isServiceConnected = true
+ mConnection.let { mService.connect(mDriver, mConnection!!) }
+ moveToNext()
+ }
+
+ override fun onServiceDisconnected(arg0: ComponentName) {
+ viewModel.isServiceConnected = false
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityHemocubeBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ setSupportActionBar(binding.myToolbar)
+ supportActionBar?.setDisplayHomeAsUpEnabled(true)
+ setupListener()
+ connectUsb(false)
+ }
+
+ private fun setupListener() {
+ DataHolder.usbConnected.observe(this) {
+ Log.d("USB OBSERVE", "HemoCube called -> $it")
+ if (it) {
+ myMenu?.get(0)?.icon =
+ ContextCompat.getDrawable(this, R.drawable.ic_baseline_usb_24)
+ } else {
+ myMenu?.get(0)?.icon =
+ ContextCompat.getDrawable(this, R.drawable.ic_baseline_usb_off_24)
+ Toast.makeText(this, "Device is Disconnected", Toast.LENGTH_SHORT).show()
+ }
+ }
+ }
+
+ open fun connectUsb(permissionGranted: Boolean) {
+ Log.d(TAG, "connectUsb() called, permission variable = $permissionGranted")
+ val manager = getSystemService(Context.USB_SERVICE) as UsbManager
+ val availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager)
+
+ if (availableDrivers.isEmpty()) {
+ Toast.makeText(this, "No device found", Toast.LENGTH_SHORT).show()
+ } else {
+ mDriver = availableDrivers[0]
+ mConnection = manager.openDevice(mDriver.device)
+
+ if (mConnection == null) {
+ requestUserPermission(manager, mDriver.device)
+ } else {
+ setupService()
+ }
+ }
+ }
+
+
+ private fun requestUserPermission(manager: UsbManager, device: UsbDevice) {
+ val mPendingIntent: PendingIntent = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
+ PendingIntent.getBroadcast(
+ this, 0, Intent(Constants.HOMOCUBE_USB_PERMISSION), PendingIntent.FLAG_MUTABLE
+ )
+ } else {
+ PendingIntent.getBroadcast(
+ this,
+ 0,
+ Intent(Constants.HOMOCUBE_USB_PERMISSION),
+ PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE
+ )
+ }
+
+ val filter = IntentFilter(Constants.HOMOCUBE_USB_PERMISSION)
+ registerReceiver(broadcastReceiver, filter)
+ manager.requestPermission(device, mPendingIntent)
+ }
+
+ private fun setupService() {
+ val intent = Intent(this, UsbService::class.java)
+ bindService(intent, connection, Context.BIND_AUTO_CREATE)
+ }
+
+ private fun moveToNext() {
+ if (supportFragmentManager.isDestroyed) return
+
+ supportFragmentManager.beginTransaction().replace(binding.fghemocube.id, HemoCubeBufferCheckFragment())
+ .commit()
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu?): Boolean {
+ menuInflater.inflate(R.menu.my_menu, menu)
+ return true
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ if (viewModel.isServiceConnected) {
+ mService.disconnect()
+ unbindService(connection)
+ viewModel.isServiceConnected = false
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/hpostesting/presentation/dashboard/GalleryFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/dashboard/GalleryFragment.kt
index 1911ca0..9307d1b 100644
--- a/app/src/main/java/com/example/hpostesting/presentation/dashboard/GalleryFragment.kt
+++ b/app/src/main/java/com/example/hpostesting/presentation/dashboard/GalleryFragment.kt
@@ -1,12 +1,12 @@
package com.example.hpostesting.presentation.dashboard
+import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
-import androidx.lifecycle.ViewModelProvider
-//import com.example.hpostesting.presentation.dashboard.ui.gallery.GalleryViewModel
+import com.example.hpostesting.presentation.buffercheck.HemocubeBufferCheckActivity
import `in`.sminnovations.hpostesting.databinding.FragmentGalleryBinding
class GalleryFragment : Fragment() {
@@ -32,6 +32,9 @@ class GalleryFragment : Fragment() {
// galleryViewModel.text.observe(viewLifecycleOwner) {
//// textView.text = it
// }
+ binding.btnSubmit.setOnClickListener {
+ startActivity(Intent(requireContext(), HemocubeBufferCheckActivity::class.java))
+ }
return root
}
diff --git a/app/src/main/res/layout/fragment_gallery.xml b/app/src/main/res/layout/fragment_gallery.xml
index 2a4b95d..6f43343 100644
--- a/app/src/main/res/layout/fragment_gallery.xml
+++ b/app/src/main/res/layout/fragment_gallery.xml
@@ -4,19 +4,21 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
- tools:context=".presentation.dashboard.GalleryFragment">
+ tools:context="com.example.hpostesting.presentation.dashboard.GalleryFragment">
-
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 15023b1..5ec2c82 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -193,5 +193,6 @@
Select Blood Group
All registered user are tested successfully
Start Incubation
+ Check Buffer
\ No newline at end of file