Commit Graph

115 Commits

Author SHA1 Message Date
dw.jang e6e9c296f2 fix: mls LED 명령 ASCII 포맷으로 변경 (buildCommand→buildCommandASCII)
기존: mls? + [0x05, 0x00] (2바이트 LE 파라미터) → LED 안 바뀜
변경: mls?5 (ASCII 숫자) → exe 프로그램과 동일 포맷

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-24 16:04:44 +09:00
dw.jang 73ceb40ed4 fix: lr_ratio 하한 1.0 제한 (500ml 팬텀에서 100ml로 과소평가 수정)
원인: CH4/CH5 lateral이 center 대비 짧아서 lr_ratio=0.32 계산
→ S = π/4 × D² × 0.32 → 용적 68% 과소평가

수정: computeLrRatio() 반환값에 .coerceAtLeast(1.0) 추가
원형(1.0)보다 좁은 방광 단면은 물리적으로 불가능하므로 하한 제한

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-24 15:53:16 +09:00
dw.jang c334b5f018 fix: CV threshold 단계적 완화 (5회 단위, 최대 0.30)
기존: cvThr = 0.15 + scanCount × 0.02 (무한 증가)
변경: 5회 단위 단계적 완화, 상한 0.30
  1~5회:  0.15 (원래 기준)
  6~10회: 0.20
  11~15회: 0.25
  16회+:  0.30 (최대)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-24 15:35:29 +09:00
dw.jang 1beb0737c6 feat: Placement 판정 결과 BLE 디버그 로거에 기록 + README 대폭 업데이트
BLE 로그 추가:
- DETACHED mean=12.3 std=8.7
- PLACEMENT_SEARCHING cv=0.234 dir=MOVE UP moderate score=35
- PLACEMENT_PASS cv=0.112 lr_dev=0.089 score=78

README 추가 섹션:
- 17. 미부착 감지 알고리즘 상세 (DetachmentDetection)
  - 원리, 상수, 실측 안전 마진 설명
- 18. Placement 전체 파이프라인 흐름도
  - Detachment → Echo → CV → LR → LED 판정
  - BLE 로그 출력 예시
- 향후 과제에 미부착 감지 완료 항목 추가

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-24 15:27:39 +09:00
dw.jang ea19b74c00 feat: DetachmentDetection 포팅 + Placement LED 4/5/6 동적 제어
DetachmentDetection (detachment_detection.py 1:1 포팅):
- ADC [20:80] 구간에서 baseline([80:100] median) 차감
- mean(|y|) < 100 AND std(y) < 100 → 미부착(detached)
- center 4채널(CH0~CH3) 기준

PlacementGuide LED 제어:
- 미부착 → mls?(4) DETACH_WARNING + "Sensor detached" 메시지
- 탐색 중 (CV > threshold) → mls?(5) ALIGN_SEARCHING
- 최적 위치 (PASS) → mls?(6) ALIGN_COMPLETE
- 스캔 종료 → mls?(0) OFF

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-24 15:21:23 +09:00
dw.jang 994d5e0c46 fix: adaptive threshold 비활성화 (기본 false, 고정 1150 복원)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-24 15:06:13 +09:00
dw.jang 6889136783 feat: adaptive threshold 구현 (percentile + 고정값 blended)
detectLowEcho: 고정 1150 → adaptive threshold (기본 활성화)
  1. ringSkip(3) 이후 신호에서 q25/q50/q75 계산
  2. percentile 기반: q25 + iqr*0.3 ~ q50 - iqr*0.3
  3. 고정값(1150) 범위 제한: ×0.7 ~ ×1.5 (805~1725)
  4. 가중 평균: 고정 40% + adaptive 60%
  → 신호 레벨에 자동 적응하되 급격한 변동 방지

