diff --git a/app/build.gradle b/app/build.gradle
index d6e5663..2081129 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -46,6 +46,7 @@ android {
buildFeatures {
dataBinding true
}
+
buildTypes {
release {
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 57c24e9..4e663b6 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -12,12 +12,8 @@
-
-
+
+
diff --git a/app/src/main/java/Constants.kt b/app/src/main/java/Constants.kt
index b23dc50..89c6cb0 100644
--- a/app/src/main/java/Constants.kt
+++ b/app/src/main/java/Constants.kt
@@ -1,12 +1,3 @@
-/**
- * Device Types (internal unique strings used to classify which device was used for a given experiment/scan)
- */
-const val DEVICE_TYPE_LS1 = "LinkSquare"
-
-const val DEVICE_TYPE_NIR = "LinkSquareNIR"
-
-const val DEVICE_TYPE_NANO = "InnoSpectra Nano"
-
const val packageId = "org.phenoapps.prospector"
/***
@@ -46,6 +37,8 @@ const val DEVICE_LINK_SQUARE = "$packageId.DEVICE_TYPE_LINK_SQUARE"
const val DEVICE_INNO_SPECTRA = "$packageId.DEVICE_TYPE_INNO_SPECTRA"
+const val DEVICE_INDIGO = "$packageId.DEVICE_TYPE_INDIGO"
+
const val EXPORT_TYPE = "$packageId.EXPORT_TYPE"
const val DEVICE_INFO = "$packageId.DEVICE_INFO"
diff --git a/app/src/main/java/org/phenoapps/prospector/activities/MainActivity.kt b/app/src/main/java/org/phenoapps/prospector/activities/MainActivity.kt
index b710204..abdce62 100644
--- a/app/src/main/java/org/phenoapps/prospector/activities/MainActivity.kt
+++ b/app/src/main/java/org/phenoapps/prospector/activities/MainActivity.kt
@@ -5,25 +5,18 @@ import ALPHA_DESC
import BULB_FRAMES
import DATE_ASC
import DATE_DESC
-import DEVICE_TYPE_LS1
-import DEVICE_TYPE_NANO
-import DEVICE_TYPE_NIR
import FIRST_CONNECT_ERROR_ON_LOAD
import LED_FRAMES
import android.Manifest
import android.app.Activity
import android.bluetooth.BluetoothAdapter
import android.content.Context
-import android.content.DialogInterface
import android.content.Intent
import android.location.LocationManager
import android.net.Uri
import android.os.*
import android.provider.Settings
import android.util.Log
-import android.widget.ListAdapter
-import android.widget.ListView
-import android.view.View
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.appcompat.app.AlertDialog
@@ -35,6 +28,11 @@ import androidx.navigation.Navigation
import androidx.preference.PreferenceManager
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.*
+import org.phenoapps.interfaces.spectrometers.Spectrometer
+import org.phenoapps.interfaces.spectrometers.Spectrometer.Companion.DEVICE_TYPE_INDIGO
+import org.phenoapps.interfaces.spectrometers.Spectrometer.Companion.DEVICE_TYPE_LS1
+import org.phenoapps.interfaces.spectrometers.Spectrometer.Companion.DEVICE_TYPE_NANO
+import org.phenoapps.interfaces.spectrometers.Spectrometer.Companion.DEVICE_TYPE_NIR
import org.phenoapps.prospector.BuildConfig
import org.phenoapps.prospector.NavigationRootDirections
import org.phenoapps.prospector.R
@@ -45,8 +43,9 @@ import org.phenoapps.prospector.data.viewmodels.MainActivityViewModel
import org.phenoapps.prospector.data.viewmodels.devices.InnoSpectraViewModel
import org.phenoapps.prospector.data.viewmodels.devices.LinkSquareViewModel
import org.phenoapps.prospector.databinding.ActivityMainBinding
-import org.phenoapps.prospector.interfaces.Spectrometer
import org.phenoapps.prospector.utils.*
+import org.phenoapps.security.Security
+import org.phenoapps.viewmodels.spectrometers.Indigo
import org.phenoapps.utils.IntentUtil
import java.io.File
@@ -74,6 +73,8 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
private val sViewModel: MainActivityViewModel by viewModels()
+ val advisor by Security().secureBluetoothActivity()
+
/**
* This activity view model is used throughout all the fragments to update connection status.
*/
@@ -135,13 +136,22 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
}
val maker = mPrefs.getString(mKeyUtil.deviceMaker, DEVICE_TYPE_LS1)
- sDeviceViewModel = if (maker == DEVICE_TYPE_LS1) {
+ sDeviceViewModel = when (maker) {
+ in setOf(DEVICE_TYPE_LS1, DEVICE_TYPE_NIR) -> {
- LinkSquareViewModel()
+ LinkSquareViewModel()
- } else {
+ }
+ DEVICE_TYPE_NANO -> {
- InnoSpectraViewModel()
+ InnoSpectraViewModel()
+
+ }
+ else -> {
+
+ Indigo()
+
+ }
}
mBinding = DataBindingUtil.setContentView(this@MainActivity, R.layout.activity_main)
@@ -505,25 +515,50 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
fun switchInnoSpectra() {
- stopDeviceConnection()
+ val current = mPrefs.getString(mKeyUtil.deviceMaker, null)
- mPrefs.edit().putString(mKeyUtil.deviceMaker, DEVICE_TYPE_NANO).apply()
+ if (current != DEVICE_TYPE_NANO) {
- sDeviceViewModel = InnoSpectraViewModel()
+ stopDeviceConnection()
- runtimeBluetoothCheck()
+ mPrefs.edit().putString(mKeyUtil.deviceMaker, DEVICE_TYPE_NANO).apply()
+
+ sDeviceViewModel = InnoSpectraViewModel()
+ runtimeBluetoothCheck()
+ }
}
fun switchLinkSquare() {
- stopDeviceConnection()
+ val current = mPrefs.getString(mKeyUtil.deviceMaker, null)
- mPrefs.edit().putString(mKeyUtil.deviceMaker, DEVICE_TYPE_LS1).apply()
+ if (current !in setOf(DEVICE_TYPE_LS1, DEVICE_TYPE_NIR)) {
- sDeviceViewModel = LinkSquareViewModel()
+ stopDeviceConnection()
- startDeviceConnection()
+ mPrefs.edit().putString(mKeyUtil.deviceMaker, DEVICE_TYPE_LS1).apply()
+
+ sDeviceViewModel = LinkSquareViewModel()
+
+ startDeviceConnection()
+ }
+ }
+
+ fun switchIndigo() {
+
+ val current = mPrefs.getString(mKeyUtil.deviceMaker, null)
+
+ if (current != DEVICE_TYPE_INDIGO) {
+
+ stopDeviceConnection()
+
+ mPrefs.edit().putString(mKeyUtil.deviceMaker, DEVICE_TYPE_INDIGO).apply()
+
+ sDeviceViewModel = Indigo()
+
+ startDeviceConnection()
+ }
}
private fun runtimeBluetoothCheck() {
@@ -736,23 +771,55 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
}
fun startDeviceConnection() {
- launch {
- withContext(Dispatchers.IO) {
- sDeviceViewModel?.connect(this@MainActivity.applicationContext)
+
+ val maker = mPrefs.getString(mKeyUtil.deviceMaker, DEVICE_TYPE_LS1)
+ sDeviceViewModel = when (maker) {
+ in setOf(DEVICE_TYPE_LS1, DEVICE_TYPE_NIR) -> {
+
+ LinkSquareViewModel()
+
+ }
+ DEVICE_TYPE_NANO -> {
+
+ InnoSpectraViewModel()
+
+ }
+ else -> {
+
+ Indigo()
+
}
}
- }
- private fun stopDeviceConnection() {
- launch {
- withContext(Dispatchers.IO) {
- if (sDeviceViewModel?.isConnected() == true)
- sDeviceViewModel?.disconnect(this@MainActivity)
+ if (sDeviceViewModel?.isConnected() != true) {
+
+ if (sDeviceViewModel is Indigo) {
+
+ (sDeviceViewModel as? Indigo)?.let { indigo ->
+ advisor.withNearby { adapter ->
+ launch {
+ withContext(Dispatchers.IO) {
+ indigo.connect(adapter, this@MainActivity)
+ }
+ }
+ }
+ }
+ } else {
+ launch {
+ withContext(Dispatchers.IO) {
+ sDeviceViewModel?.connect(this@MainActivity.applicationContext)
+ }
+ }
}
}
}
+ private fun stopDeviceConnection() {
+ if (sDeviceViewModel?.isConnected() == true)
+ sDeviceViewModel?.forceDisconnect()
+ }
+
override fun onDestroy() {
stopDeviceConnection()
@@ -769,15 +836,27 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
mConnectionHandlerThread.quit()
+ cancel()
+
super.onDestroy()
}
override fun onPause() {
- launch {
- withContext(Dispatchers.IO) {
- sDeviceViewModel?.reset(this@MainActivity)
+ if (sDeviceViewModel is Indigo) {
+ (sDeviceViewModel as? Indigo)?.let { indigo ->
+ advisor.withNearby { adapter ->
+
+ indigo.reset(adapter, this)
+
+ }
+ }
+ } else {
+ launch {
+ withContext(Dispatchers.IO) {
+ sDeviceViewModel?.reset(this@MainActivity)
+ }
}
}
@@ -884,4 +963,8 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
private fun updateLastOpenedTime() {
mPrefs.edit().putLong(mKeyUtil.lastTimeAppOpened, System.nanoTime()).apply()
}
+
+ init {
+ advisor.initialize()
+ }
}
diff --git a/app/src/main/java/org/phenoapps/prospector/data/models/Scan.kt b/app/src/main/java/org/phenoapps/prospector/data/models/Scan.kt
index 0b7d57e..4046f21 100644
--- a/app/src/main/java/org/phenoapps/prospector/data/models/Scan.kt
+++ b/app/src/main/java/org/phenoapps/prospector/data/models/Scan.kt
@@ -1,8 +1,8 @@
package org.phenoapps.prospector.data.models
-import DEVICE_TYPE_NIR
import androidx.annotation.Keep
import androidx.room.*
+import org.phenoapps.interfaces.spectrometers.Spectrometer.Companion.DEVICE_TYPE_NIR
import org.phenoapps.prospector.utils.DateUtil
@Keep
diff --git a/app/src/main/java/org/phenoapps/prospector/data/viewmodels/devices/InnoSpectraViewModel.kt b/app/src/main/java/org/phenoapps/prospector/data/viewmodels/devices/InnoSpectraViewModel.kt
index f20463b..fdc1f9f 100644
--- a/app/src/main/java/org/phenoapps/prospector/data/viewmodels/devices/InnoSpectraViewModel.kt
+++ b/app/src/main/java/org/phenoapps/prospector/data/viewmodels/devices/InnoSpectraViewModel.kt
@@ -1,6 +1,5 @@
package org.phenoapps.prospector.data.viewmodels.devices
-import DEVICE_TYPE_NANO
import android.Manifest
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothManager
@@ -22,17 +21,20 @@ import androidx.lifecycle.viewModelScope
import androidx.preference.PreferenceManager
import com.ISCSDK.ISCNIRScanSDK
import com.ISCSDK.ISCNIRScanSDK.*
-import com.stratiotechnology.linksquareapi.LSFrame
import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
+import org.phenoapps.interfaces.iot.Device
+import org.phenoapps.interfaces.spectrometers.Spectrometer
+import org.phenoapps.interfaces.spectrometers.Spectrometer.Companion.DEVICE_TYPE_NANO
import org.phenoapps.prospector.R
import org.phenoapps.prospector.fragments.preferences.InnoSpectraSettingsFragment
import org.phenoapps.prospector.fragments.nano_configuration_creator.models.Config
import org.phenoapps.prospector.interfaces.NanoEventListener
-import org.phenoapps.prospector.interfaces.Spectrometer
import org.phenoapps.prospector.receivers.DeviceInfoReceiver
import org.phenoapps.prospector.utils.KeyUtil
+import org.phenoapps.viewmodels.spectrometers.Frame
import java.lang.IllegalArgumentException
import javax.inject.Inject
import kotlin.collections.ArrayList
@@ -64,7 +66,7 @@ class InnoSpectraViewModel @Inject constructor() : ViewModel(), Spectrometer, Na
private var mNanoReceiver: InnoSpectraBase? = null
//live data that receivers will produce and listeners will consume
- private var mSpectralData: Spectrometer.Frame? = null
+ private var mSpectralData: Frame? = null
private var OnDeviceButtonClicked: (() -> Unit)? = null
@@ -72,7 +74,7 @@ class InnoSpectraViewModel @Inject constructor() : ViewModel(), Spectrometer, Na
private var mUiScan = false
- private var mDeviceInfo: Spectrometer.DeviceInfo? = null
+ private var mDeviceInfo: Device.DeviceInfo? = null
private var mDeviceStatus: InnoSpectraSettingsFragment.DeviceStatus? = null
@@ -164,6 +166,7 @@ class InnoSpectraViewModel @Inject constructor() : ViewModel(), Spectrometer, Na
override fun onServiceDisconnected(name: ComponentName?) {
mConnected = false
+ mConnectionStarting = false
mNanoSdk?.sdk?.disconnect()
mNanoSdk?.sdk?.close()
}
@@ -238,6 +241,10 @@ class InnoSpectraViewModel @Inject constructor() : ViewModel(), Spectrometer, Na
private fun isRefDataReady() = mRefDataReady
+ override fun forceDisconnect() {
+ onCleared()
+ }
+
override fun reset(context: Context?) {
context?.let { ctx ->
@@ -246,6 +253,8 @@ class InnoSpectraViewModel @Inject constructor() : ViewModel(), Spectrometer, Na
viewModelScope.launch {
+ delay(3000L)
+
connect(ctx)
}
@@ -254,7 +263,7 @@ class InnoSpectraViewModel @Inject constructor() : ViewModel(), Spectrometer, Na
override fun getDeviceError(): String { return "None" }
- override fun getDeviceInfo() = mDeviceInfo ?: Spectrometer.DeviceInfo("?", "?", "?", "?", "?", DEVICE_TYPE_NANO)
+ override fun getDeviceInfo() = mDeviceInfo ?: Device.DeviceInfo("?", "?", "?", "?", "?", DEVICE_TYPE_NANO)
override fun setEventListener(onClick: () -> Unit): LiveData = liveData {
@@ -264,7 +273,7 @@ class InnoSpectraViewModel @Inject constructor() : ViewModel(), Spectrometer, Na
}
- override fun scan(context: Context, manual: Boolean?): LiveData?> = liveData {
+ override fun scan(context: Context, manual: Boolean?): LiveData?> = liveData {
if (isConnected() && isRefDataReady()) {
@@ -295,12 +304,12 @@ class InnoSpectraViewModel @Inject constructor() : ViewModel(), Spectrometer, Na
mUiScan = false
emit(listOf(frame).map {
- LSFrame().apply {
+ Frame().apply {
this.lightSource = it.lightSource
this.length = it.length
- this.frameNo = it.frameNo
+ this.frameIndex = it.frameIndex
this.deviceType = it.deviceType
- this.raw_data = it.raw_data
+ this.rawData = it.rawData
this.data = it.data
}
})
@@ -351,7 +360,7 @@ class InnoSpectraViewModel @Inject constructor() : ViewModel(), Spectrometer, Na
}
}
- override fun onScanDataReady(spectral: Spectrometer.Frame) {
+ override fun onScanDataReady(spectral: Frame) {
if (isGattStateConnected()) {
@@ -362,17 +371,6 @@ class InnoSpectraViewModel @Inject constructor() : ViewModel(), Spectrometer, Na
override fun onGetUuid(uuid: String) {
- mDeviceInfo?.let { info ->
-// mDeviceInfo = Spectrometer.DeviceInfo(
-// info.softwareVersion,
-// info.hardwareVersion,
-// uuid,
-// info.alias,
-// info.opMode,
-// info.deviceType
-// )
- }
-
GetDeviceStatus()
}
@@ -380,7 +378,7 @@ class InnoSpectraViewModel @Inject constructor() : ViewModel(), Spectrometer, Na
override fun onGetDeviceInfo(info: DeviceInfoReceiver.NanoDeviceInfo) {
mDeviceInfo = with(info) {
- Spectrometer.DeviceInfo(
+ Device.DeviceInfo(
this.spec,
this.hardware,
this.model,
@@ -592,4 +590,14 @@ class InnoSpectraViewModel @Inject constructor() : ViewModel(), Spectrometer, Na
""".trimIndent()
}
+ override fun onCleared() {
+ super.onCleared()
+ try {
+ //viewModelScope.cancel()
+ mNanoSdk?.sdk?.disconnect()
+ mNanoSdk?.sdk?.close()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/org/phenoapps/prospector/data/viewmodels/devices/LinkSquareViewModel.kt b/app/src/main/java/org/phenoapps/prospector/data/viewmodels/devices/LinkSquareViewModel.kt
index 6a73f6a..cf7915e 100644
--- a/app/src/main/java/org/phenoapps/prospector/data/viewmodels/devices/LinkSquareViewModel.kt
+++ b/app/src/main/java/org/phenoapps/prospector/data/viewmodels/devices/LinkSquareViewModel.kt
@@ -3,8 +3,6 @@ package org.phenoapps.prospector.data.viewmodels.devices
import BULB_FRAMES
import DEVICE_IP
import DEVICE_PORT
-import DEVICE_TYPE_LS1
-import DEVICE_TYPE_NIR
import LED_FRAMES
import android.content.Context
import android.util.Log
@@ -15,7 +13,11 @@ import com.stratiotechnology.linksquareapi.LSFrame
import com.stratiotechnology.linksquareapi.LinkSquareAPI
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.*
-import org.phenoapps.prospector.interfaces.Spectrometer
+import org.phenoapps.interfaces.iot.Device
+import org.phenoapps.interfaces.spectrometers.Spectrometer
+import org.phenoapps.interfaces.spectrometers.Spectrometer.Companion.DEVICE_TYPE_LS1
+import org.phenoapps.interfaces.spectrometers.Spectrometer.Companion.DEVICE_TYPE_NIR
+import org.phenoapps.viewmodels.spectrometers.Frame
import java.io.BufferedReader
import java.io.FileReader
import java.lang.IndexOutOfBoundsException
@@ -61,6 +63,10 @@ class LinkSquareViewModel @Inject constructor() : ViewModel(), Spectrometer {
}
}
+ override fun forceDisconnect() {
+ onCleared()
+ }
+
override fun reset(context: Context?) {
sDevice?.Close()
@@ -74,7 +80,7 @@ class LinkSquareViewModel @Inject constructor() : ViewModel(), Spectrometer {
override fun getDeviceError() = sDevice?.GetLSError()
override fun getDeviceInfo() = with(sDevice?.GetDeviceInfo()) {
- Spectrometer.DeviceInfo(
+ Device.DeviceInfo(
this?.SWVersion ?: "?",
this?.HWVersion ?: "?",
this?.DeviceID ?: "-1",
@@ -116,7 +122,7 @@ class LinkSquareViewModel @Inject constructor() : ViewModel(), Spectrometer {
emit("DONE")
}
- override fun scan(context: Context, manual: Boolean?): LiveData?> = liveData {
+ override fun scan(context: Context, manual: Boolean?): LiveData?> = liveData {
with (manager(context)) {
@@ -126,7 +132,14 @@ class LinkSquareViewModel @Inject constructor() : ViewModel(), Spectrometer {
val frames = scan(ledFrames, bulbFrames)
- emit(frames)
+ emit(frames.map {
+ Frame(length = it.length,
+ deviceType = if (it.deviceType == 0) DEVICE_TYPE_LS1 else DEVICE_TYPE_NIR,
+ data = it.data,
+ lightSource = it.lightSource.toInt(),
+ frameIndex = it.frameNo,
+ rawData = it.raw_data.joinToString(" ") { f -> "$f" })
+ })
}
}
diff --git a/app/src/main/java/org/phenoapps/prospector/fragments/ConnectionFragment.kt b/app/src/main/java/org/phenoapps/prospector/fragments/ConnectionFragment.kt
index a95fd8c..8b59556 100644
--- a/app/src/main/java/org/phenoapps/prospector/fragments/ConnectionFragment.kt
+++ b/app/src/main/java/org/phenoapps/prospector/fragments/ConnectionFragment.kt
@@ -4,8 +4,11 @@ import android.os.Handler
import android.os.HandlerThread
import androidx.appcompat.widget.Toolbar
import androidx.fragment.app.Fragment
+import androidx.navigation.fragment.findNavController
import org.phenoapps.prospector.R
import org.phenoapps.prospector.activities.MainActivity
+import org.phenoapps.security.Security
+import org.phenoapps.viewmodels.spectrometers.Indigo
open class ConnectionFragment(id: Int) : Fragment(id) {
@@ -27,7 +30,6 @@ open class ConnectionFragment(id: Int) : Fragment(id) {
}
else R.drawable.ic_vector_difference_ab
)
-
}
}
}
diff --git a/app/src/main/java/org/phenoapps/prospector/fragments/ExperimentListFragment.kt b/app/src/main/java/org/phenoapps/prospector/fragments/ExperimentListFragment.kt
index a314c95..18a7016 100644
--- a/app/src/main/java/org/phenoapps/prospector/fragments/ExperimentListFragment.kt
+++ b/app/src/main/java/org/phenoapps/prospector/fragments/ExperimentListFragment.kt
@@ -35,6 +35,7 @@ import org.phenoapps.prospector.data.viewmodels.ExperimentViewModel
import org.phenoapps.prospector.databinding.FragmentExperimentListBinding
import org.phenoapps.prospector.utils.Dialogs
import org.phenoapps.prospector.utils.KeyUtil
+import org.phenoapps.viewmodels.spectrometers.Indigo
/**
* The main data fragment that displays the top-level experiment hierarchy.
@@ -146,20 +147,29 @@ class ExperimentListFragment : ConnectionFragment(R.layout.fragment_experiment_l
R.id.action_connection -> {
- val deviceViewModel = (activity as MainActivity).sDeviceViewModel
+ with (activity as? MainActivity) {
- if (deviceViewModel?.isConnected() == true) {
+ if (this?.mConnected == true) {
- deviceViewModel.reset(context)
+ if (sDeviceViewModel is Indigo) {
+ (sDeviceViewModel as? Indigo)?.let { indigo ->
+ advisor.withNearby { adapter ->
- } else {
+ indigo.reset(adapter, context)
+
+ }
+ }
+ } else {
+ sDeviceViewModel?.reset(context)
+ }
+
+ } else {
- if (findNavController().currentDestination?.id == R.id.experiment_list_fragment) {
findNavController().navigate(ExperimentListFragmentDirections
.actionToConnectInstructions())
- }
- (activity as? MainActivity)?.startDeviceConnection()
+ this?.startDeviceConnection()
+ }
}
}
}
diff --git a/app/src/main/java/org/phenoapps/prospector/fragments/SampleListFragment.kt b/app/src/main/java/org/phenoapps/prospector/fragments/SampleListFragment.kt
index ae1fdf1..3973f1c 100644
--- a/app/src/main/java/org/phenoapps/prospector/fragments/SampleListFragment.kt
+++ b/app/src/main/java/org/phenoapps/prospector/fragments/SampleListFragment.kt
@@ -5,8 +5,6 @@ import ALPHA_DESC
import CONVERT_TO_WAVELENGTHS
import DATE_ASC
import DATE_DESC
-import DEVICE_TYPE_LS1
-import DEVICE_TYPE_NIR
import android.net.Uri
import android.os.Bundle
import android.os.Handler
@@ -28,15 +26,21 @@ import androidx.recyclerview.widget.RecyclerView
import dagger.hilt.android.AndroidEntryPoint
import dagger.hilt.android.WithFragmentBindings
import kotlinx.coroutines.*
+import org.phenoapps.interfaces.spectrometers.Spectrometer
+import org.phenoapps.interfaces.spectrometers.Spectrometer.Companion.DEVICE_TYPE_LS1
+import org.phenoapps.interfaces.spectrometers.Spectrometer.Companion.DEVICE_TYPE_NIR
import org.phenoapps.prospector.R
import org.phenoapps.prospector.activities.MainActivity
import org.phenoapps.prospector.adapter.SampleAdapter
import org.phenoapps.prospector.data.models.Sample
import org.phenoapps.prospector.data.viewmodels.SampleViewModel
+import org.phenoapps.prospector.data.viewmodels.devices.InnoSpectraViewModel
+import org.phenoapps.prospector.data.viewmodels.devices.LinkSquareViewModel
import org.phenoapps.prospector.databinding.FragmentSampleListBinding
import org.phenoapps.prospector.interfaces.SampleListClickListener
import org.phenoapps.prospector.utils.*
import org.phenoapps.utils.BaseDocumentTreeUtil
+import org.phenoapps.viewmodels.spectrometers.Indigo
/**
* Similar to the experiment fragment, this displays lists of samples for a given experiment.
@@ -268,16 +272,20 @@ class SampleListFragment : ConnectionFragment(R.layout.fragment_sample_list), Co
mDeviceType = deviceType
mName = name
- val maker = mPrefs.getString(mKeyUtil.deviceMaker, DEVICE_TYPE_LS1) ?: DEVICE_TYPE_LS1
- if (maker !in deviceType) {
-
- if (DEVICE_TYPE_LS1 in deviceType) {
+ when (mDeviceType) {
+ in setOf(DEVICE_TYPE_LS1, DEVICE_TYPE_NIR) -> {
(activity as MainActivity).switchLinkSquare()
- } else {
+ }
+ Spectrometer.DEVICE_TYPE_NANO -> {
(activity as MainActivity).switchInnoSpectra()
+
+ }
+ else -> {
+
+ (activity as MainActivity).switchIndigo()
}
}
@@ -354,20 +362,27 @@ class SampleListFragment : ConnectionFragment(R.layout.fragment_sample_list), Co
R.id.action_connection -> {
- val deviceViewModel = (activity as MainActivity).sDeviceViewModel
-
with (activity as? MainActivity) {
if (this?.mConnected == true) {
- deviceViewModel?.reset(context)
- } else {
+ if (sDeviceViewModel is Indigo) {
+ (sDeviceViewModel as? Indigo)?.let { indigo ->
+ advisor.withNearby { adapter ->
- if (findNavController().currentDestination?.id == R.id.sample_list_fragment) {
- findNavController().navigate(SampleListFragmentDirections
- .actionToConnectInstructions())
+ indigo.reset(adapter, context)
+
+ }
+ }
+ } else {
+ sDeviceViewModel?.reset(context)
}
+ } else {
+
+ findNavController().navigate(SampleListFragmentDirections
+ .actionToConnectInstructions())
+
this?.startDeviceConnection()
}
}
diff --git a/app/src/main/java/org/phenoapps/prospector/fragments/ScanListFragment.kt b/app/src/main/java/org/phenoapps/prospector/fragments/ScanListFragment.kt
index a378716..319f6f7 100644
--- a/app/src/main/java/org/phenoapps/prospector/fragments/ScanListFragment.kt
+++ b/app/src/main/java/org/phenoapps/prospector/fragments/ScanListFragment.kt
@@ -2,9 +2,6 @@ package org.phenoapps.prospector.fragments
import CONVERT_TO_WAVELENGTHS
import DEVICE_ALIAS
-import DEVICE_TYPE_LS1
-import DEVICE_TYPE_NANO
-import DEVICE_TYPE_NIR
import OPERATOR
import android.graphics.Color
import android.os.Bundle
@@ -16,14 +13,12 @@ import android.view.ViewGroup
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.databinding.DataBindingUtil
-import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.tabs.TabLayout
-import com.stratiotechnology.linksquareapi.LSFrame
import dagger.hilt.android.AndroidEntryPoint
import dagger.hilt.android.WithFragmentBindings
import kotlinx.coroutines.*
@@ -39,9 +34,19 @@ import org.phenoapps.prospector.utils.*
import java.lang.IllegalStateException
import java.util.*
import com.github.mikephil.charting.components.XAxis
+import org.phenoapps.interfaces.iot.Device
+import org.phenoapps.interfaces.spectrometers.Spectrometer.Companion.DEVICE_TYPE_INDIGO
+import org.phenoapps.interfaces.spectrometers.Spectrometer.Companion.DEVICE_TYPE_LS1
+import org.phenoapps.interfaces.spectrometers.Spectrometer.Companion.DEVICE_TYPE_NANO
+import org.phenoapps.interfaces.spectrometers.Spectrometer.Companion.DEVICE_TYPE_NIR
import org.phenoapps.prospector.data.viewmodels.devices.InnoSpectraViewModel
import org.phenoapps.prospector.data.viewmodels.devices.LinkSquareViewModel
-import org.phenoapps.prospector.interfaces.Spectrometer
+import org.phenoapps.security.Security
+import org.phenoapps.viewmodels.spectrometers.Frame
+import org.phenoapps.viewmodels.spectrometers.Indigo
+import org.phenoapps.viewmodels.spectrometers.IndigoViewModel
+import org.phenoapps.viewmodels.spectrometers.IndigoViewModel.Companion.SAMPLE_SERVICE
+import org.phenoapps.viewmodels.spectrometers.IndigoViewModel.Companion.SAMPLE_TRANSMIT
/**
@@ -117,7 +122,7 @@ class ScanListFragment : ConnectionFragment(R.layout.fragment_scan_list), Corout
}
}
- private suspend fun insertScan(name: String, frames: List) {
+ private suspend fun insertScan(name: String, frames: List) {
val deviceViewModel = (activity as MainActivity).sDeviceViewModel
@@ -146,26 +151,41 @@ class ScanListFragment : ConnectionFragment(R.layout.fragment_scan_list), Corout
val sid = sViewModel.insertScanAsync(scan).await()
- if (deviceViewModel is LinkSquareViewModel) {
- frames.forEach { frame ->
+ when (deviceViewModel) {
+ is LinkSquareViewModel -> {
+ frames.forEach { frame ->
- sViewModel.insertFrame(sid, SpectralFrame(
- sid,
- frame.frameNo,
- frame.raw_data.joinToString(" ") { value -> value.toString() },
- frame.lightSource.toInt())
- )
+ sViewModel.insertFrame(sid, SpectralFrame(
+ sid,
+ frame.frameIndex ?: 0,
+ frame.rawData ?: String(),
+ frame.lightSource ?: 0)
+ )
+ }
}
- } else {
- frames.forEach { frame ->
-
- sViewModel.insertFrame(sid, SpectralFrame(
- sid,
- frame.frameNo,
- frame.raw_data.joinToString(" ") { value -> value.toString() },
- frame.lightSource.toInt(),
- wavelengths = frame.data.joinToString(" ") { value -> value.toString() }
- ))
+ is InnoSpectraViewModel -> {
+ frames.forEach { frame ->
+
+ sViewModel.insertFrame(sid, SpectralFrame(
+ sid,
+ frame.frameIndex ?: 0,
+ frame.rawData ?: String(),
+ frame.lightSource ?: 0,
+ wavelengths = frame.data?.joinToString(" ") { value -> value.toString() }
+ ))
+ }
+ }
+ else -> {
+ frames.forEach { frame ->
+
+ sViewModel.insertFrame(sid, SpectralFrame(
+ sid,
+ frame.frameIndex ?: 0,
+ frame.rawData ?: String(),
+ frame.lightSource ?: 0,
+ wavelengths = frame.wavelengths
+ ))
+ }
}
}
}
@@ -174,7 +194,7 @@ class ScanListFragment : ConnectionFragment(R.layout.fragment_scan_list), Corout
* Dialog is only called if the current connected deviceType matches the experiment deviceType.
* If they match, the dialog begins which displays the status of the scan (indeterminately)
*/
- private fun callScanDialog(device: Spectrometer.DeviceInfo, manual: Boolean? = false) {
+ private fun callScanDialog(device: Device.DeviceInfo, manual: Boolean? = false) {
if (mScansEnabled) {
@@ -188,7 +208,7 @@ class ScanListFragment : ConnectionFragment(R.layout.fragment_scan_list), Corout
if (!deviceViewModel.hasActiveScan()) {
- (activity as? MainActivity)?.notify(R.string.inno_spectra_device_not_ready)
+ (activity as? MainActivity)?.notify(R.string.device_not_ready)
mIsScanning = false
return
@@ -212,7 +232,16 @@ class ScanListFragment : ConnectionFragment(R.layout.fragment_scan_list), Corout
it?.let { frames ->
- sDeviceScope.launch {
+ if (frames.first().length == -1) { //failed
+
+ activity?.runOnUiThread {
+ dialogInterface.dismiss()
+ loadGraph()
+ mIsScanning = false
+ (activity as? MainActivity)?.notify(R.string.scan_failed)
+ }
+
+ } else sDeviceScope.launch {
withContext(Dispatchers.IO) {
@@ -322,6 +351,15 @@ class ScanListFragment : ConnectionFragment(R.layout.fragment_scan_list), Corout
ui.fragScanListLineChart.xAxis.position = XAxis.XAxisPosition.BOTTOM
ui.scanOnClick = sOnClickScan
+ if (deviceViewModel is Indigo) {
+ deviceViewModel.isConnectedLive().observe(viewLifecycleOwner) { connected ->
+ ui.scanOnClick = if (!connected) {
+ View.OnClickListener {
+ (activity as? MainActivity)?.notify(R.string.device_not_ready)
+ }
+ } else sOnClickScan
+ }
+ }
//check if experiment id is included in the arguments.
mExpId = arguments?.getLong("experiment", -1L) ?: -1L
@@ -427,49 +465,23 @@ class ScanListFragment : ConnectionFragment(R.layout.fragment_scan_list), Corout
val prefs = PreferenceManager.getDefaultSharedPreferences(requireContext())
- tabLayout.getTabAt(if (prefs.getBoolean(mKeyUtil.lastSelectedGraph, false)) { 1 } else 0)
- ?.select()
-
+ tabLayout.getTabAt(
+ when {
+ (activity as? MainActivity)?.sDeviceViewModel is Indigo -> 1
+ prefs.getBoolean(mKeyUtil.lastSelectedGraph, false) -> 1
+ else -> 0
+ }
+ )?.select()
}
private fun FragmentScanListBinding.setupToolbar() {
- val deviceViewModel = (activity as MainActivity).sDeviceViewModel
-
scanToolbar.setNavigationOnClickListener {
findNavController().popBackStack()
}
- toolbar.setOnMenuItemClickListener {
-
- when(it.itemId) {
-
- R.id.action_connection -> {
-
- with (activity as? MainActivity) {
-
- if (this?.mConnected == true) {
-
- deviceViewModel?.reset(context)
-
- } else {
-
- if (findNavController().currentDestination?.id == R.id.scan_list_fragment) {
- findNavController().navigate(ScanListFragmentDirections
- .actionToConnectInstructions())
- }
-
- this?.startDeviceConnection()
- }
- }
- }
- }
-
- true
- }
-
scanToolbar.setOnMenuItemClickListener {
when(it.itemId) {
@@ -561,6 +573,8 @@ class ScanListFragment : ConnectionFragment(R.layout.fragment_scan_list), Corout
DEVICE_TYPE_LS1 -> LinkSquareRange.max
+ DEVICE_TYPE_INDIGO -> IndigoRange.max
+
else -> InnoSpectraRange.max
}
@@ -702,6 +716,42 @@ class ScanListFragment : ConnectionFragment(R.layout.fragment_scan_list), Corout
}
}
}
+
+ mBinding?.toolbar?.setOnMenuItemClickListener { item ->
+
+ when(item.itemId) {
+
+ R.id.action_connection -> {
+
+ with (activity as? MainActivity) {
+
+ if (this?.mConnected == true) {
+
+ if (sDeviceViewModel is Indigo) {
+ (sDeviceViewModel as? Indigo)?.let { indigo ->
+ advisor.withNearby { adapter ->
+
+ indigo.reset(adapter, context)
+
+ }
+ }
+ } else {
+ sDeviceViewModel?.reset(context)
+ }
+
+ } else {
+
+ findNavController().navigate(ScanListFragmentDirections
+ .actionToConnectInstructions())
+
+ this?.startDeviceConnection()
+ }
+ }
+ }
+ }
+
+ true
+ }
}
/**
@@ -729,7 +779,7 @@ class ScanListFragment : ConnectionFragment(R.layout.fragment_scan_list), Corout
}
}
- }?.observe(viewLifecycleOwner, {})
+ }?.observe(viewLifecycleOwner) {}
} catch (e: IllegalStateException) {
@@ -781,6 +831,11 @@ class ScanListFragment : ConnectionFragment(R.layout.fragment_scan_list), Corout
override fun onPause() {
super.onPause()
+ //sDeviceScope.cancel()
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
sDeviceScope.cancel()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/org/phenoapps/prospector/fragments/preferences/SettingsFragment.kt b/app/src/main/java/org/phenoapps/prospector/fragments/preferences/SettingsFragment.kt
index d8105fc..25e48cb 100644
--- a/app/src/main/java/org/phenoapps/prospector/fragments/preferences/SettingsFragment.kt
+++ b/app/src/main/java/org/phenoapps/prospector/fragments/preferences/SettingsFragment.kt
@@ -1,5 +1,6 @@
package org.phenoapps.prospector.fragments.preferences
+import DEVICE_INDIGO
import DEVICE_INNO_SPECTRA
import DEVICE_LINK_SQUARE
import OPERATOR
@@ -104,6 +105,17 @@ class SettingsFragment : PreferenceFragmentCompat(), CoroutineScope by MainScope
}
}
+ findPreference(DEVICE_INDIGO)?.let { devicePref ->
+
+ devicePref.setOnPreferenceClickListener {
+
+ findNavController().navigate(SettingsContainerFragmentDirections
+ .actionToIndigoSettingsFragment())
+
+ true
+ }
+ }
+
findPreference(mKeyUtil.database)?.let { databasePref ->
databasePref.setOnPreferenceClickListener {
diff --git a/app/src/main/java/org/phenoapps/prospector/fragments/preferences/indigo/DeviceSearchFragment.kt b/app/src/main/java/org/phenoapps/prospector/fragments/preferences/indigo/DeviceSearchFragment.kt
new file mode 100644
index 0000000..3567ed7
--- /dev/null
+++ b/app/src/main/java/org/phenoapps/prospector/fragments/preferences/indigo/DeviceSearchFragment.kt
@@ -0,0 +1,102 @@
+package org.phenoapps.prospector.fragments.preferences.indigo
+
+import android.annotation.SuppressLint
+import android.bluetooth.le.ScanCallback
+import android.bluetooth.le.ScanResult
+import android.os.Build
+import android.widget.Toast
+import androidx.annotation.RequiresApi
+import androidx.lifecycle.liveData
+import androidx.navigation.fragment.findNavController
+import kotlinx.coroutines.delay
+import org.phenoapps.adapters.bluetooth.BluetoothDeviceAdapter
+import org.phenoapps.fragments.bluetooth.BluetoothListFragment
+import org.phenoapps.models.bluetooth.BluetoothDeviceModel
+import org.phenoapps.prospector.R
+
+@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
+class DeviceSearchFragment: BluetoothListFragment() {
+
+ companion object {
+ const val LIVE_DATA_DELAY_MS = 2000L
+ }
+
+ private var mDeviceSet = hashSetOf()
+
+ private val mScanCallback = object : ScanCallback() {
+ override fun onScanResult(callbackType: Int, result: ScanResult?) {
+ super.onScanResult(callbackType, result)
+
+ result?.device?.let { d ->
+
+ if (d.address !in mDeviceSet.map { it.device.address }) {
+
+ //Toast.makeText(context, "Found new device: ${d.address}.", Toast.LENGTH_SHORT).show()
+
+ mDeviceSet.add(BluetoothDeviceModel(d))
+ }
+ }
+ }
+ }
+
+ override fun onRecyclerReady() {
+
+ liveDeviceData().observe(viewLifecycleOwner) { devices ->
+
+ (mRecyclerView.adapter as? BluetoothDeviceAdapter)
+ ?.submitList(devices.toList())
+
+ }
+ }
+
+ private fun liveDeviceData() = liveData> {
+
+ while (true) {
+
+ delay(LIVE_DATA_DELAY_MS)
+
+ emit(mDeviceSet)
+
+ }
+ }
+
+ @SuppressLint("MissingPermission") //handled with advisor
+ override fun onPause() {
+ super.onPause()
+
+ advisor.withNearby { adapter ->
+
+ adapter.cancelDiscovery()
+
+ adapter.bluetoothLeScanner.stopScan(mScanCallback)
+
+ }
+ }
+
+ @SuppressLint("MissingPermission") //handled with advisor
+ override fun onResume() {
+
+ advisor.withNearby { adapter ->
+
+ adapter.startDiscovery()
+
+ adapter.bluetoothLeScanner.startScan(mScanCallback)
+ }
+
+ super.onResume()
+ }
+
+ override fun onItemClicked(model: Any) {
+
+ if (model is BluetoothDeviceModel) {
+
+ val deviceSelected = context?.getString(R.string.pref_indigo_device_search_selected, model.device.address) ?: model.device.address
+
+ Toast.makeText(context, deviceSelected, Toast.LENGTH_SHORT).show()
+
+ mPrefs.edit().putString(mKeys.argBluetoothDeviceAddress, model.device.address).apply()
+
+ findNavController().popBackStack()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/phenoapps/prospector/fragments/preferences/indigo/IndigoSettingsContainerFragment.kt b/app/src/main/java/org/phenoapps/prospector/fragments/preferences/indigo/IndigoSettingsContainerFragment.kt
new file mode 100644
index 0000000..9ed2fbd
--- /dev/null
+++ b/app/src/main/java/org/phenoapps/prospector/fragments/preferences/indigo/IndigoSettingsContainerFragment.kt
@@ -0,0 +1,11 @@
+package org.phenoapps.prospector.fragments.preferences.indigo
+
+import android.graphics.Color
+import org.phenoapps.fragments.toolbar.PopOnBackToolbarFragment
+
+class IndigoSettingsContainerFragment: PopOnBackToolbarFragment() {
+
+ override val containedFragment = IndigoSettingsFragment()
+
+ override val topToolbarColor: Int = Color.parseColor("#03A9F4")
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/phenoapps/prospector/fragments/preferences/indigo/IndigoSettingsFragment.kt b/app/src/main/java/org/phenoapps/prospector/fragments/preferences/indigo/IndigoSettingsFragment.kt
new file mode 100644
index 0000000..df5fa74
--- /dev/null
+++ b/app/src/main/java/org/phenoapps/prospector/fragments/preferences/indigo/IndigoSettingsFragment.kt
@@ -0,0 +1,51 @@
+package org.phenoapps.prospector.fragments.preferences.indigo
+
+import android.os.Bundle
+import androidx.navigation.fragment.findNavController
+import androidx.preference.Preference
+import androidx.preference.PreferenceFragmentCompat
+import org.phenoapps.prospector.R
+import org.phenoapps.prospector.utils.KeyUtil
+
+class IndigoSettingsFragment: PreferenceFragmentCompat() {
+
+ private val keys by lazy {
+ KeyUtil(context)
+ }
+
+ private val libKeys by lazy {
+ org.phenoapps.utils.KeyUtil(context)
+ }
+
+ override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
+ setPreferencesFromResource(R.xml.indigo_preferences, rootKey)
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ setupIndigoSearchPref()
+ }
+
+ private fun setupIndigoSearchPref() {
+ findPreference(keys.indigoSearchDevice)?.let { pref ->
+ pref.setOnPreferenceClickListener {
+
+ findNavController().navigate(IndigoSettingsContainerFragmentDirections
+ .actionIndigoSettingsToDeviceSearch())
+
+ true
+ }
+
+ val summary = preferenceManager.sharedPreferences.getString(libKeys.argBluetoothDeviceAddress, null)
+ if (summary != null) {
+ pref.summary = summary
+ }
+ }
+ }
+
+ override fun onResume() {
+ super.onResume()
+ setupIndigoSearchPref()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/phenoapps/prospector/fragments/tutorials/ConnectionInstructionsFragment.kt b/app/src/main/java/org/phenoapps/prospector/fragments/tutorials/ConnectionInstructionsFragment.kt
index 1f8577a..f247565 100644
--- a/app/src/main/java/org/phenoapps/prospector/fragments/tutorials/ConnectionInstructionsFragment.kt
+++ b/app/src/main/java/org/phenoapps/prospector/fragments/tutorials/ConnectionInstructionsFragment.kt
@@ -36,13 +36,15 @@ class ConnectionInstructionsFragment : Fragment(), OnModelClickListener {
val lsIcon = R.mipmap.linksquare_logo
val isTitle = ctx.getString(R.string.innospectra_nano)
val isIcon = R.mipmap.isc_logo
+ val indigoTitle = getString(R.string.indigo)
+ val indigoIcon = R.drawable.indigo
mBinding?.fragDeviceConnectionTutorialIndexRv?.adapter = SpectrometerAdapter(this).also {
it.submitList(mutableListOf(
SpectrometerAdapter.SpectrometerListItem(0, isTitle, isIcon),
- SpectrometerAdapter.SpectrometerListItem(1, lsTitle, lsIcon))
+ SpectrometerAdapter.SpectrometerListItem(1, lsTitle, lsIcon),
+ SpectrometerAdapter.SpectrometerListItem(2, indigoTitle, indigoIcon))
)
}
-
}
mBinding?.toolbar?.setNavigationOnClickListener {
@@ -71,6 +73,9 @@ class ConnectionInstructionsFragment : Fragment(), OnModelClickListener {
1 -> findNavController().navigate(ConnectionInstructionsFragmentDirections
.actionFromIndexToLinksquareTutorial())
+
+ 2 -> findNavController().navigate(ConnectionInstructionsFragmentDirections
+ .actionFromIndexToIndigoTutorial())
}
}
}
diff --git a/app/src/main/java/org/phenoapps/prospector/fragments/tutorials/IndigoInstructionsFragment.kt b/app/src/main/java/org/phenoapps/prospector/fragments/tutorials/IndigoInstructionsFragment.kt
new file mode 100644
index 0000000..5f5dfc9
--- /dev/null
+++ b/app/src/main/java/org/phenoapps/prospector/fragments/tutorials/IndigoInstructionsFragment.kt
@@ -0,0 +1,45 @@
+package org.phenoapps.prospector.fragments.tutorials
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.appcompat.view.ContextThemeWrapper
+import androidx.databinding.DataBindingUtil
+import androidx.fragment.app.Fragment
+import androidx.navigation.fragment.findNavController
+import org.phenoapps.prospector.R
+import org.phenoapps.prospector.activities.MainActivity
+import org.phenoapps.prospector.databinding.FragmentIndigoConnectInstructionsBinding
+
+/**
+ * A simple fragment that displays a scroll view of instructions.
+ * Includes connection instructions and basic app usage.
+ */
+class IndigoInstructionsFragment : Fragment() {
+
+ private var mBinding: FragmentIndigoConnectInstructionsBinding? = null
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+
+ val contextThemeWrapper = ContextThemeWrapper(activity, R.style.AppTheme)
+
+ val localInflater = inflater.cloneInContext(contextThemeWrapper)
+
+ mBinding = DataBindingUtil.inflate(localInflater, R.layout.fragment_indigo_connect_instructions, null, false)
+
+ mBinding?.toolbar?.setNavigationOnClickListener {
+ findNavController().popBackStack()
+ }
+
+ return mBinding?.root
+
+ }
+
+ override fun onResume() {
+ super.onResume()
+
+ (activity as? MainActivity)?.setToolbar(R.id.action_nav_data)
+
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/phenoapps/prospector/interfaces/NanoEventListener.kt b/app/src/main/java/org/phenoapps/prospector/interfaces/NanoEventListener.kt
index cf3d50b..2089f39 100644
--- a/app/src/main/java/org/phenoapps/prospector/interfaces/NanoEventListener.kt
+++ b/app/src/main/java/org/phenoapps/prospector/interfaces/NanoEventListener.kt
@@ -3,6 +3,7 @@ package org.phenoapps.prospector.interfaces
import com.ISCSDK.ISCNIRScanSDK
import org.phenoapps.prospector.fragments.preferences.InnoSpectraSettingsFragment
import org.phenoapps.prospector.receivers.DeviceInfoReceiver
+import org.phenoapps.viewmodels.spectrometers.Frame
interface NanoEventListener {
@@ -10,7 +11,7 @@ interface NanoEventListener {
fun onRefDataReady() = Unit
- fun onScanDataReady(spectral: Spectrometer.Frame) = Unit
+ fun onScanDataReady(spectral: Frame) = Unit
fun onScanStarted() = Unit
diff --git a/app/src/main/java/org/phenoapps/prospector/interfaces/Spectrometer.kt b/app/src/main/java/org/phenoapps/prospector/interfaces/Spectrometer.kt
deleted file mode 100644
index fb600ea..0000000
--- a/app/src/main/java/org/phenoapps/prospector/interfaces/Spectrometer.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-package org.phenoapps.prospector.interfaces
-
-import android.content.Context
-import android.content.SharedPreferences
-import androidx.lifecycle.LiveData
-import androidx.preference.PreferenceManager
-import com.stratiotechnology.linksquareapi.LSFrame
-
-interface Spectrometer {
-
- data class Frame(var length: Int,
- var lightSource: Byte = 0,
- var frameNo: Int,
- var deviceType: Int,
- var data: FloatArray,
- var raw_data: FloatArray)
-
- data class DeviceInfo(val softwareVersion: String,
- val hardwareVersion: String,
- val deviceId: String,
- val alias: String,
- val opMode: String,
- val deviceType: String,
- val serialNumber: String? = null,
- val humidity: String? = null,
- val temperature: String? = null)
-
- fun manager(context: Context): SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
-
- suspend fun connect(context: Context)
-
- fun disconnect(context: Context): Int?
-
- fun isConnected(): Boolean
-
- fun reset(context: Context?) = Unit
-
- fun getDeviceError(): String?
-
- fun getDeviceInfo(): DeviceInfo
-
- fun setEventListener(onClick: () -> Unit): LiveData
-
- fun scan(context: Context, manual: Boolean? = false): LiveData?>
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/phenoapps/prospector/receivers/ScanDataReadyReceiver.kt b/app/src/main/java/org/phenoapps/prospector/receivers/ScanDataReadyReceiver.kt
index a59c6eb..5491f4e 100644
--- a/app/src/main/java/org/phenoapps/prospector/receivers/ScanDataReadyReceiver.kt
+++ b/app/src/main/java/org/phenoapps/prospector/receivers/ScanDataReadyReceiver.kt
@@ -5,8 +5,10 @@ import android.content.Context
import android.content.Intent
import android.util.Log
import com.ISCSDK.ISCNIRScanSDK
+import com.stratiotechnology.linksquareapi.LSFrame
+import org.phenoapps.interfaces.spectrometers.Spectrometer.Companion.DEVICE_TYPE_NANO
import org.phenoapps.prospector.interfaces.NanoEventListener
-import org.phenoapps.prospector.interfaces.Spectrometer
+import org.phenoapps.viewmodels.spectrometers.Frame
class ScanDataReadyReceiver(private val listener: NanoEventListener) : BroadcastReceiver() {
@@ -39,12 +41,14 @@ class ScanDataReadyReceiver(private val listener: NanoEventListener) : Broadcast
intensityData[i] = intensity.toFloat()
}
- listener.onScanDataReady(Spectrometer.Frame(
+ //TODO replace device type with string
+ listener.onScanDataReady(Frame(
length = size,
lightSource = 0,
- frameNo = 1,
- deviceType = 3,
+ frameIndex = 1,
+ deviceType = DEVICE_TYPE_NANO,
data = reflectanceData,
- raw_data = intensityData))
+ rawData = intensityData.joinToString(" ") { "$it" })
+ )
}
}
\ No newline at end of file
diff --git a/app/src/main/java/org/phenoapps/prospector/utils/FileUtil.kt b/app/src/main/java/org/phenoapps/prospector/utils/FileUtil.kt
index a9e36f3..207ee4c 100644
--- a/app/src/main/java/org/phenoapps/prospector/utils/FileUtil.kt
+++ b/app/src/main/java/org/phenoapps/prospector/utils/FileUtil.kt
@@ -1,15 +1,17 @@
package org.phenoapps.prospector.utils
-import DEVICE_TYPE_LS1
-import DEVICE_TYPE_NIR
import android.content.Context
import android.net.Uri
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.apache.commons.csv.CSVFormat
import org.apache.commons.csv.CSVPrinter
+import org.phenoapps.interfaces.spectrometers.Spectrometer.Companion.DEVICE_TYPE_INDIGO
+import org.phenoapps.interfaces.spectrometers.Spectrometer.Companion.DEVICE_TYPE_LS1
+import org.phenoapps.interfaces.spectrometers.Spectrometer.Companion.DEVICE_TYPE_NIR
import org.phenoapps.prospector.R
import org.phenoapps.prospector.data.models.DeviceTypeExport
+import kotlin.math.min
/**
* handles file io for exporting and importing data; although this application currently doesn't import data.
@@ -89,6 +91,8 @@ open class FileUtil(private val ctx: Context) {
DEVICE_TYPE_LS1 -> LinkSquareExportRange.max
+ DEVICE_TYPE_INDIGO -> IndigoExportRange.max
+
else -> InnoSpectraExportRange.max
}
@@ -98,6 +102,8 @@ open class FileUtil(private val ctx: Context) {
DEVICE_TYPE_LS1 -> LinkSquareExportRange.min
+ DEVICE_TYPE_INDIGO -> IndigoExportRange.min
+
else -> InnoSpectraExportRange.min
}
@@ -119,7 +125,7 @@ open class FileUtil(private val ctx: Context) {
export.sample,
export.date,
export.deviceType,
- export.deviceId,
+ export.deviceId.replace("[\" ]", ""),
export.serial,
export.humidity,
export.temperature,
@@ -136,6 +142,8 @@ open class FileUtil(private val ctx: Context) {
DEVICE_TYPE_LS1 -> LinkSquareExportRange.max
+ DEVICE_TYPE_INDIGO -> IndigoExportRange.max
+
else -> InnoSpectraExportRange.max
}
@@ -145,6 +153,8 @@ open class FileUtil(private val ctx: Context) {
DEVICE_TYPE_LS1 -> LinkSquareExportRange.min
+ DEVICE_TYPE_INDIGO -> IndigoExportRange.min
+
else -> InnoSpectraExportRange.min
}
@@ -180,7 +190,7 @@ open class FileUtil(private val ctx: Context) {
e.sample,
e.date,
e.deviceType,
- e.deviceId,
+ export.deviceId.replace("[\" ]", ""),
e.serial,
e.humidity,
e.temperature,
diff --git a/app/src/main/java/org/phenoapps/prospector/utils/KeyUtil.kt b/app/src/main/java/org/phenoapps/prospector/utils/KeyUtil.kt
index 49932e9..7a54b27 100644
--- a/app/src/main/java/org/phenoapps/prospector/utils/KeyUtil.kt
+++ b/app/src/main/java/org/phenoapps/prospector/utils/KeyUtil.kt
@@ -58,4 +58,7 @@ class KeyUtil(private val ctx: Context?) {
//changelog version
val version by key(R.string.key_version)
+ //indigo
+ val indigoSearchDevice by key(R.string.key_pref_indigo_address)
+
}
\ No newline at end of file
diff --git a/app/src/main/java/org/phenoapps/prospector/utils/LinkSquareUtils.kt b/app/src/main/java/org/phenoapps/prospector/utils/LinkSquareUtils.kt
index 602634c..1dc71ef 100644
--- a/app/src/main/java/org/phenoapps/prospector/utils/LinkSquareUtils.kt
+++ b/app/src/main/java/org/phenoapps/prospector/utils/LinkSquareUtils.kt
@@ -1,23 +1,22 @@
package org.phenoapps.prospector.utils
-import DEVICE_TYPE_LS1
-import DEVICE_TYPE_NIR
import android.content.Context
import android.graphics.Color
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
-import com.ISCSDK.ISCNIRScanSDK
import com.github.mikephil.charting.charts.LineChart
import com.github.mikephil.charting.data.Entry
import com.github.mikephil.charting.data.LineData
import com.github.mikephil.charting.data.LineDataSet
import com.stratiotechnology.linksquareapi.LinkSquareAPI
import org.apache.commons.math.stat.StatUtils
+import org.phenoapps.interfaces.iot.Device
+import org.phenoapps.interfaces.spectrometers.Spectrometer.Companion.DEVICE_TYPE_LS1
+import org.phenoapps.interfaces.spectrometers.Spectrometer.Companion.DEVICE_TYPE_NIR
import org.phenoapps.prospector.R
import org.phenoapps.prospector.data.models.DeviceTypeExport
import org.phenoapps.prospector.fragments.ScanListFragment
-import org.phenoapps.prospector.interfaces.Spectrometer
class LinkSquareLightSources {
companion object {
@@ -71,6 +70,20 @@ class InnoSpectraExportRange {
}
}
+class IndigoRange {
+ companion object {
+ const val min: Double = 700.0
+ const val max: Double = 1100.0
+ }
+}
+
+class IndigoExportRange {
+ companion object {
+ const val min: Double = 700.0
+ const val max: Double = 1100.0
+ }
+}
+
/**
* Public helper functions for LinkSquare related processing.
*
@@ -335,7 +348,7 @@ fun buildLinkSquareDeviceInfo(context: Context, data: LinkSquareAPI.LSDeviceInfo
* Used to translate the device id to a device type.
* TODO: with the new LinkSquare 1.15 api, there is a DeviceType, must confirm that NIR=1 and LS=0
*/
-fun resolveDeviceType(context: Context, data: Spectrometer.DeviceInfo): String =
+fun resolveDeviceType(context: Context, data: Device.DeviceInfo): String =
if (data.deviceId.startsWith("NIR")) {
diff --git a/app/src/main/res/drawable-nodpi/indigo.png b/app/src/main/res/drawable-nodpi/indigo.png
new file mode 100644
index 0000000..87a63e8
Binary files /dev/null and b/app/src/main/res/drawable-nodpi/indigo.png differ
diff --git a/app/src/main/res/drawable-nodpi/indigo_tutorial_1.png b/app/src/main/res/drawable-nodpi/indigo_tutorial_1.png
new file mode 100644
index 0000000..4017282
Binary files /dev/null and b/app/src/main/res/drawable-nodpi/indigo_tutorial_1.png differ
diff --git a/app/src/main/res/drawable-nodpi/indigo_tutorial_2.png b/app/src/main/res/drawable-nodpi/indigo_tutorial_2.png
new file mode 100644
index 0000000..2d90857
Binary files /dev/null and b/app/src/main/res/drawable-nodpi/indigo_tutorial_2.png differ
diff --git a/app/src/main/res/drawable-nodpi/indigo_tutorial_3.png b/app/src/main/res/drawable-nodpi/indigo_tutorial_3.png
new file mode 100644
index 0000000..bed5df4
Binary files /dev/null and b/app/src/main/res/drawable-nodpi/indigo_tutorial_3.png differ
diff --git a/app/src/main/res/layout/fragment_indigo_connect_instructions.xml b/app/src/main/res/layout/fragment_indigo_connect_instructions.xml
new file mode 100644
index 0000000..4e6c511
--- /dev/null
+++ b/app/src/main/res/layout/fragment_indigo_connect_instructions.xml
@@ -0,0 +1,118 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/navigation/navigation.xml b/app/src/main/res/navigation/navigation.xml
index de14099..a8c2cab 100644
--- a/app/src/main/res/navigation/navigation.xml
+++ b/app/src/main/res/navigation/navigation.xml
@@ -21,6 +21,10 @@
app:destination="@id/inno_spectra_settings_fragment"
app:popUpTo="@id/settings_fragment"
app:launchSingleTop="true"/>
+
@@ -82,6 +86,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
@string/linksquare_nir
- @string/linksquare
- @string/innospectra_nano
+ - @string/indigo
- 2.34
@@ -90,4 +91,5 @@
LinkSquareNIR
InnoSpectra Nano
InnoSpectra
+ Indigo
\ No newline at end of file
diff --git a/app/src/main/res/values/keys.xml b/app/src/main/res/values/keys.xml
index 87f2e22..9cfefac 100644
--- a/app/src/main/res/values/keys.xml
+++ b/app/src/main/res/values/keys.xml
@@ -7,6 +7,7 @@
&package;VERSION
+ &package;indigo.DEVICE_ADDRESS
&package;LAST_SELECTED_GRAPH
&package;RETURN_FROM_NEW_CONFIG
&package;LAST_CONNECTED_DEVICE_ID
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index c5b2e80..787c08f 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -96,6 +96,11 @@
Wait until the configurations are read, indicated by the progress bar.
(Advanced) Create new scan configurations in the settings. It is highly recommended to use the default scan configurations.
+ Ensure your device is on, the top-most middle LED should be green, or red if already connected. Navigate to the settings in Prospector, choose Indigo, then Find a device.
+ Wait for BLE devices to appear, click on your Indigo device.
+ In the data tab, create a new experiment and select Indigo. This will initiate a device connection, please wait a moment.
+ If you can\'t find your device or scans are not completing, try to reset the device.
+
Step One
Step Two
Step Three
@@ -199,6 +204,7 @@
Device Settings
LinkSquare
InnoSpectra
+ Indigo
LinkSquare Settings Fragment
InnoSpectra Fragment
InnoSpectra
@@ -245,7 +251,7 @@
Scans can only be repeated 1 to 65535 times.
Restore Default Configs
Resetting device to load default configurations. Please wait.
- Please wait, device initializing.
+ Please wait, device initializing.
Loading configsā¦
You cannot choose this configuration, please manage saved configurations in the settings.
Add new section to config
@@ -326,6 +332,11 @@
Choose your device for instructions.
Connection Guide
Spectrometer Company
+ Indigo Settings
+ Click to search for an Indigo device to pair with.
+ Find a device
+ Selected device %s.
+ Scan failed, refreshing device connection.
Nano Battery Low
- "Scans may not be successful. "
+ Scans may not be successful.
diff --git a/app/src/main/res/xml/indigo_preferences.xml b/app/src/main/res/xml/indigo_preferences.xml
new file mode 100644
index 0000000..573254a
--- /dev/null
+++ b/app/src/main/res/xml/indigo_preferences.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index 9102884..6cd100a 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -38,6 +38,11 @@
android:key="org.phenoapps.prospector.DEVICE_TYPE_INNO_SPECTRA"
android:title="@string/pref_device_type_inno_spectra" />
+
+