feat: BLE stability fixes, NIRS streaming improvements, catheter count feature
- Fix BLE API deprecation warnings with API 33+ version checks - Move isServiceReady to onDescriptorWrite for reliable CCCD setup - Fix battery polling: immediate query on connect, pause during NIRS streaming - Add mcj retry mechanism for NIRS streaming reliability - Add debug logging to BLE, NIRS parsing, and processing pipeline - Add catheter count feature to Piezo monitoring (persistent count, add dialog, auto-decrement on catheterize) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -244,16 +244,28 @@ class BleManager private constructor(private val context: Context) {
|
||||
|
||||
// Send
|
||||
fun sendRaw(data: ByteArray) {
|
||||
val characteristic = txCharacteristic ?: return
|
||||
val gatt = bluetoothGatt ?: return
|
||||
val characteristic = txCharacteristic
|
||||
val gatt = bluetoothGatt
|
||||
if (characteristic == null) {
|
||||
Log.e(TAG, "sendRaw: txCharacteristic is null!")
|
||||
return
|
||||
}
|
||||
if (gatt == null) {
|
||||
Log.e(TAG, "sendRaw: bluetoothGatt is null!")
|
||||
return
|
||||
}
|
||||
val cmdPreview = if (data.size >= 4) String(data, 0, 4, Charsets.US_ASCII) else "?"
|
||||
Log.d(TAG, "sendRaw: $cmdPreview (${data.size} bytes)")
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
gatt.writeCharacteristic(characteristic, data, BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE)
|
||||
val result = gatt.writeCharacteristic(characteristic, data, BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE)
|
||||
Log.d(TAG, "sendRaw result: $result")
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
characteristic.value = data
|
||||
characteristic.writeType = BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE
|
||||
@Suppress("DEPRECATION")
|
||||
gatt.writeCharacteristic(characteristic)
|
||||
val ok = gatt.writeCharacteristic(characteristic)
|
||||
Log.d(TAG, "sendRaw success: $ok")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,7 +305,8 @@ class BleManager private constructor(private val context: Context) {
|
||||
|
||||
fun startBatteryPolling() {
|
||||
batteryTimer?.let { handler.removeCallbacks(it) }
|
||||
handler.postDelayed({ sendBatteryQuery() }, 1000)
|
||||
// Query immediately, then every 30s
|
||||
sendBatteryQuery()
|
||||
val poll = object : Runnable {
|
||||
override fun run() {
|
||||
sendBatteryQuery()
|
||||
@@ -301,10 +314,10 @@ class BleManager private constructor(private val context: Context) {
|
||||
}
|
||||
}
|
||||
batteryTimer = poll
|
||||
handler.postDelayed(poll, 31000)
|
||||
handler.postDelayed(poll, 30000)
|
||||
}
|
||||
|
||||
private fun stopBatteryPolling() {
|
||||
fun stopBatteryPolling() {
|
||||
batteryTimer?.let { handler.removeCallbacks(it) }
|
||||
batteryTimer = null
|
||||
}
|
||||
@@ -353,7 +366,6 @@ class BleManager private constructor(private val context: Context) {
|
||||
} catch (_: Exception) {}
|
||||
|
||||
gatt.discoverServices()
|
||||
startBatteryPolling()
|
||||
onConnectionStateChanged?.invoke(true)
|
||||
}
|
||||
BluetoothProfile.STATE_DISCONNECTED -> {
|
||||
@@ -439,6 +451,7 @@ class BleManager private constructor(private val context: Context) {
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
if (txCharacteristic != null && rxCharacteristic != null) {
|
||||
isServiceReady.value = true
|
||||
startBatteryPolling()
|
||||
Log.d(TAG, "Service ready! (CCCD written)")
|
||||
}
|
||||
} else {
|
||||
@@ -469,7 +482,15 @@ class BleManager private constructor(private val context: Context) {
|
||||
|
||||
private fun processReceivedData(data: ByteArray) {
|
||||
val prefix = String(data, 0, minOf(4, data.size), Charsets.US_ASCII)
|
||||
Log.d(TAG, "Received: $prefix (${data.size} bytes)")
|
||||
Log.d(TAG, "Received: $prefix (${data.size} bytes), callback=${
|
||||
when {
|
||||
prefix.startsWith("rcj") -> "onNirsMcjReceived=${onNirsMcjReceived != null}"
|
||||
prefix.startsWith("rta") -> "onNirsPowerOnReceived=${onNirsPowerOnReceived != null}"
|
||||
prefix.startsWith("rqq") || prefix.startsWith("rsh") -> "onNirsSensorActivated=${onNirsSensorActivated != null}"
|
||||
prefix.startsWith("rag") -> "onNirsMagReceived=${onNirsMagReceived != null}"
|
||||
else -> "n/a"
|
||||
}
|
||||
}")
|
||||
when (prefix) {
|
||||
"rta:", "rta!" -> onNirsPowerOnReceived?.invoke()
|
||||
"rsh:", "rsh!", "rqq:", "rqq!" -> onNirsSensorActivated?.invoke()
|
||||
@@ -482,6 +503,7 @@ class BleManager private constructor(private val context: Context) {
|
||||
batteryLevel.value = ((millivolts - 3700) * 100 / 500).coerceIn(0, 100)
|
||||
}
|
||||
}
|
||||
else -> Log.w(TAG, "Unknown prefix: '$prefix' hex=${data.take(8).joinToString(" ") { "%02X".format(it) }}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user