WaveformChart: threshold 점선도 adaptive 값으로 표시
useAdaptiveThreshold 플래그로 on/off 전환 가능

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-24 14:58:28 +09:00
dw.jang a02562eb31 docs: BLE 명령어 포맷, 자동측정 루프, LED 모드, 향후 과제 업데이트
- BLE 명령어 포맷: 공백 필요 패턴 (buildCommandASCII) 문서화
- 자동측정: IMU 1초 × 9 + 6ch 측정 10초 루프 설명
- LED 모드: state 코드 + Placement 연동 흐름
- 기기 정보: mid? → rid: 자동 조회 설명
- 향후 과제: 17개 완료 항목 + 5개 예정 항목

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-24 13:55:38 +09:00
dw.jang 76ec271352 fix: msp/mbb 명령어 뒤에 공백 추가 (mid?와 동일 포맷)
기기가 파라미터 없는 명령에도 공백을 요구함 (펌웨어 파서 특성)
- sendImuQuery: buildCommand("msp") → buildCommandASCII("msp", " ")
- sendFullMeasurement: buildCommand("mbb") → buildCommandASCII("mbb", " ")
- IMU 1초 쿼리 재활성화

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-24 13:49:30 +09:00
dw.jang a3c80bd074 fix: IMU(msp) 쿼리 비활성화 — 현재 기기(VBTFW0111) 미지원
msp? → rxs: cmd_not_supported 응답 확인
매 1초 불필요한 msp 전송 제거, 10초 간격 maa 측정만 유지
IMU 지원 기기 확인 후 재활성화 예정

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-24 13:48:28 +09:00
dw.jang be0264d24c fix: Spot 측정 maa 복원 (mbb는 rbb 파싱 검증 후 전환)
mbb 응답에서 rbb: 패킷 구조가 불명확하여 collector 동작 불안정.
Spot/자동측정 모두 maa(sendChannelsOnly)로 안정화.
mbb는 로그로 rbb: 바이트 구조 확인 후 전환 예정.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-24 12:30:17 +09:00
dw.jang 9842644e23 fix: mbb 측정 복원 — PiezoPacketCollector가 rbb: 헤더를 skip하도록 수정
근본 원인: mbb? 응답에서 rbb: 헤더가 먼저 오는데 collector가 모르고 무시
→ onMultiChannelComplete 콜백 안 불림 → isMeasuring 영구 true → 버튼 비활성화

수정:
- PiezoPacketCollector.addPacket(): rbb: prefix 인식 → skip + 로그
- BleManager: rbb: 수신 시 piezoCollector.addPacket()에도 전달
- PiezoMonitoringView: sendChannelsOnly→sendFullMeasurement(mbb) 복원

흐름: mbb? → rbb:(skip) → reb:×6(수집) → raa:(완료) → 콜백 정상

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-24 12:14:27 +09:00
dw.jang bf2f16b207 fix: Spot 측정 mbb→maa 복원 (rbb 헤더가 collector 혼동 유발)
mbb 응답(rbb:→reb:×6→raa:)에서 rbb: 헤더가 piezoCollector를
혼동시켜 그래프가 안 뜨는 문제 발생.

- Spot 단일 측정: sendChannelsOnly(maa) 사용
- 자동 측정 10초째: measure()→maa 사용 (mbb는 파싱 검증 후 전환)
- IMU 전송 시 isMeasuring 체크 추가 (측정 중 충돌 방지)
- sendChannelsOnly() 함수 추가 (기존 sendAllChannels와 동일)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-24 12:09:02 +09:00
dw.jang fb9b950a1c feat: Piezo 상단바에 Placement Guide 복귀 버튼 추가
MyLocation 아이콘으로 Placement Guide로 돌아갈 수 있는 버튼 추가
(Home 버튼 옆, 센서 재배치가 필요할 때 사용)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-24 11:49:45 +09:00
dw.jang af6071e18b fix: mid? 명령 포맷 변경 — buildCommandASCII("mid", " ") 공백 포함
기기에서 rxs:mid? (unknown command) 응답 → 포맷 문제 가능성
buildCommand("mid") → buildCommandASCII("mid", " ") 로 변경하여 테스트

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-24 11:45:47 +09:00
dw.jang eb5affc6b8 feat: 자동측정 IMU 1초 + 전체측정(mbb) 10초 루프
자동측정 변경 (기존: 30초 maa → 신규: 1초 msp + 10초 mbb):
- 1~9초: msp(IMU query) → rsp(accel+gyro) 1초 간격
- 10초째: mbb(전체측정) → rbb(헤더) + reb×6 + raa
- 기존 maa → mbb(sendFullMeasurement)로 전환
- mbb 응답은 rbb: 헤더 후 reb:/raa: 동일 파이프라인

