feat: add Piezo BLE data pipeline (1:1 port from iOS)

PiezoPacketCollector.kt:
- Multi-packet reb:/red:/raa: assembly
- Auto-detect Big/Little Endian
- First channel locks endianness for all channels
- 6-channel support (maa command)

BleManager.kt:
- sendAllChannels(mode) → maa command
- reb:/rer:/raa: response routing to piezoCollector
- piezoCollector instance added

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
dwjang
2026-04-21 16:06:42 +09:00
parent dc61e1d52e
commit b83cb16f35
3 changed files with 231 additions and 1 deletions
@@ -274,7 +274,9 @@ class BleManager private constructor(private val context: Context) {
}
// Piezo Commands
fun sendPiezoPowerOn(freqOption: Int, cycles: Int) {
val piezoCollector = PiezoPacketCollector()
fun sendPiezoPowerOn(freqOption: Int = 2, cycles: Int = 5) {
sendRaw(CRC16.buildCommand("mpa", intArrayOf(freqOption, cycles)))
}
@@ -286,6 +288,12 @@ class BleManager private constructor(private val context: Context) {
sendRaw(CRC16.buildCommand("mec", intArrayOf(freqOption, delayUs, 140, cycles, 1, piezoCh)))
}
/** 6-channel measurement (maa) */
fun sendAllChannels(mode: Int = 0) {
piezoCollector.startMultiChannel(6)
sendRaw(CRC16.buildCommand("maa", intArrayOf(mode)))
}
// NIRS Commands
fun sendNirsPowerOn() {
sendRaw(CRC16.buildCommand("mta", intArrayOf(1)))
@@ -505,6 +513,14 @@ class BleManager private constructor(private val context: Context) {
"rag:", "rag!" -> onNirsMagReceived?.invoke(data)
"rcj:", "rcj!" -> onNirsMcjReceived?.invoke(data)
"rpa:" -> onPiezoDataReceived?.invoke(data)
// Piezo echo responses → route to packet collector
"rer:" -> {
// VesiScan-Basic preliminary header — just acknowledge, reb: follows
logd { "rer: preliminary header (${data.size} bytes)" }
}
"reb:" -> piezoCollector.addPacket(data)
"red:" -> piezoCollector.addPacket(data)
"ree:", "raa:" -> piezoCollector.addPacket(data)
"rsn:" -> {
if (data.size >= 6) {
val millivolts = ((data[4].toInt() and 0xFF) shl 8) or (data[5].toInt() and 0xFF)