ble: rid: 파서 fixed-width 12B 필드로 + mfv? fallback
명세서 (BLE Command Table) 재확인: rid: = [tag 4B] [HW 12B] [Serial 12B] [FW 12B] [crc 2B] = 42B 각 12B 필드는 ASCII 가변 + NULL/공백/제어문자 padding 기존 파서는 whitespace split 후 prefix 매칭. padding 이 NULL 이면 동작하지만 다른 바이트(예: 0xFF, 0x20 외 임의값)면 전체가 한 토큰으로 합쳐져 fw 추출 실패. 새 펌웨어에서 firmware 안 뜨던 증상의 원인. 수정: - field(offset) 헬퍼로 정확히 12B 씩 슬라이스 후 NULL/제어 제거 - 명세대로 4 / 16 / 28 offset 에서 HW / SN / FW 분리 추가 fallback: - sendFirmwareVersionQuery() 신규 — mfv? 단독 쿼리 - rfv: 응답 핸들러 추가 - service ready 4초 후 firmwareVersion 여전히 비어있으면 mfv? 자동 송신 (mid? 미지원 펌웨어 대응)
This commit is contained in:
@@ -536,6 +536,11 @@ class BleManager private constructor(private val context: Context) {
|
||||
sendRaw(CRC16.buildCommandASCII("mid", " "))
|
||||
}
|
||||
|
||||
/** mfv? — FW Version only. mid? 응답 안 오는 펌웨어용 fallback. */
|
||||
fun sendFirmwareVersionQuery() {
|
||||
sendRaw(CRC16.buildCommandASCII("mfv", " "))
|
||||
}
|
||||
|
||||
fun sendLedMode(state: Int) {
|
||||
sendRaw(CRC16.buildCommandBE("mls", intArrayOf(state)))
|
||||
}
|
||||
@@ -995,6 +1000,13 @@ class BleManager private constructor(private val context: Context) {
|
||||
startBatteryPolling()
|
||||
startWatchdog()
|
||||
sendDeviceInfoQuery()
|
||||
// 4초 후에도 펌웨어 미수신이면 mfv? fallback (구 펌웨어는 mid? 미지원 가능성)
|
||||
handler.postDelayed({
|
||||
if (firmwareVersion.value.isEmpty() && isConnected.value) {
|
||||
debugLogger.info("FW fallback: sending mfv?")
|
||||
sendFirmwareVersionQuery()
|
||||
}
|
||||
}, 4_000)
|
||||
logd { "Service ready! (CCCD written)" }
|
||||
}
|
||||
} else {
|
||||
@@ -1115,27 +1127,38 @@ class BleManager private constructor(private val context: Context) {
|
||||
}
|
||||
}
|
||||
"rid:" -> {
|
||||
// BLE 응답 끝에 NULL byte padding이 붙는 경우가 있음 — PostgreSQL JSONB가
|
||||
// 0x00을 거부하므로 trim()으로 안 빠지는 NULL/제어문자를 명시적으로 제거.
|
||||
val info = if (data.size > 4)
|
||||
String(data, 4, data.size - 4, Charsets.US_ASCII)
|
||||
.replace(Regex("[\\x00-\\x1F\\x7F]"), " ").trim()
|
||||
else "?"
|
||||
// 명세: [tag 4B] [HW 12B] [Serial 12B] [FW 12B] [crc 2B] = 42B.
|
||||
// 각 12B 필드는 ASCII 가변 길이 + NULL/공백/제어문자 padding.
|
||||
// (구) whitespace split 방식은 padding 이 space 가 아닐 때 깨졌음.
|
||||
fun field(offset: Int): String {
|
||||
val end = (offset + 12).coerceAtMost(data.size - 2) // CRC 2B 앞까지
|
||||
if (end <= offset) return ""
|
||||
return String(data, offset, end - offset, Charsets.US_ASCII)
|
||||
.replace(Regex("[\\x00-\\x1F\\x7F]"), "").trim()
|
||||
}
|
||||
val hw = field(4)
|
||||
val sn = field(16)
|
||||
val fw = field(28)
|
||||
val info = "$hw $sn $fw".trim()
|
||||
debugLogger.rx("rid", data.size, "device_info=$info")
|
||||
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") } ?: ""
|
||||
debugLogger.info("DEVICE_INFO hw=$hw sn=$sn fw=$fw")
|
||||
handler.post {
|
||||
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)
|
||||
}
|
||||
"rfv:" -> {
|
||||
// 명세: [tag 4B] [FW ASCII N B] [crc 2B] — FW 만 별도 쿼리(mfv?) 응답.
|
||||
// mid? 가 응답 안 하는 펌웨어 fallback 용.
|
||||
if (data.size > 6) {
|
||||
val fw = String(data, 4, data.size - 6, Charsets.US_ASCII)
|
||||
.replace(Regex("[\\x00-\\x1F\\x7F]"), "").trim()
|
||||
debugLogger.rx("rfv", data.size, "fw=$fw")
|
||||
if (fw.isNotEmpty()) handler.post { firmwareVersion.value = fw }
|
||||
}
|
||||
}
|
||||
"rls:" -> {
|
||||
val state = if (data.size >= 5) data[4].toInt() and 0xFF else -1
|
||||
debugLogger.rx("rls", data.size, "led_state=$state")
|
||||
|
||||
Reference in New Issue
Block a user