d/wmr: Add an extensible headset map.

Add a mechanism for recognising known headsets and handling specific
init/deinit sequences for those that need it.
This commit is contained in:
Jan Schmidt 2021-06-24 00:36:54 +10:00
parent 6bb3577b1b
commit dfe932ffd7
3 changed files with 102 additions and 15 deletions

View file

@ -42,6 +42,21 @@
#include <unistd.h> // 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;

View file

@ -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__)

View file

@ -23,7 +23,6 @@
#include <stdlib.h>
#include <wchar.h>
/*
*
* 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;