fix: preset 감지 오류 (BV 2배 차이 근본원인) + 도넛 비율 + placement 자동통과
- autoDetectPreset: 기기이름 뒤에서 3번째 글자로 각도타입 판별 VBT26050301 → '3' → V2 (기존: VBT2604 매칭 실패 → V0 → 각도 0° → BV 절반) - 도넛차트: level 단계별 → maxVolumeMl/maxVolume 연속 비율로 변경 - Placement "Almost there" 3회 연속 → 자동 GREEN 통과 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -35,15 +35,20 @@ object PiezoHW {
|
|||||||
var activePreset: DevicePreset = DevicePreset.V0
|
var activePreset: DevicePreset = DevicePreset.V0
|
||||||
|
|
||||||
fun autoDetectPreset(deviceName: String) {
|
fun autoDetectPreset(deviceName: String) {
|
||||||
if (deviceName.startsWith("VBT2604") && deviceName.length >= 10) {
|
if (deviceName.startsWith("VBT") && deviceName.length >= 4) {
|
||||||
when (deviceName[8]) {
|
// VBT...n0x → 뒤에서 3번째 글자(n)가 각도 타입
|
||||||
'0' -> activePreset = DevicePreset.V0
|
// n=0 → V0, n=2 → V1, n=3 → V2
|
||||||
'2' -> activePreset = DevicePreset.V1
|
val n = deviceName[deviceName.length - 3]
|
||||||
'3' -> activePreset = DevicePreset.V2
|
activePreset = when (n) {
|
||||||
|
'0' -> DevicePreset.V0
|
||||||
|
'2' -> DevicePreset.V1
|
||||||
|
'3' -> DevicePreset.V2
|
||||||
|
else -> DevicePreset.V1 // 알 수 없으면 V1 기본
|
||||||
}
|
}
|
||||||
} else if (deviceName.startsWith("2025MEDIP")) {
|
} else if (deviceName.startsWith("2025MEDIP")) {
|
||||||
activePreset = DevicePreset.LEGACY_5CH
|
activePreset = DevicePreset.LEGACY_5CH
|
||||||
}
|
}
|
||||||
|
android.util.Log.d("PiezoHW", "autoDetectPreset: '$deviceName' → ${activePreset.name}")
|
||||||
}
|
}
|
||||||
|
|
||||||
val centerCh = intArrayOf(0, 1, 2, 3)
|
val centerCh = intArrayOf(0, 1, 2, 3)
|
||||||
|
|||||||
+5
-1
@@ -761,9 +761,13 @@ fun PiezoMonitoringView(appState: AppState) {
|
|||||||
|
|
||||||
// Donut chart with Bladdy
|
// Donut chart with Bladdy
|
||||||
val donutSize = if (isCompact) 220.dp else 280.dp
|
val donutSize = if (isCompact) 220.dp else 280.dp
|
||||||
|
// maxVolume 기준 비율 (0.0~1.0, 부드러운 연속값)
|
||||||
|
val maxVolumeForDonut = appState.piezoSettings.maxVolume.toDouble()
|
||||||
|
val donutProgress = if (maxVolumeForDonut > 0 && maxVolumeMl > 0)
|
||||||
|
(maxVolumeMl / maxVolumeForDonut).coerceIn(0.0, 1.0) else 0.0
|
||||||
Box(contentAlignment = Alignment.Center) {
|
Box(contentAlignment = Alignment.Center) {
|
||||||
DonutChartView(
|
DonutChartView(
|
||||||
progress = appState.bladderLevel.progress,
|
progress = donutProgress,
|
||||||
urgency = urgency,
|
urgency = urgency,
|
||||||
lineWidth = if (isCompact) 22.dp else 30.dp,
|
lineWidth = if (isCompact) 22.dp else 30.dp,
|
||||||
size = donutSize
|
size = donutSize
|
||||||
|
|||||||
+19
-3
@@ -96,6 +96,7 @@ fun PlacementGuideView(appState: AppState) {
|
|||||||
// SWEEP 추가 state
|
// SWEEP 추가 state
|
||||||
var sweepLastDetected by remember { mutableIntStateOf(0) }
|
var sweepLastDetected by remember { mutableIntStateOf(0) }
|
||||||
var sweepEverSawAll by remember { mutableStateOf(false) }
|
var sweepEverSawAll by remember { mutableStateOf(false) }
|
||||||
|
var almostThereCount by remember { mutableIntStateOf(0) }
|
||||||
|
|
||||||
// 화면 진입 시 상태 리셋
|
// 화면 진입 시 상태 리셋
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
@@ -110,7 +111,7 @@ fun PlacementGuideView(appState: AppState) {
|
|||||||
rTracker.reset()
|
rTracker.reset()
|
||||||
currentRMm = null; bestRMm = 0.0
|
currentRMm = null; bestRMm = 0.0
|
||||||
sagittalArgMaxCh = null; lateralOffsetMm = null
|
sagittalArgMaxCh = null; lateralOffsetMm = null
|
||||||
sweepLastDetected = 0; sweepEverSawAll = false
|
sweepLastDetected = 0; sweepEverSawAll = false; almostThereCount = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// 화면 벗어날 때 LED OFF
|
// 화면 벗어날 때 LED OFF
|
||||||
@@ -656,10 +657,25 @@ fun PlacementGuideView(appState: AppState) {
|
|||||||
lastHintChangeMs = now
|
lastHintChangeMs = now
|
||||||
}
|
}
|
||||||
|
|
||||||
if (guideResult.isPass) {
|
// "Almost there" 연속 3회 → 자동 GREEN 통과
|
||||||
|
val isAlmostThere = guideResult.hint.contains("Almost there")
|
||||||
|
if (isAlmostThere) almostThereCount++ else almostThereCount = 0
|
||||||
|
val autoPass = guideResult.isPass || almostThereCount >= 3
|
||||||
|
|
||||||
|
if (autoPass) {
|
||||||
isLocked = true
|
isLocked = true
|
||||||
|
almostThereCount = 0
|
||||||
if (lastLedMode != 6) { bleManager.sendLedMode(6); lastLedMode = 6 }
|
if (lastLedMode != 6) { bleManager.sendLedMode(6); lastLedMode = 6 }
|
||||||
bleManager.debugLogger.info("PLACEMENT_GREEN cv=${"%.3f".format(guideResult.cv)} lr_dev=${"%.3f".format(guideResult.lrDev)} score=${guideResult.score} otsu=${"%.0f".format(analyzer.lastOtsuThreshold)}")
|
if (guideResult.isPass) {
|
||||||
|
bleManager.debugLogger.info("PLACEMENT_GREEN cv=${"%.3f".format(guideResult.cv)} lr_dev=${"%.3f".format(guideResult.lrDev)} score=${guideResult.score} otsu=${"%.0f".format(analyzer.lastOtsuThreshold)}")
|
||||||
|
} else {
|
||||||
|
// Auto-pass: 위치 OK인데 CV 노이즈로 3회 연속 미달
|
||||||
|
directionHint = "Green! Position locked"
|
||||||
|
directionIcon = "checkmark.circle"
|
||||||
|
placementScore = 70
|
||||||
|
placementPhase = PlacementPhase.GREEN
|
||||||
|
bleManager.debugLogger.info("PLACEMENT_GREEN_AUTO cv=${"%.3f".format(guideResult.cv)} almostThereCount=3")
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
isLocked = false
|
isLocked = false
|
||||||
if (lastLedMode != 5) { bleManager.sendLedMode(5); lastLedMode = 5 }
|
if (lastLedMode != 5) { bleManager.sendLedMode(5); lastLedMode = 5 }
|
||||||
|
|||||||
Reference in New Issue
Block a user