fix(alignment): "기기 응답이 지연되고 있습니다" stuck + 재진입 stale 카운터

증상 (사용자 로그 2026-08-11 12:35):
  · 첫 alignment 완료 → PiezoMonitoringView → alignment 재진입 시
    "기기 응답이 지연되고 있습니다" 문구가 뜨고 사라지지 않음.
  · 실제 BLE 는 mtb 1회 timeout 후 다음 프레임에 즉시 raa 정상 응답 → 카운터 리셋됐으나
    화면만 못 따라감.

원인 (2가지):
  A. LaunchedEffect(mtbTimeoutCount) 에 mtbTimeoutCount==0 브랜치 없음.
     카운터 1→0 정상 복구 시 문구 초기화 로직이 없어 stuck.
  B. 재진입 시 이전 view (PiezoMonitoring) 에서 남은 mtb timeout 카운터가
     그대로 유지 → 첫 mtb 성공 전 UI 가 이미 "응답 지연" 로 초기화될 수 있음.

수정:
  A) when 절 재구성 · == 0 브랜치에서 delayed/reconnect 문구였다면 clear.
  B) 화면 진입 LaunchedEffect(Unit) 에서 consecutiveMtbTimeouts.value = 0.

RSSI 는 원인 아님 — 재진입 구간 RSSI -65~-62 로 양호.
CMDQ (depth=1) 상 이전 view 잔여 mim IMU 큐 지연이 mtb 1회 timeout 을
유발한 것으로 보이나 · 그건 즉시 자동 복구되므로 UI 층만 손보면 됨.
This commit is contained in:
2026-08-11 13:35:51 +09:00
parent 0a02fc8b87
commit 73e2596842
@@ -135,6 +135,9 @@ fun PlacementGuideView(appState: AppState) {
if (isClinicalAlign) com.medithings.vesiscan.managers.AlignmentAlgo.V2 if (isClinicalAlign) com.medithings.vesiscan.managers.AlignmentAlgo.V2
else com.medithings.vesiscan.managers.AlignmentAlgo.V1 else com.medithings.vesiscan.managers.AlignmentAlgo.V1
v2Aligner.reset() v2Aligner.reset()
// 2026-08-11: 이전 view (PiezoMonitoring 등) 에서 남은 stale mtb timeout 카운터 초기화.
// 재진입 시 첫 mtb 가 정상 응답해도 이전 값 때문에 UI 가 "응답 지연" 로 시작하는 버그 방지.
bleManager.consecutiveMtbTimeouts.value = 0
// Clinical alignment session 진입 시 — 자동으로 scan 시작 (Step 0 baseline 캡쳐). // Clinical alignment session 진입 시 — 자동으로 scan 시작 (Step 0 baseline 캡쳐).
// waitingForStart 는 true 유지 — 사용자는 여전히 Start 눌러 알고리즘 시작 결정. // waitingForStart 는 true 유지 — 사용자는 여전히 Start 눌러 알고리즘 시작 결정.
// baseline cycles 는 measurement.json 에 phase="STEP_0_BASELINE" 로 누적됨. // baseline cycles 는 measurement.json 에 phase="STEP_0_BASELINE" 로 누적됨.
@@ -177,14 +180,26 @@ fun PlacementGuideView(appState: AppState) {
// BleManager.sendMtb 는 raa 응답 대기 3초 후 consecutiveMtbTimeouts 를 증가시킴. // BleManager.sendMtb 는 raa 응답 대기 3초 후 consecutiveMtbTimeouts 를 증가시킴.
val mtbTimeoutCount by bleManager.consecutiveMtbTimeouts val mtbTimeoutCount by bleManager.consecutiveMtbTimeouts
LaunchedEffect(mtbTimeoutCount) { LaunchedEffect(mtbTimeoutCount) {
if (mtbTimeoutCount in 1..2) { val delayedMsg = context.getString(R.string.mtb_response_delayed)
directionHint = context.getString(R.string.mtb_response_delayed) val reconnectMsg = context.getString(R.string.mtb_response_reconnect)
directionIcon = "" when {
} else if (mtbTimeoutCount >= 3) { // 2026-08-11: 정상 복구 시 UI 문구 복원 (기존엔 브랜치 없어 "응답 지연" stuck).
directionHint = context.getString(R.string.mtb_response_reconnect) mtbTimeoutCount == 0 -> {
directionIcon = "" if (directionHint == delayedMsg || directionHint == reconnectMsg) {
bleManager.debugLogger.warn("MTB_FORCE_RECONNECT after $mtbTimeoutCount consecutive timeouts") directionHint = ""
bleManager.forceDisconnectAndReconnect() directionIcon = ""
}
}
mtbTimeoutCount in 1..2 -> {
directionHint = delayedMsg
directionIcon = ""
}
mtbTimeoutCount >= 3 -> {
directionHint = reconnectMsg
directionIcon = ""
bleManager.debugLogger.warn("MTB_FORCE_RECONNECT after $mtbTimeoutCount consecutive timeouts")
bleManager.forceDisconnectAndReconnect()
}
} }
} }