The open source OpenXR runtime
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

d/survive: Add survive driver

authored by

Christoph Haag and committed by
Jakob Bornecrantz
5908c334 5b2efcbb

+1337 -1
+8
CMakeLists.txt
··· 107 107 option(BUILD_WITH_PSMV "Enable Playstation Move driver" ON) 108 108 option(BUILD_WITH_HYDRA "Enable Hydra driver" ON) 109 109 option(BUILD_WITH_NS "Enable North Star driver" ON) 110 + option(BUILD_WITH_LIBSURVIVE "Enable libsurvive driver" OFF) 110 111 111 112 # You can set this from a superproject to add a driver 112 113 list(APPEND AVAILABLE_DRIVERS ARDUINO DUMMY HDK HYDRA NS OHMD PSMV PSVR RS V4L2 VIVE DAYDREAM) ··· 180 181 181 182 if(BUILD_WITH_NS) 182 183 set(BUILD_DRIVER_NS TRUE) 184 + endif() 185 + 186 + if (BUILD_WITH_LIBSURVIVE) 187 + find_package(PkgConfig REQUIRED) 188 + pkg_check_modules(SURVIVE REQUIRED IMPORTED_TARGET survive) 189 + add_definitions(-DXRT_BUILD_DRIVER_SURVIVE) 190 + set(BUILD_DRIVER_SURVIVE TRUE) 183 191 endif() 184 192 185 193 if(BUILD_WITH_PSVR)
+26
README.md
··· 178 178 xrandr --prop 179 179 ``` 180 180 181 + ## Using libsurvive 182 + 183 + To enable the libsurvive driver, libsurvive has to be installed as a library with a pkgconfig file 184 + (https://github.com/cntools/libsurvive/pull/187). 185 + 186 + When starting any libsrvive or OpenXR application, libsurvive will run calibration and save 187 + configuration and calibration data in the current working directory. 188 + 189 + Make sure the HMD can see both basestations and is not moved during calibration. 190 + 191 + To remove libsurvive's calibration data (e.g. to force recalibration) delete the following 192 + files/directories: 193 + 194 + rm -r *config.json calinfo 195 + 196 + Though working and somewhat usable, support for the libsurvive driver is **experimental**. 197 + Therefore with both meson and cmake, the survive driver has to be explicitly enabled with 198 + 199 + ``` 200 + #cmake 201 + -DBUILD_WITH_LIBSURVIVE=On 202 + 203 + #meson 204 + -Ddrivers=auto,survive 205 + ``` 206 + 181 207 ## Coding style and formatting 182 208 183 209 [clang-format][] is used,
+7
meson.build
··· 65 65 libuvc = dependency('libuvc', required: false) 66 66 vulkan = dependency('vulkan', required: true) 67 67 zlib = dependency('zlib', required: false) 68 + survive = dependency('survive', required: false) 68 69 69 70 opencv = dependency('opencv4', required: false) 70 71 if not opencv.found() ··· 181 182 if 'v4l2' not in drivers 182 183 drivers += ['v4l2'] 183 184 endif 185 + endif 186 + 187 + if survive.found() and ('survive' in drivers) 188 + if 'survive' not in drivers 189 + drivers += ['survive'] 190 + endif 184 191 endif 185 192 186 193 if drivers.length() == 0 or drivers == ['auto']
+1 -1
meson_options.txt
··· 3 3 4 4 option('drivers', 5 5 type: 'array', 6 - choices: ['auto', 'dummy', 'hdk', 'hydra', 'ns', 'ohmd', 'psmv', 'psvr', 'rs', 'v4l2', 'vive'], 6 + choices: ['auto', 'dummy', 'hdk', 'hydra', 'ns', 'ohmd', 'psmv', 'psvr', 'rs', 'v4l2', 'vive', 'survive'], 7 7 value: ['auto'], 8 8 description: 'Set of drivers to build') 9 9
+13
src/xrt/drivers/CMakeLists.txt
··· 162 162 list(APPEND ENABLED_DRIVERS v4l2) 163 163 endif() 164 164 165 + if (BUILD_WITH_LIBSURVIVE) 166 + set(SURVIVE_SOURCE_FILES 167 + survive/survive_driver.c 168 + survive/survive_interface.h 169 + survive/survive_wrap.c 170 + survive/survive_wrap.h 171 + ) 172 + 173 + add_library(drv_survive STATIC ${SURVIVE_SOURCE_FILES}) 174 + target_link_libraries(drv_survive PRIVATE xrt-interfaces aux_os aux_util aux_math PkgConfig::SURVIVE) 175 + list(APPEND ENABLED_HEADSET_DRIVERS survive) 176 + endif() 177 + 165 178 if(ENABLED_HEADSET_DRIVERS) 166 179 set(ENABLED_DRIVERS ${ENABLED_HEADSET_DRIVERS} ${ENABLED_DRIVERS}) 167 180 list(SORT ENABLED_DRIVERS)
+16
src/xrt/drivers/meson.build
··· 136 136 dependencies: [aux, zlib], 137 137 build_by_default: 'vive' in drivers, 138 138 ) 139 + 140 + lib_drv_survive = static_library( 141 + 'drv_survive', 142 + files( 143 + 'survive/survive_driver.c', 144 + 'survive/survive_interface.h', 145 + 'survive/survive_wrap.c', 146 + 'survive/survive_wrap.h' 147 + ), 148 + include_directories: [ 149 + xrt_include, 150 + cjson_include, 151 + ], 152 + dependencies: [aux, zlib, survive], 153 + build_by_default: 'survive' in drivers, 154 + )
+1165
src/xrt/drivers/survive/survive_driver.c
··· 1 + // Copyright 2019, Collabora, Ltd. 2 + // SPDX-License-Identifier: Apache-2.0 3 + /*! 4 + * @file 5 + * @brief Adapter to Libsurvive. 6 + * @author Christoph Haag <christoph.haag@collabora.com> 7 + * @author Jakob Bornecrantz <jakob@collabora.com> 8 + * @ingroup drv_survive 9 + */ 10 + 11 + #include <math.h> 12 + #include <stdio.h> 13 + #include <stdlib.h> 14 + #include <string.h> 15 + #include <assert.h> 16 + #include <string.h> 17 + 18 + #include "math/m_api.h" 19 + #include "xrt/xrt_device.h" 20 + #include "util/u_debug.h" 21 + #include "util/u_device.h" 22 + #include "util/u_misc.h" 23 + #include "util/u_time.h" 24 + #include "util/u_device.h" 25 + 26 + #include "../auxiliary/os/os_time.h" 27 + 28 + #include "xrt/xrt_prober.h" 29 + #include "survive_interface.h" 30 + 31 + #include "survive_api.h" 32 + 33 + #include "survive_wrap.h" 34 + 35 + #include "util/u_json.h" 36 + 37 + #define SURVIVE_SPEW(p, ...) \ 38 + do { \ 39 + if (p->print_spew) { \ 40 + fprintf(stderr, "%s - ", __func__); \ 41 + fprintf(stderr, __VA_ARGS__); \ 42 + fprintf(stderr, "\n"); \ 43 + } \ 44 + } while (false) 45 + 46 + #define SURVIVE_DEBUG(p, ...) \ 47 + do { \ 48 + if (p->print_debug) { \ 49 + fprintf(stderr, "%s - ", __func__); \ 50 + fprintf(stderr, __VA_ARGS__); \ 51 + fprintf(stderr, "\n"); \ 52 + } \ 53 + } while (false) 54 + 55 + #define SURVIVE_ERROR(p, ...) \ 56 + do { \ 57 + fprintf(stderr, "%s - ", __func__); \ 58 + fprintf(stderr, __VA_ARGS__); \ 59 + fprintf(stderr, "\n"); \ 60 + } while (false) 61 + 62 + struct survive_system; 63 + 64 + enum input_index 65 + { 66 + VIVE_CONTROLLER_INDEX_AIM_POSE = 0, 67 + VIVE_CONTROLLER_INDEX_GRIP_POSE, 68 + VIVE_CONTROLLER_INDEX_SYSTEM_CLICK, 69 + VIVE_CONTROLLER_INDEX_TRIGGER_CLICK, 70 + VIVE_CONTROLLER_INDEX_TRIGGER_VALUE, 71 + VIVE_CONTROLLER_INDEX_TRACKPAD, 72 + VIVE_CONTROLLER_INDEX_TRACKPAD_TOUCH, 73 + 74 + // Vive Wand specific inputs 75 + VIVE_CONTROLLER_INDEX_SQUEEZE_CLICK, 76 + VIVE_CONTROLLER_INDEX_MENU_CLICK, 77 + VIVE_CONTROLLER_INDEX_TRACKPAD_CLICK, 78 + 79 + // Valve Index specific inputs 80 + VIVE_CONTROLLER_INDEX_THUMBSTICK, 81 + VIVE_CONTROLLER_INDEX_A_CLICK, 82 + VIVE_CONTROLLER_INDEX_B_CLICK, 83 + VIVE_CONTROLLER_INDEX_THUMBSTICK_CLICK, 84 + 85 + // Valve Index Gen2, not yet supported 86 + VIVE_CONTROLLER_INDEX_THUMBSTICK_TOUCH, 87 + VIVE_CONTROLLER_INDEX_SYSTEM_TOUCH, 88 + VIVE_CONTROLLER_INDEX_A_TOUCH, 89 + VIVE_CONTROLLER_INDEX_B_TOUCH, 90 + VIVE_CONTROLLER_INDEX_SQUEEZE_VALUE, 91 + VIVE_CONTROLLER_INDEX_SQUEEZE_FORCE, 92 + VIVE_CONTROLLER_INDEX_TRIGGER_TOUCH, 93 + VIVE_CONTROLLER_INDEX_TRACKPAD_FORCE, 94 + 95 + VIVE_CONTROLLER_MAX_INDEX, 96 + }; 97 + 98 + // also used as index in sys->controllers[] array 99 + typedef enum 100 + { 101 + SURVIVE_LEFT_CONTROLLER = 0, 102 + SURVIVE_RIGHT_CONTROLLER = 1, 103 + SURVIVE_HMD = 2, 104 + } SurviveDeviceType; 105 + 106 + static bool survive_already_initialized = false; 107 + 108 + #define MAX_PENDING_EVENTS 30 109 + struct survive_device 110 + { 111 + struct xrt_device base; 112 + struct survive_system *sys; 113 + const SurviveSimpleObject *survive_obj; 114 + 115 + /* event needs to be processed if 116 + * type != SurviveSimpleEventType_None */ 117 + struct SurviveSimpleEvent pending_events[30]; 118 + int num; 119 + 120 + struct xrt_quat rot[2]; 121 + }; 122 + 123 + enum VIVE_VARIANT 124 + { 125 + VIVE_UNKNOWN = 0, 126 + VIVE_VARIANT_VIVE, 127 + VIVE_VARIANT_PRO, 128 + VIVE_VARIANT_INDEX 129 + }; 130 + 131 + struct survive_system 132 + { 133 + struct xrt_tracking_origin base; 134 + SurviveSimpleContext *ctx; 135 + struct survive_device *hmd; 136 + struct survive_device *controllers[2]; 137 + bool print_spew; 138 + bool print_debug; 139 + enum VIVE_VARIANT variant; 140 + }; 141 + 142 + static void 143 + survive_device_destroy(struct xrt_device *xdev) 144 + { 145 + printf("destroying survive device\n"); 146 + struct survive_device *survive = (struct survive_device *)xdev; 147 + 148 + if (survive == survive->sys->hmd) 149 + survive->sys->hmd = NULL; 150 + if (survive == survive->sys->controllers[SURVIVE_LEFT_CONTROLLER]) 151 + survive->sys->controllers[SURVIVE_LEFT_CONTROLLER] = NULL; 152 + if (survive == survive->sys->controllers[SURVIVE_RIGHT_CONTROLLER]) 153 + survive->sys->controllers[SURVIVE_RIGHT_CONTROLLER] = NULL; 154 + 155 + if (survive->sys->hmd == NULL && 156 + survive->sys->controllers[SURVIVE_LEFT_CONTROLLER] == NULL && 157 + survive->sys->controllers[SURVIVE_RIGHT_CONTROLLER] == NULL) { 158 + printf("Tearing down libsurvive context\n"); 159 + survive_simple_close(survive->sys->ctx); 160 + 161 + free(survive->sys); 162 + } 163 + 164 + free(survive); 165 + } 166 + 167 + static void 168 + _get_survive_pose(const SurviveSimpleObject *survive_object, 169 + SurviveSimpleContext *ctx, 170 + uint64_t *out_relation_timestamp_ns, 171 + struct xrt_space_relation *out_relation) 172 + { 173 + int64_t now = os_monotonic_get_ns(); 174 + //! @todo adjust for latency here 175 + *out_relation_timestamp_ns = now; 176 + 177 + out_relation->relation_flags = 0; 178 + 179 + for (const SurviveSimpleObject *it = 180 + survive_simple_get_first_object(ctx); 181 + it != 0; it = survive_simple_get_next_object(ctx, it)) { 182 + // const char *codename = survive_simple_object_name(it); 183 + 184 + if (survive_simple_object_get_type(it) != 185 + SurviveSimpleObject_OBJECT && 186 + survive_simple_object_get_type(it) != 187 + SurviveSimpleObject_HMD) { 188 + continue; 189 + } 190 + 191 + if (it != survive_object) 192 + continue; 193 + 194 + SurvivePose pose; 195 + 196 + uint32_t timecode = 197 + survive_simple_object_get_latest_pose(it, &pose); 198 + (void)timecode; 199 + 200 + struct xrt_quat out_rot = {.x = pose.Rot[1], 201 + .y = pose.Rot[2], 202 + .z = pose.Rot[3], 203 + .w = pose.Rot[0]}; 204 + // printf ("quat %f %f %f %f\n", out_rot.x, out_rot.y, 205 + // out_rot.z, out_rot.w); 206 + 207 + /* libsurvive looks down when it should be looking forward, so 208 + * rotate the quat. 209 + * because the HMD quat is the opposite of the in world 210 + * rotation, we rotate down. */ 211 + 212 + struct xrt_quat down_rot; 213 + down_rot.x = sqrtf(2) / 2.; 214 + down_rot.y = 0; 215 + down_rot.z = 0; 216 + down_rot.w = -sqrtf(2) / 2.; 217 + 218 + math_quat_rotate(&down_rot, &out_rot, &out_rot); 219 + 220 + 221 + math_quat_normalize(&out_rot); 222 + 223 + out_relation->pose.orientation = out_rot; 224 + 225 + /* because the quat is rotated, y and z axes are switched. */ 226 + out_relation->pose.position.x = pose.Pos[0]; 227 + out_relation->pose.position.y = pose.Pos[2]; 228 + out_relation->pose.position.z = -pose.Pos[1]; 229 + 230 + 231 + out_relation->relation_flags = 232 + (enum xrt_space_relation_flags)( 233 + XRT_SPACE_RELATION_ORIENTATION_VALID_BIT | 234 + XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT) | 235 + XRT_SPACE_RELATION_POSITION_VALID_BIT | 236 + XRT_SPACE_RELATION_POSITION_TRACKED_BIT; 237 + } 238 + } 239 + 240 + static bool 241 + _try_update_codenames(struct survive_system *sys) 242 + { 243 + // TODO: better method 244 + 245 + if (sys->hmd->survive_obj && sys->controllers[0]->survive_obj && 246 + sys->controllers[1]->survive_obj) 247 + return true; 248 + 249 + SurviveSimpleContext *ctx = sys->ctx; 250 + 251 + for (const SurviveSimpleObject *it = 252 + survive_simple_get_first_object(ctx); 253 + it != 0; it = survive_simple_get_next_object(ctx, it)) { 254 + const char *codename = survive_simple_object_name(it); 255 + 256 + enum SurviveSimpleObject_type type = 257 + survive_simple_object_get_type(it); 258 + if (type == SurviveSimpleObject_HMD && 259 + sys->hmd->survive_obj == NULL) { 260 + printf("Found HMD: %s\n", codename); 261 + sys->hmd->survive_obj = it; 262 + } 263 + if (type == SurviveSimpleObject_OBJECT) { 264 + for (int i = 0; i < 2 /* TODO */; i++) { 265 + if (sys->controllers[i]->survive_obj == it) { 266 + break; 267 + } 268 + 269 + if (sys->controllers[i]->survive_obj == NULL) { 270 + printf("Found Controller %d: %s\n", i, 271 + codename); 272 + sys->controllers[i]->survive_obj = it; 273 + break; 274 + } 275 + } 276 + } 277 + } 278 + 279 + return true; 280 + } 281 + 282 + static void 283 + survive_device_get_tracked_pose(struct xrt_device *xdev, 284 + enum xrt_input_name name, 285 + uint64_t at_timestamp_ns, 286 + uint64_t *out_relation_timestamp_ns, 287 + struct xrt_space_relation *out_relation) 288 + { 289 + struct survive_device *survive = (struct survive_device *)xdev; 290 + if ((survive == survive->sys->hmd && 291 + name != XRT_INPUT_GENERIC_HEAD_POSE) || 292 + ((survive == survive->sys->controllers[0] || 293 + survive == survive->sys->controllers[1]) && 294 + (name != XRT_INPUT_INDEX_AIM_POSE && 295 + name != XRT_INPUT_INDEX_GRIP_POSE) && 296 + (name != XRT_INPUT_VIVE_AIM_POSE && 297 + name != XRT_INPUT_VIVE_GRIP_POSE))) { 298 + 299 + SURVIVE_ERROR(survive, "unknown input name"); 300 + return; 301 + } 302 + 303 + _try_update_codenames(survive->sys); 304 + if (!survive->survive_obj) { 305 + // printf("Obj not set for %p\n", (void*)survive); 306 + return; 307 + } 308 + 309 + 310 + _get_survive_pose(survive->survive_obj, survive->sys->ctx, 311 + out_relation_timestamp_ns, out_relation); 312 + 313 + /* 314 + SURVIVE_SPEW( 315 + survive, 316 + "GET_POSITION (%f %f %f) GET_ORIENTATION (%f, %f, %f, %f)", 317 + out_relation->pose.position.x, 318 + out_relation->pose.position.y, 319 + out_relation->pose.position.z, out_rot.x, out_rot.y, 320 + out_rot.z, out_rot.w); 321 + */ 322 + // printf("Get pose %f %f %f\n", out_relation->pose.position.x, 323 + // out_relation->pose.position.y, out_relation->pose.position.z); 324 + } 325 + 326 + static void 327 + survive_device_get_view_pose(struct xrt_device *xdev, 328 + struct xrt_vec3 *eye_relation, 329 + uint32_t view_index, 330 + struct xrt_pose *out_pose) 331 + { 332 + struct xrt_pose pose = {{0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f}}; 333 + bool adjust = view_index == 0; 334 + 335 + struct survive_device *survive = (struct survive_device *)xdev; 336 + pose.orientation = survive->rot[view_index]; 337 + pose.position.x = eye_relation->x / 2.0f; 338 + pose.position.y = eye_relation->y / 2.0f; 339 + pose.position.z = eye_relation->z / 2.0f; 340 + 341 + // Adjust for left/right while also making sure there aren't any -0.f. 342 + if (pose.position.x > 0.0f && adjust) { 343 + pose.position.x = -pose.position.x; 344 + } 345 + if (pose.position.y > 0.0f && adjust) { 346 + pose.position.y = -pose.position.y; 347 + } 348 + if (pose.position.z > 0.0f && adjust) { 349 + pose.position.z = -pose.position.z; 350 + } 351 + 352 + *out_pose = pose; 353 + } 354 + 355 + struct display_info 356 + { 357 + float w_meters; 358 + float h_meters; 359 + int w_pixels; 360 + int h_pixels; 361 + }; 362 + 363 + struct device_info 364 + { 365 + struct display_info display; 366 + 367 + float lens_horizontal_separation; 368 + float lens_vertical_position; 369 + 370 + float pano_distortion_k[4]; 371 + float pano_aberration_k[4]; 372 + float pano_warp_scale; 373 + 374 + struct 375 + { 376 + float fov; 377 + 378 + struct display_info display; 379 + 380 + float lens_center_x_meters; 381 + float lens_center_y_meters; 382 + } views[2]; 383 + }; 384 + 385 + static void 386 + survive_hmd_update_inputs(struct xrt_device *xdev) 387 + {} 388 + 389 + static void 390 + _queue_event(struct survive_system *sys, 391 + SurviveSimpleObject *obj, 392 + SurviveSimpleEvent *event) 393 + { 394 + struct survive_device *dev[] = { 395 + sys->hmd, 396 + sys->controllers[SURVIVE_LEFT_CONTROLLER], 397 + sys->controllers[SURVIVE_RIGHT_CONTROLLER], 398 + }; 399 + for (int i = 0; i < 3; i++) { 400 + if (dev[i] && dev[i]->survive_obj == obj) { 401 + int queue_index = 0; 402 + for (queue_index = 0; queue_index < MAX_PENDING_EVENTS; 403 + queue_index++) { 404 + if (dev[i] 405 + ->pending_events[queue_index] 406 + .event_type == 407 + SurviveSimpleEventType_None) { 408 + break; 409 + } 410 + } 411 + if (queue_index == MAX_PENDING_EVENTS) { 412 + printf( 413 + "Pending event queue full for device %d\n", 414 + i); 415 + return; 416 + } 417 + // printf("Queue event for device %d at index %d\n", i, 418 + // queue_index); 419 + memcpy(&dev[i]->pending_events[queue_index], event, 420 + sizeof(SurviveSimpleEvent)); 421 + } 422 + } 423 + } 424 + 425 + static void 426 + _process_event(struct survive_device *survive, 427 + struct SurviveSimpleEvent *event, 428 + const SurviveSimpleObject *current, 429 + int64_t now) 430 + { 431 + // ?? 432 + const int survive_btn_id_0 = 0; 433 + const int survive_trackpad_touch_btn_id_1 = 1; 434 + 435 + const int survive_squeeze_click_btn_id_2 = 2; 436 + 437 + const int survive_a_btn_id_4 = 4; 438 + const int survive_b_btn_id_5 = 5; 439 + 440 + const int survive_menu_btn_id_12 = 12; 441 + 442 + const int survive_trigger_click_btn_id_24 = 24; 443 + 444 + const int survive_trigger_axis_id = 1; 445 + 446 + /* xy either thumbstick or trackpad */ 447 + const int survive_xy_axis_id_x = 2; 448 + const int survive_xy_axis_id_y = 3; 449 + 450 + switch (event->event_type) { 451 + case SurviveSimpleEventType_ButtonEvent: { 452 + const struct SurviveSimpleButtonEvent *e = 453 + survive_simple_get_button_event(event); 454 + 455 + if (e->object != current) { 456 + if (e->event_type == SurviveSimpleEventType_None) { 457 + // no need to queue empty event 458 + return; 459 + } 460 + _queue_event(survive->sys, e->object, event); 461 + return; 462 + } 463 + 464 + /* 465 + printf("Btn id %d type %d, axes %d ", e->button_id, 466 + e->event_type, e->axis_count); for (int i = 0; i < 467 + e->axis_count; i++) { printf("axis id: %d val %hu ", 468 + e->axis_ids[i], e->axis_val[i]); 469 + } 470 + printf("\n"); 471 + */ 472 + 473 + if (e->button_id == survive_btn_id_0) { 474 + for (int i = 0; i < e->axis_count; i++) { 475 + if (e->axis_ids[i] == survive_trigger_axis_id) { 476 + uint16_t raw = e->axis_val[0]; 477 + float scaled = (float)raw / 32768.; 478 + 479 + survive->base 480 + .inputs 481 + [VIVE_CONTROLLER_INDEX_TRIGGER_VALUE] 482 + .value.vec1.x = scaled; 483 + survive->base 484 + .inputs 485 + [VIVE_CONTROLLER_INDEX_TRIGGER_VALUE] 486 + .timestamp = now; 487 + // printf("Trigger value %f %lu\n", 488 + // survive->base.inputs[TRIGGER_VALUE].value.vec1.x, 489 + // now); 490 + } 491 + if (e->axis_ids[i] == survive_xy_axis_id_x) { 492 + enum input_index input; 493 + if (survive->base 494 + .inputs 495 + [VIVE_CONTROLLER_INDEX_TRACKPAD_TOUCH] 496 + .value.boolean) { 497 + input = 498 + VIVE_CONTROLLER_INDEX_TRACKPAD; 499 + } else { 500 + input = 501 + VIVE_CONTROLLER_INDEX_THUMBSTICK; 502 + } 503 + 504 + float x = 505 + (float)((int16_t)e->axis_val[i]) / 506 + 32768.; 507 + survive->base.inputs[input] 508 + .value.vec2.x = x; 509 + survive->base.inputs[input].timestamp = 510 + now; 511 + // printf("x: %f\n", x); 512 + } 513 + if (e->axis_ids[i] == survive_xy_axis_id_y) { 514 + enum input_index input; 515 + if (survive->base 516 + .inputs 517 + [VIVE_CONTROLLER_INDEX_TRACKPAD_TOUCH] 518 + .value.boolean) { 519 + input = 520 + VIVE_CONTROLLER_INDEX_TRACKPAD; 521 + } else { 522 + input = 523 + VIVE_CONTROLLER_INDEX_THUMBSTICK; 524 + } 525 + 526 + float y = 527 + (float)((int16_t)e->axis_val[i]) / 528 + 32768.; 529 + survive->base.inputs[input] 530 + .value.vec2.y = y; 531 + survive->base.inputs[input].timestamp = 532 + now; 533 + // printf("y: %f\n", y); 534 + } 535 + } 536 + } 537 + 538 + if (e->button_id == survive_squeeze_click_btn_id_2) { 539 + survive->base 540 + .inputs[VIVE_CONTROLLER_INDEX_SQUEEZE_CLICK] 541 + .timestamp = now; 542 + survive->base 543 + .inputs[VIVE_CONTROLLER_INDEX_SQUEEZE_CLICK] 544 + .value.boolean = e->event_type == 1; 545 + } 546 + 547 + if (e->button_id == survive_trigger_click_btn_id_24) { 548 + // 1 = pressed, 2 = released 549 + // printf("trigger click %d\n", e->event_type); 550 + 551 + survive->base 552 + .inputs[VIVE_CONTROLLER_INDEX_TRIGGER_CLICK] 553 + .timestamp = now; 554 + survive->base 555 + .inputs[VIVE_CONTROLLER_INDEX_TRIGGER_CLICK] 556 + .value.boolean = e->event_type == 1; 557 + // printf("Trigger click %d\n", 558 + // survive->base.inputs[INDEX_TRIGGER_CLICK].value.boolean); 559 + } 560 + 561 + if (e->button_id == survive_a_btn_id_4) { 562 + survive->base.inputs[VIVE_CONTROLLER_INDEX_A_CLICK] 563 + .timestamp = now; 564 + survive->base.inputs[VIVE_CONTROLLER_INDEX_A_CLICK] 565 + .value.boolean = e->event_type == 1; 566 + } 567 + 568 + if (e->button_id == survive_b_btn_id_5) { 569 + survive->base.inputs[VIVE_CONTROLLER_INDEX_B_CLICK] 570 + .timestamp = now; 571 + survive->base.inputs[VIVE_CONTROLLER_INDEX_B_CLICK] 572 + .value.boolean = e->event_type == 1; 573 + } 574 + 575 + if (e->button_id == survive_menu_btn_id_12) { 576 + survive->base.inputs[VIVE_CONTROLLER_INDEX_MENU_CLICK] 577 + .timestamp = now; 578 + survive->base.inputs[VIVE_CONTROLLER_INDEX_MENU_CLICK] 579 + .value.boolean = e->event_type == 1; 580 + } 581 + 582 + if (e->button_id == survive_trackpad_touch_btn_id_1) { 583 + survive->base 584 + .inputs[VIVE_CONTROLLER_INDEX_TRACKPAD_TOUCH] 585 + .timestamp = now; 586 + survive->base 587 + .inputs[VIVE_CONTROLLER_INDEX_TRACKPAD_TOUCH] 588 + .value.boolean = e->event_type == 1; 589 + } 590 + 591 + break; 592 + } 593 + case SurviveSimpleEventType_None: break; 594 + } 595 + } 596 + 597 + static void 598 + survive_device_update_inputs(struct xrt_device *xdev) 599 + { 600 + struct survive_device *survive = (struct survive_device *)xdev; 601 + 602 + uint64_t now = os_monotonic_get_ns(); 603 + 604 + const SurviveSimpleObject *current = survive->survive_obj; 605 + 606 + for (int i = 0; i < MAX_PENDING_EVENTS; i++) { 607 + struct SurviveSimpleEvent *event = &survive->pending_events[i]; 608 + _process_event(survive, event, current, now); 609 + 610 + survive->pending_events[i].event_type = 611 + SurviveSimpleEventType_None; 612 + } 613 + 614 + struct SurviveSimpleEvent event = {0}; 615 + while (survive_simple_next_event(survive->sys->ctx, &event) != 616 + SurviveSimpleEventType_None) { 617 + _process_event(survive, &event, current, now); 618 + } 619 + } 620 + 621 + static bool 622 + wait_for_hmd_config(SurviveSimpleContext *ctx) 623 + { 624 + for (const SurviveSimpleObject *it = 625 + survive_simple_get_first_object(ctx); 626 + it != 0; it = survive_simple_get_next_object(ctx, it)) { 627 + 628 + enum SurviveSimpleObject_type type = 629 + survive_simple_object_get_type(it); 630 + if (type == SurviveSimpleObject_HMD && survive_config_ready(it)) 631 + return true; 632 + } 633 + return false; 634 + } 635 + 636 + void 637 + print_vec3(const char *title, struct xrt_vec3 *vec) 638 + { 639 + printf("%s = %f %f %f\n", title, (double)vec->x, (double)vec->y, 640 + (double)vec->z); 641 + } 642 + 643 + static long long 644 + _json_to_int(const cJSON *item) 645 + { 646 + if (item != NULL) { 647 + return item->valueint; 648 + } else { 649 + return 0; 650 + } 651 + } 652 + 653 + static bool 654 + _json_get_matrix_3x3(const cJSON *json, 655 + const char *name, 656 + struct xrt_matrix_3x3 *result) 657 + { 658 + const cJSON *vec3_arr = cJSON_GetObjectItemCaseSensitive(json, name); 659 + 660 + // Some sanity checking. 661 + if (vec3_arr == NULL || cJSON_GetArraySize(vec3_arr) != 3) { 662 + return false; 663 + } 664 + 665 + size_t total = 0; 666 + const cJSON *vec = NULL; 667 + cJSON_ArrayForEach(vec, vec3_arr) 668 + { 669 + assert(cJSON_GetArraySize(vec) == 3); 670 + const cJSON *elem = NULL; 671 + cJSON_ArrayForEach(elem, vec) 672 + { 673 + // Just in case. 674 + if (total >= 9) { 675 + break; 676 + } 677 + 678 + assert(cJSON_IsNumber(elem)); 679 + result->v[total++] = (float)elem->valuedouble; 680 + } 681 + } 682 + 683 + return true; 684 + } 685 + 686 + static float 687 + _json_get_float(const cJSON *json, const char *name) 688 + { 689 + const cJSON *item = cJSON_GetObjectItemCaseSensitive(json, name); 690 + return (float)item->valuedouble; 691 + } 692 + 693 + static long long 694 + _json_get_int(const cJSON *json, const char *name) 695 + { 696 + const cJSON *item = cJSON_GetObjectItemCaseSensitive(json, name); 697 + return _json_to_int(item); 698 + } 699 + 700 + static void 701 + _get_color_coeffs(struct xrt_hmd_parts *hmd, 702 + const cJSON *coeffs, 703 + uint8_t eye, 704 + uint8_t channel) 705 + { 706 + // this is 4 on index, all values populated 707 + // assert(coeffs->length == 8); 708 + // only 3 coeffs contain values 709 + const cJSON *item = NULL; 710 + size_t i = 0; 711 + cJSON_ArrayForEach(item, coeffs) 712 + { 713 + hmd->distortion.vive.coefficients[eye][i][channel] = 714 + (float)item->valuedouble; 715 + ++i; 716 + if (i == 3) { 717 + break; 718 + } 719 + } 720 + } 721 + 722 + static void 723 + _get_color_coeffs_lookup(struct xrt_hmd_parts *hmd, 724 + const cJSON *eye_json, 725 + const char *name, 726 + uint8_t eye, 727 + uint8_t channel) 728 + { 729 + const cJSON *distortion = 730 + cJSON_GetObjectItemCaseSensitive(eye_json, name); 731 + if (distortion == NULL) { 732 + return; 733 + } 734 + 735 + const cJSON *coeffs = 736 + cJSON_GetObjectItemCaseSensitive(distortion, "coeffs"); 737 + if (coeffs == NULL) { 738 + return; 739 + } 740 + 741 + _get_color_coeffs(hmd, coeffs, eye, channel); 742 + } 743 + 744 + static void 745 + get_distortion_properties(struct survive_device *d, 746 + const cJSON *eye_transform_json, 747 + uint8_t eye) 748 + { 749 + struct xrt_hmd_parts *hmd = d->base.hmd; 750 + 751 + const cJSON *eye_json = cJSON_GetArrayItem(eye_transform_json, eye); 752 + if (eye_json == NULL) { 753 + return; 754 + } 755 + 756 + struct xrt_matrix_3x3 rot = {0}; 757 + if (_json_get_matrix_3x3(eye_json, "eye_to_head", &rot)) { 758 + math_quat_from_matrix_3x3(&rot, &d->rot[eye]); 759 + } 760 + 761 + // TODO: store grow_for_undistort per eye 762 + // clang-format off 763 + hmd->distortion.vive.grow_for_undistort = _json_get_float(eye_json, "grow_for_undistort"); 764 + hmd->distortion.vive.undistort_r2_cutoff[eye] = _json_get_float(eye_json, "undistort_r2_cutoff"); 765 + // clang-format on 766 + 767 + const cJSON *distortion = 768 + cJSON_GetObjectItemCaseSensitive(eye_json, "distortion"); 769 + if (distortion != NULL) { 770 + // TODO: store center per color 771 + // clang-format off 772 + hmd->distortion.vive.center[eye][0] = _json_get_float(distortion, "center_x"); 773 + hmd->distortion.vive.center[eye][1] = _json_get_float(distortion, "center_y"); 774 + // clang-format on 775 + 776 + // green 777 + const cJSON *coeffs = 778 + cJSON_GetObjectItemCaseSensitive(distortion, "coeffs"); 779 + if (coeffs != NULL) { 780 + _get_color_coeffs(hmd, coeffs, eye, 1); 781 + } 782 + } 783 + 784 + _get_color_coeffs_lookup(hmd, eye_json, "distortion_red", eye, 0); 785 + _get_color_coeffs_lookup(hmd, eye_json, "distortion_blue", eye, 2); 786 + } 787 + static bool 788 + _create_hmd_device(struct survive_system *sys) 789 + { 790 + enum u_device_alloc_flags flags = 791 + (enum u_device_alloc_flags)U_DEVICE_ALLOC_HMD; 792 + int inputs = 1; 793 + int outputs = 0; 794 + 795 + struct survive_device *survive = 796 + U_DEVICE_ALLOCATE(struct survive_device, flags, inputs, outputs); 797 + sys->hmd = survive; 798 + survive->sys = sys; 799 + survive->survive_obj = NULL; 800 + 801 + survive->base.name = XRT_DEVICE_GENERIC_HMD; 802 + snprintf(survive->base.str, XRT_DEVICE_NAME_LEN, "Survive HMD"); 803 + survive->base.destroy = survive_device_destroy; 804 + survive->base.update_inputs = survive_hmd_update_inputs; 805 + survive->base.get_tracked_pose = survive_device_get_tracked_pose; 806 + survive->base.get_view_pose = survive_device_get_view_pose; 807 + survive->base.tracking_origin = &sys->base; 808 + 809 + survive_simple_start_thread(sys->ctx); 810 + 811 + while (!wait_for_hmd_config(sys->ctx)) { 812 + printf("Waiting for survive HMD config parsing\n"); 813 + os_nanosleep(1000 * 1000 * 100); 814 + } 815 + printf("survive got HMD config\n"); 816 + 817 + while (!survive->survive_obj) { 818 + printf("Waiting for survive HMD to be found...\n"); 819 + for (const SurviveSimpleObject *it = 820 + survive_simple_get_first_object(sys->ctx); 821 + it != 0; 822 + it = survive_simple_get_next_object(sys->ctx, it)) { 823 + const char *codename = survive_simple_object_name(it); 824 + 825 + enum SurviveSimpleObject_type type = 826 + survive_simple_object_get_type(it); 827 + if (type == SurviveSimpleObject_HMD && 828 + sys->hmd->survive_obj == NULL) { 829 + printf("Found HMD: %s\n", codename); 830 + survive->survive_obj = it; 831 + } 832 + } 833 + } 834 + printf("survive HMD present\n"); 835 + 836 + survive->base.hmd->blend_mode = XRT_BLEND_MODE_OPAQUE; 837 + 838 + char *json_string = survive_get_json_config(survive->survive_obj); 839 + cJSON *json = cJSON_Parse(json_string); 840 + if (!cJSON_IsObject(json)) { 841 + printf("Could not parse JSON data."); 842 + return false; 843 + } 844 + 845 + 846 + // TODO: Replace hard coded values from OpenHMD with config 847 + double w_meters = 0.122822 / 2.0; 848 + double h_meters = 0.068234; 849 + double lens_horizontal_separation = 0.057863; 850 + double eye_to_screen_distance = 0.023226876441867737; 851 + double fov = 2 * atan2(w_meters - lens_horizontal_separation / 2.0, 852 + eye_to_screen_distance); 853 + 854 + survive->base.hmd->distortion.vive.aspect_x_over_y = 855 + 0.89999997615814209f; 856 + survive->base.hmd->distortion.vive.grow_for_undistort = 0.5f; 857 + survive->base.hmd->distortion.vive.undistort_r2_cutoff[0] = 1.0f; 858 + survive->base.hmd->distortion.vive.undistort_r2_cutoff[1] = 1.0f; 859 + 860 + survive->rot[0].w = 1.0f; 861 + survive->rot[1].w = 1.0f; 862 + 863 + uint16_t w_pixels = 1080; 864 + uint16_t h_pixels = 1200; 865 + const cJSON *device_json = 866 + cJSON_GetObjectItemCaseSensitive(json, "device"); 867 + if (device_json) { 868 + if (sys->variant != VIVE_VARIANT_INDEX) { 869 + survive->base.hmd->distortion.vive.aspect_x_over_y = 870 + _json_get_float(device_json, 871 + "physical_aspect_x_over_y"); 872 + 873 + //! @todo: fov calculation needs to be fixed, only works 874 + //! with hardcoded value 875 + // lens_horizontal_separation = _json_get_double(json, 876 + // "lens_separation"); 877 + } 878 + h_pixels = (uint16_t)_json_get_int( 879 + device_json, "eye_target_height_in_pixels"); 880 + w_pixels = (uint16_t)_json_get_int( 881 + device_json, "eye_target_width_in_pixels"); 882 + } 883 + 884 + const cJSON *eye_transform_json = 885 + cJSON_GetObjectItemCaseSensitive(json, "tracking_to_eye_transform"); 886 + if (eye_transform_json) { 887 + for (uint8_t eye = 0; eye < 2; eye++) { 888 + get_distortion_properties(survive, eye_transform_json, 889 + eye); 890 + } 891 + } 892 + 893 + printf("Survive eye resolution %dx%d\n", w_pixels, h_pixels); 894 + 895 + cJSON_Delete(json); 896 + 897 + // Main display. 898 + survive->base.hmd->screens[0].w_pixels = (int)w_pixels * 2; 899 + survive->base.hmd->screens[0].h_pixels = (int)h_pixels; 900 + 901 + if (sys->variant == VIVE_VARIANT_INDEX) 902 + survive->base.hmd->screens[0].nominal_frame_interval_ns = 903 + (uint64_t)time_s_to_ns(1.0f / 144.0f); 904 + else 905 + survive->base.hmd->screens[0].nominal_frame_interval_ns = 906 + (uint64_t)time_s_to_ns(1.0f / 90.0f); 907 + 908 + for (uint8_t eye = 0; eye < 2; eye++) { 909 + struct xrt_view *v = &survive->base.hmd->views[eye]; 910 + v->display.w_meters = (float)w_meters; 911 + v->display.h_meters = (float)h_meters; 912 + v->display.w_pixels = w_pixels; 913 + v->display.h_pixels = h_pixels; 914 + v->viewport.w_pixels = w_pixels; 915 + v->viewport.h_pixels = h_pixels; 916 + v->viewport.y_pixels = 0; 917 + v->lens_center.y_meters = (float)h_meters / 2.0f; 918 + v->rot = u_device_rotation_ident; 919 + } 920 + 921 + // Left 922 + survive->base.hmd->views[0].lens_center.x_meters = 923 + (float)(w_meters - lens_horizontal_separation / 2.0); 924 + survive->base.hmd->views[0].viewport.x_pixels = 0; 925 + 926 + // Right 927 + survive->base.hmd->views[1].lens_center.x_meters = 928 + (float)lens_horizontal_separation / 2.0f; 929 + survive->base.hmd->views[1].viewport.x_pixels = w_pixels; 930 + 931 + for (uint8_t eye = 0; eye < 2; eye++) { 932 + if (!math_compute_fovs(w_meters, 933 + (double)survive->base.hmd->views[eye] 934 + .lens_center.x_meters, 935 + fov, h_meters, 936 + (double)survive->base.hmd->views[eye] 937 + .lens_center.y_meters, 938 + 0, &survive->base.hmd->views[eye].fov)) { 939 + printf("Failed to compute the partial fields of view."); 940 + free(survive); 941 + return NULL; 942 + } 943 + } 944 + 945 + survive->base.hmd->distortion.models = XRT_DISTORTION_MODEL_VIVE; 946 + survive->base.hmd->distortion.preferred = XRT_DISTORTION_MODEL_VIVE; 947 + return true; 948 + } 949 + 950 + static bool 951 + _create_controller_device(struct survive_system *sys, int controller_num) 952 + { 953 + 954 + enum u_device_alloc_flags flags = 0; 955 + int inputs = VIVE_CONTROLLER_MAX_INDEX; 956 + int outputs = 0; 957 + struct survive_device *controller = 958 + U_DEVICE_ALLOCATE(struct survive_device, flags, inputs, outputs); 959 + sys->controllers[controller_num] = controller; 960 + controller->sys = sys; 961 + controller->survive_obj = NULL; 962 + for (int i = 0; i < MAX_PENDING_EVENTS; i++) 963 + controller->pending_events[i].event_type = 964 + SurviveSimpleEventType_None; 965 + 966 + controller->num = controller_num; 967 + controller->base.tracking_origin = &sys->base; 968 + 969 + controller->base.destroy = survive_device_destroy; 970 + controller->base.update_inputs = survive_device_update_inputs; 971 + controller->base.get_tracked_pose = survive_device_get_tracked_pose; 972 + 973 + //! @todo: May use Vive Wands + Index HMDs or Index Controllers + Vive 974 + //! HMD 975 + if (sys->variant == VIVE_VARIANT_INDEX) { 976 + controller->base.name = XRT_DEVICE_INDEX_CONTROLLER; 977 + snprintf(controller->base.str, XRT_DEVICE_NAME_LEN, 978 + "Survive Valve Index Controller %d", controller_num); 979 + 980 + controller->base.inputs[VIVE_CONTROLLER_INDEX_AIM_POSE].name = 981 + XRT_INPUT_INDEX_AIM_POSE; 982 + controller->base.inputs[VIVE_CONTROLLER_INDEX_GRIP_POSE].name = 983 + XRT_INPUT_INDEX_GRIP_POSE; 984 + 985 + controller->base.inputs[VIVE_CONTROLLER_INDEX_TRIGGER_VALUE] 986 + .name = XRT_INPUT_INDEX_TRIGGER_VALUE; 987 + controller->base.inputs[VIVE_CONTROLLER_INDEX_TRIGGER_VALUE] 988 + .value.vec1.x = 0; 989 + 990 + controller->base.inputs[VIVE_CONTROLLER_INDEX_TRIGGER_CLICK] 991 + .name = XRT_INPUT_INDEX_TRIGGER_CLICK; 992 + controller->base.inputs[VIVE_CONTROLLER_INDEX_TRIGGER_CLICK] 993 + .value.boolean = false; 994 + 995 + controller->base.inputs[VIVE_CONTROLLER_INDEX_A_CLICK].name = 996 + XRT_INPUT_INDEX_A_CLICK; 997 + controller->base.inputs[VIVE_CONTROLLER_INDEX_A_CLICK] 998 + .value.boolean = false; 999 + 1000 + controller->base.inputs[VIVE_CONTROLLER_INDEX_B_CLICK].name = 1001 + XRT_INPUT_INDEX_B_CLICK; 1002 + controller->base.inputs[VIVE_CONTROLLER_INDEX_B_CLICK] 1003 + .value.boolean = false; 1004 + 1005 + controller->base.inputs[VIVE_CONTROLLER_INDEX_TRIGGER_CLICK] 1006 + .name = XRT_INPUT_INDEX_TRIGGER_CLICK; 1007 + controller->base.inputs[VIVE_CONTROLLER_INDEX_TRIGGER_CLICK] 1008 + .value.boolean = false; 1009 + controller->base.inputs[VIVE_CONTROLLER_INDEX_TRIGGER_CLICK] 1010 + .name = XRT_INPUT_INDEX_TRIGGER_CLICK; 1011 + controller->base.inputs[VIVE_CONTROLLER_INDEX_TRIGGER_CLICK] 1012 + .value.boolean = false; 1013 + 1014 + controller->base.inputs[VIVE_CONTROLLER_INDEX_THUMBSTICK].name = 1015 + XRT_INPUT_INDEX_THUMBSTICK; 1016 + controller->base.inputs[VIVE_CONTROLLER_INDEX_TRACKPAD].name = 1017 + XRT_INPUT_INDEX_TRACKPAD; 1018 + 1019 + controller->base.inputs[VIVE_CONTROLLER_INDEX_TRACKPAD_TOUCH] 1020 + .name = XRT_INPUT_INDEX_TRACKPAD_TOUCH; 1021 + controller->base.inputs[VIVE_CONTROLLER_INDEX_TRACKPAD_TOUCH] 1022 + .value.boolean = false; 1023 + 1024 + } else { 1025 + controller->base.name = XRT_DEVICE_VIVE_WAND; 1026 + snprintf(controller->base.str, XRT_DEVICE_NAME_LEN, 1027 + "Survive Vive Wand Controller %d", controller_num); 1028 + 1029 + controller->base.inputs[VIVE_CONTROLLER_INDEX_AIM_POSE].name = 1030 + XRT_INPUT_VIVE_AIM_POSE; 1031 + controller->base.inputs[VIVE_CONTROLLER_INDEX_GRIP_POSE].name = 1032 + XRT_INPUT_VIVE_GRIP_POSE; 1033 + 1034 + controller->base.inputs[VIVE_CONTROLLER_INDEX_TRIGGER_VALUE] 1035 + .name = XRT_INPUT_VIVE_TRIGGER_VALUE; 1036 + controller->base.inputs[VIVE_CONTROLLER_INDEX_TRIGGER_VALUE] 1037 + .value.vec1.x = 0; 1038 + 1039 + controller->base.inputs[VIVE_CONTROLLER_INDEX_TRIGGER_CLICK] 1040 + .name = XRT_INPUT_VIVE_TRIGGER_CLICK; 1041 + controller->base.inputs[VIVE_CONTROLLER_INDEX_TRIGGER_CLICK] 1042 + .value.boolean = false; 1043 + 1044 + controller->base.inputs[VIVE_CONTROLLER_INDEX_MENU_CLICK].name = 1045 + XRT_INPUT_VIVE_MENU_CLICK; 1046 + controller->base.inputs[VIVE_CONTROLLER_INDEX_MENU_CLICK] 1047 + .value.boolean = false; 1048 + 1049 + controller->base.inputs[VIVE_CONTROLLER_INDEX_TRIGGER_CLICK] 1050 + .name = XRT_INPUT_VIVE_TRIGGER_CLICK; 1051 + controller->base.inputs[VIVE_CONTROLLER_INDEX_TRIGGER_CLICK] 1052 + .value.boolean = false; 1053 + controller->base.inputs[VIVE_CONTROLLER_INDEX_TRIGGER_CLICK] 1054 + .name = XRT_INPUT_VIVE_TRIGGER_CLICK; 1055 + controller->base.inputs[VIVE_CONTROLLER_INDEX_TRIGGER_CLICK] 1056 + .value.boolean = false; 1057 + 1058 + controller->base.inputs[VIVE_CONTROLLER_INDEX_TRACKPAD].name = 1059 + XRT_INPUT_VIVE_TRACKPAD; 1060 + 1061 + controller->base.inputs[VIVE_CONTROLLER_INDEX_TRACKPAD_TOUCH] 1062 + .name = XRT_INPUT_VIVE_TRACKPAD_TOUCH; 1063 + controller->base.inputs[VIVE_CONTROLLER_INDEX_TRACKPAD_TOUCH] 1064 + .value.boolean = false; 1065 + 1066 + controller->base.inputs[VIVE_CONTROLLER_INDEX_TRACKPAD_CLICK] 1067 + .name = XRT_INPUT_VIVE_TRACKPAD_CLICK; 1068 + controller->base.inputs[VIVE_CONTROLLER_INDEX_TRACKPAD_CLICK] 1069 + .value.boolean = false; 1070 + 1071 + controller->base.inputs[VIVE_CONTROLLER_INDEX_SQUEEZE_CLICK] 1072 + .name = XRT_INPUT_VIVE_SQUEEZE_CLICK; 1073 + controller->base.inputs[VIVE_CONTROLLER_INDEX_SQUEEZE_CLICK] 1074 + .value.boolean = false; 1075 + } 1076 + 1077 + 1078 + return true; 1079 + } 1080 + 1081 + DEBUG_GET_ONCE_BOOL_OPTION(survive_spew, "SURVIVE_PRINT_SPEW", false) 1082 + DEBUG_GET_ONCE_BOOL_OPTION(survive_debug, "SURVIVE_PRINT_DEBUG", false) 1083 + 1084 + static enum VIVE_VARIANT 1085 + _product_to_variant(uint16_t product_id) 1086 + { 1087 + switch (product_id) { 1088 + case VIVE_PID: return VIVE_VARIANT_VIVE; 1089 + case VIVE_PRO_MAINBOARD_PID: return VIVE_VARIANT_PRO; 1090 + case VIVE_PRO_LHR_PID: return VIVE_VARIANT_INDEX; 1091 + default: 1092 + printf("No product ids matched %.4x\n", product_id); 1093 + return VIVE_UNKNOWN; 1094 + } 1095 + } 1096 + 1097 + int 1098 + survive_found(struct xrt_prober *xp, 1099 + struct xrt_prober_device **devices, 1100 + size_t num_devices, 1101 + size_t index, 1102 + cJSON *attached_data, 1103 + struct xrt_device **out_xdevs) 1104 + { 1105 + if (survive_already_initialized) { 1106 + printf( 1107 + "Skipping libsurvive initialization, already " 1108 + "initialized\n"); 1109 + return 0; 1110 + } 1111 + 1112 + SurviveSimpleContext *actx = NULL; 1113 + #if 1 1114 + char *survive_args[] = { 1115 + "Monado-libsurvive", 1116 + //"--time-window", "1500000" 1117 + //"--use-imu", "0", 1118 + //"--use-kalman", "0" 1119 + }; 1120 + actx = survive_simple_init( 1121 + sizeof(survive_args) / sizeof(survive_args[0]), survive_args); 1122 + #else 1123 + actx = survive_simple_init(0, 0); 1124 + #endif 1125 + 1126 + if (!actx) { 1127 + SURVIVE_ERROR(survive, "failed to init survive"); 1128 + return false; 1129 + } 1130 + 1131 + struct survive_system *ss = U_TYPED_CALLOC(struct survive_system); 1132 + 1133 + struct xrt_prober_device *dev = devices[index]; 1134 + ss->variant = _product_to_variant(dev->product_id); 1135 + printf("survive: Assuming variant %d\n", ss->variant); 1136 + 1137 + ss->ctx = actx; 1138 + snprintf(ss->base.name, XRT_TRACKING_NAME_LEN, "%s", 1139 + "Libsurvive Tracking"); 1140 + ss->base.offset.position.x = 0.0f; 1141 + ss->base.offset.position.y = 0.0f; 1142 + ss->base.offset.position.z = 0.0f; 1143 + ss->base.offset.orientation.w = 1.0f; 1144 + 1145 + ss->print_spew = debug_get_bool_option_survive_spew(); 1146 + ss->print_debug = debug_get_bool_option_survive_debug(); 1147 + 1148 + _create_hmd_device(ss); 1149 + _create_controller_device(ss, 0); 1150 + _create_controller_device(ss, 1); 1151 + 1152 + // printf("Survive HMD %p, controller %p %p\n", ss->hmd, 1153 + // ss->controllers[0], ss->controllers[1]); 1154 + 1155 + if (ss->print_debug) { 1156 + u_device_dump_config(&ss->hmd->base, __func__, "libsurvive"); 1157 + } 1158 + 1159 + out_xdevs[0] = &ss->hmd->base; 1160 + out_xdevs[1] = &ss->controllers[0]->base; 1161 + out_xdevs[2] = &ss->controllers[1]->base; 1162 + 1163 + survive_already_initialized = true; 1164 + return 3; 1165 + }
+36
src/xrt/drivers/survive/survive_interface.h
··· 1 + // Copyright 2019, Collabora, Ltd. 2 + // SPDX-License-Identifier: Apache-2.0 3 + /*! 4 + * @file 5 + * @brief Interface to Libsurvive adapter. 6 + * @author Christoph Haag <christoph.haag@collabora.com> 7 + * @author Jakob Bornecrantz <jakob@collabora.com> 8 + * @ingroup drv_survive 9 + */ 10 + 11 + #pragma once 12 + 13 + #ifdef __cplusplus 14 + extern "C" { 15 + #endif 16 + 17 + #define HTC_VID 0x0bb4 18 + #define VALVE_VID 0x28de 19 + 20 + #define VIVE_PID 0x2c87 21 + #define VIVE_LIGHTHOUSE_FPGA_RX 0x2000 22 + 23 + #define VIVE_PRO_MAINBOARD_PID 0x0309 24 + #define VIVE_PRO_LHR_PID 0x2300 25 + 26 + int 27 + survive_found(struct xrt_prober *xp, 28 + struct xrt_prober_device **devices, 29 + size_t num_devices, 30 + size_t index, 31 + cJSON *attached_data, 32 + struct xrt_device **out_xdevs); 33 + 34 + #ifdef __cplusplus 35 + } 36 + #endif
+30
src/xrt/drivers/survive/survive_wrap.c
··· 1 + // Copyright 2020, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief low level libsurvive wrapper 6 + * @author Christoph Haag <christoph.haag@collabora.com> 7 + * @ingroup drv_survive 8 + */ 9 + 10 + #define SURVIVE_ENABLE_FULL_API 1 11 + #include "survive_api.h" 12 + 13 + #include "survive_wrap.h" 14 + 15 + // TODO: expose config values we need through actual survive API 16 + #include "survive.h" 17 + 18 + bool 19 + survive_config_ready(const SurviveSimpleObject *sso) 20 + { 21 + SurviveObject *so = survive_simple_get_survive_object(sso); 22 + return so->conf != 0; 23 + } 24 + 25 + char * 26 + survive_get_json_config(const SurviveSimpleObject *sso) 27 + { 28 + SurviveObject *so = survive_simple_get_survive_object(sso); 29 + return so->conf; 30 + }
+18
src/xrt/drivers/survive/survive_wrap.h
··· 1 + // Copyright 2020, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief low level libsurvive wrapper 6 + * @author Christoph Haag <christoph.haag@collabora.com> 7 + * @ingroup drv_survive 8 + */ 9 + 10 + #pragma once 11 + 12 + #include "survive_api.h" 13 + 14 + bool 15 + survive_config_ready(const SurviveSimpleObject *sso); 16 + 17 + char * 18 + survive_get_json_config(const SurviveSimpleObject *sso);
+3
src/xrt/targets/common/CMakeLists.txt
··· 67 67 target_link_libraries(target_lists PRIVATE drv_vive) 68 68 endif() 69 69 70 + if(BUILD_DRIVER_SURVIVE) 71 + target_link_libraries(target_lists PRIVATE drv_survive) 72 + endif() 70 73 71 74 #### 72 75 # Instance
+10
src/xrt/targets/common/target_lists.c
··· 42 42 #include "hydra/hydra_interface.h" 43 43 #endif 44 44 45 + #ifdef XRT_BUILD_DRIVER_SURVIVE 46 + #include "survive/survive_interface.h" 47 + #endif 48 + 45 49 #ifdef XRT_BUILD_DRIVER_VIVE 46 50 #include "vive/vive_prober.h" 47 51 #include "vive/vive_controller_interface.h" ··· 81 85 #ifdef XRT_BUILD_DRIVER_HDK 82 86 {HDK_VID, HDK_PID, hdk_found, "OSVR HDK"}, 83 87 #endif // XRT_BUILD_DRIVER_HDK 88 + 89 + #ifdef XRT_BUILD_DRIVER_SURVIVE 90 + {HTC_VID, VIVE_PID, survive_found, "HTC Vive"}, 91 + {HTC_VID, VIVE_PRO_MAINBOARD_PID, survive_found, "HTC Vive Pro"}, 92 + {VALVE_VID, VIVE_PRO_LHR_PID, survive_found, "Valve Index"}, 93 + #endif 84 94 85 95 #ifdef XRT_BUILD_DRIVER_VIVE 86 96 {HTC_VID, VIVE_PID, vive_found, "HTC Vive"},
+4
src/xrt/targets/meson.build
··· 54 54 driver_libs += [lib_drv_vive] 55 55 endif 56 56 57 + if 'survive' in drivers 58 + driver_libs += [lib_drv_survive] 59 + endif 60 + 57 61 subdir('common') 58 62 subdir('openxr') 59 63 subdir('cli')