diff --git a/src/xrt/drivers/wmr/wmr_hmd.c b/src/xrt/drivers/wmr/wmr_hmd.c index 3e0d23ae4..c8c104a2e 100644 --- a/src/xrt/drivers/wmr/wmr_hmd.c +++ b/src/xrt/drivers/wmr/wmr_hmd.c @@ -42,6 +42,21 @@ #include // for sleep() #endif +static int +wmr_hmd_activate_reverb(struct wmr_hmd *wh); +static void +wmr_hmd_deactivate_reverb(struct wmr_hmd *wh); + +const struct wmr_headset_descriptor headset_map[] = { + {WMR_HEADSET_GENERIC, NULL, "Unknown WMR HMD", NULL, NULL}, /* Catch-all for unknown headsets */ + {WMR_HEADSET_REVERB_G1, "HP Reverb VR Headset VR1000-2xxx", "HP Reverb", wmr_hmd_activate_reverb, + wmr_hmd_deactivate_reverb}, + {WMR_HEADSET_REVERB_G2, "HP Reverb Virtual Reality Headset G2", "HP Reverb G2", wmr_hmd_activate_reverb, + wmr_hmd_deactivate_reverb}, + {WMR_HEADSET_SAMSUNG_800ZAA, "Samsung Windows Mixed Reality 800ZAA", "Samsung Odyssey", NULL, NULL}, + {WMR_HEADSET_LENOVO_EXPLORER, "Lenovo VR-2511N", "Lenovo Explorer", NULL, NULL}, +}; +const int headset_map_n = sizeof(headset_map) / sizeof(headset_map[0]); /* * @@ -311,7 +326,7 @@ hololens_sensors_enable_imu(struct wmr_hmd *wh) } while (false); static int -wmr_hmd_activate(struct wmr_hmd *wh) +wmr_hmd_activate_reverb(struct wmr_hmd *wh) { struct os_hid_device *hid = wh->hid_control_dev; @@ -359,7 +374,7 @@ wmr_hmd_activate(struct wmr_hmd *wh) } static void -wmr_hmd_deactivate(struct wmr_hmd *wh) +wmr_hmd_deactivate_reverb(struct wmr_hmd *wh) { struct os_hid_device *hid = wh->hid_control_dev; @@ -497,6 +512,9 @@ wmr_read_config(struct wmr_hmd *wh) /* FIXME: The header contains little-endian values that need swapping for big-endian */ struct wmr_config_header *hdr = (struct wmr_config_header *)data; + /* Take a copy of the header */ + memcpy(&wh->config_hdr, hdr, sizeof(struct wmr_config_header)); + WMR_INFO(wh, "Manufacturer: %.*s", (int)sizeof(hdr->manufacturer), hdr->manufacturer); WMR_INFO(wh, "Device: %.*s", (int)sizeof(hdr->device), hdr->device); WMR_INFO(wh, "Serial: %.*s", (int)sizeof(hdr->serial), hdr->serial); @@ -604,7 +622,10 @@ wmr_hmd_destroy(struct xrt_device *xdev) } if (wh->hid_control_dev != NULL) { - wmr_hmd_deactivate(wh); + /* Do any deinit if we have a deinit function */ + if (wh->hmd_desc && wh->hmd_desc->deinit_func) { + wh->hmd_desc->deinit_func(wh); + } os_hid_destroy(wh->hid_control_dev); wh->hid_control_dev = NULL; } @@ -669,11 +690,14 @@ compute_distortion_wmr(struct xrt_device *xdev, int view, float u, float v, stru } struct xrt_device * -wmr_hmd_create(struct os_hid_device *hid_holo, struct os_hid_device *hid_ctrl, enum u_logging_level ll) +wmr_hmd_create(enum wmr_headset_type hmd_type, + struct os_hid_device *hid_holo, + struct os_hid_device *hid_ctrl, + enum u_logging_level ll) { enum u_device_alloc_flags flags = (enum u_device_alloc_flags)(U_DEVICE_ALLOC_HMD | U_DEVICE_ALLOC_TRACKING_NONE); - int ret = 0; + int ret = 0, i; int eye; struct wmr_hmd *wh = U_DEVICE_ALLOCATE(struct wmr_hmd, flags, 1, 0); @@ -725,6 +749,29 @@ wmr_hmd_create(struct os_hid_device *hid_holo, struct os_hid_device *hid_ctrl, e return NULL; } + /* Now that we have the config loaded, iterate the map of known headsets and see if we have + * an entry for this specific headset (otherwise the generic entry will be used) + */ + for (i = 0; i < headset_map_n; i++) { + const struct wmr_headset_descriptor *cur = &headset_map[i]; + + if (hmd_type == cur->hmd_type) { + wh->hmd_desc = cur; + if (hmd_type != WMR_HEADSET_GENERIC) + break; /* Stop checking if we have a specific match, or keep going for the GENERIC + catch-all type */ + } + + if (cur->dev_id_str && strncmp(wh->config_hdr.name, cur->dev_id_str, 64) == 0) { + hmd_type = cur->hmd_type; + wh->hmd_desc = cur; + break; + } + } + assert(wh->hmd_desc != NULL); /* We must have matched something, or the map is set up wrong */ + + WMR_INFO(wh, "Found WMR headset type: %s", wh->hmd_desc->debug_name); + // Compute centerline in the HMD's calibration coordinate space as the average of the two display poses math_quat_slerp(&wh->config.eye_params[0].pose.orientation, &wh->config.eye_params[1].pose.orientation, 0.5f, &wh->centerline.orientation); @@ -794,7 +841,7 @@ wmr_hmd_create(struct os_hid_device *hid_holo, struct os_hid_device *hid_ctrl, e u_distortion_mesh_fill_in_compute(&wh->base); /* We're set up. Activate the HMD and turn on the IMU */ - if (wmr_hmd_activate(wh) != 0) { + if (wh->hmd_desc->init_func && wh->hmd_desc->init_func(wh) != 0) { WMR_ERROR(wh, "Activation of HMD failed"); wmr_hmd_destroy(&wh->base); wh = NULL; diff --git a/src/xrt/drivers/wmr/wmr_hmd.h b/src/xrt/drivers/wmr/wmr_hmd.h index 4f8561e13..b9a210957 100644 --- a/src/xrt/drivers/wmr/wmr_hmd.h +++ b/src/xrt/drivers/wmr/wmr_hmd.h @@ -42,6 +42,30 @@ enum rvb_g1_status_bits // clang-format on }; +enum wmr_headset_type +{ + WMR_HEADSET_GENERIC, + WMR_HEADSET_REVERB_G1, + WMR_HEADSET_REVERB_G2, + WMR_HEADSET_SAMSUNG_800ZAA, + WMR_HEADSET_LENOVO_EXPLORER +}; + +struct wmr_hmd; + +struct wmr_headset_descriptor +{ + enum wmr_headset_type hmd_type; + + /* String by which we recognise the device */ + const char *dev_id_str; + /* Friendly ID string for debug */ + const char *debug_name; + + int (*init_func)(struct wmr_hmd *wh); + void (*deinit_func)(struct wmr_hmd *wh); +}; + struct wmr_hmd_distortion_params { /* Inverse affine transform to move from (undistorted) pixels @@ -61,7 +85,12 @@ struct wmr_hmd { struct xrt_device base; - // Config block read from the firmware JSON + const struct wmr_headset_descriptor *hmd_desc; + + /* firmware configuration block, with device names etc */ + struct wmr_config_header config_hdr; + + /* Config data parsed from the firmware JSON */ struct wmr_hmd_config config; //! Packet reading thread. @@ -124,7 +153,10 @@ wmr_hmd(struct xrt_device *p) } struct xrt_device * -wmr_hmd_create(struct os_hid_device *hid_holo, struct os_hid_device *hid_ctrl, enum u_logging_level ll); +wmr_hmd_create(enum wmr_headset_type hmd_type, + struct os_hid_device *hid_holo, + struct os_hid_device *hid_ctrl, + enum u_logging_level ll); #define WMR_TRACE(d, ...) U_LOG_XDEV_IFL_T(&d->base, d->log_level, __VA_ARGS__) #define WMR_DEBUG(d, ...) U_LOG_XDEV_IFL_D(&d->base, d->log_level, __VA_ARGS__) diff --git a/src/xrt/drivers/wmr/wmr_prober.c b/src/xrt/drivers/wmr/wmr_prober.c index b4dcc348e..48ddf165c 100644 --- a/src/xrt/drivers/wmr/wmr_prober.c +++ b/src/xrt/drivers/wmr/wmr_prober.c @@ -23,7 +23,6 @@ #include #include - /* * * Defines & structs. @@ -40,24 +39,31 @@ DEBUG_GET_ONCE_LOG_OPTION(wmr_log, "WMR_LOG", U_LOGGING_INFO) */ static bool -check_and_get_interface_hp(struct xrt_prober_device *device, int *out_interface) +check_and_get_interface_hp(struct xrt_prober_device *device, enum wmr_headset_type *out_hmd_type, int *out_interface) { if (device->product_id != REVERB_G1_PID && device->product_id != REVERB_G2_PID) { return false; } + if (device->product_id == REVERB_G1_PID) + *out_hmd_type = WMR_HEADSET_REVERB_G1; + else + *out_hmd_type = WMR_HEADSET_REVERB_G2; *out_interface = 0; return true; } static bool -check_and_get_interface_lenovo(struct xrt_prober_device *device, int *out_interface) +check_and_get_interface_lenovo(struct xrt_prober_device *device, + enum wmr_headset_type *out_hmd_type, + int *out_interface) { if (device->product_id != EXPLORER_PID) { return false; } + *out_hmd_type = WMR_HEADSET_LENOVO_EXPLORER; *out_interface = 0; return true; @@ -68,6 +74,7 @@ find_control_device(struct xrt_prober *xp, struct xrt_prober_device **devices, size_t num_devices, enum u_logging_level ll, + enum wmr_headset_type *out_hmd_type, struct xrt_prober_device **out_device, int *out_interface) { @@ -82,8 +89,8 @@ find_control_device(struct xrt_prober *xp, } switch (devices[i]->vendor_id) { - case HP_VID: match = check_and_get_interface_hp(devices[i], &interface); break; - case LENOVO_VID: match = check_and_get_interface_lenovo(devices[i], &interface); break; + case HP_VID: match = check_and_get_interface_hp(devices[i], out_hmd_type, &interface); break; + case LENOVO_VID: match = check_and_get_interface_lenovo(devices[i], out_hmd_type, &interface); break; default: break; } @@ -129,6 +136,7 @@ wmr_found(struct xrt_prober *xp, struct xrt_prober_device *dev_holo = devices[index]; struct xrt_prober_device *dev_ctrl = NULL; + enum wmr_headset_type hmd_type = WMR_HEADSET_GENERIC; int interface_holo = 2; int interface_ctrl = 0; @@ -141,7 +149,7 @@ wmr_found(struct xrt_prober *xp, return -1; } - if (!find_control_device(xp, devices, num_devices, ll, &dev_ctrl, &interface_ctrl)) { + if (!find_control_device(xp, devices, num_devices, ll, &hmd_type, &dev_ctrl, &interface_ctrl)) { U_LOG_IFL_E(ll, "Did not find companion control device." "\n\tCurrently only Reverb G1 and G2 is supported"); @@ -162,7 +170,7 @@ wmr_found(struct xrt_prober *xp, return -1; } - struct xrt_device *p = wmr_hmd_create(hid_holo, hid_ctrl, ll); + struct xrt_device *p = wmr_hmd_create(hmd_type, hid_holo, hid_ctrl, ll); if (!p) { U_LOG_IFL_E(ll, "Failed to create Windows Mixed Reality device"); return -1;