diff --git a/app/libs/unity-bridge.aar b/app/libs/unity-bridge.aar index 8fb521b..4ba3da3 100644 Binary files a/app/libs/unity-bridge.aar and b/app/libs/unity-bridge.aar differ diff --git a/app/src/main/java/com/kiwii/controlpanel/data/BridgeRepository.kt b/app/src/main/java/com/kiwii/controlpanel/data/BridgeRepository.kt index 558bc1a..89930b6 100644 --- a/app/src/main/java/com/kiwii/controlpanel/data/BridgeRepository.kt +++ b/app/src/main/java/com/kiwii/controlpanel/data/BridgeRepository.kt @@ -36,31 +36,63 @@ class BridgeRepository { fun getLatestPoseFrameJson(): String = KiwiiRuntimeClientBridge.getLatestPoseFrameJson() fun getLatestBodyPoseFrameJson(): String = KiwiiRuntimeClientBridge.getLatestBodyPoseFrameJson() - fun getLeftHandleIMULatest(): FloatArray = KiwiiRuntimeClientBridge.getLatestLeftHandleIMU() + fun getLeftHandleIMULatest(): FloatArray = KiwiiRuntimeClientBridge.getLeftHandleIMULatest() + fun getLeftHandleIMUQueue(): Array { - val latest = KiwiiRuntimeClientBridge.getLatestLeftHandleIMU() + val queue = readHandleImuQueueCompat("getLeftHandleIMUQueue") + if (queue.isNotEmpty()) return queue + val latest = getLeftHandleIMULatest() 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(buildHeStreamPatternJson(streamId, payload)) + KiwiiRuntimeClientBridge.submitLeftHeStream(streamId, buildHeStreamPatternJson(streamId, payload)) + + fun getRightHandleIMULatest(): FloatArray = KiwiiRuntimeClientBridge.getRightHandleIMULatest() - fun getRightHandleIMULatest(): FloatArray = KiwiiRuntimeClientBridge.getLatestRightHandleIMU() fun getRightHandleIMUQueue(): Array { - val latest = KiwiiRuntimeClientBridge.getLatestRightHandleIMU() + val queue = readHandleImuQueueCompat("getRightHandleIMUQueue") + if (queue.isNotEmpty()) return queue + val latest = getRightHandleIMULatest() 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(buildHeStreamPatternJson(streamId, payload)) + KiwiiRuntimeClientBridge.submitRightHeStream(streamId, buildHeStreamPatternJson(streamId, payload)) fun getHandleStateJson(): String = KiwiiRuntimeClientBridge.getHandleStateJson() fun setMotorWeightKg(weight: Float): com.kiwii.bridge.MotorCommandResult = KiwiiRuntimeClientBridge.setMotorWeightKg(weight) fun setMotorTrainingMode(mode: Int, param: Float): String = KiwiiRuntimeClientBridge.setMotorTrainingMode(mode, param) + fun setMotorForceControlParamsJson(paramsJson: String): String { + return try { + val method = KiwiiRuntimeClientBridge::class.java.getMethod("setMotorForceControlParamsJson", String::class.java) + method.invoke(null, paramsJson) as? String ?: "{\"error\":\"setMotorForceControlParamsJson returned null\"}" + } catch (t: Throwable) { + "{\"error\":\"setMotorForceControlParamsJson unavailable: ${t.message}\"}" + } + } fun queryMotorTrainingMode(axis: Int): String = KiwiiRuntimeClientBridge.queryMotorTrainingMode(axis) fun getLatestMotorStateJson(): String = KiwiiRuntimeClientBridge.getLatestMotorStateJson() fun getMotorControlStateJson(): String = KiwiiRuntimeClientBridge.getMotorControlStateJson() + fun getMotorDisconnectDiagnosisJson(): String { + return try { + val method = KiwiiRuntimeClientBridge::class.java.getMethod("getMotorDisconnectDiagnosisJson") + method.invoke(null) as? String ?: "{\"error\":\"getMotorDisconnectDiagnosisJson returned null\"}" + } catch (t: Throwable) { + "{\"error\":\"getMotorDisconnectDiagnosisJson unavailable: ${t.message}\"}" + } + } + fun sendMotorHeartbeat(): String { + return try { + val method = KiwiiRuntimeClientBridge::class.java.getMethod("sendMotorHeartbeat") + method.invoke(null) as? String ?: "{\"error\":\"sendMotorHeartbeat returned null\"}" + } catch (t: Throwable) { + "{\"error\":\"sendMotorHeartbeat unavailable: ${t.message}\"}" + } + } fun getTelemetryStateJson(): String = KiwiiRuntimeClientBridge.getTelemetryStateJson() fun getSafetyStateJson(): String = KiwiiRuntimeClientBridge.getSafetyStateJson() @@ -68,6 +100,41 @@ class BridgeRepository { fun submitDeviceCommandDryRun(command: String): String = KiwiiRuntimeClientBridge.submitDeviceCommandDryRun(command) fun getDeviceCommandStateJson(): String = KiwiiRuntimeClientBridge.getDeviceCommandStateJson() + private fun readHandleImuQueueCompat(methodName: String): Array { + return try { + val method = KiwiiRuntimeClientBridge::class.java.getMethod(methodName) + when (val value = method.invoke(null)) { + is Array<*> -> { + @Suppress("UNCHECKED_CAST") + value.filterIsInstance().toTypedArray() + } + is FloatArray -> splitFlatImuQueue(value) + else -> emptyArray() + } + } catch (_: Throwable) { + emptyArray() + } + } + + private fun splitFlatImuQueue(flat: FloatArray): Array { + if (flat.isEmpty()) return emptyArray() + val sampleSize = when { + flat.size % 10 == 0 -> 10 + flat.size % 9 == 0 -> 9 + flat.size % 7 == 0 -> 7 + else -> flat.size + } + if (sampleSize <= 0) return emptyArray() + val out = ArrayList() + var offset = 0 + while (offset < flat.size) { + val end = minOf(offset + sampleSize, flat.size) + out.add(flat.copyOfRange(offset, end)) + offset = end + } + return out.toTypedArray() + } + private fun buildHeStreamPatternJson(streamId: Int, payload: String): String { val trimmed = payload.trim() if (trimmed.startsWith("{")) return trimmed