The open source OpenXR runtime
at main 423 lines 11 kB view raw
1// Copyright 2025, Beyley Cardellio 2// SPDX-License-Identifier: BSL-1.0 3/*! 4 * @file 5 * @brief Interface to Oculus Rift driver code. 6 * @author Beyley Cardellio <ep1cm1n10n123@gmail.com> 7 * @ingroup drv_rift 8 */ 9 10#pragma once 11 12#include "xrt/xrt_device.h" 13#include "xrt/xrt_defines.h" 14#include "xrt/xrt_prober.h" 15 16#include "os/os_hid.h" 17#include "os/os_threading.h" 18 19#include "util/u_device.h" 20#include "util/u_logging.h" 21 22#include "math/m_imu_3dof.h" 23#include "math/m_api.h" 24#include "math/m_mathinclude.h" 25 26#include <stdlib.h> 27#include <stdio.h> 28 29#ifdef __cplusplus 30extern "C" { 31#endif 32 33#define REPORT_MAX_SIZE 69 // max size of a feature report (FEATURE_REPORT_CALIBRATE) 34#define KEEPALIVE_INTERVAL_NS 10000000000 // 10 seconds 35// give a 5% breathing room (at 10 seconds, this is 500 milliseconds of breathing room) 36#define KEEPALIVE_SEND_RATE_NS ((KEEPALIVE_INTERVAL_NS * 19) / 20) 37#define IMU_SAMPLE_RATE (1000) // 1000hz 38#define NS_PER_SAMPLE (1000 * 1000) // 1ms (1,000,000 ns) per sample 39 40#define MICROMETERS_TO_METERS(microns) (float)microns / 1000000.0f 41 42// value taken from LibOVR 0.4.4 43#define DEFAULT_EXTRA_EYE_ROTATION DEG_TO_RAD(30.0f) 44 45enum rift_feature_reports 46{ 47 // DK1 48 FEATURE_REPORT_CONFIG = 2, // get + set 49 FEATURE_REPORT_CALIBRATE = 3, // get + set 50 FEATURE_REPORT_RANGE = 4, // get + set 51 FEATURE_REPORT_REGISTER = 5, // get + set 52 FEATURE_REPORT_DFU = 6, // get + set 53 FEATURE_REPORT_DK1_KEEP_ALIVE = 8, // get + set 54 FEATURE_REPORT_DISPLAY_INFO = 9, // get + set 55 FEATURE_REPORT_SERIAL = 10, // get + set 56 57 // DK2 58 FEATURE_REPORT_TRACKING = 12, // get + set 59 FEATURE_REPORT_DISPLAY = 13, // get + set 60 FEATURE_REPORT_MAG_CALIBRATION = 14, // get + set 61 FEATURE_REPORT_POS_CALIBRATION = 15, // get + set 62 FEATURE_REPORT_CUSTOM_PATTERN = 16, // get + set 63 FEATURE_REPORT_KEEPALIVE_MUX = 17, // get + set 64 FEATURE_REPORT_MANUFACTURING = 18, // get + set 65 FEATURE_REPORT_UUID = 19, // get + set 66 FEATURE_REPORT_TEMPERATURE = 20, // get + set 67 FEATURE_REPORT_GYROOFFSET = 21, // get only 68 FEATURE_REPORT_LENS_DISTORTION = 22, // get + set 69}; 70 71enum rift_config_report_flags 72{ 73 // output the sample data raw from the sensors without converting them to known units 74 RIFT_CONFIG_REPORT_USE_RAW = 1, 75 // internal test mode for calibrating zero rate drift on gyro 76 RIFT_CONFIG_REPORT_INTERNAL_CALIBRATION = 1 << 1, 77 // use the calibration parameters stored on the device 78 RIFT_CONFIG_REPORT_USE_CALIBRATION = 1 << 2, 79 // recalibrate the gyro zero rate offset when the device is stationary 80 RIFT_CONFIG_REPORT_AUTO_CALIBRATION = 1 << 3, 81 // stop sending IN reports when the device has stopped moving for Interval milliseconds 82 RIFT_CONFIG_REPORT_MOTION_KEEP_ALIVE = 1 << 4, 83 // stop sending IN reports when the device has stopped receiving feature reports for Interval milliseconds 84 RIFT_CONFIG_REPORT_COMMAND_KEEP_ALIVE = 1 << 5, 85 // output the IN report data in the coordinate system used by LibOVR relative to the tracker, otherwise, report 86 // in the coordinate system of the device 87 RIFT_CONFIG_REPORT_USE_SENSOR_COORDINATES = 1 << 6, 88 // override the power state of the USB hub, forcing it to act as if the external power source is connected (DK2 89 // only, does nothing on DK1) 90 RIFT_CONFIG_REPORT_OVERRIDE_POWER = 1 << 7, 91}; 92 93enum rift_distortion_type 94{ 95 RIFT_DISTORTION_TYPE_DIMS = 1, 96 RIFT_DISTORTION_TYPE_K = 2, 97}; 98 99enum rift_lens_type 100{ 101 // firmware indirectly states lens type A is 0 102 RIFT_LENS_TYPE_A = 0, 103 // firmware does not state what lens type B is, 1 is an educated guess 104 RIFT_LENS_TYPE_B = 1, 105}; 106 107#define IN_REPORT_DK2 11 108 109#define CATMULL_COEFFICIENTS 11 110#define CHROMATIC_ABBERATION_COEFFEICENT_COUNT 4 111 112enum rift_lens_distortion_version 113{ 114 // no distortion data is stored 115 RIFT_LENS_DISTORTION_NONE = 0, 116 // standard distortion matrix 117 RIFT_LENS_DISTORTION_LCSV_CATMULL_ROM_10_VERSION_1 = 1, 118}; 119 120/* 121 * 122 * Packed structs for USB communication (borrowed from Rokid driver) 123 * 124 */ 125 126#if defined(__GNUC__) 127#define RIFT_PACKED __attribute__((packed)) 128#else 129#define RIFT_PACKED 130#endif /* __GNUC__ */ 131 132#if defined(_MSC_VER) 133#pragma pack(push, 1) 134#endif 135 136struct rift_config_report 137{ 138 uint16_t command_id; 139 uint8_t config_flags; 140 // the IN report rate of the headset, rate is calculated as `sample_rate / (1 + interval)` 141 uint8_t interval; 142 // sample rate of the IMU, always 1000hz on DK1/DK2, read-only 143 uint16_t sample_rate; 144} RIFT_PACKED; 145 146struct rift_display_info_report 147{ 148 uint16_t command_id; 149 uint8_t distortion_type; 150 // the horizontal resolution of the display, in pixels 151 uint16_t resolution_x; 152 // the vertical resolution of the display, in pixels 153 uint16_t resolution_y; 154 // width in micrometers 155 uint32_t display_width; 156 // height in micrometers 157 uint32_t display_height; 158 // the vertical center of the display, in micrometers 159 uint32_t center_v; 160 // the separation between the two lenses, in micrometers 161 uint32_t lens_separation; 162 uint32_t lens_distance[2]; 163 float distortion[6]; 164} RIFT_PACKED; 165 166struct rift_catmull_rom_distortion_report_data 167{ 168 // eye relief setting, in micrometers from front surface of lens 169 uint16_t eye_relief; 170 // the k coeffecients of the distortion 171 uint16_t k[CATMULL_COEFFICIENTS]; 172 uint16_t max_r; 173 uint16_t meters_per_tan_angle_at_center; 174 uint16_t chromatic_abberation[CHROMATIC_ABBERATION_COEFFEICENT_COUNT]; 175 uint8_t unused[14]; 176} RIFT_PACKED; 177 178struct rift_lens_distortion_report 179{ 180 uint16_t command_id; 181 // the amount of distortions on this device 182 uint8_t num_distortions; 183 // the index of this distortion in the devices array 184 uint8_t distortion_idx; 185 // unused bitmask field 186 uint8_t bitmask; 187 // the type of the lenses 188 uint16_t lens_type; 189 // the version of the lens distortion data 190 uint16_t distortion_version; 191 192 union { 193 struct rift_catmull_rom_distortion_report_data lcsv_catmull_rom_10; 194 } RIFT_PACKED data; 195} RIFT_PACKED; 196 197struct dk2_report_keepalive_mux 198{ 199 uint16_t command; 200 uint8_t in_report; 201 uint16_t interval; 202} RIFT_PACKED; 203 204enum rift_display_mode 205{ 206 RIFT_DISPLAY_MODE_GLOBAL, 207 RIFT_DISPLAY_MODE_ROLLING_TOP_BOTTOM, 208 RIFT_DISPLAY_MODE_ROLLING_LEFT_RIGHT, 209 RIFT_DISPLAY_MODE_ROLLING_RIGHT_LEFT, 210}; 211 212enum rift_display_limit 213{ 214 RIFT_DISPLAY_LIMIT_ACL_OFF = 0, 215 RIFT_DISPLAY_LIMIT_ACL_30 = 1, 216 RIFT_DISPLAY_LIMIT_ACL_25 = 2, 217 RIFT_DISPLAY_LIMIT_ACL_50 = 3, 218}; 219 220enum rift_display_flags 221{ 222 RIFT_DISPLAY_USE_ROLLING = 1 << 6, 223 RIFT_DISPLAY_REVERSE_ROLLING = 1 << 7, 224 RIFT_DISPLAY_HIGH_BRIGHTNESS = 1 << 8, 225 RIFT_DISPLAY_SELF_REFRESH = 1 << 9, 226 RIFT_DISPLAY_READ_PIXEL = 1 << 10, 227 RIFT_DISPLAY_DIRECT_PENTILE = 1 << 11, 228}; 229 230struct rift_display_report 231{ 232 uint16_t command_id; 233 // relative brightness setting independent of pixel persistence, only effective when high brightness is disabled 234 uint8_t brightness; 235 // a set of flags, ordered from LSB -> MSB 236 // - panel mode/shutter type (4 bits), read only, see rift_display_mode 237 // - current limit (2 bits), see rift_display_limit 238 // - use rolling (1 bit) 239 // - reverse rolling (1 bit), unavailable on released DK2 firmware for unknown reason 240 // - high brightness (1 bit), unavailable on released DK2 firmware for unpublished reason 241 // - self refresh (1 bit) 242 // - read pixel (1 bit) 243 // - direct pentile (1 bit) 244 uint32_t flags; 245 // the length of time in rows that the display is lit each frame, defaults to the full size of the display, full 246 // persistence 247 uint16_t persistence; 248 // the offset in rows from vsync that the panel is lit when using global shutter, no effect in rolling shutter, 249 // disabled on released DK2 firmware for unknown reason 250 uint16_t lighting_offset; 251 // the time in microseconds it is estimated for a pixel to settle to one value after it is set, read only 252 uint16_t pixel_settle; 253 // the number of rows including active area and blanking period used with persistence and lightingoffset, read 254 // only 255 uint16_t total_rows; 256} RIFT_PACKED; 257 258struct dk2_sensor_sample 259{ 260 uint8_t data[8]; 261} RIFT_PACKED; 262 263struct dk2_sample_pack 264{ 265 struct dk2_sensor_sample accel; 266 struct dk2_sensor_sample gyro; 267} RIFT_PACKED; 268 269#define DK2_MAX_SAMPLES 2 270struct dk2_in_report 271{ 272 uint16_t command_id; 273 uint8_t num_samples; 274 uint16_t sample_count; 275 uint16_t temperature; 276 uint32_t sample_timestamp; 277 struct dk2_sample_pack samples[DK2_MAX_SAMPLES]; 278 int16_t mag_x; 279 int16_t mag_y; 280 int16_t mag_z; 281 uint16_t frame_count; 282 uint32_t frame_timestamp; 283 uint8_t frame_id; 284 uint8_t tracking_pattern; 285 uint16_t tracking_count; 286 uint32_t tracking_timestamp; 287} RIFT_PACKED; 288 289#if defined(_MSC_VER) 290#pragma pack(pop) 291#endif 292 293struct rift_catmull_rom_distortion_data 294{ 295 // the k coeffecients of the distortion 296 float k[CATMULL_COEFFICIENTS]; 297 float max_r; 298 float meters_per_tan_angle_at_center; 299 float chromatic_abberation[CHROMATIC_ABBERATION_COEFFEICENT_COUNT]; 300}; 301 302struct rift_lens_distortion 303{ 304 // the version of the lens distortion data 305 uint16_t distortion_version; 306 // eye relief setting, in meters from surface of lens 307 float eye_relief; 308 309 union { 310 struct rift_catmull_rom_distortion_data lcsv_catmull_rom_10; 311 } RIFT_PACKED data; 312}; 313 314struct rift_scale_and_offset 315{ 316 struct xrt_vec2 scale; 317 struct xrt_vec2 offset; 318}; 319 320struct rift_viewport_fov_tan 321{ 322 float up_tan; 323 float down_tan; 324 float left_tan; 325 float right_tan; 326}; 327 328struct rift_extra_display_info 329{ 330 // gap left between the two eyes 331 float screen_gap_meters; 332 // the diameter of the lenses, may need to be extended to an array 333 float lens_diameter_meters; 334 // ipd of the headset 335 float icd; 336 337 // the fov of the headset 338 struct rift_viewport_fov_tan fov; 339 // mapping from tan-angle space to target NDC space 340 struct rift_scale_and_offset eye_to_source_ndc; 341 struct rift_scale_and_offset eye_to_source_uv; 342}; 343 344enum rift_variant 345{ 346 RIFT_VARIANT_DK1, 347 RIFT_VARIANT_DK2, 348}; 349 350#define OCULUS_VR_VID 0x2833 351 352#define OCULUS_DK2_PID 0x0021 353 354/*! 355 * Probing function for Oculus Rift devices. 356 * 357 * @ingroup drv_rift 358 * @see xrt_prober_found_func_t 359 */ 360int 361rift_found(struct xrt_prober *xp, 362 struct xrt_prober_device **devices, 363 size_t device_count, 364 size_t index, 365 cJSON *attached_data, 366 struct xrt_device **out_xdev); 367 368/*! 369 * A rift HMD device. 370 * 371 * @implements xrt_device 372 */ 373struct rift_hmd 374{ 375 struct xrt_device base; 376 377 struct xrt_pose pose; 378 379 enum u_logging_level log_level; 380 381 // has built-in mutex so thread safe 382 struct m_relation_history *relation_hist; 383 384 struct os_hid_device *hid_dev; 385 struct os_thread_helper sensor_thread; 386 bool processed_sample_packet; 387 uint32_t last_remote_sample_time_us; 388 int64_t last_remote_sample_time_ns; 389 390 struct m_imu_3dof fusion; 391 struct m_clock_windowed_skew_tracker *clock_tracker; 392 393 int64_t last_keepalive_time; 394 enum rift_variant variant; 395 struct rift_config_report config; 396 struct rift_display_info_report display_info; 397 398 struct rift_lens_distortion *lens_distortions; 399 uint16_t num_lens_distortions; 400 uint16_t distortion_in_use; 401 402 struct rift_extra_display_info extra_display_info; 403}; 404 405/// Casting helper function 406static inline struct rift_hmd * 407rift_hmd(struct xrt_device *xdev) 408{ 409 return (struct rift_hmd *)xdev; 410} 411 412struct rift_hmd * 413rift_hmd_create(struct os_hid_device *dev, enum rift_variant variant, char *device_name, char *serial_number); 414 415/*! 416 * @dir drivers/rift 417 * 418 * @brief @ref drv_rift files. 419 */ 420 421#ifdef __cplusplus 422} 423#endif