feat: BLE 로그에 파싱된 값 추가 (TX 명령어 + RX 응답 의미)
TX: "maa 6ch measure", "msn battery query", "mpa piezo power ON" 등
RX: "rsn battery=3850mV (100%)", "reb 100samples", "raa all-ch complete",
"rpa piezo ack", "rag gain calibration (24 values)" 등
펌웨어팀에 보낼 때 raw hex 없이도 통신 흐름을 이해할 수 있음
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -270,9 +270,21 @@ class BleManager private constructor(private val context: Context) {
|
|||||||
loge { "sendRaw: bluetoothGatt is null!" }
|
loge { "sendRaw: bluetoothGatt is null!" }
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val cmdPreview = if (data.size >= 4) String(data, 0, 4, Charsets.US_ASCII).trimEnd('?') else "?"
|
val cmdPreview = if (data.size >= 4) String(data, 0, 3, Charsets.US_ASCII) else "?"
|
||||||
|
val cmdDetail = when (cmdPreview) {
|
||||||
|
"maa" -> "6ch measure"
|
||||||
|
"mpa" -> "piezo power ON"
|
||||||
|
"mps" -> "piezo stop"
|
||||||
|
"mec" -> "single burst"
|
||||||
|
"msn" -> "battery query"
|
||||||
|
"mta" -> if (data.size > 4 && data[4].toInt() == 1) "NIRS power ON" else "NIRS power OFF"
|
||||||
|
"mqq" -> "NIRS activate"
|
||||||
|
"mag" -> "NIRS gain query"
|
||||||
|
"mcj" -> "NIRS MCJ query"
|
||||||
|
else -> ""
|
||||||
|
}
|
||||||
logd { "sendRaw: $cmdPreview (${data.size} bytes)" }
|
logd { "sendRaw: $cmdPreview (${data.size} bytes)" }
|
||||||
debugLogger.tx("$cmdPreview (${data.size}B)", data.size)
|
debugLogger.tx("$cmdPreview $cmdDetail", data.size)
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
val result = gatt.writeCharacteristic(characteristic, data, BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE)
|
val result = gatt.writeCharacteristic(characteristic, data, BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE)
|
||||||
logd { "sendRaw result: $result" }
|
logd { "sendRaw result: $result" }
|
||||||
@@ -724,29 +736,58 @@ class BleManager private constructor(private val context: Context) {
|
|||||||
private fun processReceivedData(data: ByteArray) {
|
private fun processReceivedData(data: ByteArray) {
|
||||||
lastRxTimestamp = System.currentTimeMillis()
|
lastRxTimestamp = System.currentTimeMillis()
|
||||||
val prefix = String(data, 0, minOf(4, data.size), Charsets.US_ASCII)
|
val prefix = String(data, 0, minOf(4, data.size), Charsets.US_ASCII)
|
||||||
debugLogger.rx(prefix.trimEnd(':', '!'), data.size)
|
|
||||||
logd { "Received: $prefix (${data.size} bytes)" }
|
logd { "Received: $prefix (${data.size} bytes)" }
|
||||||
when (prefix) {
|
when (prefix) {
|
||||||
"rta:", "rta!" -> onNirsPowerOnReceived?.invoke()
|
"rta:", "rta!" -> {
|
||||||
"rsh:", "rsh!", "rqq:", "rqq!" -> onNirsSensorActivated?.invoke()
|
debugLogger.rx("rta", data.size, "piezo power ON")
|
||||||
"rag:", "rag!" -> onNirsMagReceived?.invoke(data)
|
onNirsPowerOnReceived?.invoke()
|
||||||
"rcj:", "rcj!" -> onNirsMcjReceived?.invoke(data)
|
}
|
||||||
"rpa:" -> onPiezoDataReceived?.invoke(data)
|
"rsh:", "rsh!", "rqq:", "rqq!" -> {
|
||||||
// Piezo echo responses → route to packet collector
|
debugLogger.rx(prefix.take(3), data.size, "sensor activated")
|
||||||
"rer:" -> {
|
onNirsSensorActivated?.invoke()
|
||||||
// VesiScan-Basic preliminary header — just acknowledge, reb: follows
|
}
|
||||||
logd { "rer: preliminary header (${data.size} bytes)" }
|
"rag:", "rag!" -> {
|
||||||
|
debugLogger.rx("rag", data.size, "gain calibration (${(data.size - 6) / 2} values)")
|
||||||
|
onNirsMagReceived?.invoke(data)
|
||||||
|
}
|
||||||
|
"rcj:", "rcj!" -> {
|
||||||
|
debugLogger.rx("rcj", data.size, "MCJ packet")
|
||||||
|
onNirsMcjReceived?.invoke(data)
|
||||||
|
}
|
||||||
|
"rpa:" -> {
|
||||||
|
debugLogger.rx("rpa", data.size, "piezo ack")
|
||||||
|
onPiezoDataReceived?.invoke(data)
|
||||||
|
}
|
||||||
|
"rer:" -> {
|
||||||
|
debugLogger.rx("rer", data.size, "preliminary header")
|
||||||
|
}
|
||||||
|
"reb:" -> {
|
||||||
|
val samples = (data.size - 8) / 2
|
||||||
|
debugLogger.rx("reb", data.size, "${samples}samples")
|
||||||
|
piezoCollector.addPacket(data)
|
||||||
|
}
|
||||||
|
"red:" -> {
|
||||||
|
debugLogger.rx("red", data.size, "continuation")
|
||||||
|
piezoCollector.addPacket(data)
|
||||||
|
}
|
||||||
|
"ree:", "raa:" -> {
|
||||||
|
val tag = prefix.take(3)
|
||||||
|
debugLogger.rx(tag, data.size, if (tag == "raa") "all-ch complete" else "single-ch end")
|
||||||
|
piezoCollector.addPacket(data)
|
||||||
}
|
}
|
||||||
"reb:" -> piezoCollector.addPacket(data)
|
|
||||||
"red:" -> piezoCollector.addPacket(data)
|
|
||||||
"ree:", "raa:" -> piezoCollector.addPacket(data)
|
|
||||||
"rsn:" -> {
|
"rsn:" -> {
|
||||||
if (data.size >= 6) {
|
if (data.size >= 6) {
|
||||||
val millivolts = ((data[4].toInt() and 0xFF) shl 8) or (data[5].toInt() and 0xFF)
|
val millivolts = ((data[4].toInt() and 0xFF) shl 8) or (data[5].toInt() and 0xFF)
|
||||||
batteryLevel.value = ((millivolts - 3700) * 100 / 500).coerceIn(0, 100)
|
val pct = ((millivolts - 3700) * 100 / 500).coerceIn(0, 100)
|
||||||
|
batteryLevel.value = pct
|
||||||
|
debugLogger.rx("rsn", data.size, "battery=${millivolts}mV (${pct}%)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> logw { "Unknown prefix: '$prefix' hex=${data.take(8).joinToString(" ") { "%02X".format(it) }}" }
|
else -> {
|
||||||
|
val hex = data.take(8).joinToString(" ") { "%02X".format(it) }
|
||||||
|
debugLogger.rx("???", data.size, "unknown prefix='$prefix' hex=$hex")
|
||||||
|
logw { "Unknown prefix: '$prefix' hex=$hex" }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user