mirror of
https://gitlab.freedesktop.org/monado/monado.git
synced 2025-02-03 12:28:07 +00:00
drivers: Add a sample driver intended for use as a template.
This commit is contained in:
parent
e2c6fbdd9a
commit
33e367ee42
src/xrt/drivers
|
@ -296,6 +296,13 @@ if(XRT_BUILD_DRIVER_EUROC)
|
|||
list(APPEND ENABLED_DRIVERS euroc)
|
||||
endif()
|
||||
|
||||
# We always build the sample driver, to make sure it stays valid, but it never gets linked
|
||||
add_library(drv_sample STATIC
|
||||
sample/sample_hmd.c
|
||||
sample/sample_interface.h
|
||||
sample/sample_prober.c)
|
||||
target_link_libraries(drv_sample PRIVATE xrt-interfaces aux_util)
|
||||
|
||||
if(ENABLED_HEADSET_DRIVERS)
|
||||
set(ENABLED_DRIVERS ${ENABLED_HEADSET_DRIVERS} ${ENABLED_DRIVERS})
|
||||
list(SORT ENABLED_DRIVERS)
|
||||
|
|
192
src/xrt/drivers/sample/sample_hmd.c
Normal file
192
src/xrt/drivers/sample/sample_hmd.c
Normal file
|
@ -0,0 +1,192 @@
|
|||
// Copyright 2020-2021, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Sample HMD device, use as a starting point to make your own device driver.
|
||||
*
|
||||
*
|
||||
* Based largely on dummy_hmd.c
|
||||
*
|
||||
* @author Jakob Bornecrantz <jakob@collabora.com>
|
||||
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
|
||||
* @ingroup drv_sample
|
||||
*/
|
||||
|
||||
#include "xrt/xrt_device.h"
|
||||
|
||||
#include "os/os_time.h"
|
||||
|
||||
#include "math/m_api.h"
|
||||
#include "math/m_mathinclude.h"
|
||||
|
||||
#include "util/u_var.h"
|
||||
#include "util/u_misc.h"
|
||||
#include "util/u_time.h"
|
||||
#include "util/u_debug.h"
|
||||
#include "util/u_device.h"
|
||||
#include "util/u_logging.h"
|
||||
#include "util/u_distortion_mesh.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Structs and defines.
|
||||
*
|
||||
*/
|
||||
|
||||
/*!
|
||||
* A sample HMD device.
|
||||
*
|
||||
* @implements xrt_device
|
||||
*/
|
||||
struct sample_hmd
|
||||
{
|
||||
struct xrt_device base;
|
||||
|
||||
struct xrt_pose pose;
|
||||
|
||||
enum u_logging_level log_level;
|
||||
};
|
||||
|
||||
|
||||
/// Casting helper function
|
||||
static inline struct sample_hmd *
|
||||
sample_hmd(struct xrt_device *xdev)
|
||||
{
|
||||
return (struct sample_hmd *)xdev;
|
||||
}
|
||||
|
||||
DEBUG_GET_ONCE_LOG_OPTION(sample_log, "SAMPLE_LOG", U_LOGGING_WARN)
|
||||
|
||||
#define SH_TRACE(p, ...) U_LOG_XDEV_IFL_T(&sh->base, sh->log_level, __VA_ARGS__)
|
||||
#define SH_DEBUG(p, ...) U_LOG_XDEV_IFL_D(&sh->base, sh->log_level, __VA_ARGS__)
|
||||
#define SH_ERROR(p, ...) U_LOG_XDEV_IFL_E(&sh->base, sh->log_level, __VA_ARGS__)
|
||||
|
||||
static void
|
||||
sample_hmd_destroy(struct xrt_device *xdev)
|
||||
{
|
||||
struct sample_hmd *sh = sample_hmd(xdev);
|
||||
|
||||
// Remove the variable tracking.
|
||||
u_var_remove_root(sh);
|
||||
|
||||
u_device_free(&sh->base);
|
||||
}
|
||||
|
||||
static void
|
||||
sample_hmd_update_inputs(struct xrt_device *xdev)
|
||||
{
|
||||
// Empty, you should put code to update the attached input fields (if any)
|
||||
}
|
||||
|
||||
static void
|
||||
sample_hmd_get_tracked_pose(struct xrt_device *xdev,
|
||||
enum xrt_input_name name,
|
||||
uint64_t at_timestamp_ns,
|
||||
struct xrt_space_relation *out_relation)
|
||||
{
|
||||
struct sample_hmd *sh = sample_hmd(xdev);
|
||||
|
||||
if (name != XRT_INPUT_GENERIC_HEAD_POSE) {
|
||||
SH_ERROR(sh, "unknown input name");
|
||||
return;
|
||||
}
|
||||
|
||||
// Estimate pose at timestamp at_timestamp_ns!
|
||||
math_quat_normalize(&sh->pose.orientation);
|
||||
out_relation->pose = sh->pose;
|
||||
out_relation->relation_flags = (enum xrt_space_relation_flags)(XRT_SPACE_RELATION_ORIENTATION_VALID_BIT |
|
||||
XRT_SPACE_RELATION_POSITION_VALID_BIT |
|
||||
XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT);
|
||||
}
|
||||
|
||||
static void
|
||||
sample_hmd_get_view_pose(struct xrt_device *xdev,
|
||||
const struct xrt_vec3 *eye_relation,
|
||||
uint32_t view_index,
|
||||
struct xrt_pose *out_pose)
|
||||
{
|
||||
(void)xdev;
|
||||
// This helper function assumes a symmetric IPD
|
||||
u_device_get_view_pose(eye_relation, view_index, out_pose);
|
||||
}
|
||||
|
||||
struct xrt_device *
|
||||
sample_hmd_create(void)
|
||||
{
|
||||
// This indicates you won't be using Monado's built-in tracking algorithms.
|
||||
enum u_device_alloc_flags flags =
|
||||
(enum u_device_alloc_flags)(U_DEVICE_ALLOC_HMD | U_DEVICE_ALLOC_TRACKING_NONE);
|
||||
|
||||
struct sample_hmd *sh = U_DEVICE_ALLOCATE(struct sample_hmd, flags, 1, 0);
|
||||
sh->base.update_inputs = sample_hmd_update_inputs;
|
||||
sh->base.get_tracked_pose = sample_hmd_get_tracked_pose;
|
||||
sh->base.get_view_pose = sample_hmd_get_view_pose;
|
||||
sh->base.destroy = sample_hmd_destroy;
|
||||
sh->base.name = XRT_DEVICE_GENERIC_HMD;
|
||||
sh->base.device_type = XRT_DEVICE_TYPE_HMD;
|
||||
sh->pose.orientation.w = 1.0f; // All other values set to zero by U_DEVICE_ALLOCATE (which calls U_CALLOC)
|
||||
sh->log_level = debug_get_log_option_sample_log();
|
||||
|
||||
// Print name.
|
||||
snprintf(sh->base.str, XRT_DEVICE_NAME_LEN, "Sample HMD");
|
||||
snprintf(sh->base.serial, XRT_DEVICE_NAME_LEN, "Sample HMD S/N");
|
||||
|
||||
// Setup input.
|
||||
sh->base.inputs[0].name = XRT_INPUT_GENERIC_HEAD_POSE;
|
||||
|
||||
// Set up display details
|
||||
// refresh rate
|
||||
sh->base.hmd->screens[0].nominal_frame_interval_ns = time_s_to_ns(1.0f / 90.0f);
|
||||
|
||||
const double hFOV = 90 * (M_PI / 180.0);
|
||||
const double vFOV = 96.73 * (M_PI / 180.0);
|
||||
// center of projection
|
||||
const double hCOP = 0.529;
|
||||
const double vCOP = 0.5;
|
||||
if (
|
||||
/* right eye */
|
||||
!math_compute_fovs(1, hCOP, hFOV, 1, vCOP, vFOV, &sh->base.hmd->views[1].fov) ||
|
||||
/*
|
||||
* left eye - same as right eye, except the horizontal center of projection is moved in the opposite
|
||||
* direction now
|
||||
*/
|
||||
!math_compute_fovs(1, 1.0 - hCOP, hFOV, 1, vCOP, vFOV, &sh->base.hmd->views[0].fov)) {
|
||||
// If those failed, it means our math was impossible.
|
||||
SH_ERROR(sh, "Failed to setup basic device info");
|
||||
sample_hmd_destroy(&sh->base);
|
||||
return NULL;
|
||||
}
|
||||
const int panel_w = 1080;
|
||||
const int panel_h = 1200;
|
||||
|
||||
// Single "screen" (always the case)
|
||||
sh->base.hmd->screens[0].w_pixels = panel_w * 2;
|
||||
sh->base.hmd->screens[0].h_pixels = panel_h;
|
||||
|
||||
// Left, Right
|
||||
for (uint8_t eye = 0; eye < 2; ++eye) {
|
||||
sh->base.hmd->views[eye].display.w_pixels = panel_w;
|
||||
sh->base.hmd->views[eye].display.h_pixels = panel_h;
|
||||
sh->base.hmd->views[eye].viewport.y_pixels = 0;
|
||||
sh->base.hmd->views[eye].viewport.w_pixels = panel_w;
|
||||
sh->base.hmd->views[eye].viewport.h_pixels = panel_h;
|
||||
// if rotation is not identity, the dimensions can get more complex.
|
||||
sh->base.hmd->views[eye].rot = u_device_rotation_ident;
|
||||
}
|
||||
// left eye starts at x=0, right eye starts at x=panel_width
|
||||
sh->base.hmd->views[0].viewport.x_pixels = 0;
|
||||
sh->base.hmd->views[1].viewport.x_pixels = panel_w;
|
||||
|
||||
// Setup variable tracker: Optional but useful for debugging
|
||||
u_var_add_root(sh, "Sample HMD", true);
|
||||
u_var_add_pose(sh, &sh->pose, "pose");
|
||||
u_var_add_log_level(sh, &sh->log_level, "log_level");
|
||||
|
||||
// Distortion information, fills in xdev->compute_distortion().
|
||||
u_distortion_mesh_set_none(&sh->base);
|
||||
|
||||
return &sh->base;
|
||||
}
|
81
src/xrt/drivers/sample/sample_interface.h
Normal file
81
src/xrt/drivers/sample/sample_interface.h
Normal file
|
@ -0,0 +1,81 @@
|
|||
// Copyright 2020-2021, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Interface to sample driver.
|
||||
* @author Jakob Bornecrantz <jakob@collabora.com>
|
||||
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
|
||||
* @ingroup drv_sample
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* @defgroup drv_sample Sample driver
|
||||
* @ingroup drv
|
||||
*
|
||||
* @brief Simple do-nothing sample driver, that cannot be detected by USB VID/PID
|
||||
* and thus exposes an "auto-prober" to explicitly discover the device.
|
||||
*
|
||||
* This device has an implementation of @ref xrt_auto_prober to perform hardware
|
||||
* detection, as well as an implementation of @ref xrt_device for the actual device.
|
||||
*
|
||||
* If your device is or has USB HID that **can** be detected based on USB VID/PID,
|
||||
* you can skip the @ref xrt_auto_prober implementation, and instead implement a
|
||||
* "found" function that matches the signature expected by xrt_prober_entry::found.
|
||||
* See for example @ref hdk_found.
|
||||
*
|
||||
* After you copy and rename these files, you can customize them with the following,
|
||||
* assuming your new device type is called `struct my_device` or `md` for short, and
|
||||
* your auto-prober is called `struct my_device_auto_prober` or `mdap` for short:
|
||||
*
|
||||
* ```sh
|
||||
* # First pattern is for renaming device types,
|
||||
* # second is for renaming device variables,
|
||||
* # third is for renaming device macros.
|
||||
* # Fourth and fifth are for renaming auto prober types and variables, respectively.
|
||||
* # The last two are for renaming the environment variable and function name
|
||||
* # for the environment variable logging config.
|
||||
* sed -r -e 's/sample_hmd/my_device/g' \
|
||||
* -e 's/\bsh\b/md/g' \
|
||||
* -e 's/sample_auto_prober/my_device_auto_prober/g' \
|
||||
* -e 's/\bsap\b/mdap/g' \
|
||||
* -e 's/\bSH_/MD_/g' \
|
||||
* -e 's/sample/my_device/g' \
|
||||
* -e 's/SAMPLE/MY_DEVICE/g' \
|
||||
* -i *.c *.h
|
||||
* ```
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Create a auto prober for a sample device.
|
||||
*
|
||||
* @ingroup drv_sample
|
||||
*/
|
||||
struct xrt_auto_prober *
|
||||
sample_create_auto_prober(void);
|
||||
|
||||
/*!
|
||||
* Create a sample hmd.
|
||||
*
|
||||
* This is only exposed so that the prober (in one source file)
|
||||
* can call the construction function (in another.)
|
||||
* @ingroup drv_sample
|
||||
*/
|
||||
struct xrt_device *
|
||||
sample_hmd_create(void);
|
||||
|
||||
/*!
|
||||
* @dir drivers/sample
|
||||
*
|
||||
* @brief @ref drv_sample files.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
71
src/xrt/drivers/sample/sample_prober.c
Normal file
71
src/xrt/drivers/sample/sample_prober.c
Normal file
|
@ -0,0 +1,71 @@
|
|||
// Copyright 2020-2021, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Sample prober code.
|
||||
* @author Jakob Bornecrantz <jakob@collabora.com>
|
||||
* @ingroup drv_sample
|
||||
*/
|
||||
|
||||
#include "xrt/xrt_prober.h"
|
||||
|
||||
#include "util/u_misc.h"
|
||||
#include "util/u_debug.h"
|
||||
|
||||
#include "sample_interface.h"
|
||||
|
||||
|
||||
/*!
|
||||
* @implements xrt_auto_prober
|
||||
*/
|
||||
struct sample_auto_prober
|
||||
{
|
||||
struct xrt_auto_prober base;
|
||||
};
|
||||
|
||||
//! @private @memberof sample_auto_prober
|
||||
static inline struct sample_auto_prober *
|
||||
sample_auto_prober(struct xrt_auto_prober *p)
|
||||
{
|
||||
return (struct sample_auto_prober *)p;
|
||||
}
|
||||
|
||||
//! @private @memberof sample_auto_prober
|
||||
static void
|
||||
sample_auto_prober_destroy(struct xrt_auto_prober *p)
|
||||
{
|
||||
struct sample_auto_prober *sap = sample_auto_prober(p);
|
||||
|
||||
free(sap);
|
||||
}
|
||||
|
||||
//! @public @memberof sample_auto_prober
|
||||
static int
|
||||
sample_auto_prober_autoprobe(struct xrt_auto_prober *xap,
|
||||
cJSON *attached_data,
|
||||
bool no_hmds,
|
||||
struct xrt_prober *xp,
|
||||
struct xrt_device **out_xdevs)
|
||||
{
|
||||
struct sample_auto_prober *sap = sample_auto_prober(xap);
|
||||
(void)sap;
|
||||
|
||||
// Do not create a sample HMD if we are not looking for HMDs.
|
||||
if (no_hmds) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
out_xdevs[0] = sample_hmd_create();
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct xrt_auto_prober *
|
||||
sample_create_auto_prober()
|
||||
{
|
||||
struct sample_auto_prober *sap = U_TYPED_CALLOC(struct sample_auto_prober);
|
||||
sap->base.name = "Sample";
|
||||
sap->base.destroy = sample_auto_prober_destroy;
|
||||
sap->base.lelo_dallas_autoprobe = sample_auto_prober_autoprobe;
|
||||
|
||||
return &sap->base;
|
||||
}
|
Loading…
Reference in a new issue