BLE 명령어 추가:
- sendImuQuery(): msp 전송
- sendFullMeasurement(): mbb 전송 (piezoCollector 연동)
- sendLedMode(state): mls 전송

응답 파싱 추가:
- rxs: → "cmd_not_supported" (mid? 미지원 기기 대응)
- rbb: → full measurement header
- rsp: → IMU data

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-24 11:31:03 +09:00
dw.jang e6e339379b feat: ADC 로그 저장 + 기기정보 mid? + LED 모드 + 무한 3초 reconnect
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>
2026-04-24 10:55:29 +09:00
dw.jang fde4d0ad05 docs: low echo detection + Placement CV threshold 문서 업데이트
- Low echo: VALLEY_STOP_RISE=50, EDGE_DIST_DECAY=0.12, edge boundary, score 공식
- Placement: CV threshold 방식 전체 설명 (CV 계산, SI/LR 판정, severity, relaxation)
- 기존 urineLen score 방식 → CV threshold 방식으로 전면 교체

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-24 10:30:41 +09:00
dw.jang 4cdd69ef3d feat: low echo detection + Placement 알고리즘 업데이트 (원은지님 공유)
Low Echo Detection 업데이트:
- VALLEY_STOP_RISE: 10→50 (valley 스캔 early stop 임계)
- EDGE_DIST_DECAY: 0.12 (신규, edge 거리 penalty)
- Edge boundary 확장: left [leftLo:edge+1], right [edge-1:rightHi+1]
- Peak scoring: prominence → prominence / (1 + 0.12 × dist)
  (low echo에 가까운 peak이 더 높은 점수)

Placement 알고리즘 전면 교체 (CV threshold 방식):
- 기존 urineLen score → cos-corrected depth의 CV(변동계수)
- CV ≤ 0.15 → PASS (Best Placement)
- CV > 0.15 → FAIL → weakest channel 기반 방향 안내
  - CH0/CH1(top) weakest → MOVE DOWN
  - CH2/CH3(bottom) weakest → MOVE UP
  - severity: slight(<10%) / moderate(10~25%) / severe(≥25%)
- LR deviation: CH4/CH5 cos-corrected depth 비교
  - |lr_dev| ≤ 0.15 → PASS
  - lr_dev > 0 → MOVE RIGHT, < 0 → MOVE LEFT
