Commit Graph

4 Commits

Author SHA1 Message Date
dw.jang f025bbc0a3 feat(longrun): 장시간 측정 중단 감지 + 설정에 준비 점검 항목
같은 빌드가 태블릿 34시간 / Xiaomi 40분 이었던 문제 대응.
앱 구조(Foreground Service + connectedDevice + WakeLock)는 이미 맞았고
제조사 배터리 관리자가 프로세스를 죽인 것이라, 구조 변경이 아니라
감지와 안내로 접근한다.

- LongRunGuard: 측정 시작/생존/정상종료를 기록해 비정상 종료를 감지.
  다음 실행 때 "언제부터 언제까지 몇 분" 을 알려준다. 제조사 무관하게 동작.
- BLE 로그 헤더에 기기/제한 상태 진단줄 (실패 후 원인 판별용).
- 설정 패널에 "장시간 측정 준비" — 배터리 최적화·미사용앱 제한 상태 확인 및
  해제 진입. 자동시작은 상태를 읽을 수 없어 안내만 제공.

측정 시작을 모달로 막지 않는다. 초안에서는 Auto Scan 에 사전점검을 걸었는데
OEM_AUTOSTART 를 제조사 이름만으로 판단해서(상태 조회 API 가 없음) 설정을
완벽히 해둔 기기에도 영원히 뜨는 문제가 있었다. 고칠 수도 없는 항목으로
측정을 가로막으면 경고가 무시된다. 추측으로 경고하지 않고, 실제로 중단됐을
때만 알린다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-24 11:13:46 +09:00
dw.jang a86fefe321 fix(ble-log): 앱 시작~종료를 한 파일에 통으로 자동 저장
Downloads 에 VesiScan_BLE_*.log 가 여러 개 생기고 그마저 내용이 비던 문제.
원인이 셋이었다.

1. 재연결마다 파일이 갈라짐
   connected() 가 liveLogFile=null 로 핸들을 버려서 BLE 가 끊겼다 붙을 때마다
   새 파일이 생겼다. 앱 시작~첫 연결 구간도 별도 파일로 빠졌다.
   → 프로세스 1회당 파일 1개. 재연결 시에는 구분선만 남긴다.

2. 파일 쓰기에 동기화가 없음
   rx() 는 BLE 콜백 스레드, 나머지는 UI 스레드에서 호출되는데 매번 파일을
   새로 열어 쓰며 잠금이 없었다. 동시 쓰기로 줄이 섞이거나 유실됐다.
   → synchronized + 핸들 유지, 줄마다 flush (강제 종료에도 그 시점까지 보존).

3. 저장 실패가 조용히 묻힘
   Downloads 쓰기가 막히면 예외를 삼켜 아무 데도 안 남았다.
   → 내부 저장소로 폴백하고 실제 경로를 파일 헤더에 기록.

추가로 두 가지:

- Export 버튼이 메모리 링버퍼(2000줄)를 덤프해 "마지막 몇 분"만 나오던 것을
  실시간 세션 파일을 그대로 내보내도록 변경.
- disconnected() 가 비정상 종료 경로에서만 호출돼, 사용자가 직접 끊으면
  아무 기록 없이 로그가 끊겼다. 이유(user/unexpected/gatt_error)를 구분해
  항상 남기도록 수정.

임상 모드 step 별 ble.log 는 부가 사본으로 그대로 유지한다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-24 09:54:38 +09:00
dw.jang 1df1a4e6cd fix(logs): §A+B · scan_id 정합성 · events.jsonl 조인키 (LOG_STORAGE_ANALYSIS Priority 1)
배경 (LOG_STORAGE_ANALYSIS 2026-08-04):
  §A · ble.log 의 scan= 값이 실제 adc.csv scan_id 대비 1씩 밀림 (off-by-one)
       - 원인: measurementResult() 가 AdcCsvLogger.lastScanId 를 읽은 후에
         AdcCsvLogger.log() 가 scanCounter 를 증가시켜 실제 CSV 는 N+1 로 기록.
  §B · events.jsonl 에 scan_id 필드 부재 → 4개 로그 (adc.csv · imu.csv · ble.log ·
       events.jsonl) 간 조인 키 없음. timestamp 밀리초만으로는 autoScanIntervalMs=600ms
       에서 신뢰 불가.
  §F · BV 실패 케이스가 events.jsonl 에 아무 흔적 없음.

수정:
  AdcCsvLogger:
    - nextScanId(): Int 신규 · thread-safe counter 증가 후 id 반환
    - log(...): 새 scanId 파라미터 · 호출자가 미리 발급한 id 우선 사용
    - counterLock 으로 동시성 방어

  MeasurementLogService.logMeasurement(...):
    - scanId: Int? 파라미터 추가 · events.jsonl 에 "scan_id" 필드 기록

  BleDebugLogger.measurementResult(...):
    - scanId: Int? 파라미터 · 호출자가 발급한 id 우선 (미제공 시 legacy fallback)

  ImuCsvLogger.log(...):
    - scanId: Int? 파라미터 · 호출자가 발급한 id 우선

  PiezoMonitoringView (5 sites · onMultiChannelComplete):
    - 사이클 진입 시 val scanId = AdcCsvLogger.nextScanId() 미리 발급
    - useV41Bv · useMethodDBv · effectiveCenterWalls>=4 · totalWallCount>0 ·
      no-valid-channels 5경로 모두 scanId 전달
    - §F: BV_SKIP · BV_FAIL 케이스도 events.jsonl 에 기록 (null volume)

  ClinicalLiveView (1 site):
    - autoCapture 시 val sid = AdcCsvLogger.nextScanId() → AdcCsvLogger + ImuCsvLogger
      에 동일 id 전달

효과:
  ble.log · adc.csv · imu.csv · events.jsonl 이 scan_id 로 정합 조인 가능.
  Guardian 앱이 이벤트 재구성 시 timestamp 대신 scan_id 단일 키 사용.
  BV 실패도 audit trail 에 기록.

검증: BUILD SUCCESSFUL 8s
2026-08-04 15:58:01 +09:00
dw.jang bcbc7b440c refactor: 데모 브랜치 패키지 통일 com.example.medilightv2android → com.medithings.vesiscan
사용자앱 (feature/tab-navigation) 과 패키지 이름 일치. namespace + applicationId
둘 다 com.medithings.vesiscan 로 변경 (기존 데모 앱은 재설치 필요).

## 변경 범위
- Kotlin 148 파일: package + import 문 (714 occurrences)
- 디렉토리 이동: com/example/medilightv2android → com/medithings/vesiscan
  (main, test, androidTest 각각)
- app/build.gradle.kts: namespace, applicationId
- docs/FLAVOR_DEMO_STABLE.md: 참조 갱신
- V41DetectorCH4Test: BvDispatchResult.methodChosen → method (dto field name fix)

## 주의
- applicationId 가 바뀌므로 기존 데모 앱 (com.example.medilightv2android.demo) 은
  Android 관점에서 다른 앱으로 취급 — 재설치 시 PIN/설정 초기화됨.
- Fresh install 권장. 기존 앱 (com.example...) 은 별도로 uninstall 필요.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-02 14:30:43 +09:00