bcbc7b440c
사용자앱 (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>
95 lines
3.3 KiB
Kotlin
95 lines
3.3 KiB
Kotlin
/*
|
|
* RawBleLogger — 모든 BLE notification 의 raw bytes 를 시간순으로 파일로 dump.
|
|
*
|
|
* 용도: IMU FSR / packet 구조 / loss 진단. JSON 가공 거치기 전 원본 그대로 저장.
|
|
*
|
|
* 파일: Downloads/VesiScan_RawBLE/yyyy-MM-dd_HHmmss_raw.log
|
|
* 포맷 (한 줄당 한 notification):
|
|
* HH:mm:ss.SSS dir=RX prefix=rim len=188 hex=72 69 6D 3A 00 0F ...
|
|
*
|
|
* 사용: startCapture() / stopCapture() 토글. 활성화 시 BleManager.processReceivedData
|
|
* 가 매 notification 마다 write() 호출.
|
|
*/
|
|
package com.medithings.vesiscan.services
|
|
|
|
import android.os.Environment
|
|
import java.io.File
|
|
import java.io.FileWriter
|
|
import java.text.SimpleDateFormat
|
|
import java.util.Date
|
|
import java.util.Locale
|
|
import java.util.concurrent.atomic.AtomicBoolean
|
|
|
|
object RawBleLogger {
|
|
|
|
private val sessionFmt = SimpleDateFormat("yyyy-MM-dd_HHmmss", Locale.US)
|
|
private val timeFmt = SimpleDateFormat("HH:mm:ss.SSS", Locale.US)
|
|
private val capturing = AtomicBoolean(false)
|
|
@Volatile private var sessionFile: File? = null
|
|
@Volatile private var packetCount: Int = 0
|
|
|
|
val isCapturing: Boolean get() = capturing.get()
|
|
val currentFile: File? get() = sessionFile
|
|
val count: Int get() = packetCount
|
|
|
|
private fun getDir(): File {
|
|
val dir = File(
|
|
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
|
|
"VesiScan_RawBLE"
|
|
)
|
|
if (!dir.exists()) dir.mkdirs()
|
|
return dir
|
|
}
|
|
|
|
/** 새 파일 만들고 capture 시작. 이미 capturing 중이면 stop 후 새로 시작. */
|
|
fun startCapture(): File {
|
|
if (capturing.get()) stopCapture()
|
|
val f = File(getDir(), "${sessionFmt.format(Date())}_raw.log")
|
|
try {
|
|
FileWriter(f, false).buffered().use { w ->
|
|
w.write("# RawBleLogger session — started ${timeFmt.format(Date())}")
|
|
w.newLine()
|
|
w.write("# Format: HH:mm:ss.SSS dir=RX prefix=XXX len=N hex=AA BB ...")
|
|
w.newLine()
|
|
}
|
|
} catch (_: Exception) {}
|
|
sessionFile = f
|
|
packetCount = 0
|
|
capturing.set(true)
|
|
return f
|
|
}
|
|
|
|
fun stopCapture(): File? {
|
|
if (!capturing.get()) return sessionFile
|
|
val f = sessionFile
|
|
try {
|
|
if (f != null) {
|
|
FileWriter(f, true).buffered().use { w ->
|
|
w.write("# stopped ${timeFmt.format(Date())} — $packetCount packets")
|
|
w.newLine()
|
|
}
|
|
}
|
|
} catch (_: Exception) {}
|
|
capturing.set(false)
|
|
return f
|
|
}
|
|
|
|
/** BleManager 가 매 notification 받을 때마다 호출. capturing 아니면 즉시 return. */
|
|
fun write(data: ByteArray) {
|
|
if (!capturing.get()) return
|
|
val f = sessionFile ?: return
|
|
try {
|
|
val ts = timeFmt.format(Date())
|
|
val prefix = if (data.size >= 4)
|
|
String(data, 0, 4, Charsets.US_ASCII).replace(Regex("[^\\x20-\\x7E]"), "?")
|
|
else "?"
|
|
val hex = data.joinToString(" ") { "%02X".format(it) }
|
|
FileWriter(f, true).buffered().use { w ->
|
|
w.write("$ts dir=RX prefix=$prefix len=${data.size} hex=$hex")
|
|
w.newLine()
|
|
}
|
|
packetCount++
|
|
} catch (_: Exception) {}
|
|
}
|
|
}
|