Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
228 changes: 127 additions & 101 deletions app/src/main/java/de/tuberlin/mcc/simra/app/activities/OBSLiteActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import java.util.TreeSet
import java.util.concurrent.ConcurrentLinkedDeque
import java.util.concurrent.ConcurrentLinkedQueue


class OBSLiteActivity : BaseActivity(), SerialInputOutputManager.Listener {
private lateinit var binding: ActivityObsliteBinding
private val TAG = "OBSLiteActivity_LOG"
Expand All @@ -62,68 +61,64 @@ class OBSLiteActivity : BaseActivity(), SerialInputOutputManager.Listener {
if (ACTION_USB_PERMISSION == intent.action) {

// synchronized(this) {
val device: UsbDevice? =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
intent.getParcelableExtra(
UsbManager.EXTRA_DEVICE,
UsbDevice::class.java
)
} else {
intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
}

Log.d(TAG, "device: $device")
Log.d(
TAG,
"UsbManager.EXTRA_PERMISSION_GRANTED: ${
intent.getBooleanExtra(
UsbManager.EXTRA_PERMISSION_GRANTED,
false
)
}"
)
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
device?.apply {
usbDevice = device
binding.obsLiteMainView.visibility = View.VISIBLE
binding.loadingAnimationLayout.visibility = View.GONE
obsLiteConnected = true
updateOBSLiteButton()

val availableDrivers =
UsbSerialProber.getDefaultProber().findAllDrivers(usbManager)
if (availableDrivers.isNotEmpty()) {
val driver = availableDrivers[0]
val connection = usbManager!!.openDevice(driver.device)
port = driver.ports[0] // Most devices have just one port
try {
port.open(connection)
port.setParameters(
115200,
8,
UsbSerialPort.STOPBITS_1,
UsbSerialPort.PARITY_NONE
)
Log.d(RecorderService.TAG, "usb serial port opened")
val usbIoManager =
SerialInputOutputManager(port, this@OBSLiteActivity)
// usbIoManager!!.run()
usbIoManager.start()
} catch (e: IOException) {
throw RuntimeException(e)
}

val device: UsbDevice? =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
intent.getParcelableExtra(
UsbManager.EXTRA_DEVICE,
UsbDevice::class.java
)
} else {
intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
}

Log.d(TAG, "device: $device")
Log.d(
TAG,
"UsbManager.EXTRA_PERMISSION_GRANTED: ${
intent.getBooleanExtra(
UsbManager.EXTRA_PERMISSION_GRANTED,
false
)
}"
)
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
device?.apply {
usbDevice = device
binding.obsLiteMainView.visibility = View.VISIBLE
binding.loadingAnimationLayout.visibility = View.GONE
obsLiteConnected = true
updateOBSLiteButton()

val availableDrivers =
UsbSerialProber.getDefaultProber().findAllDrivers(usbManager)
if (availableDrivers.isNotEmpty()) {
val driver = availableDrivers[0]
val connection = usbManager!!.openDevice(driver.device)
port = driver.ports[0] // Most devices have just one port
try {
port.open(connection)
port.setParameters(
115200,
8,
UsbSerialPort.STOPBITS_1,
UsbSerialPort.PARITY_NONE
)
Log.d(RecorderService.TAG, "usb serial port opened")
val usbIoManager =
SerialInputOutputManager(port, this@OBSLiteActivity)
// usbIoManager!!.run()
usbIoManager.start()
} catch (e: IOException) {
throw RuntimeException(e)
}

}
} else {
Log.d(TAG, "permission denied for device $device")
}
} else {
Log.d(TAG, "permission denied for device $device")
}
// }
}
}

}

