From ce8072677311a82a9b641eaf509a49b75c58a07a Mon Sep 17 00:00:00 2001 From: NWB Date: Mon, 5 Jun 2023 03:57:06 -0400 Subject: [PATCH] Display SlimeVR Tracker Battery Life (#41) --- .gitignore | 3 +++ src/IVRDevice.hpp | 2 ++ src/TrackerDevice.cpp | 40 +++++++++++++++++++++++++------ src/TrackerDevice.hpp | 2 ++ src/VRDriver.cpp | 16 +++++++++++++ src/bridge/ProtobufMessages.proto | 7 ++++++ 6 files changed, 63 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index d6f4514..d37e53d 100644 --- a/.gitignore +++ b/.gitignore @@ -11,12 +11,14 @@ compile_commands.json CTestTestfile.cmake _deps CMakeUserPresets.json +vcpkg_installed/ ### CMake Patch ### # External projects *-prefix/ ### vscode ### +.vs .vscode/* !.vscode/settings.json !.vscode/tasks.json @@ -26,3 +28,4 @@ CMakeUserPresets.json # Project-specific build/* +out/ diff --git a/src/IVRDevice.hpp b/src/IVRDevice.hpp index 0ed9829..3038f23 100644 --- a/src/IVRDevice.hpp +++ b/src/IVRDevice.hpp @@ -63,6 +63,8 @@ namespace SlimeVRDriver { virtual void PositionMessage(messages::Position& position) = 0; virtual void StatusMessage(messages::TrackerStatus& status) = 0; + virtual void BatteryMessage(messages::Battery& battery) = 0; + ~IVRDevice() = default; }; }; \ No newline at end of file diff --git a/src/TrackerDevice.cpp b/src/TrackerDevice.cpp index b74064c..fbd1242 100644 --- a/src/TrackerDevice.cpp +++ b/src/TrackerDevice.cpp @@ -79,6 +79,32 @@ void SlimeVRDriver::TrackerDevice::PositionMessage(messages::Position &position) this->last_pose_ = pose; } +void SlimeVRDriver::TrackerDevice::BatteryMessage(messages::Battery &battery) +{ + if (this->device_index_ == vr::k_unTrackedDeviceIndexInvalid) + return; + + // Get the properties handle + auto props = GetDriver()->GetProperties()->TrackedDeviceToPropertyContainer(this->device_index_); + + vr::ETrackedPropertyError err; + + // Set that the tracker reports battery level in case it has not already been set to true + // It's a given that the tracker supports reporting battery life because otherwise a BatteryMessage would not be received + if (vr::VRProperties()->GetBoolProperty(props, vr::Prop_DeviceProvidesBatteryStatus_Bool, &err) != true) { + vr::VRProperties()->SetBoolProperty(props, vr::Prop_DeviceProvidesBatteryStatus_Bool, true); + } + + if (battery.is_charging()) { + vr::VRProperties()->SetBoolProperty(props, vr::Prop_DeviceIsCharging_Bool, true); + } else { + vr::VRProperties()->SetBoolProperty(props, vr::Prop_DeviceIsCharging_Bool, false); + } + + // Set the battery Level; 0 = 0%, 1 = 100% + vr::VRProperties()->SetFloatProperty(props, vr::Prop_DeviceBatteryPercentage_Float, battery.battery_level()); +} + void SlimeVRDriver::TrackerDevice::StatusMessage(messages::TrackerStatus &status) { auto pose = this->last_pose_; @@ -141,15 +167,15 @@ vr::EVRInitError SlimeVRDriver::TrackerDevice::Activate(uint32_t unObjectId) GetDriver()->GetProperties()->SetStringProperty(props, vr::Prop_RenderModelName_String, "{htc}/rendermodels/vr_tracker_vive_1_0"); // Set the icon - GetDriver()->GetProperties()->SetStringProperty(props, vr::Prop_NamedIconPathDeviceReady_String, "{slimevr}/icons/tracker_status_ready.b4bfb144.png"); + GetDriver()->GetProperties()->SetStringProperty(props, vr::Prop_NamedIconPathDeviceReady_String, "{slimevr}/icons/tracker_status_ready.png"); GetDriver()->GetProperties()->SetStringProperty(props, vr::Prop_NamedIconPathDeviceOff_String, "{slimevr}/icons/tracker_status_off.png"); - GetDriver()->GetProperties()->SetStringProperty(props, vr::Prop_NamedIconPathDeviceSearching_String, "{slimevr}/icons/tracker_status_ready.b4bfb144.png"); - GetDriver()->GetProperties()->SetStringProperty(props, vr::Prop_NamedIconPathDeviceSearchingAlert_String, "{slimevr}/icons/tracker_status_ready_alert.b4bfb144.png"); - GetDriver()->GetProperties()->SetStringProperty(props, vr::Prop_NamedIconPathDeviceReadyAlert_String, "{slimevr}/icons/tracker_status_ready_alert.b4bfb144.png"); - GetDriver()->GetProperties()->SetStringProperty(props, vr::Prop_NamedIconPathDeviceNotReady_String, "{slimevr}/icons/tracker_status_off.png"); - GetDriver()->GetProperties()->SetStringProperty(props, vr::Prop_NamedIconPathDeviceStandby_String, "{slimevr}/icons/tracker_status_standby.b4bfb144.png"); - GetDriver()->GetProperties()->SetStringProperty(props, vr::Prop_NamedIconPathDeviceAlertLow_String, "{slimevr}/icons/tracker_status_ready_low.b4bfb144.png"); + GetDriver()->GetProperties()->SetStringProperty(props, vr::Prop_NamedIconPathDeviceSearching_String, "{slimevr}/icons/tracker_status_ready.png"); + GetDriver()->GetProperties()->SetStringProperty(props, vr::Prop_NamedIconPathDeviceSearchingAlert_String, "{slimevr}/icons/tracker_status_ready_alert.png"); + GetDriver()->GetProperties()->SetStringProperty(props, vr::Prop_NamedIconPathDeviceReadyAlert_String, "{slimevr}/icons/tracker_status_ready_alert.png"); + GetDriver()->GetProperties()->SetStringProperty(props, vr::Prop_NamedIconPathDeviceNotReady_String, "{slimevr}/icons/tracker_status_error.png"); + GetDriver()->GetProperties()->SetStringProperty(props, vr::Prop_NamedIconPathDeviceStandby_String, "{slimevr}/icons/tracker_status_standby.png"); + GetDriver()->GetProperties()->SetStringProperty(props, vr::Prop_NamedIconPathDeviceAlertLow_String, "{slimevr}/icons/tracker_status_ready_low.png"); // Automatically select vive tracker roles and set hints for games that need it (Beat Saber avatar mod, for example) auto roleHint = getViveRoleHint(trackerRole); diff --git a/src/TrackerDevice.hpp b/src/TrackerDevice.hpp index c894684..3a72ec4 100644 --- a/src/TrackerDevice.hpp +++ b/src/TrackerDevice.hpp @@ -22,6 +22,8 @@ namespace SlimeVRDriver { TrackerDevice(std::string serial, int deviceId, TrackerRole trackerRole); ~TrackerDevice() = default; + virtual void BatteryMessage(messages::Battery &battery); + // Inherited via IVRDevice virtual std::string GetSerial() override; virtual void Update() override; diff --git a/src/VRDriver.cpp b/src/VRDriver.cpp index 24b4533..df6550c 100644 --- a/src/VRDriver.cpp +++ b/src/VRDriver.cpp @@ -84,6 +84,12 @@ void SlimeVRDriver::VRDriver::RunFrame() if (device != this->devices_by_id.end()) { device->second->StatusMessage(status); } + } else if (message->has_battery()) { + messages::Battery bat = message->battery(); + auto device = this->devices_by_id.find(bat.tracker_id()); + if (device != this->devices_by_id.end()) { + device->second->BatteryMessage(bat); + } } } @@ -167,6 +173,16 @@ void SlimeVRDriver::VRDriver::RunFrame() hmdPosition->set_qw((float) q.w); sendBridgeMessage(*message, *this); + + vr::ETrackedPropertyError err; + if (vr::VRProperties()->GetBoolProperty(vr::VRProperties()->TrackedDeviceToPropertyContainer(0), vr::Prop_DeviceProvidesBatteryStatus_Bool, &err) == true) { + messages::Battery* hmdBattery = google::protobuf::Arena::CreateMessage(&arena); + message->set_allocated_battery(hmdBattery); + hmdBattery->set_tracker_id(0); + hmdBattery->set_battery_level(vr::VRProperties()->GetFloatProperty(vr::VRProperties()->TrackedDeviceToPropertyContainer(0), vr::Prop_DeviceBatteryPercentage_Float, &err) * 100); + hmdBattery->set_is_charging(vr::VRProperties()->GetBoolProperty(vr::VRProperties()->TrackedDeviceToPropertyContainer(0), vr::Prop_DeviceIsCharging_Bool, &err)); + sendBridgeMessage(*message, *this); + } } else { // If bridge not connected, assume we need to resend hmd tracker add message sentHmdAddMessage = false; diff --git a/src/bridge/ProtobufMessages.proto b/src/bridge/ProtobufMessages.proto index de5d271..95325c1 100644 --- a/src/bridge/ProtobufMessages.proto +++ b/src/bridge/ProtobufMessages.proto @@ -103,11 +103,18 @@ message TrackerStatus { optional Confidence confidence = 4; } +message Battery { + int32 tracker_id = 1; + float battery_level = 2; + bool is_charging = 3; +} + message ProtobufMessage { oneof message { Position position = 1; UserAction user_action = 2; TrackerAdded tracker_added = 3; TrackerStatus tracker_status = 4; + Battery battery = 5; } } \ No newline at end of file