feat: 펌웨어 버전을 모든 로그 파일에 직접 노출

기존: meta.json에만 기록 (파일 단독으로 보면 펌웨어 확인 불가)
변경: adc.csv 컬럼 / placements.jsonl·events.jsonl 필드 / ble.log 헤더 블록 모두 노출

검사자/분석자가 각 파일 단독으로 열어도 어느 펌웨어 데이터인지 즉시 확인 가능.

변경:
- BleManager.current: companion에 instance accessor 추가 (logger 같은 context-free 컴포넌트에서 BLE state 읽기용)
- BleManager rid: 핸들러에서 debugLogger.deviceInfo(fw, hw, sn) 호출 (Headers 블록 기록)
- AdcCsvLogger: CSV 헤더에 firmware_version 컬럼 추가, 모든 행에 값 채움
  scan_id,timestamp,clinical_label,firmware_version,volume_ml,lr_ratio,...
- MeasurementLogService.logMeasurement / logPlacement: JSON에 firmware_version 필드 추가
- BleDebugLogger.deviceInfo(): 새 메서드. rid: 응답 받은 후 ble.log에 다음 블록 기록:
  ─── Device Info ───
  Firmware:  VBTFW0116
  Hardware:  VBTHW0100
  Serial:    VBT26040001
  ───────────────────

BLE 미연결 / mid 응답 안 옴 시엔 필드/값 비어있음 (정상). 응답 받자마자 자동 갱신.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-27 10:19:18 +09:00
parent de3177e5e0
commit 020a45ba92
4 changed files with 30 additions and 6 deletions
@@ -39,6 +39,9 @@ class BleManager private constructor(private val context: Context) {
instance ?: BleManager(context.applicationContext).also { instance = it }
}
/** Logger 같은 context-free 컴포넌트에서 BLE state 읽기용. instance 생성 후에만 non-null. */
val current: BleManager? get() = instance
val SERVICE_UUID: UUID = UUID.fromString("6E400001-B5A3-F393-E0A9-E50E24DCCA9E")
val TX_CHAR_UUID: UUID = UUID.fromString("6E400002-B5A3-F393-E0A9-E50E24DCCA9E")
val RX_CHAR_UUID: UUID = UUID.fromString("6E400003-B5A3-F393-E0A9-E50E24DCCA9E")
@@ -980,12 +983,16 @@ class BleManager private constructor(private val context: Context) {
debugLogger.info("DEVICE_INFO $info")
// 형식: "VBTHW0100 VBT26040001 VBTFW0111" (HW, Serial, FW)
val parts = info.split(Regex("\\s+")).filter { it.isNotBlank() }
val hw = parts.firstOrNull { it.startsWith("VBTHW") } ?: ""
val fw = parts.firstOrNull { it.startsWith("VBTFW") } ?: ""
val sn = parts.firstOrNull { it.startsWith("VBT") && !it.startsWith("VBTHW") && !it.startsWith("VBTFW") } ?: ""
handler.post {
parts.firstOrNull { it.startsWith("VBTHW") }?.let { hardwareVersion.value = it }
parts.firstOrNull { it.startsWith("VBTFW") }?.let { firmwareVersion.value = it }
parts.firstOrNull { it.startsWith("VBT") && !it.startsWith("VBTHW") && !it.startsWith("VBTFW") }
?.let { serialNumber.value = it }
if (hw.isNotEmpty()) hardwareVersion.value = hw
if (fw.isNotEmpty()) firmwareVersion.value = fw
if (sn.isNotEmpty()) serialNumber.value = sn
}
// ble.log에 헤더 블록 형태로 (텍스트 에디터로 열었을 때 즉시 보임)
debugLogger.deviceInfo(fw, hw, sn)
}
"rls:" -> {
val state = if (data.size >= 5) data[4].toInt() and 0xFF else -1