diff --git a/server/core/src/main/java/dev/slimevr/tracking/trackers/Tracker.kt b/server/core/src/main/java/dev/slimevr/tracking/trackers/Tracker.kt index bb70fbc83..cd286a9c7 100644 --- a/server/core/src/main/java/dev/slimevr/tracking/trackers/Tracker.kt +++ b/server/core/src/main/java/dev/slimevr/tracking/trackers/Tracker.kt @@ -97,9 +97,15 @@ class Tracker @JvmOverloads constructor( * NOT the same as hasRotation (other data types emulate rotation) */ val trackerDataType: TrackerDataType = TrackerDataType.ROTATION, + + /** + * Set status when tracker is sleeping + */ + val usesSleep: Boolean = false, ) { private val timer = BufferedTimer(1f) private var timeAtLastUpdate: Long = System.currentTimeMillis() + private var timeScheduledSleep: Long = MAX_VALUE private var _rotation = Quaternion.IDENTITY // IMU: +z forward, +x left, +y up @@ -261,6 +267,16 @@ class Tracker @JvmOverloads constructor( } } + if (usesSleep && status != TrackerStatus.DISCONNECTED) { + if (System.currentTimeMillis() > timeScheduledSleep) { + status = TrackerStatus.TIMED_OUT + } + // Want to also use timeout but without following disconnect + if (System.currentTimeMillis() - timeAtLastUpdate > TIMEOUT_MS) { + status = TrackerStatus.TIMED_OUT + } + } + filteringHandler.update() yawResetSmoothing.tick(deltaTime) stayAligned.update() @@ -450,4 +466,11 @@ class Tracker @JvmOverloads constructor( fun resetFilteringQuats(reference: Quaternion) { filteringHandler.resetMovingAverage(getAdjustedRotation(), reference) } + + /** + * Sets time in future if a tracker is expected to sleep + */ + fun setSleepTime(time: Long) { + this.timeScheduledSleep = time + } } diff --git a/server/core/src/main/java/dev/slimevr/tracking/trackers/hid/HIDCommon.kt b/server/core/src/main/java/dev/slimevr/tracking/trackers/hid/HIDCommon.kt index 845e37025..944a55870 100644 --- a/server/core/src/main/java/dev/slimevr/tracking/trackers/hid/HIDCommon.kt +++ b/server/core/src/main/java/dev/slimevr/tracking/trackers/hid/HIDCommon.kt @@ -95,6 +95,7 @@ class HIDCommon { allowMounting = true, usesTimeout = false, magStatus = magStatus, + usesSleep = true, ) // usesTimeout false because HID trackers aren't "Disconnected" unless receiver is physically removed probably // TODO: Could tracker maybe use "Timed out" status without marking as disconnecting? @@ -138,6 +139,13 @@ class HIDCommon { return } + if (tracker.status == TrackerStatus.TIMED_OUT) { + // If tracker was previously sleeping/shutdown, reset the sleep time and status + // If there is some other error, the relevant packet should set it a little later + tracker.setSleepTime(MAX_VALUE) + tracker.status = TrackerStatus.OK + } + // Packet data var runtime: Long? = null var timeout: Int? = null @@ -272,10 +280,11 @@ class HIDCommon { } if (timeout != null && timeout != 0) { // 0 or 65535: disable timeout - // need to schedule some time in the future to change status! this should also persist between receiver disconnect - // so it cannot rely only on status - // maybe set a time in the future that defaults to int max, when status is being read, then send appropriate status - // also, since trackers are always sending data, implement a basic timeout for this too? + if (timeout == 65535) { + tracker.setSleepTime(MAX_VALUE) + } else { + tracker.setSleepTime(System.currentTimeMillis() + timeout) + } } if (batt != null) { tracker.batteryLevel = if (batt == 128) 1f else (batt and 127).toFloat() @@ -387,6 +396,8 @@ class HIDCommon { } if (packetType == 1 || packetType == 2 || packetType == 4 || packetType == 7) { tracker.dataTick() // only data tick if there is rotation data + } else { + tracker.heartbeat() // else, something received } } }