override fun onCreate(savedInstanceState: Bundle?) {
Expand All @@ -141,27 +136,36 @@ class OBSLiteActivity : BaseActivity(), SerialInputOutputManager.Listener {
binding.handleBarWidthLeft.value =
SharedPref.Settings.Ride.OvertakeWidth.getHandlebarWidthLeft(this)
binding.handleBarWidthLeft.setOnValueChangedListener { picker, oldVal, newVal ->
SharedPref.Settings.Ride.OvertakeWidth.setTotalWidthThroughHandlebarWidthLeft(newVal, this)
SharedPref.Settings.Ride.OvertakeWidth.setTotalWidthThroughHandlebarWidthLeft(
newVal,
this
)
}
// right
binding.handleBarWidthRight.maxValue = 60
binding.handleBarWidthRight.minValue = 0
binding.handleBarWidthRight.value =
SharedPref.Settings.Ride.OvertakeWidth.getHandlebarWidthRight(this)
binding.handleBarWidthRight.setOnValueChangedListener { picker, oldVal, newVal ->
SharedPref.Settings.Ride.OvertakeWidth.setTotalWidthThroughHandlebarWidthRight(newVal, this)
SharedPref.Settings.Ride.OvertakeWidth.setTotalWidthThroughHandlebarWidthRight(
newVal,
this
)
}

// OBS-Lite
obsLiteEnabled = SharedPref.Settings.OBSLite.isEnabled(this)

usbManager = getSystemService(Context.USB_SERVICE) as UsbManager
val explicitIntent = Intent(ACTION_USB_PERMISSION)
explicitIntent.setPackage(this.packageName);


permissionIntent = PendingIntent.getBroadcast(this, 0, explicitIntent,
PendingIntent.FLAG_MUTABLE)
explicitIntent.setPackage(this.packageName)

permissionIntent = PendingIntent.getBroadcast(
this,
0,
explicitIntent,
PendingIntent.FLAG_MUTABLE
)
val filter = IntentFilter(ACTION_USB_PERMISSION)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
this.registerReceiver(usbReceiver, filter, RECEIVER_EXPORTED)
Expand All @@ -170,26 +174,23 @@ class OBSLiteActivity : BaseActivity(), SerialInputOutputManager.Listener {
}
updateOBSLiteButton()
val obsLiteUrl = SharedPref.Settings.OBSLite.getObsLiteURL(this)
binding.obsLiteURL.setText(obsLiteUrl,TextView.BufferType.EDITABLE)
binding.obsLiteURL.setText(obsLiteUrl, TextView.BufferType.EDITABLE)

val obsUsername = SharedPref.Settings.OBSLite.getObsLiteUsername(this)
binding.obsLiteUsername.setText(obsUsername,TextView.BufferType.EDITABLE)
binding.obsLiteUsername.setText(obsUsername, TextView.BufferType.EDITABLE)

val obsLiteAPIKey = SharedPref.Settings.OBSLite.getObsLiteAPIKey(this)
binding.obsLiteAPIKey.setText(obsLiteAPIKey,TextView.BufferType.EDITABLE)

binding.obsLiteAPIKey.setText(obsLiteAPIKey, TextView.BufferType.EDITABLE)
}

private fun getOBSLitePermission() {

val deviceList = usbManager?.getDeviceList()
deviceList?.values?.forEach { device ->
Log.d(TAG, "deviceList device $device")
usbDevice = device
}

usbManager?.requestPermission(usbDevice, permissionIntent)

}

private fun disconnectOBSLite() {
Expand All @@ -205,21 +206,20 @@ class OBSLiteActivity : BaseActivity(), SerialInputOutputManager.Listener {
}
}


override fun onResume() {
super.onResume()
}

override fun onPause() {
super.onPause()
val obsLiteUrl = binding.obsLiteURL.getText()
SharedPref.Settings.OBSLite.setObsLiteURL(obsLiteUrl.toString(),this)
val obsLiteUrl = binding.obsLiteURL.text
SharedPref.Settings.OBSLite.setObsLiteURL(obsLiteUrl.toString(), this)

val obsLiteUsername = binding.obsLiteUsername.getText()
SharedPref.Settings.OBSLite.setObsLiteUsername(obsLiteUsername.toString(),this)
val obsLiteUsername = binding.obsLiteUsername.text
SharedPref.Settings.OBSLite.setObsLiteUsername(obsLiteUsername.toString(), this)

val obsLiteAPIKey = binding.obsLiteAPIKey.getText()
SharedPref.Settings.OBSLite.setObsLiteAPIKey(obsLiteAPIKey.toString(),this)
val obsLiteAPIKey = binding.obsLiteAPIKey.text
SharedPref.Settings.OBSLite.setObsLiteAPIKey(obsLiteAPIKey.toString(), this)
}

override fun onDestroy() {
Expand Down Expand Up @@ -249,7 +249,6 @@ class OBSLiteActivity : BaseActivity(), SerialInputOutputManager.Listener {
}

@OptIn(ExperimentalStdlibApi::class)

/** OBS-Lite related **/

// Called when new data from usb is read
Expand All @@ -266,7 +265,6 @@ class OBSLiteActivity : BaseActivity(), SerialInputOutputManager.Listener {
handleEvent()
}
}

}

