From a3fc10815676b5d67b1592c9a2e50e10995211fa Mon Sep 17 00:00:00 2001 From: Zhifei Ge Date: Wed, 10 Jun 2026 23:46:37 +0800 Subject: [PATCH] Gate motor status on dongle and fresh telemetry --- app/libs/unity-bridge.aar | Bin 22965 -> 21402 bytes .../controlpanel/data/BridgeRepository.kt | 36 ++++++++-- .../controlpanel/data/ComponentRegistry.kt | 63 +++++++++++++++--- .../controlpanel/data/RuntimeStateSource.kt | 2 +- .../controlpanel/ui/components/DongleOps.kt | 42 +++++++++--- 5 files changed, 117 insertions(+), 26 deletions(-) diff --git a/app/libs/unity-bridge.aar b/app/libs/unity-bridge.aar index df71e2fbe5d2a4019947844318cd9cf049308100..8fb521bcbc8107d29e351757f89c7b6ad7c7ed27 100644 GIT binary patch delta 21096 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�w@3|Kx3`0}^R<5>ObRX><$JS9c zE;t9WU3wmioquPusEH0Lc=R(#AyVJ-h!z{tn={9{G1wH!+460MY^`JByB&9{5U!hY z=Wdb}j^z}xxV5#K!`dJlp8CI?sRe4+?DNf4nCqqAU?o<*&XvDsWt=1WcvCd;LVBK& zxF&NdSE@thpan;=>ca(oL{y2U`PBM5Owy;$Ga93Uihm8f&N ztfEJc9GPW3azyTL&71#w%ADzB|4y5`S2Es)n<>5JluP}N08{G>PN0YREhbekD3g(1luTmjTmykR* zD-Kf!zMVE_sO0aB66YPZb2S~}Z#Z44(3GMuk)B+2)Mqb}MQ^WC=9)p3c3eFd+Q`;v zB;Ew8iYJrTmrDSR_jfWcZ{sUp`vNy!DQ*0)valai=0l37xB=khA9>B0iq@n?J)3Zr z$$u&*Z5wRm07hQmF7c}kTV$+xS>&+Br+2;8QW+5sXNPB=$p5|y%=fp{Cs{PVg_Ktc zB&&Z$vpUs{RmHn#Iti*`;uhsw+C=aN+2-Cq<wEhE~zBgNZfP z<6+)mf5BfoMaF;NHh36+*oW;G-jC^TyRsdIAMWP-1-~o&H+nk{V-GjD{lXGO{_}RX z!_>q57r&^HXa4hUjKkE!)!o0SA)tR=>wP%N;gZQ;QDSBOUj>wh107y){uQWR^B*oh z9}aOiH~$K;g#7!N+QNj1`3_%d;Lk1T=X0>N{MXrklipYG2`%E7wh{pV0Nj(;SU4N* zF`TC}Pyhh;RR91B00000000000001_foPK|SvUg3QIq>uJCmPT5C(8k00000n6zK3 delta 22671 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 OlY~ = KiwiiRuntimeClientBridge.getLeftHandleIMUQueue() + fun getLeftHandleIMULatest(): FloatArray = KiwiiRuntimeClientBridge.getLatestLeftHandleIMU() + fun getLeftHandleIMUQueue(): Array { + val latest = KiwiiRuntimeClientBridge.getLatestLeftHandleIMU() + return if (latest.isEmpty()) emptyArray() else arrayOf(latest) + } fun submitLeftStaticEffect(effectId: Int): String = KiwiiRuntimeClientBridge.submitLeftStaticEffect(effectId) - fun submitLeftHeStream(streamId: Int, payload: String): String = KiwiiRuntimeClientBridge.submitLeftHeStream(streamId, payload) + fun submitLeftHeStream(streamId: Int, payload: String): String = + KiwiiRuntimeClientBridge.submitLeftHeStream(buildHeStreamPatternJson(streamId, payload)) - fun getRightHandleIMULatest(): FloatArray = KiwiiRuntimeClientBridge.getRightHandleIMULatest() - fun getRightHandleIMUQueue(): Array = KiwiiRuntimeClientBridge.getRightHandleIMUQueue() + fun getRightHandleIMULatest(): FloatArray = KiwiiRuntimeClientBridge.getLatestRightHandleIMU() + fun getRightHandleIMUQueue(): Array { + val latest = KiwiiRuntimeClientBridge.getLatestRightHandleIMU() + return if (latest.isEmpty()) emptyArray() else arrayOf(latest) + } fun submitRightStaticEffect(effectId: Int): String = KiwiiRuntimeClientBridge.submitRightStaticEffect(effectId) - fun submitRightHeStream(streamId: Int, payload: String): String = KiwiiRuntimeClientBridge.submitRightHeStream(streamId, payload) + fun submitRightHeStream(streamId: Int, payload: String): String = + KiwiiRuntimeClientBridge.submitRightHeStream(buildHeStreamPatternJson(streamId, payload)) fun getHandleStateJson(): String = KiwiiRuntimeClientBridge.getHandleStateJson() @@ -51,6 +68,13 @@ class BridgeRepository { fun submitDeviceCommandDryRun(command: String): String = KiwiiRuntimeClientBridge.submitDeviceCommandDryRun(command) fun getDeviceCommandStateJson(): String = KiwiiRuntimeClientBridge.getDeviceCommandStateJson() + private fun buildHeStreamPatternJson(streamId: Int, payload: String): String { + val trimmed = payload.trim() + if (trimmed.startsWith("{")) return trimmed + val escaped = payload.replace("\\", "\\\\").replace("\"", "\\\"") + return "{\"streamId\":$streamId,\"payload\":\"$escaped\"}" + } + suspend fun callAsync(block: () -> T): OperationResult = withContext(Dispatchers.IO) { try { val result = block() diff --git a/app/src/main/java/com/kiwii/controlpanel/data/ComponentRegistry.kt b/app/src/main/java/com/kiwii/controlpanel/data/ComponentRegistry.kt index 2150080..dff60df 100644 --- a/app/src/main/java/com/kiwii/controlpanel/data/ComponentRegistry.kt +++ b/app/src/main/java/com/kiwii/controlpanel/data/ComponentRegistry.kt @@ -25,6 +25,16 @@ class ComponentRegistry( private var previousStates = emptyMap() + private companion object { + const val MOTOR_TELEMETRY_FRESH_TIMEOUT_MS = 5000L + } + + // Motor is physically downstream of the SmartBase Dongle. + // Keep the latest Dongle card decision from the same detection loop so Motor cannot remain green + // after the Dongle transport is disconnected, while preserving v4 Dongle detection behavior. + @Volatile + private var latestDongleCardStateForMotorGate: ComponentState = ComponentState.GREY + fun startDetection() { scope.launch(Dispatchers.IO) { while (isActive) { @@ -95,11 +105,12 @@ class ComponentRegistry( private fun dumpDebugOnce() { if (debugDumped || !repo.isBound()) return debugDumped = true + // 首页首次检测不要调用 getDebugSnapshotJson / camera / motor 等重 API。 + // 这些 API 会触发 native snapshot 或 camera state 路径;RuntimeHost 刚启动时容易与 + // native init/camera warm-start 形成 Binder 等待,导致 NOT_BOUND 或 service ANR。 val apis = mapOf( - "getCameraStateJson" to runCatching { repo.getCameraStateJson() }.getOrDefault("EXCEPTION"), - "getLatestMotorStateJson" to runCatching { repo.getLatestMotorStateJson() }.getOrDefault("EXCEPTION"), - "getDebugSnapshotJson(first200)" to runCatching { repo.getDebugSnapshotJson().take(200) }.getOrDefault("EXCEPTION"), - "getHandleStateJson" to runCatching { repo.getHandleStateJson() }.getOrDefault("EXCEPTION"), + "isBound" to repo.isBound().toString(), + "getDongleStateJson(first400)" to runCatching { repo.getDongleStateJson().take(400) }.getOrDefault("EXCEPTION") ) for ((name, value) in apis) { logger.log(LogEntry( @@ -153,12 +164,32 @@ class ComponentRegistry( } private fun checkDongle(): ComponentState { + val state = computeDongleState() + latestDongleCardStateForMotorGate = state + return state + } + + private fun computeDongleState(): ComponentState { return try { - // Dongle 是 USB 外设,状态在 getDebugSnapshotJson 的全量数据中 - val json = repo.getDebugSnapshotJson() + val json = repo.getDongleStateJson() if (isUnavailable(json)) return ComponentState.GREY - // dongleState 字段存在说明 Dongle USB 已连接并被 RuntimeHost 识别 - if (json.contains("\"dongleState\"")) { + val obj = JSONObject(json) + val transport = obj.optJSONObject("transport") ?: return ComponentState.GREY + + val active = obj.optBoolean("active", false) || obj.optBoolean("available", false) || obj.optBoolean("connected", false) + val transportActive = transport.optBoolean("active", false) || transport.optBoolean("connected", false) + val usbBridgeRegistered = transport.optBoolean("usbBridgeRegistered", false) + val readLoopRunning = transport.optBoolean("readLoopRunning", false) + val usbPresent = transport.optBoolean("usbPresent", false) + val state = transport.optString("state", "") + + // Dongle 首页卡片表达“USB transport 已经被 RuntimeHost 打开并注册”, + // 不要求 lastUsbInAgeMs < 3s。是否有上行数据滞后由 detail page 的 dataStale/lastUsbInAgeMs 显示。 + if ((active || transportActive || state == "CONNECTED") && + usbPresent && + usbBridgeRegistered && + readLoopRunning + ) { ComponentState.ACTIVE } else { ComponentState.GREY @@ -170,11 +201,23 @@ class ComponentRegistry( private fun checkMotor(): ComponentState { return try { + // Motor is physically downstream of the SmartBase Dongle. + // V7 requires fresh motor telemetry; stale cached telemetry after Dongle re-plug must not turn Motor green. + if (latestDongleCardStateForMotorGate != ComponentState.ACTIVE) return ComponentState.GREY + val json = repo.getLatestMotorStateJson() if (isUnavailable(json)) return ComponentState.GREY - // motor-runtime-state.v1 has top-level "available" field + val obj = JSONObject(json) - if (obj.optBoolean("available", false)) ComponentState.ACTIVE else ComponentState.GREY + if (obj.optString("contractVersion", "") != "kiwii.motor-runtime-state.v1") return ComponentState.GREY + if (obj.optBoolean("blockedByDongleTransport", false)) return ComponentState.GREY + if (obj.optBoolean("blockedByMotorTelemetry", false)) return ComponentState.GREY + if (!obj.optBoolean("available", false)) return ComponentState.GREY + + val dataAgeMs = obj.optLong("dataAgeMs", Long.MAX_VALUE) + if (dataAgeMs < 0L || dataAgeMs > MOTOR_TELEMETRY_FRESH_TIMEOUT_MS) return ComponentState.GREY + + ComponentState.ACTIVE } catch (_: Exception) { ComponentState.GREY } diff --git a/app/src/main/java/com/kiwii/controlpanel/data/RuntimeStateSource.kt b/app/src/main/java/com/kiwii/controlpanel/data/RuntimeStateSource.kt index 135e9cb..c892bff 100644 --- a/app/src/main/java/com/kiwii/controlpanel/data/RuntimeStateSource.kt +++ b/app/src/main/java/com/kiwii/controlpanel/data/RuntimeStateSource.kt @@ -15,7 +15,7 @@ class AarProxyStateSource(private val bridge: BridgeRepository) : RuntimeStateSo ComponentType.LEFT_HANDLE, ComponentType.RIGHT_HANDLE -> bridge.getHandleStateJson() ComponentType.MOTOR -> bridge.getLatestMotorStateJson() ComponentType.BALANCE_BOARD -> bridge.getDebugSnapshotJson() - ComponentType.DONGLE -> bridge.getDebugSnapshotJson() + ComponentType.DONGLE -> bridge.getDongleStateJson() ComponentType.TELEMETRY_SAFETY -> bridge.getTelemetryStateJson() ComponentType.SESSION_LOG -> "{}" } diff --git a/app/src/main/java/com/kiwii/controlpanel/ui/components/DongleOps.kt b/app/src/main/java/com/kiwii/controlpanel/ui/components/DongleOps.kt index 91ea41d..7af475d 100644 --- a/app/src/main/java/com/kiwii/controlpanel/ui/components/DongleOps.kt +++ b/app/src/main/java/com/kiwii/controlpanel/ui/components/DongleOps.kt @@ -2,20 +2,44 @@ package com.kiwii.controlpanel.ui.components import android.content.Context import android.view.View -import android.widget.TextView -import androidx.core.content.ContextCompat -import com.kiwii.controlpanel.R +import com.kiwii.controlpanel.model.ComponentType +import com.kiwii.controlpanel.ui.detail.ComponentDetailViewModel -class DongleOps(context: Context) : BaseOps(context) { +class DongleOps( + context: Context, + private val viewModel: ComponentDetailViewModel +) : BaseOps(context) { override fun createView(): View { val layout = verticalLayout() - layout.addView(TextView(context).apply { - text = "暂无 SDK API" - textSize = 12f - setTextColor(ContextCompat.getColor(context, R.color.rhs_subtitle)) - setPadding(0, 32, 0, 32) + + layout.addView(createSection("Dongle Transport")) + layout.addView(createButton("getDongleStateJson") { + viewModel.executeOperation(ComponentType.DONGLE, "getDongleStateJson") { + viewModel.bridgeRepo.getDongleStateJson() + } }) + + layout.addView(createButton("getDebugSnapshotJson") { + viewModel.executeOperation(ComponentType.DONGLE, "getDebugSnapshotJson") { + viewModel.bridgeRepo.getDebugSnapshotJson() + } + }) + + layout.addView(createSection("Transport Probe")) + layout.addView(createButton("queryMotorTrainingMode") { + viewModel.executeOperation(ComponentType.DONGLE, "queryMotorTrainingMode", "axis=0") { + viewModel.bridgeRepo.queryMotorTrainingMode(0) + } + }) + + layout.addView(createSection("Expected fields")) + layout.addView(createButton("Inspect transport + slots") { + viewModel.executeOperation(ComponentType.DONGLE, "inspectDongleDiagnostics") { + viewModel.bridgeRepo.getDongleStateJson() + } + }) + return layout } }