feat: 펌웨어 버전 앱 내 표시 (Settings + ClinicalHome)
연결 시 자동으로 받던 mid?/rid: device_info를 UI에 노출. 이전에는 BLE 디버그 로그에만 기록되어 사용자가 접근 불가했음. BleManager: - firmwareVersion / hardwareVersion / serialNumber 3개 MutableState 추가 - rid: 응답 파싱 — "VBTHW0100 VBT26040001 VBTFW0111" 형식을 공백 split + prefix 매칭(VBTHW/VBTFW/VBT)으로 안전 추출 - disconnect 시 3 필드 모두 clear PiezoMonitoringView Settings overlay: - 기존 "Version" 행을 "App" + "Firmware" 두 행으로 분리 - FW 없으면 "—" 표시 (연결 대기 중) - dev 모드 한정 "Serial" 행 추가 (회사 자산 추적용) ClinicalHomeView BLE 연결 카드: - deviceName 아래 "FW: VBTFW0116" 한 줄 추가 - 검사자가 별도 클릭 없이 펌웨어 버전 즉시 확인 가능 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -70,6 +70,10 @@ class BleManager private constructor(private val context: Context) {
|
|||||||
val isScanning = mutableStateOf(false)
|
val isScanning = mutableStateOf(false)
|
||||||
val isConnected = mutableStateOf(false)
|
val isConnected = mutableStateOf(false)
|
||||||
val connectedDeviceName = mutableStateOf("")
|
val connectedDeviceName = mutableStateOf("")
|
||||||
|
// mid? → rid: 응답에서 파싱. 연결 직후 자동 채워짐.
|
||||||
|
val firmwareVersion = mutableStateOf("") // "VBTFW0116"
|
||||||
|
val hardwareVersion = mutableStateOf("") // "VBTHW0100"
|
||||||
|
val serialNumber = mutableStateOf("") // "VBT26040001"
|
||||||
val batteryLevel = mutableStateOf(0)
|
val batteryLevel = mutableStateOf(0)
|
||||||
val bluetoothEnabled = mutableStateOf(bluetoothAdapter?.isEnabled == true)
|
val bluetoothEnabled = mutableStateOf(bluetoothAdapter?.isEnabled == true)
|
||||||
val isServiceReady = mutableStateOf(false)
|
val isServiceReady = mutableStateOf(false)
|
||||||
@@ -755,6 +759,9 @@ class BleManager private constructor(private val context: Context) {
|
|||||||
isConnected.value = false
|
isConnected.value = false
|
||||||
isServiceReady.value = false
|
isServiceReady.value = false
|
||||||
connectedDeviceName.value = ""
|
connectedDeviceName.value = ""
|
||||||
|
firmwareVersion.value = ""
|
||||||
|
hardwareVersion.value = ""
|
||||||
|
serialNumber.value = ""
|
||||||
batteryLevel.value = 0
|
batteryLevel.value = 0
|
||||||
|
|
||||||
val idx = discoveredDevices.indexOfFirst { it.address == gatt.device.address }
|
val idx = discoveredDevices.indexOfFirst { it.address == gatt.device.address }
|
||||||
@@ -971,6 +978,14 @@ class BleManager private constructor(private val context: Context) {
|
|||||||
val info = if (data.size > 4) String(data, 4, data.size - 4, Charsets.US_ASCII).trim() else "?"
|
val info = if (data.size > 4) String(data, 4, data.size - 4, Charsets.US_ASCII).trim() else "?"
|
||||||
debugLogger.rx("rid", data.size, "device_info=$info")
|
debugLogger.rx("rid", data.size, "device_info=$info")
|
||||||
debugLogger.info("DEVICE_INFO $info")
|
debugLogger.info("DEVICE_INFO $info")
|
||||||
|
// 형식: "VBTHW0100 VBT26040001 VBTFW0111" (HW, Serial, FW)
|
||||||
|
val parts = info.split(Regex("\\s+")).filter { it.isNotBlank() }
|
||||||
|
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 }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"rls:" -> {
|
"rls:" -> {
|
||||||
val state = if (data.size >= 5) data[4].toInt() and 0xFF else -1
|
val state = if (data.size >= 5) data[4].toInt() and 0xFF else -1
|
||||||
|
|||||||
@@ -103,6 +103,13 @@ fun ClinicalHomeView(appState: AppState) {
|
|||||||
Text("BLE Connected", fontWeight = FontWeight.Bold, fontSize = 14.sp)
|
Text("BLE Connected", fontWeight = FontWeight.Bold, fontSize = 14.sp)
|
||||||
Text(bleManager.connectedDeviceName.value,
|
Text(bleManager.connectedDeviceName.value,
|
||||||
fontSize = 11.sp, color = MlSecondaryText)
|
fontSize = 11.sp, color = MlSecondaryText)
|
||||||
|
// 펌웨어 버전 (mid? → rid: 응답 파싱, 연결 직후 자동 채워짐)
|
||||||
|
val fwVersion by bleManager.firmwareVersion
|
||||||
|
if (fwVersion.isNotEmpty()) {
|
||||||
|
Text("FW: $fwVersion",
|
||||||
|
fontSize = 11.sp, color = MlSecondaryText,
|
||||||
|
fontWeight = FontWeight.SemiBold)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Text("BLE Not Connected", fontWeight = FontWeight.Bold, fontSize = 14.sp,
|
Text("BLE Not Connected", fontWeight = FontWeight.Bold, fontSize = 14.sp,
|
||||||
|
|||||||
+36
-2
@@ -1580,12 +1580,12 @@ fun PiezoMonitoringView(appState: AppState) {
|
|||||||
HorizontalDivider(modifier = Modifier.padding(vertical = dividerPadding))
|
HorizontalDivider(modifier = Modifier.padding(vertical = dividerPadding))
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
|
||||||
// Version (BuildConfig.VERSION_NAME) — read-only
|
// App Version
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
Text("Version", fontSize = 13.sp, color = MlSecondaryText)
|
Text("App", fontSize = 13.sp, color = MlSecondaryText)
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
Text(
|
Text(
|
||||||
com.example.medilightv2android.BuildConfig.VERSION_NAME,
|
com.example.medilightv2android.BuildConfig.VERSION_NAME,
|
||||||
@@ -1594,6 +1594,40 @@ fun PiezoMonitoringView(appState: AppState) {
|
|||||||
color = MlPrimary,
|
color = MlPrimary,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
// Firmware Version (mid? → rid: 응답에서 파싱, 연결 시 자동)
|
||||||
|
val fwVersion by bleManager.firmwareVersion
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Text("Firmware", fontSize = 13.sp, color = MlSecondaryText)
|
||||||
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
|
Text(
|
||||||
|
if (fwVersion.isNotEmpty()) fwVersion else "—",
|
||||||
|
fontSize = 13.sp,
|
||||||
|
fontWeight = FontWeight.SemiBold,
|
||||||
|
color = if (fwVersion.isNotEmpty()) MlPrimary else MlSecondaryText,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// Serial Number (dev 모드에서만)
|
||||||
|
if (appState.isDevMode) {
|
||||||
|
val serial by bleManager.serialNumber
|
||||||
|
if (serial.isNotEmpty()) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Text("Serial", fontSize = 13.sp, color = MlSecondaryText)
|
||||||
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
|
Text(
|
||||||
|
serial,
|
||||||
|
fontSize = 11.sp,
|
||||||
|
fontWeight = FontWeight.SemiBold,
|
||||||
|
color = MlSecondaryText,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
HorizontalDivider()
|
HorizontalDivider()
|
||||||
|
|||||||
Reference in New Issue
Block a user