debug(posture): logcat 로 IMU 흐름 가시화 — ImuDbg 태그 도입

증상: PiezoMonitoring 진입해도 자세 ?_ 만 표시, logcat 에 rsp/POSTURE
      로그 안 보임.

원인: debugLogger.tx/rx 는 내부 Entry 리스트에만 적재하고 android.util.Log
      호출 안 함 → adb logcat | grep 에 안 보임.

수정: 핵심 IMU 흐름에 android.util.Log.d("ImuDbg", ...) 추가.

  PiezoMonitoringView.LaunchedEffect:
    - 시작 시 isConnected/isDemoMode 값 로그
    - sendImuQuery 매 호출 "→ sendImuQuery (msp)"
    - 연결 안 되어 있으면 "skip (not connected)"
    - imuCollector.onComplete 결과 (자세 + pitch/acc/gyro)
    - imuCollector.onLog 도 ImuDbg 로 forward (parseRsp 로그 보임)

  BleManager:
    - rsp: 응답 시 hex dump 도 ImuDbg 로 (debugLogger 와 별개)
    - rxs: (cmd_not_supported) 응답 시 ImuDbg 로 warn

  rxs: 중복 핸들러 정리 (기존 1개 → 새 1개로 통합)

테스트: "adb logcat | grep ImuDbg" 한 줄로 전체 흐름 확인 가능.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-06-23 14:30:50 +09:00
parent 1774681a18
commit 33b072c336
2 changed files with 15 additions and 8 deletions
@@ -1199,10 +1199,6 @@ class BleManager private constructor(private val context: Context) {
val state = if (data.size >= 5) data[4].toInt() and 0xFF else -1
debugLogger.rx("rls", data.size, "led_state=$state")
}
"rxs:" -> {
val echoCmd = if (data.size > 4) String(data, 4, minOf(data.size - 4, 10), Charsets.US_ASCII).trim() else "?"
debugLogger.rx("rxs", data.size, "cmd_not_supported: $echoCmd")
}
"rbb:" -> {
debugLogger.rx("rbb", data.size, "full measurement header (battery+IMU+temp)")
onMbbHeaderReceived?.invoke(data)
@@ -1212,9 +1208,15 @@ class BleManager private constructor(private val context: Context) {
// msp 명령 응답 — IMU 데이터. format 불명확이라 defensive parsing.
val hex = data.take(kotlin.math.min(data.size, 24)).joinToString(" ") { "%02X".format(it) }
debugLogger.rx("rsp", data.size, "IMU data hex=$hex")
android.util.Log.d("ImuDbg", "rsp RX len=${data.size} hex=$hex")
imuCollector.parseRsp(data)
onImuReceived?.invoke(data)
}
"rxs:" -> {
val echoCmd = if (data.size > 4) String(data, 4, minOf(data.size - 4, 10), Charsets.US_ASCII).trim() else "?"
android.util.Log.w("ImuDbg", "rxs cmd_not_supported: $echoCmd")
debugLogger.rx("rxs", data.size, "cmd_not_supported: $echoCmd")
}
"rim:" -> {
val num = if (data.size >= 6) ((data[4].toInt() and 0xFF) shl 8) or (data[5].toInt() and 0xFF) else 0
debugLogger.rx("rim", data.size, "IMU ${num} samples")
@@ -591,24 +591,29 @@ fun PiezoMonitoringView(appState: AppState) {
}
}
// IMU polling + 자세 분류 (Phase 1) — 5초 주기로 msp 명령 → rim: 응답 받아 분류.
// monitoring 페이지 머무는 동안만 작동. demo 모드는 fake 자세 (toggle 없이 SUPINE).
// IMU polling + 자세 분류 (Phase 1) — 5초 주기로 msp 명령 → rsp: 응답 받아 분류.
LaunchedEffect(isConnected, isDemoMode) {
Log.d("ImuDbg", "LaunchedEffect start isConnected=$isConnected isDemoMode=$isDemoMode")
if (isDemoMode) {
currentPosture = com.example.medilightv2android.managers.Posture.SUPINE
return@LaunchedEffect
}
bleManager.imuCollector.onComplete = { samples ->
val r = com.example.medilightv2android.managers.ImuPostureClassifier.classify(samples)
// UNKNOWN 이면 직전 posture 유지 (motion artifact 시 잠깐 흔들림 방지)
if (r.posture != com.example.medilightv2android.managers.Posture.UNKNOWN) {
currentPosture = r.posture
}
Log.d("PiezoMonitor", "POSTURE ${r.posture} pitch=${"%.1f".format(r.pitchDeg)}° accMag=${"%.2f".format(r.accMag)}g gyro=${"%.1f".format(r.gyroMagDps)}dps (${r.reason})")
Log.d("ImuDbg", "POSTURE ${r.posture} pitch=${"%.1f".format(r.pitchDeg)}° accMag=${"%.2f".format(r.accMag)}g gyro=${"%.1f".format(r.gyroMagDps)}dps (${r.reason}) samples=${samples.size}")
}
bleManager.imuCollector.onLog = { msg ->
Log.d("ImuDbg", "imuCollector log: $msg")
}
while (isActive) {
if (isConnected) {
Log.d("ImuDbg", "→ sendImuQuery (msp)")
bleManager.sendImuQuery()
} else {
Log.d("ImuDbg", "skip (not connected)")
}
kotlinx.coroutines.delay(5000)
}