Monado OpenXR Runtime
rift_internal.h
Go to the documentation of this file.
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 "util/u_device.h"
13#include "util/u_logging.h"
14
15#include "math/m_imu_3dof.h"
16#include "math/m_api.h"
17#include "math/m_mathinclude.h"
18
19#include "os/os_hid.h"
20#include "os/os_threading.h"
21
22#include <stdlib.h>
23#include <stdio.h>
24#include <assert.h>
25
26#include "rift_interface.h"
27
28
29#define HMD_TRACE(hmd, ...) U_LOG_XDEV_IFL_T(&hmd->base, hmd->log_level, __VA_ARGS__)
30#define HMD_DEBUG(hmd, ...) U_LOG_XDEV_IFL_D(&hmd->base, hmd->log_level, __VA_ARGS__)
31#define HMD_INFO(hmd, ...) U_LOG_XDEV_IFL_I(&hmd->base, hmd->log_level, __VA_ARGS__)
32#define HMD_WARN(hmd, ...) U_LOG_XDEV_IFL_W(&hmd->base, hmd->log_level, __VA_ARGS__)
33#define HMD_ERROR(hmd, ...) U_LOG_XDEV_IFL_E(&hmd->base, hmd->log_level, __VA_ARGS__)
34
35#define REPORT_MAX_SIZE 69 // max size of a feature report (FEATURE_REPORT_CALIBRATE)
36#define KEEPALIVE_INTERVAL_NS 10000000000 // 10 seconds
37// give a 5% breathing room (at 10 seconds, this is 500 milliseconds of breathing room)
38#define KEEPALIVE_SEND_RATE_NS ((KEEPALIVE_INTERVAL_NS * 19) / 20)
39#define IMU_SAMPLE_RATE (1000) // 1000hz
40#define NS_PER_SAMPLE (1000 * 1000) // 1ms (1,000,000 ns) per sample
41
42#define MICROMETERS_TO_METERS(microns) ((float)microns / 1000000.0f)
43
44// value taken from LibOVR 0.4.4
45#define DEFAULT_EXTRA_EYE_ROTATION DEG_TO_RAD(30.0f)
46
47#define IN_REPORT_DK2 11
48
49// asserts the size of a type is equal to the byte size provided
50#define SIZE_ASSERT(type, size) \
51 static_assert(sizeof(type) == (size), "Size of " #type " is not " #size " bytes as was expected")
52
53enum rift_feature_reports
54{
55 // DK1
56 FEATURE_REPORT_CONFIG = 2, // get + set
57 FEATURE_REPORT_CALIBRATE = 3, // get + set
58 FEATURE_REPORT_RANGE = 4, // get + set
59 FEATURE_REPORT_REGISTER = 5, // get + set
60 FEATURE_REPORT_DFU = 6, // get + set
61 FEATURE_REPORT_DK1_KEEP_ALIVE = 8, // get + set
62 FEATURE_REPORT_DISPLAY_INFO = 9, // get + set
63 FEATURE_REPORT_SERIAL = 10, // get + set
64
65 // DK2
66 FEATURE_REPORT_TRACKING = 12, // get + set
67 FEATURE_REPORT_DISPLAY = 13, // get + set
68 FEATURE_REPORT_MAG_CALIBRATION = 14, // get + set
69 FEATURE_REPORT_POS_CALIBRATION = 15, // get + set
70 FEATURE_REPORT_CUSTOM_PATTERN = 16, // get + set
71 FEATURE_REPORT_KEEPALIVE_MUX = 17, // get + set
72 FEATURE_REPORT_MANUFACTURING = 18, // get + set
73 FEATURE_REPORT_UUID = 19, // get + set
74 FEATURE_REPORT_TEMPERATURE = 20, // get + set
75 FEATURE_REPORT_GYROOFFSET = 21, // get only
76 FEATURE_REPORT_LENS_DISTORTION = 22, // get + set
77
78 // CV1
79 FEATURE_REPORT_RADIO_CONTROL = 26, // get + set
80 FEATURE_REPORT_RADIO_READ_DATA_CMD = 27, // @todo: get + ???
81 FEATURE_REPORT_ENABLE_COMPONENTS = 29, // @todo: ??? + set
82};
83
84enum rift_config_report_flags
85{
86 // output the sample data raw from the sensors without converting them to known units
87 RIFT_CONFIG_REPORT_USE_RAW = 1,
88 // internal test mode for calibrating zero rate drift on gyro
89 RIFT_CONFIG_REPORT_INTERNAL_CALIBRATION = 1 << 1,
90 // use the calibration parameters stored on the device
91 RIFT_CONFIG_REPORT_USE_CALIBRATION = 1 << 2,
92 // recalibrate the gyro zero rate offset when the device is stationary
93 RIFT_CONFIG_REPORT_AUTO_CALIBRATION = 1 << 3,
94 // stop sending IN reports when the device has stopped moving for Interval milliseconds
95 RIFT_CONFIG_REPORT_MOTION_KEEP_ALIVE = 1 << 4,
96 // stop sending IN reports when the device has stopped receiving feature reports for Interval milliseconds
97 RIFT_CONFIG_REPORT_COMMAND_KEEP_ALIVE = 1 << 5,
98 // output the IN report data in the coordinate system used by LibOVR relative to the tracker, otherwise, report
99 // in the coordinate system of the device
100 RIFT_CONFIG_REPORT_USE_SENSOR_COORDINATES = 1 << 6,
101 // override the power state of the USB hub, forcing it to act as if the external power source is connected (DK2
102 // only, does nothing on DK1)
103 RIFT_CONFIG_REPORT_OVERRIDE_POWER = 1 << 7,
104};
105
106enum rift_distortion_type
107{
108 RIFT_DISTORTION_TYPE_DIMS = 1,
109 RIFT_DISTORTION_TYPE_K = 2,
110};
111
112enum rift_lens_type
113{
114 // firmware indirectly states lens type A is 0
115 RIFT_LENS_TYPE_A = 0,
116 // firmware does not state what lens type B is, 1 is an educated guess
117 RIFT_LENS_TYPE_B = 1,
118};
119
120enum rift_lens_distortion_version
121{
122 // no distortion data is stored
123 RIFT_LENS_DISTORTION_NONE = 0,
124 // standard distortion matrix
125 RIFT_LENS_DISTORTION_LCSV_CATMULL_ROM_10_VERSION_1 = 1,
126};
127
128enum rift_component_flags
129{
130 RIFT_COMPONENT_DISPLAY = 1 << 0,
131 RIFT_COMPONENT_AUDIO = 1 << 1,
132 RIFT_COMPONENT_LEDS = 1 << 2,
133};
134
135/*
136 *
137 * Packed structs for USB communication
138 *
139 */
140
141#pragma pack(push, 1)
142
144{
145 uint16_t command_id;
146 uint8_t config_flags;
147 // the IN report rate of the headset, rate is calculated as `sample_rate / (1 + interval)`
148 uint8_t interval;
149 // sample rate of the IMU, always 1000hz on DK1/DK2, read-only
150 uint16_t sample_rate;
151};
152
153SIZE_ASSERT(struct rift_config_report, 6);
154
156{
157 uint16_t command_id;
158 uint8_t distortion_type;
159 // the horizontal resolution of the display, in pixels
160 uint16_t resolution_x;
161 // the vertical resolution of the display, in pixels
162 uint16_t resolution_y;
163 // width in micrometers
164 uint32_t display_width;
165 // height in micrometers
166 uint32_t display_height;
167 // the vertical center of the display, in micrometers
168 uint32_t center_v;
169 // the separation between the two lenses, in micrometers
170 uint32_t lens_separation;
171 uint32_t lens_distance[2];
172 float distortion[6];
173};
174
175SIZE_ASSERT(struct rift_display_info_report, 55);
176
177#define CATMULL_COEFFICIENTS 11
178#define CHROMATIC_ABBERATION_COEFFEICENT_COUNT 4
179
181{
182 // eye relief setting, in micrometers from front surface of lens
183 uint16_t eye_relief;
184 // the k coeffecients of the distortion
185 uint16_t k[CATMULL_COEFFICIENTS];
186 uint16_t max_r;
187 uint16_t meters_per_tan_angle_at_center;
188 uint16_t chromatic_abberation[CHROMATIC_ABBERATION_COEFFEICENT_COUNT];
189 uint8_t unused[14];
190};
191
192SIZE_ASSERT(struct rift_catmull_rom_distortion_report_data, 50);
193
195{
196 uint16_t command_id;
197 // the amount of distortions on this device
198 uint8_t num_distortions;
199 // the index of this distortion in the devices array
200 uint8_t distortion_idx;
201 // unused bitmask field
202 uint8_t bitmask;
203 // the type of the lenses
204 uint16_t lens_type;
205 // the version of the lens distortion data
206 uint16_t distortion_version;
207
208 union {
209 struct rift_catmull_rom_distortion_report_data lcsv_catmull_rom_10;
210 } data;
211};
212
213SIZE_ASSERT(struct rift_lens_distortion_report, 9 + sizeof(struct rift_catmull_rom_distortion_report_data));
214
216{
217 uint16_t command;
218 uint8_t in_report;
219 uint16_t interval;
220};
221
222SIZE_ASSERT(struct rift_dk2_keepalive_mux_report, 5);
223
224enum rift_display_mode
225{
226 RIFT_DISPLAY_MODE_GLOBAL,
227 RIFT_DISPLAY_MODE_ROLLING_TOP_BOTTOM,
228 RIFT_DISPLAY_MODE_ROLLING_LEFT_RIGHT,
229 RIFT_DISPLAY_MODE_ROLLING_RIGHT_LEFT,
230};
231
232enum rift_display_limit
233{
234 RIFT_DISPLAY_LIMIT_ACL_OFF = 0,
235 RIFT_DISPLAY_LIMIT_ACL_30 = 1,
236 RIFT_DISPLAY_LIMIT_ACL_25 = 2,
237 RIFT_DISPLAY_LIMIT_ACL_50 = 3,
238};
239
240enum rift_display_flags
241{
242 RIFT_DISPLAY_USE_ROLLING = 1 << 6,
243 RIFT_DISPLAY_REVERSE_ROLLING = 1 << 7,
244 RIFT_DISPLAY_HIGH_BRIGHTNESS = 1 << 8,
245 RIFT_DISPLAY_SELF_REFRESH = 1 << 9,
246 RIFT_DISPLAY_READ_PIXEL = 1 << 10,
247 RIFT_DISPLAY_DIRECT_PENTILE = 1 << 11,
248};
249
251{
252 uint16_t command_id;
253 // relative brightness setting independent of pixel persistence, only effective when high brightness is disabled
254 uint8_t brightness;
255 // a set of flags, ordered from LSB -> MSB
256 // - panel mode/shutter type (4 bits), read only, see rift_display_mode
257 // - current limit (2 bits), see rift_display_limit
258 // - use rolling (1 bit)
259 // - reverse rolling (1 bit), unavailable on released DK2 firmware for unknown reason
260 // - high brightness (1 bit), unavailable on released DK2 firmware for unpublished reason
261 // - self refresh (1 bit)
262 // - read pixel (1 bit)
263 // - direct pentile (1 bit)
264 uint32_t flags;
265 // the length of time in rows that the display is lit each frame, defaults to the full size of the display, full
266 // persistence
267 uint16_t persistence;
268 // the offset in rows from vsync that the panel is lit when using global shutter, no effect in rolling shutter,
269 // disabled on released DK2 firmware for unknown reason
270 uint16_t lighting_offset;
271 // the time in microseconds it is estimated for a pixel to settle to one value after it is set, read only
272 uint16_t pixel_settle;
273 // the number of rows including active area and blanking period used with persistence and lightingoffset, read
274 // only
275 uint16_t total_rows;
276};
277
278SIZE_ASSERT(struct rift_display_report, 15);
279
281{
282 uint8_t data[8];
283};
284
285SIZE_ASSERT(struct rift_dk2_sensor_sample, 8);
286
288{
289 struct rift_dk2_sensor_sample accel;
290 struct rift_dk2_sensor_sample gyro;
291};
292
293SIZE_ASSERT(struct rift_dk2_sample_pack, sizeof(struct rift_dk2_sensor_sample) * 2);
294
296{
297 int16_t mag_x;
298 int16_t mag_y;
299 int16_t mag_z;
300};
301
302SIZE_ASSERT(struct rift_dk2_version_data, 6);
303
305{
306 uint16_t presence_sensor;
307 uint16_t iad_adc_value;
308 uint16_t unk;
309};
310
311SIZE_ASSERT(struct rift_cv1_version_data, 6);
312static_assert(sizeof(struct rift_cv1_version_data) == sizeof(struct rift_dk2_version_data),
313 "Incorrect version data size");
314
315#define DK2_MAX_SAMPLES 2
317{
318 uint16_t command_id;
319 uint8_t num_samples;
320 uint16_t sample_count;
321 uint16_t temperature;
322 uint32_t sample_timestamp;
323 struct rift_dk2_sample_pack samples[DK2_MAX_SAMPLES];
324 union {
325 struct rift_dk2_version_data dk2;
326 struct rift_cv1_version_data cv1;
327 };
328 uint16_t frame_count;
329 uint32_t frame_timestamp;
330 uint8_t frame_id;
331 uint8_t tracking_pattern;
332 uint16_t tracking_count;
333 uint32_t tracking_timestamp;
334};
335
336SIZE_ASSERT(struct dk2_in_report, 63);
337
339{
340 uint16_t command_id;
341 // which components to enable, see rift_component_flags
342 uint8_t flags;
343};
344
345SIZE_ASSERT(struct rift_enable_components_report, 3);
346
348{
349 uint16_t command_id;
350 struct rift_dk2_sample_pack offset;
351 struct rift_dk2_sample_pack matrix_samples[3];
352 uint16_t temperature;
353};
354
355SIZE_ASSERT(struct rift_imu_calibration_report, sizeof(struct rift_dk2_sample_pack) * 4 + 4);
356
357#pragma pack(pop)
358
359/*
360 *
361 * Parsed structs for internal use
362 *
363 */
364
366{
367 // the k coeffecients of the distortion
368 float k[CATMULL_COEFFICIENTS];
369 float max_r;
370 float meters_per_tan_angle_at_center;
371 float chromatic_abberation[CHROMATIC_ABBERATION_COEFFEICENT_COUNT];
372};
373
375{
376 // the version of the lens distortion data
377 uint16_t distortion_version;
378 // eye relief setting, in meters from surface of lens
379 float eye_relief;
380
381 union {
382 struct rift_catmull_rom_distortion_data lcsv_catmull_rom_10;
383 } data;
384};
385
387{
388 struct xrt_vec2 scale;
389 struct xrt_vec2 offset;
390};
391
393{
394 float up_tan;
395 float down_tan;
396 float left_tan;
397 float right_tan;
398};
399
401{
402 // gap left between the two eyes
403 float screen_gap_meters;
404 // the diameter of the lenses, may need to be extended to an array
405 float lens_diameter_meters;
406 // ipd of the headset
407 float icd;
408
409 // the fov of the headset
410 struct rift_viewport_fov_tan fov;
411 // mapping from tan-angle space to target NDC space
412 struct rift_scale_and_offset eye_to_source_ndc;
413 struct rift_scale_and_offset eye_to_source_uv;
414};
415
417{
418 struct xrt_vec3 gyro_offset;
419 struct xrt_vec3 accel_offset;
420 struct xrt_matrix_3x3 gyro_matrix;
421 struct xrt_matrix_3x3 accel_matrix;
422 float temperature;
423};
424
425/*!
426 * A rift HMD device.
427 *
428 * @implements xrt_device
429 */
431{
432 struct xrt_device base;
433
434 enum u_logging_level log_level;
435
436 // has built-in mutex so thread safe
437 struct m_relation_history *relation_hist;
438
439 struct os_hid_device *hid_dev;
440 struct os_thread_helper sensor_thread;
441 bool processed_sample_packet;
442 uint32_t last_remote_sample_time_us;
443 timepoint_ns last_remote_sample_time_ns;
444 timepoint_ns last_sample_local_timestamp_ns;
445
446 struct m_imu_3dof fusion;
447 struct m_clock_windowed_skew_tracker *clock_tracker;
448
449 timepoint_ns last_keepalive_time;
450 enum rift_variant variant;
451 struct rift_config_report config;
453
454 const struct rift_lens_distortion *lens_distortions;
455 uint16_t num_lens_distortions;
456 uint16_t distortion_in_use;
457
458 struct rift_extra_display_info extra_display_info;
459 float icd_override_m;
460
461 bool presence;
462
463 bool imu_needs_calibration;
464 struct rift_imu_calibration imu_calibration;
465};
466
467/// Casting helper function
468static inline struct rift_hmd *
469rift_hmd(struct xrt_device *xdev)
470{
471 return (struct rift_hmd *)xdev;
472}
u_logging_level
Logging level enum.
Definition: u_logging.h:45
int64_t timepoint_ns
Integer timestamp type.
Definition: u_time.h:77
C interface to math library.
A IMU fusion specially made for 3dof devices.
Wrapper header for <math.h> to ensure pi-related math constants are defined.
Wrapper around OS native hid functions.
Wrapper around OS threading native functions.
Interface to Oculus Rift driver code.
static struct rift_hmd * rift_hmd(struct xrt_device *xdev)
Casting helper function.
Definition: rift_internal.h:469
Definition: oh_device.c:483
Definition: rift_internal.h:317
Definition: m_space.cpp:87
Definition: m_clock_tracking.c:35
Definition: m_imu_3dof.h:35
Definition: m_relation_history.cpp:49
Representing a single hid interface on a device.
Definition: os_hid.h:29
All in one helper that handles locking, waiting for change and starting a thread.
Definition: os_threading.h:478
Definition: rift_internal.h:366
Definition: rift_internal.h:181
Definition: rift_internal.h:144
Definition: rift_internal.h:305
Definition: rift_internal.h:156
Definition: rift_internal.h:251
Definition: rift_internal.h:216
Definition: rift_internal.h:288
Definition: rift_internal.h:281
Definition: rift_internal.h:296
Definition: rift_internal.h:339
Definition: rift_internal.h:401
A rift HMD device.
Definition: rift_internal.h:431
Definition: rift_internal.h:348
Definition: rift_internal.h:417
Definition: rift_internal.h:195
Definition: rift_internal.h:375
Definition: rift_internal.h:387
Definition: rift_internal.h:393
A single HMD or input device.
Definition: xrt_device.h:310
A tightly packed 3x3 matrix of floats.
Definition: xrt_defines.h:546
A 2 element vector with single floats.
Definition: xrt_defines.h:268
A 3 element vector with single floats.
Definition: xrt_defines.h:289
Misc helpers for device drivers.
Basic logging functionality.