- 반복 시 CV threshold 완화 (+0.02/회)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-24 10:22:05 +09:00
dw.jang 98d3b11a46 docs: Python↔Android 1:1 검증 결과 + BLE 재연결 시스템 상세 문서화
- 전수 상수 비교 테이블 (V0/V1/V2 좌표, 각도, 음향 상수, lr_ratio)
- 알고리즘 수준 비교 (전처리, low-echo, lr_ratio, BV 추정)
- 결론: 모든 항목 완벽 일치 (Adaptive TGC는 Python에도 미포함)
- BLE 재연결 시스템 흐름도 + Watchdog + GATT 에러 경로 설명
- BLE 디버그 로거 사용법
- GreenZoneConstants.kt 주석 오류 수정 (1600→1150)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-23 16:18:49 +09:00
dw.jang df42a47d7d feat: BLE 로그에 파싱된 값 추가 (TX 명령어 + RX 응답 의미)
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>
2026-04-23 15:40:23 +09:00
dw.jang 796bce19a2 cleanup: WATCHDOG_CHECK 디버그 로그 제거 (이벤트성 로그만 유지)
WATCHDOG_STARTED/TIMEOUT/GATT_ERROR/RECONNECT 등 이벤트 로그는 유지.
5초마다 찍히던 WATCHDOG_CHECK/THREAD 상태 로그 제거.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-23 15:35:19 +09:00
dw.jang a474935e3c fix: GATT 에러로 끊길 때도 자동 reconnect 시작 (핵심 버그 수정)
근본 원인: 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>
2026-04-23 15:13:11 +09:00
dw.jang d3006d91dc debug: watchdog Thread 매 체크마다 로그 기록 (WATCHDOG_CHECK)
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>
2026-04-23 14:59:07 +09:00
dw.jang c99eb068a5 fix: watchdog GATT close + 로그를 watchdog Thread에서 직접 실행
기존: 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>
2026-04-23 14:39:54 +09:00
dw.jang 7ab3d878e7 fix: watchdog 누락 경로 수정 + 시작 로그 추가
- CCCD 없는 경로(no CCCD, no RX)에서도 startWatchdog() + startBatteryPolling() 호출
- watchdog 시작 시 WATCHDOG_STARTED 로그 기록 (실제 동작 확인용)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-23 14:22:40 +09:00
dw.jang 988fbd9dbd fix: watchdog을 별도 Thread로 분리 (handler 블로킹 방지)
기존: 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>
2026-04-23 14:09:16 +09:00
dw.jang 9d32d13452 fix: BLE reconnect를 fresh scan→connect 방식으로 변경
기존: 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>
2026-04-23 14:02:08 +09:00
dw.jang d4e2627efe fix: BLE watchdog — 좀비 연결 감지 + 강제 reconnect
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>
2026-04-23 12:27:13 +09:00
dw.jang 506248655d fix: BLE 로그 Downloads 폴더에 저장 (파일 탐색기 접근 가능)
- exportToDownloads(): Downloads/VesiScan_BLE_날짜.log 로 저장
- 실패 시 fallback으로 내부 저장소에 저장
- Toast로 저장 경로 안내

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-23 12:22:07 +09:00
dw.jang 6f4488f1ae fix: BV 측정 최소 center 3채널 이상 요구 + 실패 시 사용자 안내
- center 채널 3개 미만이면 BV 계산 스킵 (신뢰도 부족 방지)
- 1~2채널: "측정 부족 (N/4채널) — 센서 위치를 조절해주세요"
- 0채널: "방광이 감지되지 않았습니다. 센서 접촉을 확인해주세요."
- BleDebugLogger에 BV_SKIP/BV_FAIL 기록

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-23 12:08:52 +09:00
dw.jang f220cca187 feat: BLE 디버그 로거 — 펌웨어 디버깅용 상세 통신 로그
BleDebugLogger 신규:
- TX/RX 패킷 기록 (타임스탬프 ms, 데이터 크기)
- RSSI 실시간 추적 (5초마다 readRemoteRssi)
- 연결/끊김/재연결 이벤트 + GATT status code
- 패킷 타임아웃, 채널 누락, Endian 감지 로그
- 측정 결과 (volumeMl, lrRatio, validChannels)
- 파일 내보내기 (.log / .jsonl) + 클립보드 복사
- 세션 통계 (TX/RX/ERR/RSSI avg/min/max)

BleManager 연동:
- sendRaw() → TX 로그
- processReceivedData() → RX 로그
- connected/disconnected/reconnecting/reconnectFailed 이벤트
- onReadRemoteRssi 콜백 → RSSI 기록

