The open source OpenXR runtime

d/rift_s: Port OpenHMD Oculus Rift S driver

Port across the Oculus Rift S driver from OpenHMD as a native
Monado driver.

This is mostly the same as the OpenHMD 3DOF driver, with
slightly better HMD distortion correction, various small
fixes, some capsense touch detection support.

Controller poses are rotated 40° to match grip pose.

+3935
+3
CMakeLists.txt
··· 295 295 option_with_deps(XRT_BUILD_DRIVER_QWERTY "Enable Qwerty driver" DEPENDS XRT_HAVE_SDL2) 296 296 option_with_deps(XRT_BUILD_DRIVER_REALSENSE "Enable RealSense device driver" DEPENDS XRT_HAVE_REALSENSE) 297 297 option_with_deps(XRT_BUILD_DRIVER_REMOTE "Enable remote debugging driver" DEPENDS "XRT_HAVE_LINUX OR ANDROID") 298 + option_with_deps(XRT_BUILD_DRIVER_RIFT_S "Enable Oculus Rift S device driver" DEPENDS XRT_HAVE_HIDAPI XRT_HAVE_V4L2) 298 299 option_with_deps(XRT_BUILD_DRIVER_SURVIVE "Enable libsurvive driver" DEPENDS SURVIVE_FOUND) 299 300 option_with_deps(XRT_BUILD_DRIVER_ULV2 "Enable Ultraleap v2 driver" DEPENDS LeapV2_FOUND) 300 301 option_with_deps(XRT_BUILD_DRIVER_VF "Build video frame driver (for video file support, uses gstreamer)" DEPENDS XRT_HAVE_GST) ··· 347 348 "PSVR" 348 349 "REALSENSE" 349 350 "REMOTE" 351 + "RIFT_S" 350 352 "SURVIVE" 351 353 "V4L2" 352 354 "ULV2" ··· 518 520 message(STATUS "# DRIVER_QWERTY: ${XRT_BUILD_DRIVER_QWERTY}") 519 521 message(STATUS "# DRIVER_REALSENSE: ${XRT_BUILD_DRIVER_REALSENSE}") 520 522 message(STATUS "# DRIVER_REMOTE: ${XRT_BUILD_DRIVER_REMOTE}") 523 + message(STATUS "# DRIVER_RIFT_S: ${XRT_BUILD_DRIVER_RIFT_S}") 521 524 message(STATUS "# DRIVER_SIMULATED: ${XRT_BUILD_DRIVER_SIMULATED}") 522 525 message(STATUS "# DRIVER_SIMULAVR: ${XRT_BUILD_DRIVER_SIMULAVR}") 523 526 message(STATUS "# DRIVER_TWRAP: ${XRT_BUILD_DRIVER_TWRAP}")
+29
src/xrt/drivers/CMakeLists.txt
··· 199 199 list(APPEND ENABLED_HEADSET_DRIVERS remote) 200 200 endif() 201 201 202 + if(XRT_BUILD_DRIVER_RIFT_S) 203 + add_library( 204 + drv_rift_s STATIC 205 + rift_s/rift_s_builder.c 206 + rift_s/rift_s_interface.h 207 + rift_s/rift_s_controller.c 208 + rift_s/rift_s_controller.h 209 + rift_s/rift_s_firmware.c 210 + rift_s/rift_s_firmware.h 211 + rift_s/rift_s_hmd.c 212 + rift_s/rift_s_hmd.h 213 + rift_s/rift_s_protocol.c 214 + rift_s/rift_s_protocol.h 215 + rift_s/rift_s_radio.c 216 + rift_s/rift_s_radio.h 217 + rift_s/rift_s.c 218 + rift_s/rift_s.h 219 + ) 220 + target_link_libraries( 221 + drv_rift_s 222 + PRIVATE 223 + xrt-interfaces 224 + aux_util 225 + aux_math 226 + xrt-external-cjson 227 + ) 228 + list(APPEND ENABLED_HEADSET_DRIVERS rift-s) 229 + endif() 230 + 202 231 set(VIVE_CONFIG_INCLUDE "${CMAKE_CURRENT_SOURCE_DIR}/vive") 203 232 if(XRT_BUILD_DRIVER_VIVE) 204 233 add_library(
+440
src/xrt/drivers/rift_s/rift_s.c
··· 1 + /* 2 + * Copyright 2013, Fredrik Hultin. 3 + * Copyright 2013, Jakob Bornecrantz. 4 + * Copyright 2016 Philipp Zabel 5 + * Copyright 2019-2022 Jan Schmidt 6 + * SPDX-License-Identifier: BSL-1.0 7 + * 8 + */ 9 + 10 + /*! 11 + * @file 12 + * @brief Oculus Rift S headset tracking system 13 + * 14 + * The Rift S system provides the HID/USB polling thread 15 + * and dispatches incoming packets to the HMD and controller 16 + * implementations. 17 + * 18 + * Ported from OpenHMD 19 + * 20 + * @author Jan Schmidt <jan@centricular.com> 21 + * @ingroup drv_rift_s 22 + */ 23 + 24 + /* Oculus Rift S Driver - HID/USB Driver Implementation */ 25 + 26 + #include <stdlib.h> 27 + #include <string.h> 28 + #include <stdio.h> 29 + #include <time.h> 30 + #include <assert.h> 31 + #include <inttypes.h> 32 + 33 + #include "math/m_api.h" 34 + #include "math/m_vec3.h" 35 + 36 + #include "os/os_time.h" 37 + 38 + #include "util/u_device.h" 39 + #include "util/u_distortion_mesh.h" 40 + #include "util/u_trace_marker.h" 41 + #include "util/u_var.h" 42 + 43 + #include "xrt/xrt_device.h" 44 + 45 + #include "rift_s.h" 46 + #include "rift_s_hmd.h" 47 + #include "rift_s_controller.h" 48 + 49 + static void * 50 + rift_s_run_thread(void *ptr); 51 + static void 52 + rift_s_system_free(struct rift_s_system *sys); 53 + 54 + struct rift_s_system * 55 + rift_s_system_create(const unsigned char *hmd_serial_no, 56 + struct os_hid_device *hid_hmd, 57 + struct os_hid_device *hid_status, 58 + struct os_hid_device *hid_controllers) 59 + { 60 + int ret; 61 + 62 + DRV_TRACE_MARKER(); 63 + 64 + struct rift_s_system *sys = U_TYPED_CALLOC(struct rift_s_system); 65 + sys->base.type = XRT_TRACKING_TYPE_NONE; 66 + sys->base.offset.orientation.w = 1.0f; 67 + 68 + /* Init refcount */ 69 + sys->ref.count = 1; 70 + 71 + sys->handles[HMD_HID] = hid_hmd; 72 + sys->handles[STATUS_HID] = hid_status; 73 + sys->handles[CONTROLLER_HID] = hid_controllers; 74 + 75 + ret = os_mutex_init(&sys->dev_mutex); 76 + if (ret != 0) { 77 + RIFT_S_ERROR("Failed to init device mutex"); 78 + goto cleanup; 79 + } 80 + // 81 + // Thread and other state. 82 + ret = os_thread_helper_init(&sys->oth); 83 + if (ret != 0) { 84 + RIFT_S_ERROR("Failed to init packet processing thread"); 85 + goto cleanup; 86 + } 87 + 88 + rift_s_radio_state_init(&sys->radio_state); 89 + 90 + /* Create the HMD now. Controllers are created in the 91 + * rift_s_system_get_controller() call later */ 92 + struct rift_s_hmd *hmd = rift_s_hmd_create(sys, hmd_serial_no); 93 + if (hmd == NULL) { 94 + RIFT_S_ERROR("Failed to create Oculus Rift S device."); 95 + goto cleanup; 96 + } 97 + 98 + sys->hmd = hmd; 99 + 100 + // Start the packet reading thread 101 + ret = os_thread_helper_start(&sys->oth, rift_s_run_thread, sys); 102 + if (ret != 0) { 103 + RIFT_S_ERROR("Failed to start packet processing thread"); 104 + goto cleanup; 105 + } 106 + 107 + /* Turn on the headset and display connection */ 108 + if (rift_s_hmd_enable(sys->handles[HMD_HID], true) < 0) { 109 + RIFT_S_ERROR("Failed to enable Rift S"); 110 + goto cleanup; 111 + } 112 + 113 + // Allow time for enumeration of available displays by host system, so the compositor can select among them. 114 + RIFT_S_INFO( 115 + "Sleeping until the HMD display is powered up so, the available displays " 116 + "can be enumerated by the host system."); 117 + 118 + // Two seconds seems to be needed for the display connection to stabilise 119 + os_nanosleep((uint64_t)U_TIME_1S_IN_NS * 2); 120 + 121 + RIFT_S_DEBUG("Oculus Rift S driver ready"); 122 + 123 + return sys; 124 + 125 + cleanup: 126 + if (sys->hmd != NULL) { 127 + xrt_device_destroy((struct xrt_device **)&sys->hmd); 128 + } 129 + rift_s_system_reference(&sys, NULL); 130 + return NULL; 131 + } 132 + 133 + static void 134 + rift_s_system_free(struct rift_s_system *sys) 135 + { 136 + /* Stop the packet reading thread */ 137 + os_thread_helper_destroy(&sys->oth); 138 + 139 + rift_s_radio_state_clear(&sys->radio_state); 140 + 141 + if (sys->handles[HMD_HID]) { 142 + if (rift_s_hmd_enable(sys->handles[HMD_HID], false) < 0) { 143 + RIFT_S_WARN("Failed to disable Rift S"); 144 + } 145 + } 146 + 147 + for (int i = 0; i < 3; i++) { 148 + if (sys->handles[i] != NULL) 149 + os_hid_destroy(sys->handles[i]); 150 + } 151 + 152 + os_mutex_destroy(&sys->dev_mutex); 153 + 154 + free(sys); 155 + } 156 + 157 + /* Reference count handling for rift_s_system */ 158 + void 159 + rift_s_system_reference(struct rift_s_system **dst, struct rift_s_system *src) 160 + { 161 + struct rift_s_system *old_dst = *dst; 162 + 163 + if (old_dst == src) { 164 + return; 165 + } 166 + 167 + if (src) { 168 + xrt_reference_inc(&src->ref); 169 + } 170 + 171 + *dst = src; 172 + 173 + if (old_dst) { 174 + if (xrt_reference_dec(&old_dst->ref)) { 175 + rift_s_system_free(old_dst); 176 + } 177 + } 178 + } 179 + 180 + struct os_hid_device * 181 + rift_s_system_hid_handle(struct rift_s_system *sys) 182 + { 183 + return sys->handles[HMD_HID]; 184 + } 185 + 186 + rift_s_radio_state * 187 + rift_s_system_radio(struct rift_s_system *sys) 188 + { 189 + return &sys->radio_state; 190 + } 191 + 192 + struct xrt_device * 193 + rift_s_system_get_hmd(struct rift_s_system *sys) 194 + { 195 + return (struct xrt_device *)sys->hmd; 196 + } 197 + 198 + void 199 + rift_s_system_remove_hmd(struct rift_s_system *sys) 200 + { 201 + os_mutex_lock(&sys->dev_mutex); 202 + sys->hmd = NULL; 203 + os_mutex_unlock(&sys->dev_mutex); 204 + } 205 + 206 + struct xrt_device * 207 + rift_s_system_get_controller(struct rift_s_system *sys, int index) 208 + { 209 + assert(index >= 0 || index < MAX_TRACKED_DEVICES); 210 + assert(sys->controllers[index] == NULL); // Ensure only called once per controller 211 + 212 + os_mutex_lock(&sys->dev_mutex); 213 + if (index == 0) { 214 + sys->controllers[0] = rift_s_controller_create(sys, XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER); 215 + } else { 216 + sys->controllers[1] = rift_s_controller_create(sys, XRT_DEVICE_TYPE_RIGHT_HAND_CONTROLLER); 217 + } 218 + os_mutex_unlock(&sys->dev_mutex); 219 + 220 + return (struct xrt_device *)sys->controllers[index]; 221 + } 222 + 223 + void 224 + rift_s_system_remove_controller(struct rift_s_system *sys, struct rift_s_controller *ctrl) 225 + { 226 + os_mutex_lock(&sys->dev_mutex); 227 + 228 + for (int i = 0; i < MAX_TRACKED_DEVICES; i++) { 229 + if (sys->controllers[i] == ctrl) { 230 + sys->controllers[i] = NULL; 231 + break; 232 + } 233 + } 234 + 235 + os_mutex_unlock(&sys->dev_mutex); 236 + } 237 + 238 + /* Packet reading / handling */ 239 + static int 240 + update_tracked_device_types(struct rift_s_system *sys) 241 + { 242 + int res; 243 + rift_s_devices_list_t dev_list; 244 + struct os_hid_device *hid = sys->handles[HMD_HID]; 245 + 246 + res = rift_s_read_devices_list(hid, &dev_list); 247 + if (res < 0) 248 + return res; 249 + 250 + for (int i = 0; i < dev_list.num_devices; i++) { 251 + rift_s_device_type_record_t *dev = dev_list.devices + i; 252 + int d; 253 + 254 + for (d = 0; d < sys->num_active_tracked_devices; d++) { 255 + if (sys->tracked_device[d].device_id == dev->device_id) { 256 + if (sys->tracked_device[d].device_type != dev->device_type) { 257 + sys->tracked_device[d].device_type = dev->device_type; 258 + RIFT_S_DEBUG("Tracked device 0x%16" PRIx64 " type %u now online", 259 + dev->device_id, dev->device_type); 260 + } 261 + break; 262 + } 263 + } 264 + 265 + if (d == sys->num_active_tracked_devices) { 266 + RIFT_S_WARN("Got a device type record for an unknown device 0x%16" PRIx64 "\n", dev->device_id); 267 + } 268 + } 269 + 270 + return 0; 271 + } 272 + 273 + static void 274 + handle_hmd_report(struct rift_s_system *sys, timepoint_ns local_ts, const unsigned char *buf, int size) 275 + { 276 + rift_s_hmd_report_t report; 277 + 278 + if (!rift_s_parse_hmd_report(&report, buf, size)) { 279 + return; 280 + } 281 + 282 + os_mutex_lock(&sys->dev_mutex); 283 + if (sys->hmd != NULL) { 284 + rift_s_hmd_handle_report(sys->hmd, local_ts, &report); 285 + } 286 + os_mutex_unlock(&sys->dev_mutex); 287 + } 288 + 289 + static void 290 + handle_controller_report(struct rift_s_system *sys, timepoint_ns local_ts, const unsigned char *buf, int size) 291 + { 292 + rift_s_controller_report_t report; 293 + 294 + if (!rift_s_parse_controller_report(&report, buf, size)) { 295 + rift_s_hexdump_buffer("Invalid Controller Report", buf, size); 296 + return; 297 + } 298 + 299 + if (report.device_id == 0x00) { 300 + /* Dummy report. Ignore it */ 301 + return; 302 + } 303 + 304 + int i; 305 + struct rift_s_tracked_device *td = NULL; 306 + 307 + for (i = 0; i < sys->num_active_tracked_devices; i++) { 308 + if (sys->tracked_device[i].device_id == report.device_id) { 309 + td = sys->tracked_device + i; 310 + break; 311 + } 312 + } 313 + 314 + if (td == NULL) { 315 + if (sys->num_active_tracked_devices == MAX_TRACKED_DEVICES) { 316 + RIFT_S_ERROR("Too many controllers. Can't add %08" PRIx64 "\n", report.device_id); 317 + return; 318 + } 319 + 320 + /* Add a new controller to the online list */ 321 + td = sys->tracked_device + sys->num_active_tracked_devices; 322 + sys->num_active_tracked_devices++; 323 + 324 + memset(td, 0, sizeof(struct rift_s_tracked_device)); 325 + td->device_id = report.device_id; 326 + 327 + update_tracked_device_types(sys); 328 + } 329 + 330 + struct rift_s_controller *ctrl = NULL; 331 + 332 + os_mutex_lock(&sys->dev_mutex); 333 + 334 + switch (td->device_type) { 335 + /* If we didn't already succeed in reading the type for this device, try again */ 336 + case RIFT_S_DEVICE_TYPE_UNKNOWN: update_tracked_device_types(sys); break; 337 + case RIFT_S_DEVICE_LEFT_CONTROLLER: ctrl = sys->controllers[0]; break; 338 + case RIFT_S_DEVICE_RIGHT_CONTROLLER: ctrl = sys->controllers[1]; break; 339 + default: break; /* Ignore unknown device type */ 340 + } 341 + 342 + if (ctrl != NULL) { 343 + rift_s_controller_update_configuration(ctrl, td->device_id); 344 + 345 + if (!rift_s_controller_handle_report(ctrl, local_ts, &report)) { 346 + rift_s_hexdump_buffer("Invalid Controller Report Content", buf, size); 347 + } 348 + } 349 + os_mutex_unlock(&sys->dev_mutex); 350 + } 351 + 352 + static bool 353 + handle_packets(struct rift_s_system *sys) 354 + { 355 + unsigned char buf[FEATURE_BUFFER_SIZE]; 356 + bool ret = true; 357 + 358 + // Handle keep alive messages 359 + timepoint_ns now = os_monotonic_get_ns(); 360 + 361 + if ((now - sys->last_keep_alive) / U_TIME_1MS_IN_NS >= KEEPALIVE_INTERVAL_MS) { 362 + // send keep alive message 363 + rift_s_send_keepalive(sys->handles[HMD_HID]); 364 + // Update the time of the last keep alive we have sent. 365 + sys->last_keep_alive = now; 366 + } 367 + 368 + /* Poll each of the 3 HID interfaces for messages and process them */ 369 + for (int i = 0; i < 3; i++) { 370 + if (sys->handles[i] == NULL) 371 + continue; 372 + 373 + while (ret) { 374 + int size = os_hid_read(sys->handles[i], buf, FEATURE_BUFFER_SIZE, 0); 375 + if (size < 0) { 376 + RIFT_S_ERROR("error reading from HMD device"); 377 + ret = false; 378 + break; 379 + } else if (size == 0) { 380 + break; // No more messages, return. 381 + } 382 + 383 + now = os_monotonic_get_ns(); 384 + 385 + if (buf[0] == 0x65) 386 + handle_hmd_report(sys, now, buf, size); 387 + else if (buf[0] == 0x67) 388 + handle_controller_report(sys, now, buf, size); 389 + else if (buf[0] == 0x66) { 390 + /* System state packet. Enable the screen if the prox sensor is 391 + * triggered. */ 392 + bool prox_sensor = (buf[1] == 0) ? false : true; 393 + os_mutex_lock(&sys->dev_mutex); 394 + if (sys->hmd != NULL) { 395 + rift_s_hmd_set_proximity(sys->hmd, prox_sensor); 396 + } 397 + os_mutex_unlock(&sys->dev_mutex); 398 + } else { 399 + RIFT_S_WARN("Unknown Rift S report 0x%02x!", buf[0]); 400 + } 401 + } 402 + } 403 + 404 + return ret; 405 + } 406 + 407 + 408 + static void * 409 + rift_s_run_thread(void *ptr) 410 + { 411 + DRV_TRACE_MARKER(); 412 + 413 + struct rift_s_system *sys = (struct rift_s_system *)ptr; 414 + 415 + os_thread_helper_lock(&sys->oth); 416 + while (os_thread_helper_is_running_locked(&sys->oth)) { 417 + os_thread_helper_unlock(&sys->oth); 418 + 419 + bool success = handle_packets(sys); 420 + 421 + if (success) { 422 + rift_s_radio_update(&sys->radio_state, sys->handles[HMD_HID]); 423 + } 424 + 425 + os_thread_helper_lock(&sys->oth); 426 + 427 + if (!success) { 428 + break; 429 + } 430 + 431 + if (os_thread_helper_is_running_locked(&sys->oth)) { 432 + os_nanosleep(U_TIME_1MS_IN_NS / 2); 433 + } 434 + } 435 + os_thread_helper_unlock(&sys->oth); 436 + 437 + RIFT_S_DEBUG("Exiting packet reading thread"); 438 + 439 + return NULL; 440 + }
+106
src/xrt/drivers/rift_s/rift_s.h
··· 1 + /* 2 + * Copyright 2013, Fredrik Hultin. 3 + * Copyright 2013, Jakob Bornecrantz. 4 + * Copyright 2016 Philipp Zabel 5 + * Copyright 2019-2022 Jan Schmidt 6 + * SPDX-License-Identifier: BSL-1.0 7 + * 8 + * OpenHMD - Free and Open Source API and drivers for immersive technology. 9 + */ 10 + 11 + /*! 12 + * @file 13 + * @brief Oculus Rift S Driver Internal Interface 14 + * @author Jan Schmidt <jan@centricular.com> 15 + * @ingroup drv_rift_s 16 + */ 17 + 18 + #pragma once 19 + 20 + #include "os/os_threading.h" 21 + #include "util/u_logging.h" 22 + #include "xrt/xrt_defines.h" 23 + #include "xrt/xrt_tracking.h" 24 + 25 + #include "rift_s_protocol.h" 26 + #include "rift_s_radio.h" 27 + 28 + #ifndef RIFT_S_H 29 + #define RIFT_S_H 30 + 31 + struct rift_s_hmd; 32 + struct rift_s_controller; 33 + 34 + extern enum u_logging_level rift_s_log_level; 35 + 36 + #define RIFT_S_TRACE(...) U_LOG_IFL_T(rift_s_log_level, __VA_ARGS__) 37 + #define RIFT_S_DEBUG(...) U_LOG_IFL_D(rift_s_log_level, __VA_ARGS__) 38 + #define RIFT_S_INFO(...) U_LOG_IFL_I(rift_s_log_level, __VA_ARGS__) 39 + #define RIFT_S_WARN(...) U_LOG_IFL_W(rift_s_log_level, __VA_ARGS__) 40 + #define RIFT_S_ERROR(...) U_LOG_IFL_E(rift_s_log_level, __VA_ARGS__) 41 + 42 + #define MAX_TRACKED_DEVICES 2 43 + 44 + #define HMD_HID 0 45 + #define STATUS_HID 1 46 + #define CONTROLLER_HID 2 47 + 48 + /* Structure to track online devices and type */ 49 + struct rift_s_tracked_device 50 + { 51 + uint64_t device_id; 52 + rift_s_device_type device_type; 53 + }; 54 + 55 + struct rift_s_system 56 + { 57 + struct xrt_tracking_origin base; 58 + struct xrt_reference ref; 59 + 60 + /* Packet processing thread */ 61 + struct os_thread_helper oth; 62 + struct os_hid_device *handles[3]; 63 + uint64_t last_keep_alive; 64 + 65 + /* state tracking for tracked devices on our radio link */ 66 + int num_active_tracked_devices; 67 + struct rift_s_tracked_device tracked_device[MAX_TRACKED_DEVICES]; 68 + 69 + /* Radio comms manager */ 70 + rift_s_radio_state radio_state; 71 + 72 + /* Device lock protects device access */ 73 + struct os_mutex dev_mutex; 74 + 75 + /* HMD device */ 76 + struct rift_s_hmd *hmd; 77 + 78 + /* Controller devices */ 79 + struct rift_s_controller *controllers[MAX_TRACKED_DEVICES]; 80 + }; 81 + 82 + struct rift_s_system * 83 + rift_s_system_create(const unsigned char *hmd_serial_no, 84 + struct os_hid_device *hid_hmd, 85 + struct os_hid_device *hid_status, 86 + struct os_hid_device *hid_controllers); 87 + 88 + struct os_hid_device * 89 + rift_s_system_hid_handle(struct rift_s_system *sys); 90 + rift_s_radio_state * 91 + rift_s_system_radio(struct rift_s_system *sys); 92 + 93 + struct xrt_device * 94 + rift_s_system_get_hmd(struct rift_s_system *sys); 95 + void 96 + rift_s_system_remove_hmd(struct rift_s_system *sys); 97 + 98 + struct xrt_device * 99 + rift_s_system_get_controller(struct rift_s_system *sys, int index); 100 + void 101 + rift_s_system_remove_controller(struct rift_s_system *sys, struct rift_s_controller *ctrl); 102 + 103 + void 104 + rift_s_system_reference(struct rift_s_system **dst, struct rift_s_system *src); 105 + 106 + #endif
+202
src/xrt/drivers/rift_s/rift_s_builder.c
··· 1 + // Copyright 2019, Collabora, Ltd. 2 + // Copyright 2022, Jan Schmidt 3 + // SPDX-License-Identifier: BSL-1.0 4 + /*! 5 + * @file 6 + * @brief Oculus Rift S prober code. 7 + * @author Jan Schmidt <jan@centricular.com> 8 + * @ingroup drv_rift_s 9 + */ 10 + 11 + #include <stdio.h> 12 + #include <stdlib.h> 13 + #include <wchar.h> 14 + 15 + #include "os/os_hid.h" 16 + 17 + #include "xrt/xrt_prober.h" 18 + 19 + #include "util/u_builders.h" 20 + #include "util/u_misc.h" 21 + #include "util/u_debug.h" 22 + #include "util/u_logging.h" 23 + #include "util/u_system_helpers.h" 24 + #include "util/u_trace_marker.h" 25 + 26 + #include "rift_s_interface.h" 27 + #include "rift_s.h" 28 + #include "rift_s_hmd.h" 29 + 30 + enum u_logging_level rift_s_log_level; 31 + 32 + /* Interfaces for the various reports / HID controls */ 33 + #define RIFT_S_INTF_HMD 6 34 + #define RIFT_S_INTF_STATUS 7 35 + #define RIFT_S_INTF_CONTROLLERS 8 36 + 37 + /* 38 + * 39 + * Defines & structs. 40 + * 41 + */ 42 + 43 + DEBUG_GET_ONCE_LOG_OPTION(rift_s_log, "RIFT_S_LOG", U_LOGGING_WARN) 44 + 45 + static xrt_result_t 46 + rift_s_estimate_system(struct xrt_builder *xb, 47 + cJSON *config, 48 + struct xrt_prober *xp, 49 + struct xrt_builder_estimate *estimate) 50 + { 51 + struct xrt_prober_device **xpdevs = NULL; 52 + size_t xpdev_count = 0; 53 + xrt_result_t xret = XRT_SUCCESS; 54 + 55 + U_ZERO(estimate); 56 + 57 + xret = xrt_prober_lock_list(xp, &xpdevs, &xpdev_count); 58 + if (xret != XRT_SUCCESS) { 59 + return xret; 60 + } 61 + 62 + struct xrt_prober_device *dev = 63 + u_builder_find_prober_device(xpdevs, xpdev_count, OCULUS_VR_INC_VID, OCULUS_RIFT_S_PID, XRT_BUS_TYPE_USB); 64 + if (dev != NULL) { 65 + estimate->certain.head = true; 66 + estimate->certain.left = true; 67 + estimate->certain.right = true; 68 + } 69 + 70 + xret = xrt_prober_unlock_list(xp, &xpdevs); 71 + assert(xret == XRT_SUCCESS); 72 + 73 + return XRT_SUCCESS; 74 + } 75 + 76 + static xrt_result_t 77 + rift_s_open_system(struct xrt_builder *xb, cJSON *config, struct xrt_prober *xp, struct xrt_system_devices **out_xsysd) 78 + { 79 + struct xrt_prober_device **xpdevs = NULL; 80 + size_t xpdev_count = 0; 81 + xrt_result_t xret = XRT_SUCCESS; 82 + 83 + assert(out_xsysd != NULL); 84 + assert(*out_xsysd == NULL); 85 + 86 + DRV_TRACE_MARKER(); 87 + 88 + rift_s_log_level = debug_get_log_option_rift_s_log(); 89 + struct u_system_devices *usysd = u_system_devices_allocate(); 90 + 91 + xret = xrt_prober_lock_list(xp, &xpdevs, &xpdev_count); 92 + if (xret != XRT_SUCCESS) { 93 + goto unlock_and_fail; 94 + } 95 + 96 + struct xrt_prober_device *dev_hmd = 97 + u_builder_find_prober_device(xpdevs, xpdev_count, OCULUS_VR_INC_VID, OCULUS_RIFT_S_PID, XRT_BUS_TYPE_USB); 98 + if (dev_hmd == NULL) { 99 + goto unlock_and_fail; 100 + } 101 + 102 + struct os_hid_device *hid_hmd = NULL; 103 + int result = xrt_prober_open_hid_interface(xp, dev_hmd, RIFT_S_INTF_HMD, &hid_hmd); 104 + if (result != 0) { 105 + RIFT_S_ERROR("Failed to open Rift S HMD interface"); 106 + goto unlock_and_fail; 107 + } 108 + 109 + struct os_hid_device *hid_status = NULL; 110 + result = xrt_prober_open_hid_interface(xp, dev_hmd, RIFT_S_INTF_STATUS, &hid_status); 111 + if (result != 0) { 112 + os_hid_destroy(hid_hmd); 113 + RIFT_S_ERROR("Failed to open Rift S status interface"); 114 + goto unlock_and_fail; 115 + } 116 + 117 + struct os_hid_device *hid_controllers = NULL; 118 + result = xrt_prober_open_hid_interface(xp, dev_hmd, RIFT_S_INTF_CONTROLLERS, &hid_controllers); 119 + if (result != 0) { 120 + os_hid_destroy(hid_hmd); 121 + os_hid_destroy(hid_status); 122 + RIFT_S_ERROR("Failed to open Rift S controllers interface"); 123 + goto unlock_and_fail; 124 + } 125 + 126 + unsigned char hmd_serial_no[XRT_DEVICE_NAME_LEN]; 127 + result = xrt_prober_get_string_descriptor(xp, dev_hmd, XRT_PROBER_STRING_SERIAL_NUMBER, hmd_serial_no, 128 + XRT_DEVICE_NAME_LEN); 129 + if (result < 0) { 130 + RIFT_S_WARN("Could not read Rift S serial number from USB"); 131 + snprintf((char *)hmd_serial_no, XRT_DEVICE_NAME_LEN, "Unknown"); 132 + } 133 + 134 + xret = xrt_prober_unlock_list(xp, &xpdevs); 135 + if (xret != XRT_SUCCESS) { 136 + goto fail; 137 + } 138 + 139 + struct rift_s_system *sys = rift_s_system_create(hmd_serial_no, hid_hmd, hid_status, hid_controllers); 140 + if (sys == NULL) { 141 + RIFT_S_ERROR("Failed to initialise Oculus Rift S driver"); 142 + goto fail; 143 + } 144 + 145 + struct xrt_device *xdev = rift_s_system_get_hmd(sys); 146 + usysd->base.xdevs[usysd->base.xdev_count++] = xdev; 147 + usysd->base.roles.head = xdev; 148 + 149 + xdev = rift_s_system_get_controller(sys, 0); 150 + usysd->base.xdevs[usysd->base.xdev_count++] = xdev; 151 + usysd->base.roles.left = xdev; 152 + 153 + xdev = rift_s_system_get_controller(sys, 1); 154 + usysd->base.xdevs[usysd->base.xdev_count++] = xdev; 155 + usysd->base.roles.right = xdev; 156 + 157 + *out_xsysd = &usysd->base; 158 + 159 + return XRT_SUCCESS; 160 + 161 + unlock_and_fail: 162 + xret = xrt_prober_unlock_list(xp, &xpdevs); 163 + if (xret != XRT_SUCCESS) { 164 + return xret; 165 + } 166 + 167 + /* Fallthrough */ 168 + fail: 169 + u_system_devices_destroy(&usysd); 170 + return XRT_ERROR_DEVICE_CREATION_FAILED; 171 + } 172 + 173 + /* 174 + * 175 + * 'Exported' functions. 176 + * 177 + */ 178 + static const char *driver_list[] = { 179 + "rift-s", 180 + }; 181 + 182 + static void 183 + rift_s_destroy(struct xrt_builder *xb) 184 + { 185 + free(xb); 186 + } 187 + 188 + struct xrt_builder * 189 + rift_s_builder_create(void) 190 + { 191 + 192 + struct xrt_builder *xb = U_TYPED_CALLOC(struct xrt_builder); 193 + xb->estimate_system = rift_s_estimate_system; 194 + xb->open_system = rift_s_open_system; 195 + xb->destroy = rift_s_destroy; 196 + xb->identifier = "rift_s"; 197 + xb->name = "Oculus Rift S"; 198 + xb->driver_identifiers = driver_list; 199 + xb->driver_identifier_count = ARRAY_SIZE(driver_list); 200 + 201 + return xb; 202 + }
+736
src/xrt/drivers/rift_s/rift_s_controller.c
··· 1 + /* 2 + * Copyright 2020 Jan Schmidt 3 + * SPDX-License-Identifier: BSL-1.0 4 + * 5 + * OpenHMD - Free and Open Source API and drivers for immersive technology. 6 + */ 7 + /*! 8 + * @file 9 + * @brief Oculus Rift S Touch Controller driver 10 + * 11 + * Handles communication and calibration information for the Touch Controllers 12 + * 13 + * Ported from OpenHMD 14 + * 15 + * @author Jan Schmidt <jan@centricular.com> 16 + * @ingroup drv_rift_s 17 + */ 18 + 19 + 20 + #include <string.h> 21 + #include <stdio.h> 22 + #include <assert.h> 23 + #include <inttypes.h> 24 + 25 + #include "math/m_api.h" 26 + #include "math/m_space.h" 27 + #include "math/m_vec3.h" 28 + 29 + #include "os/os_hid.h" 30 + 31 + #include "util/u_device.h" 32 + #include "util/u_trace_marker.h" 33 + #include "util/u_var.h" 34 + 35 + #include "rift_s.h" 36 + #include "rift_s_hmd.h" 37 + #include "rift_s_radio.h" 38 + #include "rift_s_protocol.h" 39 + #include "rift_s_controller.h" 40 + 41 + /* Set to 1 to print controller states continuously */ 42 + #define DUMP_CONTROLLER_STATE 0 43 + 44 + #define DEG_TO_RAD(D) ((D)*M_PI / 180.) 45 + 46 + static struct xrt_binding_input_pair simple_inputs_rift_s[4] = { 47 + {XRT_INPUT_SIMPLE_SELECT_CLICK, XRT_INPUT_TOUCH_TRIGGER_VALUE}, 48 + {XRT_INPUT_SIMPLE_MENU_CLICK, XRT_INPUT_TOUCH_MENU_CLICK}, 49 + {XRT_INPUT_SIMPLE_GRIP_POSE, XRT_INPUT_TOUCH_GRIP_POSE}, 50 + {XRT_INPUT_SIMPLE_AIM_POSE, XRT_INPUT_TOUCH_AIM_POSE}, 51 + }; 52 + 53 + static struct xrt_binding_output_pair simple_outputs_rift_s[1] = { 54 + {XRT_OUTPUT_NAME_SIMPLE_VIBRATION, XRT_OUTPUT_NAME_TOUCH_HAPTIC}, 55 + }; 56 + 57 + static struct xrt_binding_profile binding_profiles_rift_s[1] = { 58 + { 59 + .name = XRT_DEVICE_SIMPLE_CONTROLLER, 60 + .inputs = simple_inputs_rift_s, 61 + .input_count = ARRAY_SIZE(simple_inputs_rift_s), 62 + .outputs = simple_outputs_rift_s, 63 + .output_count = ARRAY_SIZE(simple_outputs_rift_s), 64 + }, 65 + }; 66 + 67 + enum touch_controller_input_index 68 + { 69 + /* Left controller */ 70 + OCULUS_TOUCH_X_CLICK = 0, 71 + OCULUS_TOUCH_X_TOUCH, 72 + OCULUS_TOUCH_Y_CLICK, 73 + OCULUS_TOUCH_Y_TOUCH, 74 + OCULUS_TOUCH_MENU_CLICK, 75 + 76 + /* Right controller */ 77 + OCULUS_TOUCH_A_CLICK = 0, 78 + OCULUS_TOUCH_A_TOUCH, 79 + OCULUS_TOUCH_B_CLICK, 80 + OCULUS_TOUCH_B_TOUCH, 81 + OCULUS_TOUCH_SYSTEM_CLICK, 82 + 83 + /* Common */ 84 + OCULUS_TOUCH_SQUEEZE_VALUE, 85 + OCULUS_TOUCH_TRIGGER_TOUCH, 86 + OCULUS_TOUCH_TRIGGER_VALUE, 87 + OCULUS_TOUCH_THUMBSTICK_CLICK, 88 + OCULUS_TOUCH_THUMBSTICK_TOUCH, 89 + OCULUS_TOUCH_THUMBSTICK, 90 + OCULUS_TOUCH_THUMBREST_TOUCH, 91 + OCULUS_TOUCH_GRIP_POSE, 92 + OCULUS_TOUCH_AIM_POSE, 93 + 94 + INPUT_INDICES_LAST 95 + }; 96 + #define SET_TOUCH_INPUT(d, NAME) ((d)->base.inputs[OCULUS_TOUCH_##NAME].name = XRT_INPUT_TOUCH_##NAME) 97 + #define DEBUG_TOUCH_INPUT_BOOL(d, NAME, label) \ 98 + u_var_add_bool((d), &(d)->base.inputs[OCULUS_TOUCH_##NAME].value.boolean, label) 99 + #define DEBUG_TOUCH_INPUT_F32(d, NAME, label) \ 100 + u_var_add_f32((d), &(d)->base.inputs[OCULUS_TOUCH_##NAME].value.vec1.x, label) 101 + #define DEBUG_TOUCH_INPUT_VEC2(d, NAME, label1, label2) \ 102 + u_var_add_f32((d), &(d)->base.inputs[OCULUS_TOUCH_##NAME].value.vec2.x, label1); \ 103 + u_var_add_f32((d), &(d)->base.inputs[OCULUS_TOUCH_##NAME].value.vec2.y, label2) 104 + 105 + #if DUMP_CONTROLLER_STATE 106 + static void 107 + print_controller_state(struct rift_s_controller *ctrl) 108 + { 109 + if (rift_s_log_level > U_LOGGING_TRACE) 110 + return; // Only log at TRACE log_level 111 + 112 + /* Dump the controller state if we see something unexpected / unknown, otherwise be quiet */ 113 + if (ctrl->extra_bytes_len == 0 && ctrl->mask08 == 0x50 && ctrl->mask0e == 0) 114 + return; 115 + 116 + char buf[16384] = ""; 117 + int bufsize = sizeof(buf) - 2; 118 + int printed = 0; 119 + 120 + printed += snprintf(buf + printed, bufsize - printed, 121 + "Controller %16lx type 0x%08x IMU ts %8u v2 %x accel %6d %6d %6d gyro %6d %6d %6d | ", 122 + ctrl->device_id, ctrl->device_type, ctrl->imu_timestamp32, ctrl->imu_unknown_varying2, 123 + ctrl->raw_accel[0], ctrl->raw_accel[1], ctrl->raw_accel[2], ctrl->raw_gyro[0], 124 + ctrl->raw_gyro[1], ctrl->raw_gyro[2]); 125 + 126 + printed += snprintf(buf + printed, bufsize - printed, "unk %02x %02x buttons %02x fingers %02x | ", 127 + ctrl->mask08, ctrl->mask0e, ctrl->buttons, ctrl->fingers); 128 + printed += snprintf(buf + printed, bufsize - printed, "trigger %5d grip %5d |", ctrl->trigger, ctrl->grip); 129 + printed += 130 + snprintf(buf + printed, bufsize - printed, "joystick x %5d y %5d |", ctrl->joystick_x, ctrl->joystick_y); 131 + 132 + if (ctrl->device_type == RIFT_S_DEVICE_LEFT_CONTROLLER) { 133 + printed += 134 + snprintf(buf + printed, bufsize - printed, "capsense x %u y %u joy %u trig %u | ", 135 + ctrl->capsense_a_x, ctrl->capsense_b_y, ctrl->capsense_joystick, ctrl->capsense_trigger); 136 + } else if (ctrl->device_type == RIFT_S_DEVICE_RIGHT_CONTROLLER) { 137 + printed += 138 + snprintf(buf + printed, bufsize - printed, "capsense a %u b %u joy %u trig %u | ", 139 + ctrl->capsense_a_x, ctrl->capsense_b_y, ctrl->capsense_joystick, ctrl->capsense_trigger); 140 + } else { 141 + printed += 142 + snprintf(buf + printed, bufsize - printed, "capsense ?? %u ?? %u ?? %u ?? %u | ", 143 + ctrl->capsense_a_x, ctrl->capsense_b_y, ctrl->capsense_joystick, ctrl->capsense_trigger); 144 + } 145 + 146 + if (ctrl->extra_bytes_len) { 147 + printed += snprintf(buf + printed, bufsize - printed, " | extra "); 148 + printed += rift_s_snprintf_hexdump_buffer(buf + printed, bufsize - printed, NULL, ctrl->extra_bytes, 149 + ctrl->extra_bytes_len); 150 + } 151 + 152 + RIFT_S_TRACE("%s", buf); 153 + } 154 + #endif 155 + 156 + static void 157 + handle_imu_update(struct rift_s_controller *ctrl, 158 + timepoint_ns local_ts, 159 + uint32_t imu_timestamp, 160 + const int16_t raw_accel[3], 161 + const int16_t raw_gyro[3]) 162 + { 163 + /* Logic to update 64-bit ns timestamp from 164 + * 32-bit µS device timestamp that wraps every 71.5 minutes */ 165 + uint32_t dt = 0; 166 + 167 + if (ctrl->imu_time_valid) { 168 + dt = imu_timestamp - ctrl->imu_timestamp32; 169 + 170 + /* Sometimes we see 1-2 repeated IMU updates from a controller, 171 + * that must be ignored or else time jumps wildly */ 172 + if (dt == 0 || dt > 2147483648) { 173 + RIFT_S_TRACE("Controller %" PRIx64 " - ignoring repeated IMU update", ctrl->device_id); 174 + return; 175 + } 176 + 177 + ctrl->last_imu_device_time_ns += (timepoint_ns)dt * OS_NS_PER_USEC; 178 + } else { 179 + ctrl->last_imu_device_time_ns = (timepoint_ns)imu_timestamp * OS_NS_PER_USEC; 180 + ctrl->imu_time_valid = true; 181 + } 182 + ctrl->imu_timestamp32 = imu_timestamp; 183 + ctrl->last_imu_local_time_ns = local_ts; 184 + 185 + if (!ctrl->have_calibration || !ctrl->have_config) 186 + return; /* We need to finish reading the calibration or config blocks first */ 187 + 188 + const float gyro_scale = ctrl->config.gyro_scale; 189 + const float accel_scale = MATH_GRAVITY_M_S2 * ctrl->config.accel_scale; 190 + 191 + struct xrt_vec3 gyro, accel; 192 + 193 + gyro.x = DEG_TO_RAD(gyro_scale * raw_gyro[0]); 194 + gyro.y = DEG_TO_RAD(gyro_scale * raw_gyro[1]); 195 + gyro.z = DEG_TO_RAD(gyro_scale * raw_gyro[2]); 196 + 197 + accel.x = accel_scale * raw_accel[0]; 198 + accel.y = accel_scale * raw_accel[1]; 199 + accel.z = accel_scale * raw_accel[2]; 200 + 201 + /* Apply correction offsets first, then rectify */ 202 + accel = m_vec3_sub(accel, ctrl->calibration.accel.offset); 203 + gyro = m_vec3_sub(gyro, ctrl->calibration.gyro.offset); 204 + 205 + math_matrix_3x3_transform_vec3(&ctrl->calibration.accel.rectification, &accel, &ctrl->accel); 206 + math_matrix_3x3_transform_vec3(&ctrl->calibration.gyro.rectification, &gyro, &ctrl->gyro); 207 + 208 + m_imu_3dof_update(&ctrl->fusion, ctrl->last_imu_device_time_ns, &ctrl->accel, &ctrl->gyro); 209 + ctrl->pose.orientation = ctrl->fusion.rot; 210 + 211 + #if 0 212 + RIFT_S_DEBUG("%" PRIx64 " dt %u device time %u ns %" PRIu64 213 + " raw accel %d %d %d gyro %d %d %d -> accel %f %f %f gyro %f %f %f\n", 214 + ctrl->device_id, dt, imu_timestamp, ctrl->last_imu_device_time_ns, raw_accel[0], raw_accel[1], 215 + raw_accel[2], raw_gyro[0], raw_gyro[1], raw_gyro[2], ctrl->accel.x, ctrl->accel.y, ctrl->accel.z, 216 + ctrl->gyro.x, ctrl->gyro.y, ctrl->gyro.z); 217 + #endif 218 + } 219 + 220 + bool 221 + rift_s_controller_handle_report(struct rift_s_controller *ctrl, 222 + timepoint_ns local_ts, 223 + rift_s_controller_report_t *report) 224 + { 225 + #if DUMP_CONTROLLER_STATE 226 + bool saw_imu_update = false; 227 + #endif 228 + bool saw_controls_update = false; 229 + 230 + os_mutex_lock(&ctrl->mutex); 231 + 232 + /* Collect state updates */ 233 + ctrl->extra_bytes_len = 0; 234 + 235 + for (int i = 0; i < report->num_info; i++) { 236 + rift_s_controller_info_block_t *info = report->info + i; 237 + 238 + switch (info->block_id) { 239 + case RIFT_S_CTRL_MASK08: 240 + saw_controls_update = true; 241 + ctrl->mask08 = info->maskbyte.val; 242 + break; 243 + case RIFT_S_CTRL_BUTTONS: 244 + saw_controls_update = true; 245 + ctrl->buttons = info->maskbyte.val; 246 + break; 247 + case RIFT_S_CTRL_FINGERS: 248 + saw_controls_update = true; 249 + ctrl->fingers = info->maskbyte.val; 250 + break; 251 + case RIFT_S_CTRL_MASK0e: 252 + saw_controls_update = true; 253 + ctrl->mask0e = info->maskbyte.val; 254 + break; 255 + case RIFT_S_CTRL_TRIGGRIP: { 256 + saw_controls_update = true; 257 + ctrl->trigger = (uint16_t)(info->triggrip.vals[1] & 0x0f) << 8 | info->triggrip.vals[0]; 258 + ctrl->grip = 259 + (uint16_t)(info->triggrip.vals[1] & 0xf0) >> 4 | ((uint16_t)(info->triggrip.vals[2]) << 4); 260 + break; 261 + } 262 + case RIFT_S_CTRL_JOYSTICK: 263 + saw_controls_update = true; 264 + ctrl->joystick_x = info->joystick.val; 265 + ctrl->joystick_y = info->joystick.val >> 16; 266 + break; 267 + case RIFT_S_CTRL_CAPSENSE: 268 + saw_controls_update = true; 269 + ctrl->capsense_a_x = info->capsense.a_x; 270 + ctrl->capsense_b_y = info->capsense.b_y; 271 + ctrl->capsense_joystick = info->capsense.joystick; 272 + ctrl->capsense_trigger = info->capsense.trigger; 273 + break; 274 + case RIFT_S_CTRL_IMU: { 275 + int j; 276 + 277 + #if DUMP_CONTROLLER_STATE 278 + /* print the state before updating the IMU timestamp a 2nd time */ 279 + if (saw_imu_update) 280 + print_controller_state(ctrl); 281 + saw_imu_update = true; 282 + #endif 283 + 284 + ctrl->imu_unknown_varying2 = info->imu.unknown_varying2; 285 + 286 + for (j = 0; j < 3; j++) { 287 + ctrl->raw_accel[j] = info->imu.accel[j]; 288 + ctrl->raw_gyro[j] = info->imu.gyro[j]; 289 + } 290 + handle_imu_update(ctrl, local_ts, info->imu.timestamp, ctrl->raw_accel, ctrl->raw_gyro); 291 + break; 292 + } 293 + default: 294 + RIFT_S_WARN("Invalid controller info block with ID %02x from device %08" PRIx64 295 + ". Please report it.\n", 296 + info->block_id, ctrl->device_id); 297 + } 298 + } 299 + 300 + if (saw_controls_update) 301 + ctrl->last_controls_local_time_ns = local_ts; 302 + 303 + if (report->extra_bytes_len > 0) { 304 + if (report->extra_bytes_len > sizeof(ctrl->extra_bytes)) { 305 + RIFT_S_WARN("Controller report from %16" PRIx64 " had too many extra bytes - %u (max %u)\n", 306 + ctrl->device_id, report->extra_bytes_len, 307 + (unsigned int)(sizeof(ctrl->extra_bytes))); 308 + report->extra_bytes_len = sizeof(ctrl->extra_bytes); 309 + } 310 + memcpy(ctrl->extra_bytes, report->extra_bytes, report->extra_bytes_len); 311 + } 312 + ctrl->extra_bytes_len = report->extra_bytes_len; 313 + 314 + #if DUMP_CONTROLLER_STATE 315 + print_controller_state(ctrl); 316 + #endif 317 + 318 + /* Finally, update and output the log */ 319 + if (report->flags & 0x04) { 320 + /* New log line is starting, reset the counter */ 321 + ctrl->log_bytes = 0; 322 + } 323 + 324 + if (ctrl->log_flags & 0x04 || (ctrl->log_flags & 0x02) != (report->flags & 0x02)) { 325 + /* New log bytes in this report, collect them */ 326 + for (int i = 0; i < 3; i++) { 327 + uint8_t c = report->log[i]; 328 + if (c != '\0') { 329 + if (ctrl->log_bytes == (MAX_LOG_SIZE - 1)) { 330 + /* Log line got too long... output it */ 331 + ctrl->log[MAX_LOG_SIZE - 1] = '\0'; 332 + RIFT_S_DEBUG("Controller: %s", ctrl->log); 333 + ctrl->log_bytes = 0; 334 + } 335 + ctrl->log[ctrl->log_bytes++] = c; 336 + } else if (ctrl->log_bytes > 0) { 337 + /* Found the end of the string */ 338 + ctrl->log[ctrl->log_bytes] = '\0'; 339 + rift_s_hexdump_buffer("Controller debug", ctrl->log, ctrl->log_bytes); 340 + ctrl->log_bytes = 0; 341 + } 342 + } 343 + } 344 + ctrl->log_flags = report->flags; 345 + 346 + os_mutex_unlock(&ctrl->mutex); 347 + return true; 348 + } 349 + 350 + #define READ_LE16(b) (b)[0] | ((b)[1]) << 8 351 + #define READ_LE32(b) (b)[0] | ((b)[1]) << 8 | ((b)[2]) << 16 | ((b)[3]) << 24 352 + #define READ_LEFLOAT32(b) (*(float *)(b)); 353 + 354 + static void 355 + ctrl_config_cb(bool success, uint8_t *response_bytes, int response_bytes_len, struct rift_s_controller *ctrl) 356 + { 357 + ctrl->reading_config = false; 358 + if (!success) { 359 + RIFT_S_WARN("Failed to read controller config"); 360 + return; 361 + } 362 + 363 + if (response_bytes_len < 5) { 364 + RIFT_S_WARN("Failed to read controller config - short result"); 365 + return; 366 + } 367 + 368 + /* Response 0u32 0x10 00 7d a0 0f f4 01 f4 01 00 00 80 3a ff ff f9 3d 369 + * 0x7d00 = 32000 0x0fa0 = 4000 0x01f4 = 500 0x01f4 = 500 370 + * 0x3a800000 = 0.9765625e-03 = 1/1024 371 + * 0x3df9ffff = 0.1220703 = 1/8192 372 + */ 373 + 374 + response_bytes_len = response_bytes[4]; 375 + if (response_bytes_len < 16) { 376 + char buf[16384] = ""; 377 + int bufsize = sizeof(buf) - 2; 378 + int printed = 0; 379 + 380 + printed += rift_s_snprintf_hexdump_buffer(buf + printed, bufsize - printed, "Controller Config", 381 + response_bytes, response_bytes_len); 382 + 383 + RIFT_S_ERROR("Failed to read controller config block - only got %d bytes\n%s", response_bytes_len, buf); 384 + return; 385 + } 386 + response_bytes += 5; 387 + 388 + ctrl->config.accel_limit = READ_LE16(response_bytes + 0); 389 + ctrl->config.gyro_limit = READ_LE16(response_bytes + 2); 390 + ctrl->config.accel_hz = READ_LE16(response_bytes + 4); 391 + ctrl->config.gyro_hz = READ_LE16(response_bytes + 6); 392 + ctrl->config.accel_scale = READ_LEFLOAT32(response_bytes + 8); 393 + ctrl->config.gyro_scale = READ_LEFLOAT32(response_bytes + 12); 394 + 395 + ctrl->have_config = true; 396 + 397 + RIFT_S_INFO("Read config for controller 0x%16" PRIx64 398 + " type %08x. " 399 + "limit/scale/hz Accel %u %f %u Gyro %u %f %u", 400 + ctrl->device_id, ctrl->device_type, ctrl->config.accel_limit, ctrl->config.accel_scale, 401 + ctrl->config.accel_hz, ctrl->config.gyro_limit, ctrl->config.gyro_scale, ctrl->config.gyro_hz); 402 + } 403 + 404 + static void 405 + ctrl_json_cb(bool success, uint8_t *response_bytes, int response_bytes_len, struct rift_s_controller *ctrl) 406 + { 407 + ctrl->reading_calibration = false; 408 + 409 + if (!success) { 410 + RIFT_S_WARN("Failed to read controller calibration block"); 411 + return; 412 + } 413 + 414 + RIFT_S_TRACE("Got Controller calibration:\n%s", response_bytes); 415 + 416 + if (rift_s_controller_parse_imu_calibration((char *)response_bytes, &ctrl->calibration) == 0) { 417 + ctrl->have_calibration = true; 418 + } else { 419 + RIFT_S_ERROR("Failed to parse controller configuration for controller 0x%16" PRIx64 "\n", 420 + ctrl->device_id); 421 + } 422 + } 423 + 424 + static void 425 + rift_s_update_input_bool(struct rift_s_controller *ctrl, int index, int64_t when_ns, int val) 426 + { 427 + ctrl->base.inputs[index].timestamp = when_ns; 428 + ctrl->base.inputs[index].value.boolean = (val != 0); 429 + } 430 + 431 + static void 432 + rift_s_update_input_analog(struct rift_s_controller *ctrl, int index, int64_t when_ns, float val) 433 + { 434 + ctrl->base.inputs[index].timestamp = when_ns; 435 + ctrl->base.inputs[index].value.vec1.x = val; 436 + } 437 + 438 + static void 439 + rift_s_update_input_vec2(struct rift_s_controller *ctrl, int index, int64_t when_ns, float x, float y) 440 + { 441 + ctrl->base.inputs[index].timestamp = when_ns; 442 + ctrl->base.inputs[index].value.vec2.x = x; 443 + ctrl->base.inputs[index].value.vec2.y = y; 444 + } 445 + 446 + static void 447 + rift_s_controller_update_inputs(struct xrt_device *xdev) 448 + { 449 + struct rift_s_controller *ctrl = (struct rift_s_controller *)(xdev); 450 + 451 + os_mutex_lock(&ctrl->mutex); 452 + 453 + uint64_t last_ns = ctrl->last_controls_local_time_ns; 454 + 455 + if (ctrl->device_type == RIFT_S_DEVICE_LEFT_CONTROLLER) { 456 + rift_s_update_input_bool(ctrl, OCULUS_TOUCH_X_CLICK, last_ns, ctrl->buttons & RIFT_S_BUTTON_A_X); 457 + rift_s_update_input_bool(ctrl, OCULUS_TOUCH_Y_CLICK, last_ns, ctrl->buttons & RIFT_S_BUTTON_B_Y); 458 + rift_s_update_input_bool(ctrl, OCULUS_TOUCH_MENU_CLICK, last_ns, 459 + ctrl->buttons & RIFT_S_BUTTON_MENU_OCULUS); 460 + rift_s_update_input_bool( 461 + ctrl, OCULUS_TOUCH_X_TOUCH, last_ns, 462 + !!((ctrl->fingers & RIFT_S_FINGER_A_X_STRONG) || 463 + ((ctrl->fingers & RIFT_S_FINGER_A_X_WEAK) && 464 + !(ctrl->fingers & (RIFT_S_FINGER_B_Y_STRONG | RIFT_S_FINGER_STICK_STRONG))))); 465 + rift_s_update_input_bool( 466 + ctrl, OCULUS_TOUCH_Y_TOUCH, last_ns, 467 + !!((ctrl->fingers & RIFT_S_FINGER_B_Y_STRONG) || 468 + ((ctrl->fingers & RIFT_S_FINGER_B_Y_WEAK) && 469 + !(ctrl->fingers & (RIFT_S_FINGER_A_X_STRONG | RIFT_S_FINGER_STICK_STRONG))))); 470 + } else { 471 + rift_s_update_input_bool(ctrl, OCULUS_TOUCH_A_CLICK, last_ns, ctrl->buttons & RIFT_S_BUTTON_A_X); 472 + rift_s_update_input_bool(ctrl, OCULUS_TOUCH_B_CLICK, last_ns, ctrl->buttons & RIFT_S_BUTTON_B_Y); 473 + rift_s_update_input_bool(ctrl, OCULUS_TOUCH_SYSTEM_CLICK, last_ns, 474 + ctrl->buttons & RIFT_S_BUTTON_MENU_OCULUS); 475 + rift_s_update_input_bool( 476 + ctrl, OCULUS_TOUCH_A_TOUCH, last_ns, 477 + !!((ctrl->fingers & RIFT_S_FINGER_A_X_STRONG) || 478 + ((ctrl->fingers & RIFT_S_FINGER_A_X_WEAK) && 479 + !(ctrl->fingers & (RIFT_S_FINGER_B_Y_STRONG | RIFT_S_FINGER_STICK_STRONG))))); 480 + rift_s_update_input_bool( 481 + ctrl, OCULUS_TOUCH_B_TOUCH, last_ns, 482 + !!((ctrl->fingers & RIFT_S_FINGER_B_Y_STRONG) || 483 + ((ctrl->fingers & RIFT_S_FINGER_B_Y_WEAK) && 484 + !(ctrl->fingers & (RIFT_S_FINGER_A_X_STRONG | RIFT_S_FINGER_STICK_STRONG))))); 485 + } 486 + 487 + rift_s_update_input_analog(ctrl, OCULUS_TOUCH_SQUEEZE_VALUE, last_ns, 1.0 - (float)(ctrl->grip) / 4096.0); 488 + rift_s_update_input_analog(ctrl, OCULUS_TOUCH_TRIGGER_VALUE, last_ns, 1.0 - (float)(ctrl->trigger) / 4096.0); 489 + 490 + rift_s_update_input_bool(ctrl, OCULUS_TOUCH_TRIGGER_TOUCH, last_ns, 491 + !!(ctrl->fingers & (RIFT_S_FINGER_TRIGGER_WEAK | RIFT_S_FINGER_TRIGGER_STRONG))); 492 + 493 + rift_s_update_input_bool(ctrl, OCULUS_TOUCH_THUMBSTICK_CLICK, last_ns, ctrl->buttons & RIFT_S_BUTTON_STICK); 494 + 495 + rift_s_update_input_bool(ctrl, OCULUS_TOUCH_THUMBSTICK_TOUCH, last_ns, 496 + !!((ctrl->fingers & RIFT_S_FINGER_STICK_STRONG) || 497 + ((ctrl->fingers & RIFT_S_FINGER_STICK_WEAK) && 498 + !(ctrl->fingers & (RIFT_S_FINGER_A_X_STRONG | RIFT_S_FINGER_B_Y_STRONG))))); 499 + 500 + rift_s_update_input_vec2(ctrl, OCULUS_TOUCH_THUMBSTICK, last_ns, 501 + (float)(ctrl->joystick_x) / 32768.0, /* FIXME: Scale this properly */ 502 + (float)(ctrl->joystick_y) / 32768.0 /* FIXME: Scale this properly */ 503 + ); 504 + 505 + /* FIXME: Output touch detections: 506 + OCULUS_TOUCH_THUMBREST_TOUCH, - does Rift S have a thumbrest? 507 + */ 508 + 509 + os_mutex_unlock(&ctrl->mutex); 510 + } 511 + 512 + static void 513 + rift_s_controller_set_output(struct xrt_device *xdev, enum xrt_output_name name, const union xrt_output_value *value) 514 + { 515 + /* TODO: Implement haptic sending */ 516 + } 517 + 518 + static void 519 + rift_s_controller_get_fusion_pose(struct rift_s_controller *ctrl, 520 + enum xrt_input_name name, 521 + uint64_t at_timestamp_ns, 522 + struct xrt_space_relation *out_relation) 523 + { 524 + out_relation->pose = ctrl->pose; 525 + out_relation->linear_velocity.x = 0.0f; 526 + out_relation->linear_velocity.y = 0.0f; 527 + out_relation->linear_velocity.z = 0.0f; 528 + 529 + /*! 530 + * @todo This is hack, fusion reports angvel relative to the device bu 531 + 532 + * it needs to be in relation to the base space. Rotating it with the 533 + * device orientation is enough to get it into the right space, angula 534 + 535 + * velocity is a derivative so needs a special rotation. 536 + */ 537 + math_quat_rotate_derivative(&ctrl->pose.orientation, &ctrl->fusion.last.gyro, &out_relation->angular_velocity); 538 + 539 + out_relation->relation_flags = (enum xrt_space_relation_flags)( 540 + XRT_SPACE_RELATION_ORIENTATION_VALID_BIT | XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT | 541 + XRT_SPACE_RELATION_ANGULAR_VELOCITY_VALID_BIT | XRT_SPACE_RELATION_LINEAR_VELOCITY_VALID_BIT); 542 + } 543 + 544 + static void 545 + rift_s_controller_get_tracked_pose(struct xrt_device *xdev, 546 + enum xrt_input_name name, 547 + uint64_t at_timestamp_ns, 548 + struct xrt_space_relation *out_relation) 549 + { 550 + struct rift_s_controller *ctrl = (struct rift_s_controller *)(xdev); 551 + 552 + if (name != XRT_INPUT_TOUCH_AIM_POSE && name != XRT_INPUT_TOUCH_GRIP_POSE) { 553 + RIFT_S_ERROR("unknown pose name requested"); 554 + return; 555 + } 556 + 557 + struct xrt_relation_chain xrc = {0}; 558 + 559 + struct xrt_pose pose_correction = {0}; 560 + 561 + /* Rotate the grip/aim pose up by 40 degrees around the X axis */ 562 + struct xrt_vec3 axis = {1.0, 0, 0}; 563 + 564 + math_quat_from_angle_vector(DEG_TO_RAD(40), &axis, &pose_correction.orientation); 565 + 566 + m_relation_chain_push_pose(&xrc, &pose_correction); 567 + 568 + /* Apply the fusion rotation */ 569 + struct xrt_space_relation *rel = m_relation_chain_reserve(&xrc); 570 + 571 + os_mutex_lock(&ctrl->mutex); 572 + rift_s_controller_get_fusion_pose(ctrl, name, at_timestamp_ns, rel); 573 + os_mutex_unlock(&ctrl->mutex); 574 + 575 + m_relation_chain_resolve(&xrc, out_relation); 576 + } 577 + 578 + static void 579 + rift_s_controller_get_view_poses(struct xrt_device *xdev, 580 + const struct xrt_vec3 *default_eye_relation, 581 + uint64_t at_timestamp_ns, 582 + uint32_t view_count, 583 + struct xrt_space_relation *out_head_relation, 584 + struct xrt_fov *out_fovs, 585 + struct xrt_pose *out_poses) 586 + { 587 + u_device_get_view_poses(xdev, default_eye_relation, at_timestamp_ns, view_count, out_head_relation, out_fovs, 588 + out_poses); 589 + } 590 + 591 + static void 592 + rift_s_controller_destroy(struct xrt_device *xdev) 593 + { 594 + struct rift_s_controller *ctrl = (struct rift_s_controller *)(xdev); 595 + 596 + /* Tell the system this controller is going away */ 597 + rift_s_system_remove_controller(ctrl->sys, ctrl); 598 + 599 + /* Release the HMD reference */ 600 + rift_s_system_reference(&ctrl->sys, NULL); 601 + 602 + u_var_remove_root(ctrl); 603 + 604 + m_imu_3dof_close(&ctrl->fusion); 605 + 606 + os_mutex_destroy(&ctrl->mutex); 607 + 608 + u_device_free(&ctrl->base); 609 + } 610 + 611 + struct rift_s_controller * 612 + rift_s_controller_create(struct rift_s_system *sys, enum xrt_device_type device_type) 613 + { 614 + DRV_TRACE_MARKER(); 615 + 616 + enum u_device_alloc_flags flags = (enum u_device_alloc_flags)(U_DEVICE_ALLOC_TRACKING_NONE); 617 + 618 + struct rift_s_controller *ctrl = U_DEVICE_ALLOCATE(struct rift_s_controller, flags, INPUT_INDICES_LAST, 1); 619 + if (ctrl == NULL) { 620 + return NULL; 621 + } 622 + 623 + /* Store a ref to the parent hmd, released in destroy */ 624 + rift_s_system_reference(&ctrl->sys, sys); 625 + 626 + os_mutex_init(&ctrl->mutex); 627 + 628 + ctrl->base.update_inputs = rift_s_controller_update_inputs; 629 + ctrl->base.set_output = rift_s_controller_set_output; 630 + ctrl->base.get_tracked_pose = rift_s_controller_get_tracked_pose; 631 + ctrl->base.get_view_poses = rift_s_controller_get_view_poses; 632 + ctrl->base.destroy = rift_s_controller_destroy; 633 + ctrl->base.name = XRT_DEVICE_TOUCH_CONTROLLER; 634 + ctrl->base.device_type = device_type; 635 + 636 + if (device_type == XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER) { 637 + ctrl->device_type = RIFT_S_DEVICE_LEFT_CONTROLLER; 638 + } else { 639 + ctrl->device_type = RIFT_S_DEVICE_RIGHT_CONTROLLER; 640 + } 641 + 642 + ctrl->pose.orientation.w = 1.0f; // All other values set to zero by U_DEVICE_ALLOCATE (which calls U_CALLOC) 643 + m_imu_3dof_init(&ctrl->fusion, M_IMU_3DOF_USE_GRAVITY_DUR_20MS); 644 + 645 + // Setup inputs and outputs 646 + if (device_type == XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER) { 647 + snprintf(ctrl->base.str, XRT_DEVICE_NAME_LEN, "Oculus Rift S Left Touch Controller"); 648 + snprintf(ctrl->base.serial, XRT_DEVICE_NAME_LEN, "Left Controller"); 649 + SET_TOUCH_INPUT(ctrl, X_CLICK); 650 + SET_TOUCH_INPUT(ctrl, X_TOUCH); 651 + SET_TOUCH_INPUT(ctrl, Y_CLICK); 652 + SET_TOUCH_INPUT(ctrl, Y_TOUCH); 653 + SET_TOUCH_INPUT(ctrl, MENU_CLICK); 654 + } else { 655 + snprintf(ctrl->base.str, XRT_DEVICE_NAME_LEN, "Oculus Rift S Right Touch Controller"); 656 + snprintf(ctrl->base.serial, XRT_DEVICE_NAME_LEN, "Right Controller"); 657 + SET_TOUCH_INPUT(ctrl, A_CLICK); 658 + SET_TOUCH_INPUT(ctrl, A_TOUCH); 659 + SET_TOUCH_INPUT(ctrl, B_CLICK); 660 + SET_TOUCH_INPUT(ctrl, B_TOUCH); 661 + SET_TOUCH_INPUT(ctrl, SYSTEM_CLICK); 662 + } 663 + 664 + SET_TOUCH_INPUT(ctrl, SQUEEZE_VALUE); 665 + SET_TOUCH_INPUT(ctrl, TRIGGER_TOUCH); 666 + SET_TOUCH_INPUT(ctrl, TRIGGER_VALUE); 667 + SET_TOUCH_INPUT(ctrl, THUMBSTICK_CLICK); 668 + SET_TOUCH_INPUT(ctrl, THUMBSTICK_TOUCH); 669 + SET_TOUCH_INPUT(ctrl, THUMBSTICK); 670 + SET_TOUCH_INPUT(ctrl, THUMBREST_TOUCH); 671 + SET_TOUCH_INPUT(ctrl, GRIP_POSE); 672 + SET_TOUCH_INPUT(ctrl, AIM_POSE); 673 + 674 + ctrl->base.outputs[0].name = XRT_OUTPUT_NAME_TOUCH_HAPTIC; 675 + 676 + ctrl->base.binding_profiles = binding_profiles_rift_s; 677 + ctrl->base.binding_profile_count = ARRAY_SIZE(binding_profiles_rift_s); 678 + 679 + u_var_add_root(ctrl, ctrl->base.str, true); 680 + u_var_add_gui_header(ctrl, NULL, "Tracking"); 681 + u_var_add_pose(ctrl, &ctrl->pose, "Tracked Pose"); 682 + 683 + u_var_add_gui_header(ctrl, NULL, "3DoF Tracking"); 684 + m_imu_3dof_add_vars(&ctrl->fusion, ctrl, ""); 685 + 686 + u_var_add_gui_header(ctrl, NULL, "Controls"); 687 + if (device_type == XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER) { 688 + DEBUG_TOUCH_INPUT_BOOL(ctrl, X_CLICK, "X button"); 689 + DEBUG_TOUCH_INPUT_BOOL(ctrl, X_TOUCH, "X button touch"); 690 + DEBUG_TOUCH_INPUT_BOOL(ctrl, Y_CLICK, "Y button"); 691 + DEBUG_TOUCH_INPUT_BOOL(ctrl, Y_TOUCH, "Y button touch"); 692 + DEBUG_TOUCH_INPUT_BOOL(ctrl, MENU_CLICK, "Menu button"); 693 + } else { 694 + DEBUG_TOUCH_INPUT_BOOL(ctrl, A_CLICK, "A button"); 695 + DEBUG_TOUCH_INPUT_BOOL(ctrl, A_TOUCH, "A button touch"); 696 + DEBUG_TOUCH_INPUT_BOOL(ctrl, B_CLICK, "B button"); 697 + DEBUG_TOUCH_INPUT_BOOL(ctrl, B_TOUCH, "B button touch"); 698 + DEBUG_TOUCH_INPUT_BOOL(ctrl, SYSTEM_CLICK, "Oculus button"); 699 + } 700 + 701 + DEBUG_TOUCH_INPUT_F32(ctrl, SQUEEZE_VALUE, "Grip value"); 702 + 703 + DEBUG_TOUCH_INPUT_BOOL(ctrl, TRIGGER_TOUCH, "Trigger touch"); 704 + DEBUG_TOUCH_INPUT_F32(ctrl, TRIGGER_VALUE, "Trigger"); 705 + DEBUG_TOUCH_INPUT_BOOL(ctrl, THUMBSTICK_CLICK, "Thumbstick click"); 706 + DEBUG_TOUCH_INPUT_BOOL(ctrl, THUMBSTICK_TOUCH, "Thumbstick touch"); 707 + DEBUG_TOUCH_INPUT_VEC2(ctrl, THUMBSTICK, "Thumbstick X", "Thumbstick Y"); 708 + DEBUG_TOUCH_INPUT_BOOL(ctrl, THUMBREST_TOUCH, "Thumbrest touch"); 709 + 710 + return ctrl; 711 + } 712 + 713 + void 714 + rift_s_controller_update_configuration(struct rift_s_controller *ctrl, uint64_t device_id) 715 + { 716 + rift_s_radio_state *radio = rift_s_system_radio(ctrl->sys); 717 + 718 + if (ctrl->device_id != device_id) { 719 + ctrl->device_id = device_id; 720 + snprintf(ctrl->base.serial, XRT_DEVICE_NAME_LEN, "%016" PRIx64, device_id); 721 + // If the device ID changed somehow, re-read the JSON blocks 722 + ctrl->have_config = ctrl->have_calibration = false; 723 + } 724 + 725 + if (!ctrl->have_config && !ctrl->reading_config) { 726 + const uint8_t config_req[] = {0x32, 0x20, 0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 727 + rift_s_radio_queue_command(radio, ctrl->device_id, config_req, sizeof(config_req), 728 + (rift_s_radio_completion_fn)ctrl_config_cb, ctrl); 729 + ctrl->reading_config = true; 730 + } 731 + 732 + if (!ctrl->have_calibration && !ctrl->reading_calibration) { 733 + rift_s_radio_get_json_block(radio, ctrl->device_id, (rift_s_radio_completion_fn)ctrl_json_cb, ctrl); 734 + ctrl->reading_calibration = true; 735 + } 736 + }
+117
src/xrt/drivers/rift_s/rift_s_controller.h
··· 1 + /* 2 + * Copyright 2020 Jan Schmidt 3 + * SPDX-License-Identifier: BSL-1.0 4 + * 5 + * OpenHMD - Free and Open Source API and drivers for immersive technology. 6 + */ 7 + 8 + /*! 9 + * @file 10 + * @brief Oculus Rift S Touch Controller interface 11 + * @author Jan Schmidt <jan@centricular.com> 12 + * @ingroup drv_rift_s 13 + */ 14 + 15 + #ifndef RIFT_S_CONTROLLER_H 16 + #define RIFT_S_CONTROLLER_H 17 + 18 + #include "math/m_imu_3dof.h" 19 + 20 + #include "os/os_time.h" 21 + #include "xrt/xrt_device.h" 22 + 23 + #include "rift_s.h" 24 + 25 + #define MAX_LOG_SIZE 1024 26 + 27 + typedef struct 28 + { 29 + uint16_t accel_limit; 30 + uint16_t gyro_limit; 31 + uint16_t accel_hz; 32 + uint16_t gyro_hz; 33 + 34 + float accel_scale; 35 + float gyro_scale; 36 + } rift_s_controller_config; 37 + 38 + struct rift_s_controller 39 + { 40 + struct xrt_device base; 41 + 42 + struct os_mutex mutex; 43 + 44 + struct xrt_pose pose; 45 + 46 + /* The system this controller belongs to / receives reports from */ 47 + struct rift_s_system *sys; 48 + 49 + uint64_t device_id; 50 + rift_s_device_type device_type; 51 + 52 + /* Debug logs */ 53 + /* 0x04 = new log line 54 + * 0x02 = parity bit, toggles each line when receiving log chars 55 + * other bits, unknown */ 56 + uint8_t log_flags; 57 + int log_bytes; 58 + uint8_t log[MAX_LOG_SIZE]; 59 + 60 + /* IMU tracking */ 61 + bool imu_time_valid; 62 + uint32_t imu_timestamp32; 63 + timepoint_ns last_imu_device_time_ns; 64 + timepoint_ns last_imu_local_time_ns; 65 + 66 + uint16_t imu_unknown_varying2; 67 + int16_t raw_accel[3]; 68 + int16_t raw_gyro[3]; 69 + 70 + struct xrt_vec3 accel; 71 + struct xrt_vec3 gyro; 72 + struct xrt_vec3 mag; 73 + struct m_imu_3dof fusion; 74 + 75 + /* Controls / buttons state */ 76 + timepoint_ns last_controls_local_time_ns; 77 + 78 + /* 0x8, 0x0c 0x0d or 0xe block */ 79 + uint8_t mask08; 80 + uint8_t buttons; 81 + uint8_t fingers; 82 + uint8_t mask0e; 83 + 84 + uint16_t trigger; 85 + uint16_t grip; 86 + 87 + int16_t joystick_x; 88 + int16_t joystick_y; 89 + 90 + uint8_t capsense_a_x; 91 + uint8_t capsense_b_y; 92 + uint8_t capsense_joystick; 93 + uint8_t capsense_trigger; 94 + 95 + uint8_t extra_bytes_len; 96 + uint8_t extra_bytes[48]; 97 + 98 + bool reading_config; 99 + bool have_config; 100 + rift_s_controller_config config; 101 + 102 + bool reading_calibration; 103 + bool have_calibration; 104 + struct rift_s_controller_imu_calibration calibration; 105 + }; 106 + 107 + struct rift_s_controller * 108 + rift_s_controller_create(struct rift_s_system *sys, enum xrt_device_type device_type); 109 + 110 + void 111 + rift_s_controller_update_configuration(struct rift_s_controller *ctrl, uint64_t device_id); 112 + bool 113 + rift_s_controller_handle_report(struct rift_s_controller *ctrl, 114 + timepoint_ns local_ts, 115 + rift_s_controller_report_t *report); 116 + 117 + #endif
+423
src/xrt/drivers/rift_s/rift_s_firmware.c
··· 1 + /* 2 + * Copyright 2020 Jan Schmidt 3 + * SPDX-License-Identifier: BSL-1.0 4 + * 5 + * OpenHMD - Free and Open Source API and drivers for immersive technology. 6 + */ 7 + /*! 8 + * @file 9 + * @brief Oculus Rift S firmware parsing 10 + * 11 + * Functions for parsing JSON configuration from the HMD 12 + * and Touch Controller firmware. 13 + * 14 + * @author Jan Schmidt <jan@centricular.com> 15 + * @ingroup drv_rift_s 16 + */ 17 + 18 + /* Oculus Rift S Driver - firmware JSON parsing functions */ 19 + #include <string.h> 20 + #include <stdio.h> 21 + 22 + #include "util/u_json.h" 23 + #include "util/u_misc.h" 24 + 25 + #include "rift_s_firmware.h" 26 + 27 + #define JSON_INT(a, b, c) u_json_get_int(u_json_get(a, b), c) 28 + #define JSON_FLOAT(a, b, c) u_json_get_float(u_json_get(a, b), c) 29 + #define JSON_DOUBLE(a, b, c) u_json_get_double(u_json_get(a, b), c) 30 + #define JSON_VEC3(a, b, c) u_json_get_vec3_array(u_json_get(a, b), c) 31 + #define JSON_MATRIX_3X3_ARRAY(a, b, c) u_json_get_float_array(u_json_get(a, b), c.v, 9) 32 + #define JSON_MATRIX_4x4_ARRAY(a, b, c) u_json_get_float_array(u_json_get(a, b), c.v, 16) 33 + 34 + int 35 + rift_s_parse_proximity_threshold(char *json_string, int *proximity_threshold) 36 + { 37 + cJSON *json_root = cJSON_Parse(json_string); 38 + if (!cJSON_IsObject(json_root)) { 39 + RIFT_S_ERROR("Could not parse JSON IMU calibration data."); 40 + cJSON_Delete(json_root); 41 + return -1; 42 + } 43 + 44 + if (!JSON_INT(json_root, "threshold", proximity_threshold)) 45 + goto fail; 46 + 47 + cJSON_Delete(json_root); 48 + return 0; 49 + 50 + fail: 51 + RIFT_S_WARN("Unrecognised Rift S Proximity Threshold JSON data.\n%s", json_string); 52 + cJSON_Delete(json_root); 53 + return -1; 54 + } 55 + 56 + static bool 57 + check_file_format_version(cJSON *json_root, float expected_version, float *version_number) 58 + { 59 + const cJSON *obj = u_json_get(json_root, "FileFormat"); 60 + if (!cJSON_IsObject(json_root)) { 61 + return false; 62 + } 63 + 64 + const cJSON *version = u_json_get(obj, "Version"); 65 + char *version_str = cJSON_GetStringValue(version); 66 + if (version_str == NULL) { 67 + return false; 68 + } 69 + 70 + *version_number = strtof(version_str, NULL); 71 + if (*version_number != expected_version) 72 + return false; 73 + 74 + return true; 75 + } 76 + 77 + int 78 + rift_s_parse_imu_calibration(char *json_string, struct rift_s_imu_calibration *c) 79 + { 80 + const cJSON *obj, *imu; 81 + float version_number = -1; 82 + 83 + cJSON *json_root = cJSON_Parse(json_string); 84 + if (!cJSON_IsObject(json_root)) { 85 + RIFT_S_ERROR("Could not parse JSON IMU calibration data."); 86 + cJSON_Delete(json_root); 87 + return -1; 88 + } 89 + 90 + if (!check_file_format_version(json_root, 1.0, &version_number)) { 91 + goto fail; 92 + } 93 + 94 + imu = u_json_get(json_root, "ImuCalibration"); 95 + if (!cJSON_IsObject(imu)) { 96 + goto fail; 97 + } 98 + 99 + if (!JSON_MATRIX_4x4_ARRAY(imu, "DeviceFromImu", c->device_from_imu)) 100 + goto fail; 101 + 102 + /* Monado / Eigen expect column major 4x4 isometry, so transpose */ 103 + math_matrix_4x4_transpose(&c->device_from_imu, &c->device_from_imu); 104 + 105 + obj = u_json_get(imu, "Gyroscope"); 106 + if (!cJSON_IsObject(obj) || !JSON_MATRIX_3X3_ARRAY(obj, "RectificationMatrix", c->gyro.rectification)) { 107 + goto fail; 108 + } 109 + 110 + obj = u_json_get(obj, "Offset"); 111 + if (!cJSON_IsObject(obj) || !JSON_VEC3(obj, "ConstantOffset", &c->gyro.offset)) { 112 + goto fail; 113 + } 114 + 115 + obj = u_json_get(imu, "Accelerometer"); 116 + if (!cJSON_IsObject(obj) || !JSON_MATRIX_3X3_ARRAY(obj, "RectificationMatrix", c->accel.rectification)) { 117 + goto fail; 118 + } 119 + 120 + obj = u_json_get(obj, "Offset"); 121 + if (!cJSON_IsObject(obj) || !JSON_VEC3(obj, "OffsetAtZeroDegC", &c->accel.offset_at_0C) || 122 + !JSON_VEC3(obj, "OffsetTemperatureCoefficient", &c->accel.temp_coeff)) { 123 + goto fail; 124 + } 125 + 126 + cJSON_Delete(json_root); 127 + return 0; 128 + 129 + fail: 130 + RIFT_S_WARN("Unrecognised Rift S IMU Calibration JSON data. Version %f\n%s\n", version_number, json_string); 131 + cJSON_Delete(json_root); 132 + return -1; 133 + } 134 + 135 + static bool 136 + rift_s_config_parse_camera_config(struct rift_s_camera_calibration *cam_config, int camera_id, const cJSON *camera_json) 137 + { 138 + const cJSON *obj, *item; 139 + int id = -1; 140 + 141 + item = u_json_get(camera_json, "Id"); 142 + if (item == NULL || (id = strtol(cJSON_GetStringValue(item), NULL, 10)) != camera_id) { 143 + RIFT_S_ERROR("Camera entry id %d doesn't match expected %d", id, camera_id); 144 + return false; 145 + } 146 + 147 + int camera_dims[2]; 148 + 149 + obj = u_json_get(camera_json, "ImageSize"); 150 + if (obj == NULL || u_json_get_int_array(obj, camera_dims, 2) != (size_t)2) { 151 + RIFT_S_ERROR("Missing/invalid camera ImageSize in camera %d", camera_id); 152 + return false; 153 + } 154 + 155 + cam_config->roi.extent.w = camera_dims[0]; 156 + cam_config->roi.extent.h = camera_dims[1]; 157 + 158 + /* Camera images are stacked horizontally in the received image */ 159 + cam_config->roi.offset.w = camera_id * cam_config->roi.extent.w; 160 + cam_config->roi.offset.h = 0; 161 + 162 + if (!JSON_MATRIX_4x4_ARRAY(camera_json, "DeviceFromCamera", cam_config->device_from_camera)) { 163 + RIFT_S_ERROR("Missing/invalid camera DeviceFromCamera in camera %d", camera_id); 164 + return false; 165 + } 166 + 167 + /* Monado / Eigen expect column major 4x4 isometry, so transpose */ 168 + math_matrix_4x4_transpose(&cam_config->device_from_camera, &cam_config->device_from_camera); 169 + 170 + obj = u_json_get(camera_json, "Projection"); 171 + item = u_json_get(obj, "Model"); 172 + if (item == NULL || strcmp(cJSON_GetStringValue(item), "PinholeSymmetric") != 0) { 173 + RIFT_S_ERROR("Missing/invalid camera projection model type %s in camera %d", 174 + item != NULL ? cJSON_GetStringValue(item) : "NULL", camera_id); 175 + return false; 176 + } 177 + 178 + /* Projection coefficients f, cx, cy */ 179 + float focal_params[3]; 180 + 181 + item = u_json_get(obj, "Coefficients"); 182 + if (item == NULL || u_json_get_float_array(item, focal_params, 3) != (size_t)3) { 183 + RIFT_S_ERROR("Missing/invalid camera projection coefficients in camera %d", camera_id); 184 + return false; 185 + } 186 + 187 + cam_config->projection.fx = cam_config->projection.fy = focal_params[0]; 188 + cam_config->projection.cx = focal_params[1]; 189 + cam_config->projection.cy = focal_params[2]; 190 + 191 + /* Fisheye62 distortion */ 192 + obj = u_json_get(camera_json, "Distortion"); 193 + item = u_json_get(obj, "Model"); 194 + if (item == NULL || strcmp(cJSON_GetStringValue(item), "Fisheye62") != 0) { 195 + RIFT_S_ERROR("Missing/invalid camera distortion model type %s in camera %d", 196 + item != NULL ? cJSON_GetStringValue(item) : "NULL", camera_id); 197 + return false; 198 + } 199 + 200 + /* Projection coefficients k1, k2, k3, k4, k5, k6, p1, p2 */ 201 + float dist_params[8]; 202 + 203 + item = u_json_get(obj, "Coefficients"); 204 + if (item == NULL || u_json_get_float_array(item, dist_params, 8) != (size_t)8) { 205 + RIFT_S_ERROR("Missing/invalid camera distortion coefficients in camera %d", camera_id); 206 + return false; 207 + } 208 + 209 + for (int i = 0; i < 6; i++) { 210 + cam_config->distortion.k[i] = dist_params[i]; 211 + } 212 + cam_config->distortion.p1 = dist_params[6]; 213 + cam_config->distortion.p2 = dist_params[7]; 214 + 215 + return true; 216 + } 217 + 218 + int 219 + rift_s_parse_camera_calibration_block(char *json_string, struct rift_s_camera_calibration_block *c) 220 + { 221 + const cJSON *item; 222 + float version_number = -1; 223 + 224 + cJSON *json_root = cJSON_Parse(json_string); 225 + if (!cJSON_IsObject(json_root)) { 226 + RIFT_S_ERROR("Could not parse JSON camera calibration data."); 227 + cJSON_Delete(json_root); 228 + return -1; 229 + } 230 + 231 + if (!check_file_format_version(json_root, 1.0, &version_number)) { 232 + goto fail; 233 + } 234 + 235 + cJSON *cameras = cJSON_GetObjectItemCaseSensitive(json_root, "CameraCalibration"); 236 + if (!cJSON_IsArray(cameras)) { 237 + RIFT_S_ERROR("Cameras: not found or not an Array"); 238 + return false; 239 + } 240 + 241 + int camera_id = 0; 242 + cJSON_ArrayForEach(item, cameras) 243 + { 244 + if (camera_id == RIFT_S_MAX_CAMERAS) { 245 + RIFT_S_ERROR("Too many camera calibration entries"); 246 + goto fail; 247 + } 248 + 249 + if (!rift_s_config_parse_camera_config(c->cameras + camera_id, camera_id, item)) { 250 + goto fail; 251 + } 252 + 253 + camera_id++; 254 + } 255 + 256 + 257 + cJSON_Delete(json_root); 258 + return 0; 259 + 260 + fail: 261 + RIFT_S_WARN("Unrecognised Rift S Camera Calibration JSON data. Version %f\n%s\n", version_number, json_string); 262 + cJSON_Delete(json_root); 263 + return -1; 264 + } 265 + 266 + static bool 267 + json_read_led_point(const cJSON *led_model, struct rift_s_led *led, int n) 268 + { 269 + const cJSON *array; 270 + double point[9]; 271 + char name[32]; 272 + 273 + snprintf(name, 32, "Point%d", n); 274 + array = u_json_get(led_model, name); 275 + if (!cJSON_IsArray(array) || cJSON_GetArraySize(array) != 9) { 276 + return false; 277 + } 278 + 279 + int j = 0; 280 + const cJSON *item = NULL; 281 + cJSON_ArrayForEach(item, array) 282 + { 283 + if (!cJSON_IsNumber(item)) { 284 + return false; 285 + } 286 + point[j++] = item->valuedouble; 287 + } 288 + 289 + led->pos.x = point[0]; 290 + led->pos.y = point[1]; 291 + led->pos.z = point[2]; 292 + led->dir.x = point[3]; 293 + led->dir.y = point[4]; 294 + led->dir.z = point[5]; 295 + led->angles.x = point[6]; 296 + led->angles.y = point[7]; 297 + led->angles.z = point[8]; 298 + 299 + return true; 300 + } 301 + 302 + static bool 303 + json_read_lensing_model(const cJSON *lensing_model, struct rift_s_lensing_model *model, int n) 304 + { 305 + const cJSON *array; 306 + char name[32]; 307 + 308 + snprintf(name, 32, "Model%d", n); 309 + array = u_json_get(lensing_model, name); 310 + if (!cJSON_IsArray(array) || cJSON_GetArraySize(array) != 5) { 311 + return false; 312 + } 313 + 314 + model->num_points = cJSON_GetArrayItem(array, 0)->valueint; 315 + 316 + for (int j = 0; j < 4; j++) { 317 + const cJSON *item = cJSON_GetArrayItem(array, j + 1); 318 + if (!cJSON_IsNumber(item)) { 319 + return false; 320 + } 321 + 322 + model->points[j] = item->valuedouble; 323 + } 324 + 325 + return true; 326 + } 327 + 328 + int 329 + rift_s_controller_parse_imu_calibration(char *json_string, struct rift_s_controller_imu_calibration *c) 330 + { 331 + const cJSON *obj, *version, *leds; 332 + const cJSON *item = NULL; 333 + int i; 334 + 335 + cJSON *json_root = cJSON_Parse(json_string); 336 + if (!cJSON_IsObject(json_root)) { 337 + RIFT_S_ERROR("Could not parse JSON Controller IMU calibration data."); 338 + cJSON_Delete(json_root); 339 + return -1; 340 + } 341 + 342 + obj = u_json_get(json_root, "TrackedObject"); 343 + if (!cJSON_IsObject(obj)) { 344 + goto fail; 345 + } 346 + 347 + version = u_json_get(obj, "FlsVersion"); 348 + char *version_str = cJSON_GetStringValue(version); 349 + if (version_str == NULL || strcmp(version_str, "1.0.10")) { 350 + RIFT_S_ERROR("Controller calibration version number has changed - got %s", version_str); 351 + goto fail; 352 + } 353 + 354 + if (!JSON_VEC3(obj, "ImuPosition", &c->imu_position)) 355 + goto fail; 356 + 357 + if (!JSON_MATRIX_4x4_ARRAY(obj, "AccCalibration", c->accel_calibration)) 358 + goto fail; 359 + 360 + if (!JSON_MATRIX_4x4_ARRAY(obj, "GyroCalibration", c->gyro_calibration)) 361 + goto fail; 362 + 363 + /* LED positions */ 364 + leds = u_json_get(obj, "ModelPoints"); 365 + if (!cJSON_IsObject(leds)) { 366 + goto fail; 367 + } 368 + 369 + c->num_leds = cJSON_GetArraySize(leds); 370 + c->leds = calloc(c->num_leds, sizeof(struct rift_s_led)); 371 + i = 0; 372 + cJSON_ArrayForEach(item, leds) 373 + { 374 + if (!json_read_led_point(leds, c->leds + i, i)) 375 + goto fail; 376 + i++; 377 + } 378 + 379 + /* LED lensing models */ 380 + leds = u_json_get(obj, "Lensing"); 381 + if (!cJSON_IsObject(leds)) { 382 + goto fail; 383 + } 384 + 385 + c->num_lensing_models = cJSON_GetArraySize(leds); 386 + c->lensing_models = calloc(c->num_lensing_models, sizeof(struct rift_s_lensing_model)); 387 + i = 0; 388 + cJSON_ArrayForEach(item, leds) 389 + { 390 + if (!json_read_lensing_model(leds, c->lensing_models + i, i)) 391 + goto fail; 392 + } 393 + 394 + if (!JSON_MATRIX_3X3_ARRAY(json_root, "gyro_m", c->gyro.rectification) || 395 + !JSON_VEC3(json_root, "gyro_b", &c->gyro.offset) || 396 + !JSON_MATRIX_3X3_ARRAY(json_root, "acc_m", c->accel.rectification) || 397 + !JSON_VEC3(json_root, "acc_b", &c->accel.offset)) { 398 + goto fail; 399 + } 400 + 401 + cJSON_Delete(json_root); 402 + return 0; 403 + 404 + fail: 405 + RIFT_S_WARN("Unrecognised Rift S Controller Calibration JSON data.\n%s\n", json_string); 406 + rift_s_controller_free_imu_calibration(c); 407 + cJSON_Delete(json_root); 408 + return -1; 409 + } 410 + 411 + void 412 + rift_s_controller_free_imu_calibration(struct rift_s_controller_imu_calibration *c) 413 + { 414 + if (c->lensing_models) { 415 + free(c->lensing_models); 416 + c->lensing_models = NULL; 417 + } 418 + 419 + if (c->leds) { 420 + free(c->leds); 421 + c->leds = NULL; 422 + } 423 + }
+150
src/xrt/drivers/rift_s/rift_s_firmware.h
··· 1 + /* 2 + * Copyright 2020 Jan Schmidt 3 + * SPDX-License-Identifier: BSL-1.0 4 + * 5 + * OpenHMD - Free and Open Source API and drivers for immersive technology. 6 + */ 7 + /*! 8 + * @file 9 + * @brief Oculus Rift S firmware parsing interface 10 + * 11 + * Functions for parsing JSON configuration from the HMD 12 + * and Touch Controller firmware. 13 + * 14 + * @author Jan Schmidt <jan@centricular.com> 15 + * @ingroup drv_rift_s 16 + */ 17 + #ifndef __RTFT_S_FIRMWARE__ 18 + #define __RTFT_S_FIRMWARE__ 19 + 20 + #include "math/m_mathinclude.h" 21 + #include "math/m_api.h" 22 + 23 + #include "rift_s.h" 24 + 25 + enum rift_s_firmware_block 26 + { 27 + RIFT_S_FIRMWARE_BLOCK_SERIAL_NUM = 0x0B, 28 + RIFT_S_FIRMWARE_BLOCK_THRESHOLD = 0xD, 29 + RIFT_S_FIRMWARE_BLOCK_IMU_CALIB = 0xE, 30 + RIFT_S_FIRMWARE_BLOCK_CAMERA_CALIB = 0xF, 31 + RIFT_S_FIRMWARE_BLOCK_DISPLAY_COLOR_CALIB = 0x10, 32 + RIFT_S_FIRMWARE_BLOCK_LENS_CALIB = 0x12 33 + }; 34 + 35 + enum rift_s_camera_ids 36 + { 37 + RIFT_S_CAMERA_TOP = 0x0, 38 + RIFT_S_CAMERA_SIDE_LEFT = 0x1, 39 + RIFT_S_CAMERA_FRONT_RIGHT = 0x2, 40 + RIFT_S_CAMERA_FRONT_LEFT = 0x3, 41 + RIFT_S_CAMERA_SIDE_RIGHT = 0x4, 42 + }; 43 + 44 + struct rift_s_imu_calibration 45 + { 46 + struct xrt_matrix_4x4 device_from_imu; 47 + 48 + struct 49 + { 50 + struct xrt_matrix_3x3 rectification; 51 + struct xrt_vec3 offset; 52 + } gyro; 53 + 54 + struct 55 + { 56 + struct xrt_matrix_3x3 rectification; 57 + struct xrt_vec3 offset_at_0C; 58 + struct xrt_vec3 temp_coeff; 59 + } accel; 60 + }; 61 + 62 + struct rift_s_projection_pinhole 63 + { 64 + float cx, cy; /* Principal point */ 65 + float fx, fy; /* Focal length */ 66 + }; 67 + 68 + struct rift_s_fisheye62_distortion 69 + { 70 + float k[6]; /* Radial distortion coefficients */ 71 + float p2, p1; /* Tangential distortion parameters */ 72 + }; 73 + 74 + struct rift_s_camera_calibration 75 + { 76 + struct xrt_rect roi; 77 + struct xrt_matrix_4x4 device_from_camera; 78 + 79 + struct rift_s_projection_pinhole projection; 80 + struct rift_s_fisheye62_distortion distortion; 81 + }; 82 + 83 + #define RIFT_S_MAX_CAMERAS 5 84 + 85 + struct rift_s_camera_calibration_block 86 + { 87 + struct rift_s_camera_calibration cameras[RIFT_S_MAX_CAMERAS]; 88 + }; 89 + 90 + /* Rift S controller LED entry */ 91 + struct rift_s_led 92 + { 93 + // Relative position in metres 94 + struct xrt_vec3 pos; 95 + // Normal 96 + struct xrt_vec3 dir; 97 + 98 + // 85.0, 80.0, 0.0 in all entries so far 99 + struct xrt_vec3 angles; 100 + }; 101 + 102 + struct rift_s_lensing_model 103 + { 104 + int num_points; 105 + float points[4]; 106 + }; 107 + 108 + struct rift_s_controller_imu_calibration 109 + { 110 + struct 111 + { 112 + struct xrt_matrix_3x3 rectification; 113 + struct xrt_vec3 offset; 114 + } gyro; 115 + 116 + struct 117 + { 118 + struct xrt_matrix_3x3 rectification; 119 + struct xrt_vec3 offset; 120 + } accel; 121 + 122 + struct xrt_vec3 imu_position; 123 + 124 + uint8_t num_leds; 125 + struct rift_s_led *leds; 126 + 127 + /* For some reason we have a separate calibration 128 + * 4x4 matrix on top of the separate rectification 129 + * and offset for gyro and accel 130 + */ 131 + struct xrt_matrix_4x4 gyro_calibration; 132 + struct xrt_matrix_4x4 accel_calibration; 133 + 134 + /* Lensing models */ 135 + int num_lensing_models; 136 + struct rift_s_lensing_model *lensing_models; 137 + }; 138 + 139 + int 140 + rift_s_parse_proximity_threshold(char *json, int *proximity_threshold); 141 + int 142 + rift_s_parse_imu_calibration(char *json, struct rift_s_imu_calibration *c); 143 + int 144 + rift_s_parse_camera_calibration_block(char *json, struct rift_s_camera_calibration_block *c); 145 + int 146 + rift_s_controller_parse_imu_calibration(char *json, struct rift_s_controller_imu_calibration *c); 147 + void 148 + rift_s_controller_free_imu_calibration(struct rift_s_controller_imu_calibration *c); 149 + 150 + #endif
+433
src/xrt/drivers/rift_s/rift_s_hmd.c
··· 1 + /* 2 + * Copyright 2013, Fredrik Hultin. 3 + * Copyright 2013, Jakob Bornecrantz. 4 + * Copyright 2016 Philipp Zabel 5 + * Copyright 2019-2022 Jan Schmidt 6 + * SPDX-License-Identifier: BSL-1.0 7 + * 8 + */ 9 + /*! 10 + * @file 11 + * @brief Driver code for Oculus Rift S headsets 12 + * 13 + * Implementation for the HMD communication, calibration and 14 + * IMU integration. 15 + * 16 + * Ported from OpenHMD 17 + * 18 + * @author Jan Schmidt <jan@centricular.com> 19 + * @ingroup drv_rift_s 20 + */ 21 + 22 + /* Oculus Rift S Driver - HID/USB Driver Implementation */ 23 + 24 + #include <stdlib.h> 25 + #include <string.h> 26 + #include <stdio.h> 27 + #include <time.h> 28 + #include <assert.h> 29 + #include <inttypes.h> 30 + 31 + #include "math/m_api.h" 32 + #include "math/m_vec3.h" 33 + 34 + #include "os/os_time.h" 35 + 36 + #include "util/u_device.h" 37 + #include "util/u_trace_marker.h" 38 + #include "util/u_var.h" 39 + 40 + #include "xrt/xrt_device.h" 41 + 42 + #include "rift_s_hmd.h" 43 + 44 + #define DEG_TO_RAD(D) ((D)*M_PI / 180.) 45 + 46 + static void 47 + rift_s_update_inputs(struct xrt_device *xdev) 48 + {} 49 + 50 + static void 51 + rift_s_get_tracked_pose(struct xrt_device *xdev, 52 + enum xrt_input_name name, 53 + uint64_t at_timestamp_ns, 54 + struct xrt_space_relation *out_relation) 55 + { 56 + struct rift_s_hmd *hmd = (struct rift_s_hmd *)(xdev); 57 + 58 + if (name != XRT_INPUT_GENERIC_HEAD_POSE) { 59 + RIFT_S_ERROR("Unknown input name"); 60 + return; 61 + } 62 + 63 + U_ZERO(out_relation); 64 + 65 + // Estimate pose at timestamp at_timestamp_ns! 66 + os_mutex_lock(&hmd->mutex); 67 + math_quat_normalize(&hmd->pose.orientation); 68 + out_relation->pose = hmd->pose; 69 + out_relation->relation_flags = (enum xrt_space_relation_flags)(XRT_SPACE_RELATION_ORIENTATION_VALID_BIT | 70 + XRT_SPACE_RELATION_POSITION_VALID_BIT | 71 + XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT); 72 + os_mutex_unlock(&hmd->mutex); 73 + } 74 + 75 + static void 76 + rift_s_get_view_poses(struct xrt_device *xdev, 77 + const struct xrt_vec3 *default_eye_relation, 78 + uint64_t at_timestamp_ns, 79 + uint32_t view_count, 80 + struct xrt_space_relation *out_head_relation, 81 + struct xrt_fov *out_fovs, 82 + struct xrt_pose *out_poses) 83 + { 84 + u_device_get_view_poses(xdev, default_eye_relation, at_timestamp_ns, view_count, out_head_relation, out_fovs, 85 + out_poses); 86 + } 87 + 88 + void 89 + rift_s_hmd_handle_report(struct rift_s_hmd *hmd, timepoint_ns local_ts, rift_s_hmd_report_t *report) 90 + { 91 + const uint32_t TICK_LEN_US = 1000000 / hmd->imu_config.imu_hz; 92 + uint32_t dt = TICK_LEN_US; 93 + 94 + os_mutex_lock(&hmd->mutex); 95 + 96 + if (hmd->last_imu_timestamp_ns != 0) { 97 + /* Avoid wrap-around on 32-bit device times */ 98 + dt = report->timestamp - hmd->last_imu_timestamp32; 99 + } else { 100 + hmd->last_imu_timestamp_ns = report->timestamp; 101 + } 102 + hmd->last_imu_timestamp32 = report->timestamp; 103 + hmd->last_imu_local_timestamp_ns = local_ts; 104 + 105 + const float gyro_scale = 1.0 / hmd->imu_config.gyro_scale; 106 + const float accel_scale = MATH_GRAVITY_M_S2 / hmd->imu_config.accel_scale; 107 + const float temperature_scale = 1.0 / hmd->imu_config.temperature_scale; 108 + const float temperature_offset = hmd->imu_config.temperature_offset; 109 + 110 + for (int i = 0; i < 3; i++) { 111 + rift_s_hmd_imu_sample_t *s = report->samples + i; 112 + 113 + if (s->marker & 0x80) 114 + break; /* Sample (and remaining ones) are invalid */ 115 + 116 + struct xrt_vec3 gyro, accel; 117 + 118 + gyro.x = DEG_TO_RAD(gyro_scale * s->gyro[0]); 119 + gyro.y = DEG_TO_RAD(gyro_scale * s->gyro[1]); 120 + gyro.z = DEG_TO_RAD(gyro_scale * s->gyro[2]); 121 + 122 + accel.x = accel_scale * s->accel[0]; 123 + accel.y = accel_scale * s->accel[1]; 124 + accel.z = accel_scale * s->accel[2]; 125 + 126 + /* Apply correction offsets first, then rectify */ 127 + accel = m_vec3_sub(accel, hmd->imu_calibration.accel.offset_at_0C); 128 + gyro = m_vec3_sub(gyro, hmd->imu_calibration.gyro.offset); 129 + 130 + math_matrix_3x3_transform_vec3(&hmd->imu_calibration.accel.rectification, &accel, &hmd->raw_accel); 131 + math_matrix_3x3_transform_vec3(&hmd->imu_calibration.gyro.rectification, &gyro, &hmd->raw_gyro); 132 + 133 + /* FIXME: This doesn't seem to produce the right numbers, but it's OK - we don't use it anyway */ 134 + hmd->temperature = temperature_scale * (s->temperature - temperature_offset) + 25; 135 + 136 + #if 0 137 + printf ("Sample %d dt %f accel %f %f %f gyro %f %f %f\n", 138 + i, dt_sec, hmd->raw_accel.x, hmd->raw_accel.y, hmd->raw_accel.z, 139 + hmd->raw_gyro.x, hmd->raw_gyro.y, hmd->raw_gyro.z); 140 + #endif 141 + 142 + // Do 3DOF fusion 143 + m_imu_3dof_update(&hmd->fusion, hmd->last_imu_timestamp_ns, &hmd->raw_accel, &hmd->raw_gyro); 144 + 145 + hmd->last_imu_timestamp_ns += (uint64_t)dt * OS_NS_PER_USEC; 146 + dt = TICK_LEN_US; 147 + } 148 + 149 + hmd->pose.orientation = hmd->fusion.rot; 150 + os_mutex_unlock(&hmd->mutex); 151 + } 152 + 153 + static bool 154 + rift_s_compute_distortion(struct xrt_device *xdev, int view, float u, float v, struct xrt_uv_triplet *result) 155 + { 156 + struct rift_s_hmd *hmd = (struct rift_s_hmd *)(xdev); 157 + return u_compute_distortion_panotools(&hmd->distortion_vals[view], u, v, result); 158 + } 159 + 160 + #if 0 161 + static int 162 + dump_fw_block(struct os_hid_device *handle, uint8_t block_id) { 163 + int res; 164 + char *data = NULL; 165 + int len; 166 + 167 + res = rift_s_read_firmware_block (handle, block_id, &data, &len); 168 + if (res < 0) 169 + return res; 170 + 171 + free (data); 172 + return 0; 173 + } 174 + #endif 175 + 176 + static int 177 + read_hmd_calibration(struct rift_s_hmd *hmd, struct os_hid_device *hid_hmd) 178 + { 179 + char *json = NULL; 180 + int json_len = 0; 181 + 182 + int ret = rift_s_read_firmware_block(hid_hmd, RIFT_S_FIRMWARE_BLOCK_IMU_CALIB, &json, &json_len); 183 + if (ret < 0) 184 + return ret; 185 + 186 + ret = rift_s_parse_imu_calibration(json, &hmd->imu_calibration); 187 + free(json); 188 + 189 + if (ret < 0) 190 + return ret; 191 + 192 + ret = rift_s_read_firmware_block(hid_hmd, RIFT_S_FIRMWARE_BLOCK_CAMERA_CALIB, &json, &json_len); 193 + if (ret < 0) 194 + return ret; 195 + 196 + ret = rift_s_parse_camera_calibration_block(json, &hmd->camera_calibration); 197 + free(json); 198 + 199 + return ret; 200 + } 201 + 202 + static int 203 + rift_s_hmd_read_proximity_threshold(struct rift_s_hmd *hmd, struct os_hid_device *hid_hmd) 204 + { 205 + char *json = NULL; 206 + int json_len = 0; 207 + 208 + int ret = rift_s_read_firmware_block(hid_hmd, RIFT_S_FIRMWARE_BLOCK_THRESHOLD, &json, &json_len); 209 + if (ret < 0) 210 + return ret; 211 + 212 + ret = rift_s_parse_proximity_threshold(json, &hmd->proximity_threshold); 213 + free(json); 214 + 215 + return ret; 216 + } 217 + 218 + static void 219 + rift_s_hmd_destroy(struct xrt_device *xdev) 220 + { 221 + struct rift_s_hmd *hmd = (struct rift_s_hmd *)(xdev); 222 + 223 + DRV_TRACE_MARKER(); 224 + 225 + /* Remove this device from the system */ 226 + rift_s_system_remove_hmd(hmd->sys); 227 + 228 + /* Drop the reference to the system */ 229 + rift_s_system_reference(&hmd->sys, NULL); 230 + 231 + u_var_remove_root(hmd); 232 + 233 + m_imu_3dof_close(&hmd->fusion); 234 + 235 + os_mutex_destroy(&hmd->mutex); 236 + 237 + u_device_free(&hmd->base); 238 + } 239 + 240 + struct rift_s_hmd * 241 + rift_s_hmd_create(struct rift_s_system *sys, const unsigned char *hmd_serial_no) 242 + { 243 + int ret; 244 + 245 + DRV_TRACE_MARKER(); 246 + 247 + enum u_device_alloc_flags flags = 248 + (enum u_device_alloc_flags)(U_DEVICE_ALLOC_HMD | U_DEVICE_ALLOC_TRACKING_NONE); 249 + 250 + struct rift_s_hmd *hmd = U_DEVICE_ALLOCATE(struct rift_s_hmd, flags, 1, 0); 251 + if (hmd == NULL) { 252 + return NULL; 253 + } 254 + 255 + /* Take a reference to the rift_s_system */ 256 + rift_s_system_reference(&hmd->sys, sys); 257 + 258 + hmd->base.tracking_origin = &sys->base; 259 + 260 + hmd->base.update_inputs = rift_s_update_inputs; 261 + hmd->base.get_tracked_pose = rift_s_get_tracked_pose; 262 + hmd->base.get_view_poses = rift_s_get_view_poses; 263 + hmd->base.destroy = rift_s_hmd_destroy; 264 + hmd->base.name = XRT_DEVICE_GENERIC_HMD; 265 + hmd->base.device_type = XRT_DEVICE_TYPE_HMD; 266 + hmd->pose.orientation.w = 1.0f; // All other values set to zero by U_DEVICE_ALLOCATE (which calls U_CALLOC) 267 + 268 + m_imu_3dof_init(&hmd->fusion, M_IMU_3DOF_USE_GRAVITY_DUR_20MS); 269 + 270 + // Pose / state lock 271 + ret = os_mutex_init(&hmd->mutex); 272 + if (ret != 0) { 273 + RIFT_S_ERROR("Failed to init mutex!"); 274 + goto cleanup; 275 + } 276 + 277 + // Print name. 278 + snprintf(hmd->base.str, XRT_DEVICE_NAME_LEN, "Oculus Rift S"); 279 + snprintf(hmd->base.serial, XRT_DEVICE_NAME_LEN, "%s", hmd_serial_no); 280 + 281 + // Setup input. 282 + hmd->base.inputs[0].name = XRT_INPUT_GENERIC_HEAD_POSE; 283 + 284 + hmd->last_imu_timestamp_ns = 0; 285 + 286 + struct os_hid_device *hid_hmd = rift_s_system_hid_handle(hmd->sys); 287 + 288 + if (rift_s_read_panel_info(hid_hmd, &hmd->panel_info) < 0) { 289 + RIFT_S_ERROR("Failed to read Rift S device info"); 290 + goto cleanup; 291 + } 292 + 293 + if (rift_s_read_firmware_version(hid_hmd) < 0) { 294 + RIFT_S_ERROR("Failed to read Rift S firmware version"); 295 + goto cleanup; 296 + } 297 + 298 + if (rift_s_read_imu_config(hid_hmd, &hmd->imu_config) < 0) { 299 + RIFT_S_ERROR("Failed to read IMU configuration block"); 300 + goto cleanup; 301 + } 302 + 303 + if (read_hmd_calibration(hmd, hid_hmd) < 0) 304 + goto cleanup; 305 + 306 + /* Configure the proximity sensor threshold */ 307 + if (rift_s_hmd_read_proximity_threshold(hmd, hid_hmd) < 0) 308 + goto cleanup; 309 + 310 + RIFT_S_DEBUG("Configuring firmware provided proximity sensor threshold %u", hmd->proximity_threshold); 311 + 312 + if (rift_s_protocol_set_proximity_threshold(hid_hmd, (uint16_t)hmd->proximity_threshold) < 0) 313 + goto cleanup; 314 + 315 + #if 0 316 + dump_fw_block(hid_hmd, 0xB); 317 + dump_fw_block(hid_hmd, 0xF); 318 + dump_fw_block(hid_hmd, 0x10); 319 + dump_fw_block(hid_hmd, 0x12); 320 + #endif 321 + 322 + // Set up display details 323 + // FIXME: These are all wrong and should be derived from HMD reports 324 + // refresh rate 325 + hmd->base.hmd->screens[0].nominal_frame_interval_ns = time_s_to_ns(1.0f / 80.0f); 326 + 327 + /* In the Rift S, there's one panel that is rotated 328 + * to the right, so reported to the OS as a 329 + * 1440x2560 wxh panel that needs to be split 330 + * in two and each view rotated for rendering */ 331 + const int view_w = 1440; 332 + const int view_h = 1280; 333 + 334 + /* screen is the physical width/height of the panel 335 + * as presented to the OS */ 336 + hmd->base.hmd->screens[0].w_pixels = view_w; 337 + hmd->base.hmd->screens[0].h_pixels = view_h * 2; 338 + 339 + // Left, Right eye view setup 340 + for (uint8_t eye = 0; eye < 2; ++eye) { 341 + // Display w/h need to be swapped, as the client sees / renders 342 + hmd->base.hmd->views[eye].display.w_pixels = view_h; 343 + hmd->base.hmd->views[eye].display.h_pixels = view_w; 344 + // Viewport is position on the output panel 345 + hmd->base.hmd->views[eye].viewport.y_pixels = 0; 346 + hmd->base.hmd->views[eye].viewport.w_pixels = view_w; 347 + hmd->base.hmd->views[eye].viewport.h_pixels = view_h; 348 + hmd->base.hmd->views[eye].rot = u_device_rotation_right; 349 + } 350 + // left eye starts at y=0, right eye starts at y=view_height 351 + hmd->base.hmd->views[0].viewport.y_pixels = 0; 352 + hmd->base.hmd->views[1].viewport.y_pixels = view_h; 353 + 354 + /* FIXME: Incorrection distortion taken from the Rift CV1 for now */ 355 + const double display_w_meters = 0.149760f / 2.0; // Per-eye width 356 + const double display_h_meters = 0.093600f; 357 + const double lens_sep = 0.074f; 358 + const double hFOV = DEG_TO_RAD(105.0); 359 + 360 + // center of projection 361 + const double hCOP = lens_sep / 2.0; 362 + const double vCOP = display_h_meters / 2.0; 363 + 364 + struct u_panotools_values distortion_vals = { 365 + .distortion_k = {0.819f, -0.241f, 0.324f, 0.098f, 0.0}, 366 + .aberration_k = {0.9952420f, 1.0f, 1.0008074f}, 367 + .scale = display_w_meters - 368 + lens_sep / 2.0, // Assume distortion is across the larger distance from lens center to edge 369 + .lens_center = {display_w_meters - hCOP, vCOP}, 370 + .viewport_size = {display_w_meters, display_h_meters}, 371 + }; 372 + 373 + if ( 374 + /* right eye */ 375 + !math_compute_fovs(display_w_meters, hCOP, hFOV, display_h_meters, vCOP, 0.0, 376 + &hmd->base.hmd->distortion.fov[1]) || 377 + /* 378 + * left eye - same as right eye, except the horizontal center of projection is moved in the opposite 379 + * direction now 380 + */ 381 + !math_compute_fovs(display_w_meters, display_w_meters - hCOP, hFOV, display_h_meters, vCOP, 0.0, 382 + &hmd->base.hmd->distortion.fov[0])) { 383 + // If those failed, it means our math was impossible. 384 + RIFT_S_ERROR("Failed to setup basic device info"); 385 + goto cleanup; 386 + } 387 + 388 + hmd->distortion_vals[0] = distortion_vals; 389 + // Move the lens center for the right view 390 + distortion_vals.lens_center.x = hCOP; 391 + hmd->distortion_vals[1] = distortion_vals; 392 + 393 + hmd->base.hmd->distortion.models = XRT_DISTORTION_MODEL_COMPUTE; 394 + hmd->base.hmd->distortion.preferred = XRT_DISTORTION_MODEL_COMPUTE; 395 + hmd->base.compute_distortion = rift_s_compute_distortion; 396 + u_distortion_mesh_fill_in_compute(&hmd->base); 397 + 398 + /* Set Opaque blend mode */ 399 + hmd->base.hmd->blend_modes[0] = XRT_BLEND_MODE_OPAQUE; 400 + hmd->base.hmd->blend_mode_count = 1; 401 + 402 + // Setup variable tracker: Optional but useful for debugging 403 + u_var_add_root(hmd, "Oculus Rift S", true); 404 + 405 + u_var_add_gui_header(hmd, NULL, "Tracking"); 406 + u_var_add_pose(hmd, &hmd->pose, "pose"); 407 + 408 + u_var_add_gui_header(hmd, NULL, "3DoF Tracking"); 409 + m_imu_3dof_add_vars(&hmd->fusion, hmd, ""); 410 + 411 + u_var_add_gui_header(hmd, NULL, "Misc"); 412 + u_var_add_log_level(hmd, &rift_s_log_level, "log_level"); 413 + 414 + RIFT_S_DEBUG("Oculus Rift S HMD serial %s initialised.", hmd_serial_no); 415 + 416 + return hmd; 417 + 418 + cleanup: 419 + rift_s_system_reference(&hmd->sys, NULL); 420 + return NULL; 421 + } 422 + 423 + void 424 + rift_s_hmd_set_proximity(struct rift_s_hmd *hmd, bool prox_sensor) 425 + { 426 + /* Enable the screen if the prox sensor is triggered, or turn it off otherwise. */ 427 + if (prox_sensor != hmd->display_on) { 428 + struct os_hid_device *hid_hmd = rift_s_system_hid_handle(hmd->sys); 429 + 430 + rift_s_set_screen_enable(hid_hmd, prox_sensor); 431 + hmd->display_on = prox_sensor; 432 + } 433 + }
+68
src/xrt/drivers/rift_s/rift_s_hmd.h
··· 1 + /* 2 + * Copyright 2013, Fredrik Hultin. 3 + * Copyright 2013, Jakob Bornecrantz. 4 + * Copyright 2016 Philipp Zabel 5 + * Copyright 2019-2022 Jan Schmidt 6 + * SPDX-License-Identifier: BSL-1.0 7 + */ 8 + 9 + /*! 10 + * @file 11 + * @brief Interface to the Oculus Rift S HMD driver code. 12 + * @author Jan Schmidt <jan@centricular.com> 13 + * @ingroup drv_rift_s 14 + */ 15 + 16 + #pragma once 17 + 18 + #include "math/m_imu_3dof.h" 19 + #include "util/u_distortion_mesh.h" 20 + #include "xrt/xrt_defines.h" 21 + #include "xrt/xrt_device.h" 22 + 23 + #include "rift_s.h" 24 + #include "rift_s_protocol.h" 25 + #include "rift_s_firmware.h" 26 + 27 + /* Oculus Rift S HMD Internal Interface */ 28 + #ifndef RIFT_S_HMD_H 29 + #define RIFT_S_HMD_H 30 + 31 + struct rift_s_hmd 32 + { 33 + struct xrt_device base; 34 + 35 + struct rift_s_system *sys; 36 + 37 + /* 3DOF fusion */ 38 + struct os_mutex mutex; 39 + uint32_t last_imu_timestamp32; /* 32-bit µS device timestamp */ 40 + timepoint_ns last_imu_timestamp_ns; 41 + timepoint_ns last_imu_local_timestamp_ns; 42 + struct m_imu_3dof fusion; 43 + struct xrt_pose pose; 44 + struct xrt_vec3 raw_mag, raw_accel, raw_gyro; 45 + 46 + /* Auxiliary state */ 47 + float temperature; 48 + bool display_on; 49 + 50 + /* Configuration / calibration info */ 51 + rift_s_panel_info_t panel_info; 52 + rift_s_imu_config_t imu_config; 53 + struct rift_s_imu_calibration imu_calibration; 54 + int proximity_threshold; 55 + struct rift_s_camera_calibration_block camera_calibration; 56 + 57 + /* Temporary distortion values for mesh calc */ 58 + struct u_panotools_values distortion_vals[2]; 59 + }; 60 + 61 + struct rift_s_hmd * 62 + rift_s_hmd_create(struct rift_s_system *sys, const unsigned char *hmd_serial_no); 63 + void 64 + rift_s_hmd_handle_report(struct rift_s_hmd *hmd, timepoint_ns local_ts, rift_s_hmd_report_t *report); 65 + void 66 + rift_s_hmd_set_proximity(struct rift_s_hmd *hmd, bool prox_sensor); 67 + 68 + #endif
+46
src/xrt/drivers/rift_s/rift_s_interface.h
··· 1 + // Copyright 2020-2021, Collabora, Ltd. 2 + // Copyright 2022 Jan Schmidt 3 + // SPDX-License-Identifier: BSL-1.0 4 + /*! 5 + * @file 6 + * @brief Interface to rift_s driver. 7 + * @author Jan Schmidt <jan@centricular.com> 8 + * @ingroup drv_rift_s 9 + */ 10 + 11 + #pragma once 12 + 13 + #include "xrt/xrt_prober.h" 14 + 15 + #ifdef __cplusplus 16 + extern "C" { 17 + #endif 18 + 19 + /*! 20 + * @defgroup drv_rift_s Oculus Rift S driver 21 + * @ingroup drv 22 + * 23 + * @brief Driver for the Oculus Rift S and touch controllers 24 + * 25 + */ 26 + 27 + #define OCULUS_VR_INC_VID 0x2833 28 + #define OCULUS_RIFT_S_PID 0x0051 29 + 30 + /*! 31 + * Builder setup for Oculus Rift S HMD. 32 + * 33 + * @ingroup drv_rift_s 34 + */ 35 + struct xrt_builder * 36 + rift_s_builder_create(void); 37 + 38 + /*! 39 + * @dir drivers/rift_s 40 + * 41 + * @brief @ref drv_rift_s files. 42 + */ 43 + 44 + #ifdef __cplusplus 45 + } 46 + #endif
+528
src/xrt/drivers/rift_s/rift_s_protocol.c
··· 1 + /* 2 + * Copyright 2013, Fredrik Hultin. 3 + * Copyright 2013, Jakob Bornecrantz. 4 + * Copyright 2016 Philipp Zabel 5 + * Copyright 2019 Lucas Teske <lucas@teske.com.br> 6 + * Copyright 2019-2020 Jan Schmidt 7 + * SPDX-License-Identifier: BSL-1.0 8 + * 9 + * OpenHMD - Free and Open Source API and drivers for immersive technology. 10 + */ 11 + 12 + /*! 13 + * @file 14 + * @brief Oculus Rift S USB protocol implementation 15 + * 16 + * Functions for interpreting the USB protocol to the 17 + * headset and Touch Controllers (via the headset's radio link) 18 + * 19 + * Ported from OpenHMD 20 + * 21 + * @author Jan Schmidt <jan@centricular.com> 22 + */ 23 + 24 + #include <assert.h> 25 + #include <stdio.h> 26 + #include <stdlib.h> 27 + #include <string.h> 28 + 29 + #include "os/os_hid.h" 30 + #include "os/os_time.h" 31 + 32 + #include "xrt/xrt_defines.h" 33 + 34 + #include "rift_s.h" 35 + #include "rift_s_protocol.h" 36 + 37 + /* FIXME: The code in this file is not portable to big-endian as-is - it needs endian swaps */ 38 + bool 39 + rift_s_parse_hmd_report(rift_s_hmd_report_t *report, const unsigned char *buf, int size) 40 + { 41 + if (buf[0] != 0x65) 42 + return false; 43 + 44 + if (size != 64 || size != sizeof(rift_s_hmd_report_t)) 45 + return false; 46 + 47 + *report = *(rift_s_hmd_report_t *)(buf); 48 + 49 + return true; 50 + } 51 + 52 + bool 53 + rift_s_parse_controller_report(rift_s_controller_report_t *report, const unsigned char *buf, int size) 54 + { 55 + uint8_t avail; 56 + 57 + if (buf[0] != 0x67) 58 + return false; 59 + 60 + if (size < 62) { 61 + RIFT_S_WARN("Controller report with size %d - please report it", size); 62 + return false; 63 + } 64 + 65 + report->id = buf[0]; 66 + report->device_id = *(uint64_t *)(buf + 1); 67 + report->data_len = buf[9]; 68 + report->num_info = 0; 69 + report->extra_bytes_len = 0; 70 + report->flags = 0; 71 + memset(report->log, 0, sizeof(report->log)); 72 + 73 + if (report->data_len < 4) { 74 + if (report->data_len != 0) 75 + RIFT_S_WARN("Controller report with data len %u - please report it", report->data_len); 76 + return true; // No more to read 77 + } 78 + 79 + /* Advance the buffer pointer to the end of the common header. 80 + * We now have data_len bytes left to read 81 + */ 82 + buf += 10; 83 + size -= 10; 84 + 85 + if (report->data_len > size) { 86 + RIFT_S_WARN("Controller report with data len %u > packet size 62 - please report it", report->data_len); 87 + report->data_len = size; 88 + } 89 + 90 + avail = report->data_len; 91 + 92 + report->flags = buf[0]; 93 + report->log[0] = buf[1]; 94 + report->log[1] = buf[2]; 95 + report->log[2] = buf[3]; 96 + buf += 4; 97 + avail -= 4; 98 + 99 + /* While we have at least 2 bytes (type + at least 1 byte data), read a block */ 100 + while (avail > 1 && report->num_info < sizeof(report->info) / sizeof(report->info[0])) { 101 + rift_s_controller_info_block_t *info = report->info + report->num_info; 102 + size_t block_size = 0; 103 + info->block_id = buf[0]; 104 + 105 + switch (info->block_id) { 106 + case RIFT_S_CTRL_MASK08: 107 + case RIFT_S_CTRL_BUTTONS: 108 + case RIFT_S_CTRL_FINGERS: 109 + case RIFT_S_CTRL_MASK0e: block_size = sizeof(rift_s_controller_maskbyte_block_t); break; 110 + case RIFT_S_CTRL_TRIGGRIP: block_size = sizeof(rift_s_controller_triggrip_block_t); break; 111 + case RIFT_S_CTRL_JOYSTICK: block_size = sizeof(rift_s_controller_joystick_block_t); break; 112 + case RIFT_S_CTRL_CAPSENSE: block_size = sizeof(rift_s_controller_capsense_block_t); break; 113 + case RIFT_S_CTRL_IMU: block_size = sizeof(rift_s_controller_imu_block_t); break; 114 + default: break; 115 + } 116 + 117 + if (block_size == 0 || avail < block_size) 118 + break; /* Invalid block, or not enough data */ 119 + 120 + memcpy(info->raw.data, buf, block_size); 121 + buf += block_size; 122 + avail -= block_size; 123 + report->num_info++; 124 + } 125 + 126 + if (avail > 0) { 127 + assert(avail < sizeof(report->extra_bytes)); 128 + report->extra_bytes_len = avail; 129 + memcpy(report->extra_bytes, buf, avail); 130 + } 131 + 132 + return true; 133 + } 134 + 135 + int 136 + rift_s_snprintf_hexdump_buffer(char *outbuf, size_t outbufsize, const char *label, const unsigned char *buf, int length) 137 + { 138 + int indent = 0; 139 + char ascii[17]; 140 + int printed = 0; 141 + 142 + if (label) 143 + indent = strlen(label) + 2; 144 + printed += snprintf(outbuf + printed, outbufsize - printed, "%s: ", label); 145 + 146 + ascii[16] = '\0'; 147 + for (int i = 0; i < length; i++) { 148 + printed += snprintf(outbuf + printed, outbufsize - printed, "%02x ", buf[i]); 149 + 150 + if (buf[i] >= ' ' && buf[i] <= '~') 151 + ascii[i % 16] = buf[i]; 152 + else 153 + ascii[i % 16] = '.'; 154 + 155 + if ((i % 16) == 15 || (i + 1) == length) { 156 + if ((i % 16) < 15) { 157 + int remain = 15 - (i % 16); 158 + ascii[(i + 1) % 16] = '\0'; 159 + /* Pad the hex dump out to 48 chars */ 160 + printed += snprintf(outbuf + printed, outbufsize - printed, "%*s", 3 * remain, " "); 161 + } 162 + printed += snprintf(outbuf + printed, outbufsize - printed, "| %s", ascii); 163 + 164 + if ((i + 1) != length) 165 + printed += snprintf(outbuf + printed, outbufsize - printed, "\n%*s", indent, " "); 166 + } 167 + } 168 + 169 + return printed; 170 + } 171 + 172 + void 173 + rift_s_hexdump_buffer(const char *label, const unsigned char *buf, int length) 174 + { 175 + char outbuf[16384] = ""; 176 + int bufsize = sizeof(outbuf) - 2; 177 + int printed = 0; 178 + 179 + printed += rift_s_snprintf_hexdump_buffer(outbuf, bufsize - printed, label, buf, length); 180 + 181 + RIFT_S_DEBUG("%s", outbuf); 182 + } 183 + 184 + static int 185 + get_feature_report(struct os_hid_device *hid, uint8_t cmd, uint8_t *buf, int len) 186 + { 187 + memset(buf, 0, len); 188 + buf[0] = cmd; 189 + return os_hid_get_feature(hid, buf[0], buf, len); 190 + } 191 + 192 + static int 193 + read_one_fw_block(struct os_hid_device *dev, uint8_t block_id, uint32_t pos, uint8_t read_len, uint8_t *buf) 194 + { 195 + unsigned char req[64] = { 196 + 0x4a, 197 + 0x00, 198 + }; 199 + int ret, loops = 0; 200 + bool send_req = true; 201 + 202 + req[2] = block_id; 203 + 204 + do { 205 + if (send_req) { 206 + /* FIXME: Little-endian code: */ 207 + *(uint32_t *)(req + 3) = pos; 208 + req[7] = read_len; 209 + ret = os_hid_set_feature(dev, req, 64); 210 + if (ret < 0) { 211 + RIFT_S_ERROR("Report 74 SET failed"); 212 + return ret; 213 + } 214 + } 215 + 216 + ret = get_feature_report(dev, 0x4A, buf, 64); 217 + if (ret < 0) { 218 + RIFT_S_ERROR("Report 74 GET failed"); 219 + return ret; 220 + } 221 + /* Loop until the result matches the address we asked for and 222 + * the 2nd byte == 0x00 (0x1 = busy or req ignored?), or 20 attempts have passed */ 223 + if (memcmp(req, buf, 7) == 0) 224 + break; 225 + 226 + /* Or if the 2nd byte of the return result is 0x1, the read is being processed, 227 + * don't send the req again. If it's 0x00, we seem to need to re-send the request */ 228 + send_req = (buf[1] == 0x00); 229 + 230 + /* FIXME: Avoid the sleep and just try again later? */ 231 + os_nanosleep(U_TIME_1MS_IN_NS * 2); 232 + } while (loops++ < 20); 233 + 234 + if (loops > 20) 235 + return -1; 236 + 237 + return ret; 238 + } 239 + 240 + int 241 + rift_s_read_firmware_block(struct os_hid_device *dev, uint8_t block_id, char **data_out, int *len_out) 242 + { 243 + uint32_t pos = 0x00, block_len; 244 + unsigned char buf[64] = { 245 + 0x4a, 246 + 0x00, 247 + }; 248 + unsigned char *outbuf; 249 + size_t total_read = 0; 250 + int ret; 251 + 252 + ret = read_one_fw_block(dev, block_id, 0, 0xC, buf); 253 + if (ret < 0) { 254 + RIFT_S_ERROR("Failed to read fw block %02x header", block_id); 255 + return ret; 256 + } 257 + 258 + /* The block header is 12 bytes. 8 byte checksum, 4 byte size? */ 259 + block_len = *(uint32_t *)(buf + 16); 260 + 261 + if (block_len < 0xC || block_len == 0xFFFFFFFF) 262 + return -1; /* Invalid block */ 263 + 264 + #if 0 265 + uint64_t checksum = *(uint64_t *)(buf + 8); 266 + printf ("FW Block %02x Header. Checksum(?) %08lx len %d\n", block_id, checksum, block_len); 267 + #endif 268 + 269 + /* Copy the contents of the fw block, minus the header */ 270 + outbuf = malloc(block_len + 1); 271 + outbuf[block_len] = 0; 272 + total_read = 0x0; 273 + 274 + for (pos = 0x0; pos < block_len; pos += 56) { 275 + uint8_t read_len = 56; 276 + if (pos + read_len > block_len) 277 + read_len = block_len - pos; 278 + 279 + ret = read_one_fw_block(dev, block_id, pos + 0xC, read_len, buf); 280 + if (ret < 0) { 281 + RIFT_S_ERROR("Failed to read fw block %02x at pos 0x%08x len %d", block_id, pos, read_len); 282 + free(outbuf); 283 + return ret; 284 + } 285 + memcpy(outbuf + total_read, buf + 8, read_len); 286 + total_read += read_len; 287 + } 288 + 289 + if (total_read > 0) { 290 + if (total_read < block_len) { 291 + RIFT_S_ERROR("Short FW read - only read %u bytes of %u", (unsigned int)total_read, block_len); 292 + free(outbuf); 293 + return -1; 294 + } 295 + 296 + #if 0 297 + char label[64]; 298 + sprintf (label, "FW Block %02x", block_id); 299 + if (outbuf[0] == '{' && outbuf[total_read-2] == '}' && outbuf[total_read-1] == 0) 300 + printf ("%s\n", outbuf); // Dump JSON string 301 + else 302 + rift_s_hexdump_buffer (label, outbuf, total_read); 303 + #endif 304 + } 305 + 306 + *data_out = (char *)(outbuf); 307 + *len_out = block_len; 308 + 309 + return ret; 310 + } 311 + 312 + void 313 + rift_s_send_keepalive(struct os_hid_device *hid) 314 + { 315 + /* HID report 147 (0x93) 0xbb8 = 3000ms timeout, sent every 1000ms */ 316 + unsigned char buf[6] = {0x93, 0x01, 0xb8, 0x0b, 0x00, 0x00}; 317 + os_hid_set_feature(hid, buf, 6); 318 + } 319 + 320 + int 321 + rift_s_send_camera_report(struct os_hid_device *hid, bool enable, bool radio_sync_bit) 322 + { 323 + /* 324 + * 05 O1 O2 P1 P1 P2 P2 P3 P3 P4 P4 P5 P5 E1 E1 E3 325 + * E4 E5 U1 U2 U3 A1 A1 A1 A1 A2 A2 A2 A2 A3 A3 A3 326 + * A3 A4 A4 A4 A4 A5 A5 A5 A5 327 + * 328 + * O1 = Camera stream on (0x00 = off, 0x1 = on) 329 + * O2 = Radio Sync maybe? 330 + * Px = Vertical offset / position of camera x passthrough view 331 + * Ex = Exposure of camera x passthrough view 332 + * Ax = ? of camera x. 4 byte LE, Always seems to take values 0x3f0-0x4ff 333 + * but I can't see the effect on the image 334 + * U1U2U3 = 26 00 40 always? 335 + */ 336 + unsigned char buf[41] = { 337 + #if 0 338 + 0x05, 0x01, 0x01, 0xb3, 0x36, 0xb3, 0x36, 0xb3, 0x36, 0xb3, 0x36, 0xb3, 0x36, 0xf0, 0xf0, 0xf0, 339 + 0xf0, 0xf0, 0x26, 0x00, 0x40, 0x7a, 0x04, 0x00, 0x00, 0xa7, 0x04, 0x00, 0x00, 0xa7, 0x04, 0x00, 340 + 0x00, 0xa5, 0x04, 0x00, 0x00, 0xa8, 0x04, 0x00, 0x00 341 + #else 342 + 0x05, 343 + 0x01, 344 + 0x01, 345 + 0xb3, 346 + 0x36, 347 + 0xb3, 348 + 0x36, 349 + 0xb3, 350 + 0x36, 351 + 0xb3, 352 + 0x36, 353 + 0xb3, 354 + 0x36, 355 + 0xf0, 356 + 0xf0, 357 + 0xf0, 358 + 0xf0, 359 + 0xf0, 360 + 0x26, 361 + 0x00, 362 + 0x40, 363 + 0x7a, 364 + 0x04, 365 + 0x00, 366 + 0x00, 367 + 0xa7, 368 + 0x04, 369 + 0x00, 370 + 0x00, 371 + 0xa7, 372 + 0x04, 373 + 0x00, 374 + 0x00, 375 + 0xa5, 376 + 0x04, 377 + 0x00, 378 + 0x00, 379 + 0xa8, 380 + 0x04, 381 + 0x00, 382 + 0x00 383 + #endif 384 + }; 385 + 386 + buf[1] = enable ? 0x1 : 0x0; 387 + buf[2] = radio_sync_bit ? 0x1 : 0x0; 388 + 389 + return os_hid_set_feature(hid, buf, 41); 390 + } 391 + 392 + int 393 + rift_s_set_screen_enable(struct os_hid_device *hid, bool enable) 394 + { 395 + uint8_t buf[2]; 396 + 397 + // Enable/disable LCD screen 398 + buf[0] = 0x08; 399 + buf[1] = enable ? 0x01 : 0; 400 + return os_hid_set_feature(hid, buf, 2); 401 + } 402 + 403 + int 404 + rift_s_read_panel_info(struct os_hid_device *hid, rift_s_panel_info_t *panel_info) 405 + { 406 + uint8_t buf[FEATURE_BUFFER_SIZE]; 407 + 408 + int res = get_feature_report(hid, 0x06, buf, FEATURE_BUFFER_SIZE); 409 + if (res < (int)sizeof(rift_s_panel_info_t)) { 410 + RIFT_S_ERROR("Failed to read %d bytes of panel info", FEATURE_BUFFER_SIZE); 411 + return res; 412 + } 413 + rift_s_hexdump_buffer("panel info", buf, res); 414 + 415 + *panel_info = *(rift_s_panel_info_t *)buf; 416 + 417 + return 0; 418 + } 419 + 420 + int 421 + rift_s_read_firmware_version(struct os_hid_device *hid) 422 + { 423 + uint8_t buf[FEATURE_BUFFER_SIZE]; 424 + int res; 425 + 426 + res = get_feature_report(hid, 0x01, buf, 43); 427 + if (res < 0) { 428 + return res; 429 + } 430 + 431 + rift_s_hexdump_buffer("Firmware version", buf, res); 432 + return 0; 433 + } 434 + 435 + int 436 + rift_s_read_imu_config(struct os_hid_device *hid, rift_s_imu_config_t *imu_config) 437 + { 438 + uint8_t buf[FEATURE_BUFFER_SIZE]; 439 + int res; 440 + 441 + res = get_feature_report(hid, 0x09, buf, FEATURE_BUFFER_SIZE); 442 + if (res < 21) 443 + return -1; 444 + 445 + *imu_config = *(rift_s_imu_config_t *)buf; 446 + 447 + return 0; 448 + } 449 + 450 + int 451 + rift_s_protocol_set_proximity_threshold(struct os_hid_device *hid, uint16_t threshold) 452 + { 453 + uint8_t buf[3]; 454 + 455 + /* Proximity sensor threshold 0x07 */ 456 + buf[0] = 0x07; 457 + buf[1] = threshold & 0xff; 458 + buf[2] = (threshold >> 8) & 0xff; 459 + 460 + return os_hid_set_feature(hid, buf, 3); 461 + } 462 + 463 + int 464 + rift_s_hmd_enable(struct os_hid_device *hid, bool enable) 465 + { 466 + uint8_t buf[3]; 467 + int res; 468 + 469 + /* Enable device */ 470 + buf[0] = 0x14; 471 + buf[1] = enable ? 0x01 : 0x00; 472 + if ((res = os_hid_set_feature(hid, buf, 2)) < 0) 473 + return res; 474 + 475 + /* Turn on radio to controllers */ 476 + buf[0] = 0x0A; 477 + buf[1] = enable ? 0x02 : 0x00; 478 + if ((res = os_hid_set_feature(hid, buf, 2)) < 0) 479 + return res; 480 + 481 + if (!enable) { 482 + /* Shutting off - turn off the LCD */ 483 + res = rift_s_set_screen_enable(hid, false); 484 + if (res < 0) 485 + return res; 486 + } 487 + 488 + /* Enables prox sensor + HMD IMU etc */ 489 + buf[0] = 0x02; 490 + buf[1] = enable ? 0x01 : 0x00; 491 + if ((res = os_hid_set_feature(hid, buf, 2)) < 0) 492 + return res; 493 + 494 + /* Send camera report with enable=true enables the streaming. The 495 + * 2nd byte seems something to do with sync, but doesn't always work, 496 + * not sure why yet. */ 497 + return rift_s_send_camera_report(hid, enable, false); 498 + } 499 + 500 + /* Read the list of devices on the radio link */ 501 + int 502 + rift_s_read_devices_list(struct os_hid_device *handle, rift_s_devices_list_t *dev_list) 503 + { 504 + unsigned char buf[200]; 505 + 506 + int res = get_feature_report(handle, 0x0c, buf, sizeof(buf)); 507 + if (res < 3) { 508 + /* This happens when the Rift is just starting, we'll try again later */ 509 + return -1; 510 + } 511 + 512 + int num_records = (res - 3) / 28; 513 + if (num_records > buf[2]) 514 + num_records = buf[2]; 515 + if (num_records > DEVICES_LIST_MAX_DEVICES) 516 + num_records = DEVICES_LIST_MAX_DEVICES; 517 + 518 + unsigned char *pos = buf + 3; 519 + 520 + for (int i = 0; i < num_records; i++) { 521 + dev_list->devices[i] = *(rift_s_device_type_record_t *)(pos); 522 + pos += sizeof(rift_s_device_type_record_t); 523 + assert(sizeof(rift_s_device_type_record_t) == 28); 524 + } 525 + dev_list->num_devices = num_records; 526 + 527 + return 0; 528 + }
+271
src/xrt/drivers/rift_s/rift_s_protocol.h
··· 1 + /* 2 + * Copyright 2019 Lucas Teske <lucas@teske.com.br> 3 + * Copyright 2019-2020 Jan Schmidt 4 + * SPDX-License-Identifier: BSL-1.0 5 + * 6 + * OpenHMD - Free and Open Source API and drivers for immersive technology. 7 + */ 8 + 9 + /*! 10 + * @file 11 + * @brief Oculus Rift S USB protocol implementation interface. 12 + * 13 + * Functions for interpreting the USB protocol to the 14 + * headset and Touch Controllers (via the headset's radio link) 15 + * 16 + * Ported from OpenHMD 17 + * 18 + * @author Jan Schmidt <jan@centricular.com> 19 + */ 20 + #ifndef __RIFT_S_PROTOCOL__ 21 + #define __RIFT_S_PROTOCOL__ 22 + 23 + #include <stdlib.h> 24 + #include "os/os_hid.h" 25 + #include "xrt/xrt_defines.h" 26 + 27 + #define FEATURE_BUFFER_SIZE 256 28 + 29 + #define KEEPALIVE_INTERVAL_MS 1000 30 + #define CAMERA_REPORT_INTERVAL_MS 1000 31 + 32 + #define RIFT_S_BUTTON_A_X 0x01 33 + #define RIFT_S_BUTTON_B_Y 0x02 34 + #define RIFT_S_BUTTON_STICK 0x04 35 + #define RIFT_S_BUTTON_MENU_OCULUS 0x08 36 + 37 + #define RIFT_S_BUTTON_UNKNOWN 0x10 // Unknown mask value seen sometimes. Low battery? 38 + 39 + #define RIFT_S_FINGER_A_X_STRONG 0x01 40 + #define RIFT_S_FINGER_B_Y_STRONG 0x02 41 + #define RIFT_S_FINGER_STICK_STRONG 0x04 42 + #define RIFT_S_FINGER_TRIGGER_STRONG 0x08 43 + #define RIFT_S_FINGER_A_X_WEAK 0x10 44 + #define RIFT_S_FINGER_B_Y_WEAK 0x20 45 + #define RIFT_S_FINGER_STICK_WEAK 0x40 46 + #define RIFT_S_FINGER_TRIGGER_WEAK 0x80 47 + 48 + typedef enum 49 + { 50 + RIFT_S_CTRL_MASK08 = 0x08, /* Unknown. Vals seen 0x28, 0x0a, 0x32, 0x46, 0x00... */ 51 + RIFT_S_CTRL_BUTTONS = 0x0c, /* Button states */ 52 + RIFT_S_CTRL_FINGERS = 0x0d, /* Finger positions */ 53 + RIFT_S_CTRL_MASK0e = 0x0e, /* Unknown. Only seen 0x00 */ 54 + RIFT_S_CTRL_TRIGGRIP = 0x1b, /* Trigger + Grip */ 55 + RIFT_S_CTRL_JOYSTICK = 0x22, /* Joystick X/Y */ 56 + RIFT_S_CTRL_CAPSENSE = 0x27, /* Capsense */ 57 + RIFT_S_CTRL_IMU = 0x91 58 + } rift_s_controller_block_id_t; 59 + 60 + typedef enum 61 + { 62 + RIFT_S_DEVICE_TYPE_UNKNOWN = 0, 63 + RIFT_S_DEVICE_LEFT_CONTROLLER = 0x13001101, 64 + RIFT_S_DEVICE_RIGHT_CONTROLLER = 0x13011101, 65 + } rift_s_device_type; 66 + 67 + #pragma pack(push, 1) 68 + typedef struct 69 + { 70 + uint8_t id; 71 + 72 + uint32_t timestamp; 73 + uint16_t unknown_varying2; 74 + 75 + int16_t accel[3]; 76 + int16_t gyro[3]; 77 + } rift_s_controller_imu_block_t; 78 + 79 + typedef struct 80 + { 81 + /* 0x08, 0x0c, 0x0d or 0x0e block */ 82 + uint8_t id; 83 + 84 + uint8_t val; 85 + } rift_s_controller_maskbyte_block_t; 86 + 87 + typedef struct 88 + { 89 + /* 0x1b trigger/grip block */ 90 + uint8_t id; 91 + uint8_t vals[3]; 92 + } rift_s_controller_triggrip_block_t; 93 + 94 + typedef struct 95 + { 96 + /* 0x22 joystick axes block */ 97 + uint8_t id; 98 + uint32_t val; 99 + } rift_s_controller_joystick_block_t; 100 + 101 + typedef struct 102 + { 103 + /* 0x27 - capsense block */ 104 + uint8_t id; 105 + 106 + uint8_t a_x; 107 + uint8_t b_y; 108 + uint8_t joystick; 109 + uint8_t trigger; 110 + } rift_s_controller_capsense_block_t; 111 + 112 + typedef struct 113 + { 114 + uint8_t data[19]; 115 + } rift_s_controller_raw_block_t; 116 + 117 + typedef union { 118 + uint8_t block_id; 119 + rift_s_controller_imu_block_t imu; 120 + rift_s_controller_maskbyte_block_t maskbyte; 121 + rift_s_controller_triggrip_block_t triggrip; 122 + rift_s_controller_joystick_block_t joystick; 123 + rift_s_controller_capsense_block_t capsense; 124 + rift_s_controller_raw_block_t raw; 125 + } rift_s_controller_info_block_t; 126 + #pragma pack(pop) 127 + 128 + typedef struct 129 + { 130 + uint8_t id; 131 + 132 + uint64_t device_id; 133 + 134 + /* Length of the data block, which contains variable length entries 135 + * If this is < 4, then the flags and log aren't valid. */ 136 + uint8_t data_len; 137 + 138 + /* 0x04 = new log line 139 + * 0x02 = parity bit, toggles each line when receiving log chars 140 + * other bits, unknown */ 141 + uint8_t flags; 142 + // Contains up to 3 bytes of debug log chars 143 + uint8_t log[3]; 144 + 145 + uint8_t num_info; 146 + rift_s_controller_info_block_t info[8]; 147 + 148 + uint8_t extra_bytes_len; 149 + uint8_t extra_bytes[48]; 150 + } rift_s_controller_report_t; 151 + 152 + #pragma pack(push, 1) 153 + typedef struct 154 + { 155 + uint8_t marker; 156 + 157 + int16_t accel[3]; 158 + int16_t gyro[3]; 159 + int16_t temperature; 160 + } rift_s_hmd_imu_sample_t; 161 + 162 + typedef struct 163 + { 164 + uint8_t id; 165 + uint16_t unknown_const1; 166 + 167 + uint32_t timestamp; 168 + 169 + rift_s_hmd_imu_sample_t samples[3]; 170 + 171 + uint8_t marker; 172 + uint8_t unknown2; 173 + 174 + /* Frame timestamp and ID increment when the screen is running, 175 + * every 12.5 ms (80Hz) */ 176 + uint32_t frame_timestamp; 177 + int16_t unknown_zero1; 178 + int16_t frame_id; 179 + int16_t unknown_zero2; 180 + } rift_s_hmd_report_t; 181 + 182 + /* Read using report 6 */ 183 + typedef struct 184 + { 185 + uint8_t cmd; 186 + uint16_t v_resolution; 187 + uint16_t h_resolution; 188 + uint16_t unknown1; 189 + uint8_t refresh_rate; 190 + uint8_t unknown2[14]; 191 + } rift_s_panel_info_t; 192 + 193 + /* Read using report 9 */ 194 + typedef struct 195 + { 196 + uint8_t cmd; 197 + uint32_t imu_hz; 198 + float gyro_scale; /* Gyro = reading / gyro_scale - in degrees */ 199 + float accel_scale; /* Accel = reading * g / accel_scale */ 200 + float temperature_scale; /* Temperature = reading / scale + offset */ 201 + float temperature_offset; 202 + } rift_s_imu_config_t; 203 + 204 + /* Packet read from endpoint 11 (0x0b) */ 205 + typedef struct 206 + { 207 + uint8_t cmd; 208 + uint8_t seqnum; 209 + uint8_t busy_flag; 210 + uint8_t response_bytes[197]; 211 + } rift_s_hmd_radio_response_t; 212 + 213 + /* Struct for sending radio commands to 0x12 / 0x13 */ 214 + typedef struct 215 + { 216 + uint8_t cmd; 217 + uint64_t device_id; 218 + uint8_t cmd_bytes[52]; 219 + } rift_s_hmd_radio_command_t; 220 + 221 + typedef struct 222 + { 223 + uint64_t device_id; 224 + uint32_t device_type; 225 + uint64_t empty[2]; 226 + } rift_s_device_type_record_t; 227 + #pragma pack(pop) 228 + 229 + /* The maximum number that can fit in a 200 byte report */ 230 + #define DEVICES_LIST_MAX_DEVICES 7 231 + 232 + typedef struct 233 + { 234 + uint8_t num_devices; 235 + 236 + rift_s_device_type_record_t devices[DEVICES_LIST_MAX_DEVICES]; 237 + } rift_s_devices_list_t; 238 + 239 + int 240 + rift_s_read_firmware_version(struct os_hid_device *hid); 241 + int 242 + rift_s_read_panel_info(struct os_hid_device *hid, rift_s_panel_info_t *panel_info); 243 + int 244 + rift_s_read_imu_config(struct os_hid_device *hid, rift_s_imu_config_t *imu_config); 245 + int 246 + rift_s_read_fw_proximity_threshold(struct os_hid_device *hid, int *proximity_threshold); 247 + int 248 + rift_s_protocol_set_proximity_threshold(struct os_hid_device *hid, uint16_t threshold); 249 + int 250 + rift_s_hmd_enable(struct os_hid_device *hid, bool enable); 251 + int 252 + rift_s_set_screen_enable(struct os_hid_device *hid, bool enable); 253 + 254 + void 255 + rift_s_send_keepalive(struct os_hid_device *hid); 256 + bool 257 + rift_s_parse_hmd_report(rift_s_hmd_report_t *report, const unsigned char *buf, int size); 258 + bool 259 + rift_s_parse_controller_report(rift_s_controller_report_t *report, const unsigned char *buf, int size); 260 + int 261 + rift_s_read_firmware_block(struct os_hid_device *handle, uint8_t block_id, char **data_out, int *len_out); 262 + 263 + int 264 + rift_s_read_devices_list(struct os_hid_device *handle, rift_s_devices_list_t *dev_list); 265 + 266 + void 267 + rift_s_hexdump_buffer(const char *label, const unsigned char *buf, int length); // Debugging 268 + int 269 + rift_s_snprintf_hexdump_buffer( 270 + char *outbuf, size_t outbufsize, const char *label, const unsigned char *buf, int length); // Debugging 271 + #endif
+303
src/xrt/drivers/rift_s/rift_s_radio.c
··· 1 + /* 2 + * Copyright 2020 Jan Schmidt 3 + * SPDX-License-Identifier: BSL-1.0 4 + * 5 + * OpenHMD - Free and Open Source API and drivers for immersive technology. 6 + */ 7 + /*! 8 + * @file 9 + * @brief Oculus Rift S HMD Radio management 10 + * 11 + * Functions for serialising requests to communicate with 12 + * Touch controllers over the HMDs wireless radio link, 13 + * collecting responses and delivering them back via callbacks. 14 + * 15 + * Ported from OpenHMD 16 + * 17 + * @author Jan Schmidt <jan@centricular.com> 18 + */ 19 + #include <stdlib.h> 20 + #include <string.h> 21 + #include <stdio.h> 22 + #include <assert.h> 23 + 24 + #include "util/u_misc.h" 25 + #include "rift_s.h" 26 + #include "rift_s_radio.h" 27 + #include "rift_s_protocol.h" 28 + 29 + #define MIN(a, b) ((a) < (b) ? (a) : (b)) 30 + 31 + /* Struct that forms a double linked queue of pending commands, 32 + * with the head being the currently active command */ 33 + struct rift_s_radio_command 34 + { 35 + rift_s_radio_command *prev; 36 + rift_s_radio_command *next; 37 + 38 + /* Request packet data */ 39 + rift_s_hmd_radio_command_t read_command; 40 + 41 + /* Completion callback */ 42 + rift_s_radio_completion_fn cb; 43 + void *cb_data; 44 + }; 45 + 46 + static int 47 + get_radio_response_report(struct os_hid_device *hid, rift_s_hmd_radio_response_t *radio_response) 48 + { 49 + int ret; 50 + 51 + radio_response->cmd = 0xb; 52 + ret = os_hid_get_feature(hid, radio_response->cmd, (uint8_t *)(radio_response), 53 + sizeof(rift_s_hmd_radio_response_t)); 54 + 55 + return ret; 56 + } 57 + 58 + void 59 + rift_s_radio_update(rift_s_radio_state *state, struct os_hid_device *hid) 60 + { 61 + bool read_another = false; 62 + 63 + do { 64 + /* Send a radio command if there is none active and some pending */ 65 + if (state->command_result_pending == false && state->pending_commands) { 66 + rift_s_radio_command *cmd = state->pending_commands; 67 + rift_s_hmd_radio_command_t *pkt = &cmd->read_command; 68 + 69 + pkt->cmd = 0x12; 70 + os_hid_set_feature(hid, (uint8_t *)pkt, sizeof(*pkt)); 71 + // rift_s_hexdump_buffer ("ControllerFWSend", (unsigned char *)(pkt), sizeof(*pkt)); 72 + state->command_result_pending = true; 73 + } 74 + 75 + if (!state->command_result_pending) 76 + break; /* Nothing to do right now */ 77 + 78 + /* There's a command result pending, poll the radio response until it's complete */ 79 + rift_s_hmd_radio_response_t radio_response; 80 + 81 + /* The radio response is ready when the busy flag has cleared, and the seqnum 82 + * has incremented */ 83 + int ret = get_radio_response_report(hid, &radio_response); 84 + 85 + if (ret < 2) { 86 + break; /* HID read failed - bail */ 87 + } 88 + 89 + if (radio_response.busy_flag != 0x00 || radio_response.seqnum == state->last_radio_seqnum) { 90 + if (radio_response.busy_flag) 91 + state->last_radio_seqnum = radio_response.seqnum; 92 + return; 93 + } 94 + state->last_radio_seqnum = radio_response.seqnum; 95 + 96 + /* We have the controller response! */ 97 + assert(ret > 3 && ret <= (int)sizeof(radio_response)); 98 + 99 + state->command_result_pending = false; 100 + // rift_s_hexdump_buffer ("ControllerFWReply", (unsigned char *)(&radio_response), ret); 101 + 102 + assert(state->pending_commands != NULL); 103 + 104 + rift_s_radio_command *cmd = state->pending_commands; 105 + 106 + /* Pop the head off the cmds queue, because it's complete now */ 107 + state->pending_commands = cmd->next; 108 + if (state->pending_commands == NULL) 109 + state->pending_commands_tail = NULL; 110 + else 111 + state->pending_commands->prev = NULL; 112 + 113 + /* Call the completion callback */ 114 + if (cmd->cb) 115 + cmd->cb(true, radio_response.response_bytes, ret - 3, cmd->cb_data); 116 + free(cmd); 117 + read_another = true; 118 + 119 + } while (read_another); 120 + } 121 + 122 + void 123 + rift_s_radio_state_init(rift_s_radio_state *state) 124 + { 125 + state->command_result_pending = false; 126 + state->pending_commands = NULL; 127 + state->pending_commands_tail = NULL; 128 + state->last_radio_seqnum = -1; 129 + } 130 + 131 + void 132 + rift_s_radio_state_clear(rift_s_radio_state *state) 133 + { 134 + /* Clear and free any pending commands. */ 135 + rift_s_radio_command *head = state->pending_commands; 136 + while (head != NULL) { 137 + rift_s_radio_command *prev = head; 138 + head = prev->next; 139 + 140 + if (prev->cb) 141 + prev->cb(false, NULL, 0, prev->cb_data); 142 + free(prev); 143 + } 144 + 145 + state->pending_commands = state->pending_commands_tail = NULL; 146 + } 147 + 148 + void 149 + rift_s_radio_queue_command(rift_s_radio_state *state, 150 + const uint64_t device_id, 151 + const uint8_t *cmd_bytes, 152 + const int cmd_bytes_len, 153 + rift_s_radio_completion_fn cb, 154 + void *cb_data) 155 + { 156 + rift_s_radio_command *cmd = U_TYPED_CALLOC(rift_s_radio_command); 157 + 158 + assert(cmd_bytes_len <= (int)sizeof(cmd->read_command.cmd_bytes)); 159 + 160 + cmd->read_command.device_id = device_id; 161 + memcpy(cmd->read_command.cmd_bytes, cmd_bytes, cmd_bytes_len); 162 + cmd->cb = cb; 163 + cmd->cb_data = cb_data; 164 + 165 + /* Append to the pending commands queue. The command itself will be sent by the update() function 166 + * when possible */ 167 + if (state->pending_commands_tail == NULL) { 168 + assert(state->pending_commands == NULL); 169 + state->pending_commands = state->pending_commands_tail = cmd; 170 + } else { 171 + state->pending_commands_tail->next = cmd; 172 + cmd->prev = state->pending_commands_tail; 173 + state->pending_commands_tail = cmd; 174 + } 175 + } 176 + 177 + /* The current blocks are ~2-3KB, so this should be enough to read 178 + * the JSON config: */ 179 + #define MAX_JSON_LEN 4096 180 + 181 + typedef struct rift_s_radio_json_read_state 182 + { 183 + rift_s_radio_state *state; 184 + uint64_t device_id; 185 + rift_s_radio_completion_fn cb; 186 + void *cb_data; 187 + 188 + uint32_t cur_offset; 189 + uint16_t block_len; /* Expected length, from the header */ 190 + 191 + uint8_t data[MAX_JSON_LEN + 1]; 192 + uint16_t data_len; 193 + 194 + } rift_s_radio_json_read_state; 195 + 196 + static void 197 + read_json_cb(bool success, uint8_t *response_bytes, int response_bytes_len, rift_s_radio_json_read_state *json_read) 198 + { 199 + if (!success) { 200 + /* Failed, report to the caller */ 201 + goto fail; 202 + } 203 + 204 + if (response_bytes_len < 5) { 205 + RIFT_S_WARN("Not enough bytes in radio response - needed 5, got %d\n", response_bytes_len); 206 + goto fail; 207 + } 208 + 209 + uint8_t reply_len = response_bytes[4]; 210 + response_bytes += 5; 211 + 212 + if (json_read->cur_offset == 0) { 213 + /* Read the header 0u32 0x20 01 00 62 09 7b 22 67 79 | .{..... ..b.{"gy 214 + 72 6f 5f 6d 22 3a 5b 2d 30 2e 30 31 34 33 35 36 | ro_m":[-0.014356 215 + 38 38 36 36 2c 2d 30 2e | 8866,-0. 216 + = len 0x20, 0001 (file type, or sequence number?), 0x0962 = file length */ 217 + if (reply_len < 4) { 218 + RIFT_S_WARN("Not enough bytes in remote configuration header - needed 4, got %d\n", reply_len); 219 + goto fail; /* Not enough bytes in header */ 220 + } 221 + 222 + uint16_t file_type = (response_bytes[1] << 8) | response_bytes[0]; 223 + uint16_t block_len = (response_bytes[3] << 8) | response_bytes[2]; 224 + 225 + if (file_type != 1) { 226 + RIFT_S_WARN("Unknown file type in remote configuration header - expected 1, got %d\n", 227 + file_type); 228 + goto fail; 229 + } 230 + /* Assert if the MAX_JSON_LEN ever needs expanding */ 231 + assert(block_len <= MAX_JSON_LEN); 232 + if (block_len > MAX_JSON_LEN) { 233 + RIFT_S_WARN( 234 + "Remote configuration block too long. Please expand the read buffer (needed %u bytes)\n", 235 + block_len); 236 + goto fail; 237 + } 238 + 239 + json_read->block_len = block_len; 240 + json_read->cur_offset = 0x4; 241 + } else { 242 + uint16_t data_remain = json_read->block_len - json_read->data_len; 243 + 244 + if (reply_len > data_remain) 245 + reply_len = data_remain; /* Truncate any over-read */ 246 + 247 + /* Append these bytes to the buffer */ 248 + memcpy(json_read->data + json_read->data_len, response_bytes, reply_len); 249 + json_read->data_len += reply_len; 250 + } 251 + 252 + /* If there is no more to read, then report success to the caller and return */ 253 + if (json_read->data_len >= json_read->block_len) { 254 + json_read->data[json_read->data_len] = 0; 255 + 256 + if (json_read->cb) 257 + json_read->cb(true, json_read->data, json_read->data_len, json_read->cb_data); 258 + free(json_read); 259 + return; 260 + } 261 + 262 + /* Otherwise request more data */ 263 + uint8_t read_len = MIN(0x20, json_read->block_len - json_read->data_len); 264 + uint8_t read_cmd[] = {0x2b, 0x20, 0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00}; 265 + 266 + read_cmd[4] = json_read->cur_offset; 267 + read_cmd[5] = json_read->cur_offset >> 8; 268 + read_cmd[6] = json_read->cur_offset >> 16; 269 + read_cmd[7] = json_read->cur_offset >> 24; 270 + read_cmd[8] = read_len; 271 + 272 + rift_s_radio_queue_command(json_read->state, json_read->device_id, read_cmd, sizeof(read_cmd), 273 + (rift_s_radio_completion_fn)read_json_cb, json_read); 274 + 275 + json_read->cur_offset += read_len; 276 + return; 277 + 278 + fail: 279 + if (json_read->cb) 280 + json_read->cb(success, json_read->data, json_read->data_len, json_read->cb_data); 281 + free(json_read); 282 + return; 283 + } 284 + 285 + void 286 + rift_s_radio_get_json_block(rift_s_radio_state *state, 287 + const uint64_t device_id, 288 + rift_s_radio_completion_fn cb, 289 + void *cb_data) 290 + { 291 + /* Configuration JSON block reading */ 292 + rift_s_radio_json_read_state *json_read = U_TYPED_CALLOC(rift_s_radio_json_read_state); 293 + /* cmd = 0x2b reply_buffer_len = 0x20 timeout(?) = 0x3e8 (=1000) offset = 0u32 len = 0x20 */ 294 + const uint8_t read_cmd[] = {0x2b, 0x20, 0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00}; 295 + 296 + json_read->state = state; 297 + json_read->device_id = device_id; 298 + json_read->cb = cb; 299 + json_read->cb_data = cb_data; 300 + 301 + rift_s_radio_queue_command(state, device_id, read_cmd, sizeof(read_cmd), 302 + (rift_s_radio_completion_fn)read_json_cb, json_read); 303 + }
+68
src/xrt/drivers/rift_s/rift_s_radio.h
··· 1 + /* 2 + * Copyright 2020 Jan Schmidt 3 + * SPDX-License-Identifier: BSL-1.0 4 + * 5 + * OpenHMD - Free and Open Source API and drivers for immersive technology. 6 + * 7 + * The Rift S talks to remote devices via HID radio control reports 8 + * the need to be serialised and coordinated to work properly. 9 + * 10 + */ 11 + /*! 12 + * @file 13 + * @brief Oculus Rift S HMD Radio management interface 14 + * 15 + * Functions for serialising requests to communicate with 16 + * Touch controllers over the HMDs wireless radio link, 17 + * collecting responses and delivering them back via callbacks. 18 + * 19 + * Ported from OpenHMD 20 + * 21 + * @author Jan Schmidt <jan@centricular.com> 22 + */ 23 + 24 + #pragma once 25 + 26 + #ifndef RIFT_S_RADIO_H 27 + #define RIFT_S_RADIO_H 28 + 29 + #include "os/os_hid.h" 30 + #include "xrt/xrt_defines.h" 31 + 32 + typedef struct rift_s_radio_command rift_s_radio_command; 33 + typedef struct rift_s_radio_state rift_s_radio_state; 34 + 35 + typedef void (*rift_s_radio_completion_fn)(bool success, 36 + uint8_t *response_bytes, 37 + int response_bytes_len, 38 + void *cb_data); 39 + 40 + struct rift_s_radio_state 41 + { 42 + bool command_result_pending; 43 + int last_radio_seqnum; 44 + 45 + rift_s_radio_command *pending_commands; 46 + rift_s_radio_command *pending_commands_tail; 47 + }; 48 + 49 + void 50 + rift_s_radio_state_init(rift_s_radio_state *state); 51 + void 52 + rift_s_radio_state_clear(rift_s_radio_state *state); 53 + 54 + void 55 + rift_s_radio_update(rift_s_radio_state *state, struct os_hid_device *hid); 56 + void 57 + rift_s_radio_queue_command(rift_s_radio_state *state, 58 + const uint64_t device_id, 59 + const uint8_t *cmd_bytes, 60 + const int cmd_bytes_len, 61 + rift_s_radio_completion_fn cb, 62 + void *cb_data); 63 + void 64 + rift_s_radio_get_json_block(rift_s_radio_state *state, 65 + const uint64_t device_id, 66 + rift_s_radio_completion_fn cb, 67 + void *cb_data); 68 + #endif
+4
src/xrt/targets/common/CMakeLists.txt
··· 112 112 target_link_libraries(target_lists PRIVATE drv_remote) 113 113 endif() 114 114 115 + if(XRT_BUILD_DRIVER_RIFT_S) 116 + target_link_libraries(target_lists PRIVATE drv_rift_s) 117 + endif() 118 + 115 119 if(XRT_HAVE_V4L2) 116 120 target_link_libraries(target_lists PRIVATE drv_v4l2) 117 121 endif()
+8
src/xrt/targets/common/target_lists.c
··· 36 36 #include "psvr/psvr_interface.h" 37 37 #endif 38 38 39 + #ifdef XRT_BUILD_DRIVER_RIFT_S 40 + #include "rift_s/rift_s_interface.h" 41 + #endif 42 + 39 43 #ifdef XRT_BUILD_DRIVER_HYDRA 40 44 #include "hydra/hydra_interface.h" 41 45 #endif ··· 88 92 * Builders 89 93 */ 90 94 xrt_builder_create_func_t target_builder_list[] = { 95 + #ifdef XRT_BUILD_DRIVER_RIFT_S 96 + rift_s_builder_create, 97 + #endif 98 + 91 99 #ifdef T_BUILDER_RGB_TRACKING 92 100 t_builder_rgb_tracking_create, 93 101 #endif // T_BUILDER_RGB_TRACKING