docs: v6 전체 업데이트 (1.0.0-design, VBTFW0116 짝, 2026-05-26 기준)

a1042b8(v5) 이후 13개 커밋을 반영해 세 문서 일괄 갱신.

USER_GUIDE.md:
- 헤더: VBTAND0101 → 1.0.0-design (versionCode 24), 권장 펌웨어 VBTFW0116
- PIN DEMO 자동통과 안내 (배포 전 정리 필요)
- Personalization 평행 2-카드 (Maximum Bladder Capacity + Catheter Threshold)
- Sensor Alignment 리디자인 (38sp 큰 타이틀, pubic bone 빨강, 3-stop gradient, Canvas 화살표/아치 제거)
- Measurement Screen top bar에 Home 아이콘 + Voiding/ 텍스트 + 48sp Recorded Dialog
- Auto Scan 600ms로 단축 + 측정 사이클 ~330ms 실측 안내
- 설정 패널 폰/태블릿 자동 폰트 분기 (fontScale 표 추가)
- Dev Mode 추가 기능 (DeviceScan 측정 직진입 버튼, Status 더미 주입)
- Navigation에 placementFromMonitoring 라우팅 분기 설명 + startFromHome fix

VesiScan_Android_Pipeline_Summary.md:
- v6 주요 변경 요약 (헤더에 한눈 보기)
- §5.1 BLE 통신: Connection Parameter 협상 (MTU 247, CONN_PRIORITY HIGH), maa throttle
  state-based gate, 측정 사이클 실측 표
- 측정 흐름: Auto/Single Scan 600ms 동기화 + Voiding 시 자동 stop
- 연속 스캔 동작: Placement loop 1000 → 600ms + v6 화면 디자인 변경 박스
- §14 BLE 명령어 포맷: VBTFW0116 신규 사항 (pending slot 1→8, 안드로이드 짝꿍 변경)
- §22 향후 과제: v6 완료 항목 12개 추가

