1. ADC 로그: 측정 완료 시 MeasurementLogService.logMeasurement() 호출
→ 6채널 raw ADC + 채널별 ant/post/score 저장 (JSONL)
2. 기기 정보: 연결 직후 mid? 전송 → rid: 응답 파싱 → 로그 기록
(HW Version, Serial Number, FW Version 일괄 조회)
3. LED 모드: Placement Guide 연동
- 스캔 시작 → mls?(5) ALIGN_SEARCHING
- PASS → mls?(6) ALIGN_COMPLETE
- 스캔 종료 → mls?(0) OFF
4. Reconnect: 3/5/10초 5회 → 3초 간격 무한 재시도
(연결됐다가 끊어진 경우, 사용자가 Home 돌아갈 때까지)
5. BLE 로그: mid/mls TX 파싱, rid:/rls: RX 파싱 추가
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
TX: "maa 6ch measure", "msn battery query", "mpa piezo power ON" 등
RX: "rsn battery=3850mV (100%)", "reb 100samples", "raa all-ch complete",
"rpa piezo ack", "rag gain calibration (24 values)" 등
펌웨어팀에 보낼 때 raw hex 없이도 통신 흐름을 이해할 수 있음
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
WATCHDOG_STARTED/TIMEOUT/GATT_ERROR/RECONNECT 등 이벤트 로그는 유지.
5초마다 찍히던 WATCHDOG_CHECK/THREAD 상태 로그 제거.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
근본 원인: Android BLE가 disconnect 시 STATUS_DISCONNECTED가 아닌
GATT 에러(status≠0)로 콜백을 보냄. 기존 에러 경로에서는
reconnectAttempt>0일 때만 재연결 → 첫 끊김 시 재연결 안 됨.
수정:
- wasConnected 체크: 이전에 연결됨 + 사용자 disconnect 아님 → 자동 reconnect
- GATT_ERROR 로그 + DISCONNECTED(gatt_error) 로그 기록
- stopBatteryPolling/stopWatchdog 호출 추가
- watchdog: connected=false 감지 시 무한 루프 대신 break
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
watchdog이 실제로 돌고 있는지, 어디서 멈추는지 진단용.
매 5초: WATCHDOG_CHECK silence=Xms connected=true/false
interrupt 시: WATCHDOG_THREAD interrupted
flag 종료 시: WATCHDOG_THREAD stopped
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
기존: handler.post 안에서 로그+disconnect → handler 블로킹 시 둘 다 안 됨
변경:
- debugLogger.error() → watchdog Thread에서 직접 호출 (CopyOnWriteArrayList 스레드 안전)
- gatt.disconnect()/close() → watchdog Thread에서 직접 호출 (GATT는 any thread OK)
- UI 업데이트 + reconnect만 handler.post로 전달
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- CCCD 없는 경로(no CCCD, no RX)에서도 startWatchdog() + startBatteryPolling() 호출
- watchdog 시작 시 WATCHDOG_STARTED 로그 기록 (실제 동작 확인용)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
기존: handler.postDelayed로 watchdog 실행 → BLE 스택이 handler를
블로킹하면 watchdog도 멈춤 (좀비 상태 감지 불가)
변경: 별도 daemon Thread에서 5초마다 lastRxTimestamp 체크
→ BLE handler가 블로킹되어도 독립적으로 15초 타임아웃 감지
→ 감지 시 handler.post로 메인 스레드에서 forceDisconnectAndReconnect 실행
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
기존: connectGatt(autoConnect=true) — Android에서 매우 불안정, 수분 걸림
변경: BLE 스캔으로 기기를 다시 찾은 후 connectGatt(autoConnect=false)로 빠르게 연결
재연결 흐름:
1. watchdog 15초 타임아웃 → forceDisconnectAndReconnect()
2. scheduleAutoReconnect() → 3s/5s/10s 백오프
3. attemptAutoReconnect():
- BLE 스캔 시작 (기기 이름 or MAC 주소 매칭)
- 발견 시 즉시 connectGatt(autoConnect=false) → 빠른 연결
- 8초 스캔 타임아웃 → 다음 attempt
- 최대 5회 시도 후 실패 처리
4. 모든 단계 BleDebugLogger에 기록
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Android BLE가 disconnect 콜백을 안 보내는 경우(좀비 연결) 대응:
- 마지막 RX로부터 15초간 응답 없으면 강제 disconnect → auto reconnect
- processReceivedData()에서 lastRxTimestamp 갱신
- 5초마다 watchdog 체크
- WATCHDOG_TIMEOUT 이벤트 BleDebugLogger에 기록
- 수동 disconnect 시 watchdog 해제
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- BleManager: 배터리 폴링 30초→5초 (펌웨어 15초 타임아웃 방지, iOS 동일)
- BleManager: 자동 reconnect with 백오프 (3s→5s→10s, 최대 5회)
- scheduleAutoReconnect() + attemptAutoReconnect()
- GATT 에러 시에도 백오프 재시도
- 수동 disconnect 시 자동 reconnect 취소
- PiezoMonitoringView: 끊김 시 즉시 파란 배너(RECONNECTING)
- 성공 시 배너 자동 숨김 + 배터리 폴링 재시작
- 5회 실패 시 빨간 배너 + 수동 Reconnect 버튼
- 측정 중 끊김 → isMeasuring 리셋 + 자동측정 중지
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
CRITICAL: In multi-channel mode, "ree:" packets between channels
were silently dropped instead of saving the current channel data.
This caused channel data loss when channels are separated by "ree:".
Fixed: Added missing isMultiChannel + ree: branch that calls
saveCurrentChannel() — matching Swift behavior exactly.
Found via line-by-line Swift vs Kotlin verification.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
A. Reminder: ReminderService (AlarmManager chain), ReminderSettingsView,
bell icon in Piezo top bar, reschedule on catheterization
B. Consent: ConsentView (3 mandatory items), onboarding→consent→registration flow,
persistent consent storage, sex field in User + Registration Step 2
C. Diary: 24hUV, NUV, NPI, max capacity, day/night frequency metrics card
D. Design: DesignTokens.kt, 48dp touch targets, DonutChart semantics, pressScale modifier
E. Quality: BuildConfig.DEBUG log wrapping, DateFormatter caching, background I/O for diary store
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Clear mcj callback immediately on stop to prevent stale responses from
triggering new polling chains. Delay battery polling resume by 500ms to
avoid command collision with in-flight mcj response. Add sendNirsPowerOff
for future use.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix BLE API deprecation warnings with API 33+ version checks
- Move isServiceReady to onDescriptorWrite for reliable CCCD setup
- Fix battery polling: immediate query on connect, pause during NIRS streaming
- Add mcj retry mechanism for NIRS streaming reliability
- Add debug logging to BLE, NIRS parsing, and processing pipeline
- Add catheter count feature to Piezo monitoring (persistent count, add dialog, auto-decrement on catheterize)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Port of MedilightV2 iOS app to Android with Kotlin + Jetpack Compose.
Includes BLE connectivity, NIRS/Piezo sensor modes, Rive animations,
interactive measurement history charts, and foldable device support.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>