PiezoMonitoringView:
- Developer Tools 하단에 BLE Debug Panel 추가
- 2초 자동 갱신, 색상 코딩 (TX=파랑, RX=초록, ERR=빨강, RSSI=노랑, CONN=보라)
- 클립보드 복사 / 파일 저장 / 클리어 버튼

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-23 11:47:36 +09:00
dw.jang 079774c869 feat: Placement Guide 실시간 연속 스캔 (3초 간격)
- 수동 1회 → 자동 반복 스캔 (Start/Stop 토글)
- 3초마다 maa 전송 → Score 실시간 갱신
- 사용자가 센서 움직이면서 점수 변화를 즉시 확인 가능
- "Scanning every 3s — move sensor and watch the score" 안내 문구

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-23 11:29:02 +09:00
dw.jang c114592ab1 feat: 6ch 알고리즘 포팅 + urineLen 기반 정밀 Placement Guide
6ch 알고리즘 (config_6ch.py / bv_estimation.py 포팅):
- PiezoHW: V0/V1/V2 프리셋 (Snell's law 굴절 각도)
- computeLrRatio(): CH4/CH5 lateral에서 타원 단면 비율 동적 계산
- estimateBladderVolume6ch(): center 4ch + lateral lr_ratio
- denoise(): TVD 제거, SG 필터만 사용
- LOW_ECHO_AMP: 1600→1150, distancePerSample: 1.771

Placement Guide 2단계:
- 1단계: 이진 판정 (잡힘/안잡힘) → 기본 방향
- 2단계: urineLen 기반 정밀 가이드 (대칭+균형+크기)
  - 세로: CH0/CH3 비율 1.5배 이상이면 방향 제시
  - 가로: CH4/CH5 차이 5칸 이상이면 방향 제시
- Placement Score = 세로대칭(30%) + 가로균형(30%) + 중앙크기(40%)
- 각 채널에 urineLen 숫자 표시

VesiScan_Android_Pipeline_Summary.md 문서 작성

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-23 10:22:57 +09:00
dw.jang a95815c42d fix: Piezo 진입 시 bladderLevel 0으로 초기화 (이전 세션 값 잔류 방지)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-22 17:46:16 +09:00
dw.jang 6f5801b4b6 feat: BLE 자동 reconnect + 배터리 폴링 5초 (keep-alive)
- 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>
2026-04-22 17:40:00 +09:00
dw.jang d8a725b21b fix: 도넛차트 recomposition 버그 + Spot 롱프레스 자동측정 + BV 4채널(CH0~CH3)
- bladderLevel.copy() 할당으로 Compose recomposition 트리거 (도넛차트 실시간 갱신)
- Spot 버튼: Button→Box+detectTapGestures (탭=단일, 롱프레스=30초 자동측정)
- startAutoMeasure() + LaunchedEffect 30초 반복 루프
- BV 추정 CH0~CH4(5ch)→CH0~CH3(4ch) 세로 채널만 사용

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-22 17:23:46 +09:00
dw.jang 5cc2321ff4 fix: placement direction guide 수정 + sensor layout 확대 + BLE prefix 필터(2025/VBT)
- PlacementGuideView: 방향 가이드 로직 수정 (CH0=배꼽, CH3=치골 기준)
  CH0✅CH3❌→UP, CH3✅CH0❌→DOWN, 좌우도 동일하게 보정
- SensorLayoutCanvas: 스케일 16px/mm, 방광 280×220, body 400×400
- DeviceScanView: BLE prefix 필터 "2025" | "VBT"

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-22 16:19:53 +09:00
dw.jang d8db7671ac feat: iOS 동기화 — 알림설정, Quick Save, 일지 요약바, 디자인토큰, BLE필터 제거, 그래프 축·클립·Placement 확대
- ReminderSettingsView: 간격 리스트+체크, 유동 토글, 팝업 알림, 요약, 권한 배너 (iOS ReminderView 동일)
- ReminderService: 기본값 iOS 동기화(120분, 8시), 5종 랜덤 메시지, usePopup/isFlexible/permissionGranted
- PiezoMonitoringView: 배뇨기록 다이얼로그 iOS DiaryRecordSheet 스타일 + Quick Save
- VoidingDiaryView: 요약 바(건수+총량+평균), 의료지표 4+3 배열, 총 횟수 추가
- DesignTokens: iOS DS enum과 동일 값 (44dp touch, 12dp medium radius, spacing md=16/lg=24/xl=32)
- DeviceScanView: BLE prefix 필터 제거 (VBT 등 신규 기기 지원)
- WaveformChart: Y축(amplitude)/X축(depth mm) 라벨, clip으로 셀 오버플로 방지
- PlacementGuideView: 센서 레이아웃 확대(300→400dp), 스캔 후 채널별 에코 그래프 표시

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-22 14:03:02 +09:00
dwjang 5a084ac5a9 feat: auto-detect device preset from BLE name
VBT260400xy → FLAT, VBT260402xy → NEW_CASE2, VBT260403xy → NEW_CASE1
2025MEDIP → LEGACY_5CH

Auto-called on BLE connect. Logged to debug.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-21 17:29:38 +09:00
dwjang 549a2c722e feat: PlacementGuideView + MeasurementLogService + navigation flow
PlacementGuideView.kt:
- 6-sensor Canvas layout (CH0-CH3 vertical + CH4/CH5 lateral wings)
- Per-channel UrinAI detection (green/red color coding)
- Direction guidance (up/down/left/right)
- Check Position → maa → detect → display
- Start Measurement when 4+ channels detected

MeasurementLogService.kt:
- JSON Lines format, daily rotation
- Events: measurement, placement, ble_connected/disconnected, error
- 90-day auto-purge
- App internal storage: vesiscan_logs/YYYY-MM-DD.jsonl

AppState.kt + MainActivity.kt:
- PLACEMENT_GUIDE screen added to navigation
- Flow: personalization → placementGuide → piezoMonitoring

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-21 16:43:02 +09:00
dwjang c136d64665 feat: full Piezo measurement pipeline + waveform charts in PiezoMonitoringView
Major update matching iOS PiezoMonitoringView:

measure() — real BLE measurement via maa:
- sendAllChannels → piezoCollector → analyzeMultiChannel
- Build walls → estimateBladderVolume (Frustum)
- Auto-retry on timeout (max 2, 15s each)
- Volume-based bladder level update

UI additions:
- Max Volume info card (orange)
- Volume card shows measured value
- Developer Tools (collapsible):
  - 6-Channel Analysis with Measure button
  - Zone indicator (GOOD/PARTIAL/ADJUST)
  - Channel status bar (green/red, urine length)
  - Per-channel waveform charts (Canvas):
    - Raw (light blue) + Denoised (blue) overlay
    - Threshold line (1600, orange dashed)
    - Low-echo span (yellow)
    - Urine region (cyan) with ant(green)/post(red) markers
    - Y-axis 0-2500 fixed, X-axis depth in mm

resetMeasurement() on catheterize

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-21 16:38:33 +09:00
dwjang 444aa6280f fix: critical bug in PiezoPacketCollector processEndPacket
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>
2026-04-21 16:21:43 +09:00
dwjang c1c6dfc16a feat: port algorithm core from iOS (4 files)
GreenZoneConstants.kt — all 16 constants (thresholds, physical)
UrinAI.kt — urine gatekeeper (binary threshold detection)
PiezoEchoAnalyzer.kt — low-echo detection with prominence-based wall selection
PiezoBVEstimator.kt — Frustum BV estimation with device presets

1:1 port from Swift, same logic, same constants.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-21 16:14:07 +09:00
dwjang b83cb16f35 feat: add Piezo BLE data pipeline (1:1 port from iOS)
PiezoPacketCollector.kt:
- Multi-packet reb:/red:/raa: assembly
- Auto-detect Big/Little Endian
- First channel locks endianness for all channels
- 6-channel support (maa command)

BleManager.kt:
- sendAllChannels(mode) → maa command
- reb:/rer:/raa: response routing to piezoCollector
- piezoCollector instance added

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-21 16:06:42 +09:00
dwjang dc61e1d52e i18n: add Korean/English localization via strings.xml
Replace hardcoded Korean UI strings in Piezo, CatheterizeSheet,
VoidingDiary, and UrineCameraScreen with stringResource() calls.
Add values/strings.xml (English) and values-ko/strings.xml (Korean).
System language setting now controls app language.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 11:27:32 +09:00
dw.jang 0e186234d2 UX: 수기 입력 기본값을 현재 추정 용량(estimatedVolume)으로 설정
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-08 09:34:02 +09:00
dw.jang 0e13f2bbb6 feat: consent screen, reminder system, medical metrics, sex field, design tokens, code quality
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>
2026-04-07 14:26:02 +09:00
dw.jang 1d5c6f15f8 UX: Piezo compact icon buttons 36dp → 44dp (minimum touch target)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 15:00:46 +09:00
dw.jang 65d5d81e9c UX fix: delete button touch target 24dp → 48dp (default IconButton)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 14:52:24 +09:00