// handles distance event and user input events of obs lite
Expand All @@ -285,35 +283,62 @@ class OBSLiteActivity : BaseActivity(), SerialInputOutputManager.Listener {
// Log.d(TAG, "" + event)
// event is distance event
if (event.hasDistanceMeasurement() && event.distanceMeasurement.distance < 5) {
// convert distance to cm + handlebar width
val distance = ((event.distanceMeasurement.distance * 100) + SharedPref.Settings.Ride.OvertakeWidth.getHandlebarWidth(this)).toInt()
// Rohwert (Meter -> cm)
val rawDistanceCm = (event.distanceMeasurement.distance * 100).toInt()
// left sensor event
if (event.distanceMeasurement.sourceId == 1) {
binding.leftSensorTextView.text = this@OBSLiteActivity.getString(R.string.obs_lite_text_last_distance_left,distance)
setColePassBarColor(distance,binding.leftSensorProgressBar)
// Linker Sensor -> linke Lenkerbreite verwenden
val handlebarWidthLeftCm =
SharedPref.Settings.Ride.OvertakeWidth.getHandlebarWidthLeft(this)
val correctedDistanceLeft =
(rawDistanceCm - handlebarWidthLeftCm).coerceAtLeast(0)

binding.leftSensorTextView.text = this@OBSLiteActivity.getString(
R.string.obs_lite_text_last_distance_left,
correctedDistanceLeft
)
setColePassBarColor(correctedDistanceLeft, binding.leftSensorProgressBar)
val eventTime = event.getTime(0).seconds
if (startTime == -1L) {
startTime = eventTime
}
// calculate minimal moving median for when the user presses obs lite button
movingMedian.newValue(distance)
// calculate median for when the user presses obs lite button
// Moving-Median arbeitet mit bereits korrigiertem Abstand (cm)
movingMedian.newValue(correctedDistanceLeft)
// right sensor event
} else {
binding.rightSensorTextView.text = this@OBSLiteActivity.getString(R.string.obs_lite_text_last_distance_right,distance)
setColePassBarColor(distance,binding.rightSensorProgressBar)
// Rechter Sensor -> rechte Lenkerbreite verwenden
val handlebarWidthRightCm =
SharedPref.Settings.Ride.OvertakeWidth.getHandlebarWidthRight(this)
val correctedDistanceRight =
(rawDistanceCm - handlebarWidthRightCm).coerceAtLeast(0)

binding.rightSensorTextView.text = this@OBSLiteActivity.getString(
R.string.obs_lite_text_last_distance_right,
correctedDistanceRight
)
setColePassBarColor(correctedDistanceRight, binding.rightSensorProgressBar)
}
// event is user input event
} else if (event.hasUserInput()) {
// Der Median enthält bereits den korrigierten Abstand in cm
val dm: DistanceMeasurement = DistanceMeasurement.newBuilder()
.setDistance(movingMedian.median.toFloat()).build()
.setDistance(movingMedian.median.toFloat()) // cm
.build()

event = event.toBuilder().setDistanceMeasurement(dm).build()

binding.userInputProgressbarTextView.text = this@OBSLiteActivity.getString(R.string.overtake_distance_left,movingMedian.median)
setColePassBarColor(movingMedian.median,binding.leftSensorUserInputProgressBar)
binding.userInputProgressbarTextView.text =
this@OBSLiteActivity.getString(
R.string.overtake_distance_left,
movingMedian.median
)
setColePassBarColor(
movingMedian.median,
binding.leftSensorUserInputProgressBar
)
binding.userInputTextView.text =
this@OBSLiteActivity.getString(R.string.overtake_press_button) + event

}
} catch (_: InvalidProtocolBufferException) {
}
Expand Down Expand Up @@ -350,11 +375,10 @@ class OBSLiteActivity : BaseActivity(), SerialInputOutputManager.Listener {
// handles the byteListQueues, which contain the COBS packages
private fun fillByteList(data: ByteArray?) {
for (datum in data!!) {
if (lastByteRead?.toInt() == 0x00){ // start new COBS package when last byte was 00
if (lastByteRead?.toInt() == 0x00) { // start new COBS package when last byte was 00
val newByteList = LinkedList<Byte>()
newByteList.add(datum)
byteListQueue.add(newByteList)

} else { // COBS package is not completed yet, continue the same package
if (byteListQueue.isNotEmpty()) {
byteListQueue.last.add(datum)
Expand All @@ -375,7 +399,8 @@ class OBSLiteActivity : BaseActivity(), SerialInputOutputManager.Listener {
private fun updateOBSLiteButton() {
runOnUiThread {
if (obsLiteConnected) {
binding.usbButton.text = getString(R.string.obs_activity_button_disconnect_device)
binding.usbButton.text =
getString(R.string.obs_activity_button_disconnect_device)
binding.usbButton.setOnClickListener {
disconnectOBSLite()
}
Expand All @@ -386,7 +411,6 @@ class OBSLiteActivity : BaseActivity(), SerialInputOutputManager.Listener {
}
}
}

}

/**
Expand All @@ -398,9 +422,9 @@ class OBSLiteActivity : BaseActivity(), SerialInputOutputManager.Listener {
var distanceArray: ArrayList<Int> = ArrayList()
var windowSize = 3
var median = 0

// Pair class for the value and its index
class Pair // Constructor
(private var value: Int, private var index: Int) : Comparable<Pair?> {
class Pair(private var value: Int, private var index: Int) : Comparable<Pair?> {
// This method will be used by the treeset to search a value by index and setting the tree nodes (left or right)
override fun compareTo(other: Pair?): Int {

Expand Down Expand Up @@ -431,15 +455,15 @@ class OBSLiteActivity : BaseActivity(), SerialInputOutputManager.Listener {
}
}


// Function to print the median for the current window
fun printMedian(minSet: TreeSet<Pair?>, maxSet: TreeSet<Pair?>, window: Int): Int {

// If the window size is even then the median will be the average of the two middle elements
return if (window % 2 == 0) {
(((minSet.last()!!.value() + maxSet.first()!!.value()) / 2.0).toInt())
} else {
(if (minSet.size > maxSet.size) minSet.last()!!.value() else maxSet.first()!!.value())
(if (minSet.size > maxSet.size) minSet.last()!!.value() else maxSet.first()!!
.value())
}
}

Expand Down Expand Up @@ -513,10 +537,12 @@ class OBSLiteActivity : BaseActivity(), SerialInputOutputManager.Listener {
distanceArray = distanceArray.drop(1) as ArrayList<Int>
}
distanceArray.add(distance)
// calculate median only if if distanceArray is big enough.
// calculate median only if distanceArray is big enough.
if (distanceArray.size >= windowSize) {
median = findMedian(distanceArray, windowSize).minOrNull()!!
val medians = findMedian(distanceArray, windowSize)
// Statt globalem Minimum: Median des letzten Fensters verwenden
median = medians.last()
}
}
}
}
}
Loading