docs/ALGORITHM_COMPARISON.md:
- Placement loop 1s → 600ms, canSendMaa 게이트 단계 명시
- v6 BLE 사이클 실측 (330ms 평균)
- Measurement Modes: 800 → 600ms, Voiding 자동 stop
- 신규 섹션: BLE maa Throttle — State-Based Gate (배경/구현/효과/logcat 키워드)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-26 10:26:00 +09:00
parent 31e9b8acbb
commit 4252464ef6
3 changed files with 296 additions and 32 deletions
+72 -5
View File
@@ -133,17 +133,20 @@ EDGE_DIST_DECAY=0.12, VALLEY_STOP_RISE=50, etc.
## Placement Test Algorithm
### Overview (2026-05-11 updated)
### Overview (2026-05-26 updated — v6)
```
Screen entry → "Place VesiScan above the pubic bone, then press Start"
↓ Start Alignment 버튼 탭 (waitingForStart=false)
전체 상태 리셋
↓
[1-second interval loop]
[600ms interval loop] ← v6: 1000ms → 600ms (BleManager throttle과 동기화)
↓
mpa (first time, 500ms delay) → maa → 6ch reb
↓
↓ (maa 전 BleManager.canSendMaa() 게이트 통과 필요)
│ - State gate: !piezoCollector.isComplete 이면 차단 (3s 후 FORCE)
│ - Time gate: 마지막 송신 < 600ms 이면 차단
│
Detachment check (6ch received, THR=30) → LED 4 if detached
↓
Wall detection (Method A/B/C) → urineLen ≥ 12
@@ -161,6 +164,11 @@ GREEN: 7s hold + 3 consecutive fail to exit
Screen exit → LED OFF
```
### v6 BLE 사이클 실측 (VBTFW0116 + MTU 247 + CONN_PRIORITY HIGH)
한 측정 사이클 (TX maa → RX raa): **평균 ~330ms** (이전 ~1.2~1.4s 대비 4배 향상).
600ms loop delay 안에 한 사이클이 안정적으로 완료됨.
### Guide Modes
**Gradient** (default): weighted center gradient → LATERAL → GREEN
@@ -173,13 +181,14 @@ Screen exit → LED OFF
**Stage 2 LATERAL**: |len4-len5| ≤ 10 → GREEN, else "Slide left/right ←→"
**Stage 3 GREEN**: CV ≤ threshold AND |LR dev| ≤ 0.20 → "In position!" (7s hold)
### Measurement Modes
### Measurement Modes (v6 업데이트)
- **Auto Scan**: min 800ms gap, 10-sample trimmed mean (max/min removed, 8 avg)
- **Auto Scan**: **min 600ms gap** (state-based throttle: `!isComplete` + 600ms), 10-sample trimmed mean (max/min removed, 8 avg)
- **Single Scan (Spot)**: 5회 측정 → trimmed mean (max 8 attempts, min 3)
- valid ≥ 4 channels only
- Analysis on coroutine (Dispatchers.Default)
- Auto fail: 2ch+ missing 5 consecutive → realign dialog
- **Voiding/Catheterization 클릭 시 Auto Scan 자동 stop + 측정 상태 정규화** (displayMaxVolumeMl/window/timer 모두 0)
- Detachment → LED 4 (once), recovery → LED 0 (once)
- Foreground Service: BLE connection maintained during screen off
- BLE 로그: 실시간 파일 기록 (Downloads/VesiScan_BLE_*.log, 화면 잠금에도 보존)
@@ -203,3 +212,61 @@ GREEN exit: 3회 연속 실패 (greenFailCount)
±15% 이내: 223/223 (100%)
범위: 441~537ml
```
---
## BLE maa Throttle — State-Based Gate (v6, 2026-05-26)
### 배경: CH0/CH1만 도착 + BV_FAIL/BV_SKIP 증상
이전 throttle은 시간 단독 `now - lastMaaSentMs < 800ms` 만 검사. 펌웨어 응답이
~1.2~1.4초 걸리는 환경에서 800ms 시점에 새 maa가 송신되면:
1. `sendChannelsOnly()` 통과 → `piezoCollector.startMultiChannel(6)` → collector reset
2. **큐에 떠다니던 이전 사이클의 reb / raa 패킷이 새 collector의 시작 부분에 잘못 들어감**
3. 결과: 한 채널만 들고 raa로 종료 → `BV_FAIL no valid channels` 또는 `BV_SKIP center=0 total=5/6`
실측 로그 (FW VBTFW0111, 2026-05-22):
```
TX maa #1 → reb×5 → (raa 큐 밀림) → TX maa #2 → reb×1 + raa → BV_FAIL scan=656
```
### v6 신규 게이트
```kotlin
private fun canSendMaa(caller: String): Boolean {
val now = System.currentTimeMillis()
val collectorBusy = piezoCollector.isMultiChannel && !piezoCollector.isComplete
val sinceLast = now - lastMaaSentMs
if (collectorBusy) {
if (sinceLast < 3000) return false // (A) state 차단
// 3s 넘으면 강제 통과 (FORCE) — deadlock 방지
}
if (sinceLast < 600) return false // (B) time 차단
return true
}
```
| 게이트 | 차단 | 풀림 |
|---|---|---|
| (A) State | `isMultiChannel && !isComplete` | raa 도착 OR 3s FORCE |
| (B) Time | `sinceLast < 600` | 600ms 경과 |
두 게이트 모두 통과해야 maa 송신. State gate가 race 방어, time gate가 burst 방어.
### 효과 (FW VBTFW0116 + MTU 247 + CONN_PRIORITY HIGH 조합)
- 한 사이클 응답: 1.2s → **330ms** (4배)
- 6/6 채널 도착률: 부분응답 잦음 → **100% 도착, 유실 0건**
- BV_FAIL/BV_SKIP 빈도: 자주 → 관찰되지 않음
### Logcat 키워드
| 로그 | 의미 |
|---|---|
| `maa BUSY [...] — prev response in progress (Xms)` | State gate 차단 (정상 방어) |
| `maa FORCE [...] — prev incomplete after Xms` | 3s 넘게 raa 없음 → 포기하고 진행 |
| `maa THROTTLED [...] — Xms since last` | Time gate 차단 (정상 방어) |
| (로그 없음) | 정상 송신 |
| `MTU changed: 247 (status=0)` | MTU 정상 협상 (CCCD write 직전) |
| `CONN_PRIORITY HIGH requested (ok=true)` | priority 요청 큐잉 성공 (수락 여부는 sniffer로만 확인 가능) |