diff --git a/app/src/main/java/com/medithings/vesiscan/ble/BleManager.kt b/app/src/main/java/com/medithings/vesiscan/ble/BleManager.kt index 8c65e02..fdb793a 100644 --- a/app/src/main/java/com/medithings/vesiscan/ble/BleManager.kt +++ b/app/src/main/java/com/medithings/vesiscan/ble/BleManager.kt @@ -469,6 +469,7 @@ class BleManager private constructor(private val context: Context) { else "?" }" "msp" -> "IMU query" + "mim" -> "IMU FIFO (15 samples)" "mbb" -> "full measurement (battery+IMU+temp+6ch)" else -> "" } @@ -576,6 +577,18 @@ class BleManager private constructor(private val context: Context) { sendRaw(CRC16.buildCommandASCII("msp", " ")) } + /** + * IMU FIFO 폴링 (2026-07-03 펌웨어 신규 mim?): + * - piezo burst 없음 (무음) + * - IMU 15 sample (300ms window) 를 rim: 프레임으로 반환 + * - 응답 스키마는 mtb? 의 rim: 와 동일 → imuCollector.parseRim + onComplete 재사용 + * idle 폴링에서 walking detector 의 sliding window 를 채우기 위해 사용. + */ + fun sendImuFifoQuery() { + imuCollector.reset() + sendRaw(CRC16.buildCommandASCII("mim", " ")) + } + /** 전체 측정: 배터리+IMU+온도+6ch piezo (rbb→reb×6→raa) */ fun sendFullMeasurement() { piezoCollector.startMultiChannel(6) diff --git a/app/src/main/java/com/medithings/vesiscan/managers/GreenZoneConstants.kt b/app/src/main/java/com/medithings/vesiscan/managers/GreenZoneConstants.kt index 948579f..52d3898 100644 --- a/app/src/main/java/com/medithings/vesiscan/managers/GreenZoneConstants.kt +++ b/app/src/main/java/com/medithings/vesiscan/managers/GreenZoneConstants.kt @@ -64,12 +64,15 @@ object GreenZoneConstants { @Volatile var postureAccMagMax: Float = 1.2f /** - * Posture polling 간격 (ms). PiezoMonitoring 에서 msp 보내는 주기. - * 6/30 변경: mtb (1Hz × 15sample) → msp (5Hz × 1sample) 로 전환. piezo burst 가청음 제거. - * Walking detector 의 1.5초 window 안에 7-8 sample 확보 위해 200ms 주기. + * Posture polling 간격 (ms). PiezoMonitoring idle 폴링 주기. + * 이력: + * 6/30 : mtb (1Hz × 15sample) → msp (5Hz × 1sample) — piezo 무음 확보, 주기 200ms + * (walking window 1.5초 안에 7-8 샘플 확보용) + * 7/03 : msp → mim (1Hz × 15sample, 무음) — piezo 무음 유지 + 시계열 15샘플 확보. + * 단일 폴링당 300ms 시계열 얻으므로 주기 1000ms 로 완화 (BLE 왕복 5배 감소). * dev 모드에서 조정 가능. */ - @Volatile var posturePollIntervalMs: Long = 200L + @Volatile var posturePollIntervalMs: Long = 1000L // ── Walking detector 임계값 (flowchart 4-2 / 5-2) ───────────────── /** Walking 인정 최소 pitch (deg). |pitch| > 이 값 이라야 walking 후보. */ diff --git a/app/src/main/java/com/medithings/vesiscan/ui/views/monitoring/PiezoMonitoringView.kt b/app/src/main/java/com/medithings/vesiscan/ui/views/monitoring/PiezoMonitoringView.kt index a7dc339..449c7f5 100644 --- a/app/src/main/java/com/medithings/vesiscan/ui/views/monitoring/PiezoMonitoringView.kt +++ b/app/src/main/java/com/medithings/vesiscan/ui/views/monitoring/PiezoMonitoringView.kt @@ -758,11 +758,12 @@ fun PiezoMonitoringView(appState: AppState) { com.medithings.vesiscan.services.PostureEventLogger.startSession(context) } - // IMU polling + 자세 분류 — msp 명령 (rsp: 응답, IMU-only). - // 6/30: 이전엔 mtb (piezo 6ch + IMU) 폴링으로 매 cycle piezo burst 가청음 발생. - // 사용자앱에서 msp 의 rsp: 응답 정상 (실측 VBTFW0120, 18B = tag+12B sample+crc) 확정 후 - // 데모도 동일 적용. WalkingDetector window (1.5초) 확보 위해 폴링 주기 1000→200ms. - // 둘 다 imuCollector.parseRsp/parseRim 가 같은 onComplete 콜백 트리거 → classifier 동일. + // IMU polling + 자세 분류 — 2026-07-03: msp → mim 전환 (펌웨어 신규 명령). + // 6/30 (msp): piezo 무음 확보했지만 1샘플/폴링이라 WalkingDetector 1.5초 window + // 확보 위해 200ms 폴링 → BLE 왕복 5배 트래픽 + 나이퀴스트 aliasing 위험. + // 7/03 (mim): 15샘플/폴링(300ms 시계열) + piezo 무음. WalkingDetector 가 요구하는 + // 시계열 밀도 확보. 폴링 주기 200 → 1000ms 로 완화 (BLE 왕복 5배 감소, 배터리 유리). + // 응답 프레임 rim: 는 mtb? 와 동일 — imuCollector.parseRim + onComplete 그대로 재사용. LaunchedEffect(isConnected, isDemoMode) { Log.d("ImuDbg", "LaunchedEffect start isConnected=$isConnected isDemoMode=$isDemoMode") if (isDemoMode) { @@ -820,16 +821,16 @@ fun PiezoMonitoringView(appState: AppState) { Log.d("ImuDbg", "imuCollector log: $msg") } while (isActive) { - // msp 는 piezo burst 없는 IMU-only — Auto/Single Scan 중에도 충돌 없이 가능. + // mim 은 piezo burst 없는 IMU FIFO (15 sample) — Auto/Single Scan 중에도 충돌 없이 가능. // 단 isMeasuring (현재 measure() 호출 중) / isSpotInProgress 짧은 시간만 skip // (BLE 큐 충돌 방어). // Auto Scan 자체는 mtb 응답에 IMU 가 들어있어 자동으로 posture 갱신됨 (parseRim). if (isConnected && !isMeasuring && !isSpotInProgress) { if (!isAutoMeasuring) { - // idle — msp polling (무음) - bleManager.sendImuQuery() + // idle — mim FIFO 폴링 (15샘플/burst, 무음) + bleManager.sendImuFifoQuery() } - // isAutoMeasuring=true 면 mtb 의 rim: 가 알아서 posture 갱신, msp skip + // isAutoMeasuring=true 면 mtb 의 rim: 가 알아서 posture 갱신, mim skip } kotlinx.coroutines.delay(GreenZoneConstants.posturePollIntervalMs) }