mirror of
https://gitlab.freedesktop.org/monado/monado.git
synced 2025-01-29 18:08:29 +00:00
d/android: Add Android sensors driver.
This commit is contained in:
parent
ad42bbff9e
commit
f4113ef15b
|
@ -174,9 +174,11 @@ cmake_dependent_option(XRT_BUILD_DRIVER_NS "Enable North Star driver" ON "XRT_HA
|
|||
# This one defaults to off, even if we find the deps.
|
||||
cmake_dependent_option(XRT_BUILD_DRIVER_SURVIVE "Enable libsurvive driver" OFF "SURVIVE_FOUND" OFF)
|
||||
|
||||
cmake_dependent_option(XRT_BUILD_DRIVER_ANDROID "Enable Android sensors driver" ON "ANDROID" OFF)
|
||||
|
||||
# You can set this from a superproject to add a driver
|
||||
# All drivers must be listed in here to be included in the generated header!
|
||||
list(APPEND AVAILABLE_DRIVERS ARDUINO DUMMY HDK HYDRA NS OHMD PSMV PSVR RS V4L2 VIVE DAYDREAM REMOTE SURVIVE)
|
||||
list(APPEND AVAILABLE_DRIVERS "ANDROID" ARDUINO DUMMY HDK HYDRA NS OHMD PSMV PSVR RS V4L2 VIVE DAYDREAM REMOTE SURVIVE)
|
||||
|
||||
|
||||
# Package name needs to be known by the native code itself.
|
||||
|
@ -280,6 +282,7 @@ message(STATUS "# FEATURE_OPENXR_LAYER_CYLINDER: ${XRT_FEATURE_OPENXR_
|
|||
message(STATUS "# FEATURE_OPENXR_LAYER_EQUIRECT: ${XRT_FEATURE_OPENXR_LAYER_EQUIRECT}")
|
||||
message(STATUS "# FEATURE_OPENXR_LAYER_EQUIRECT_LEGACY: ${XRT_FEATURE_OPENXR_LAYER_EQUIRECT_LEGACY}")
|
||||
message(STATUS "#")
|
||||
message(STATUS "# DRIVER_ANDROID: ${XRT_BUILD_DRIVER_ANDROID}")
|
||||
message(STATUS "# DRIVER_ARDUINO: ${XRT_BUILD_DRIVER_ARDUINO}")
|
||||
message(STATUS "# DRIVER_DAYDREAM: ${XRT_BUILD_DRIVER_DAYDREAM}")
|
||||
message(STATUS "# DRIVER_DUMMY: ${XRT_BUILD_DRIVER_DUMMY}")
|
||||
|
|
1
doc/changes/drivers/mr.581.md
Normal file
1
doc/changes/drivers/mr.581.md
Normal file
|
@ -0,0 +1 @@
|
|||
Add initial "Cardboard" phone-holder driver for Android.
|
|
@ -194,6 +194,19 @@ if (XRT_BUILD_DRIVER_SURVIVE)
|
|||
list(APPEND ENABLED_HEADSET_DRIVERS survive)
|
||||
endif()
|
||||
|
||||
if(XRT_BUILD_DRIVER_ANDROID)
|
||||
set(ANDROID_SOURCE_FILES
|
||||
android/android_prober.c
|
||||
android/android_prober.h
|
||||
android/android_sensors.c
|
||||
android/android_sensors.h
|
||||
)
|
||||
|
||||
add_library(drv_android STATIC ${ANDROID_SOURCE_FILES})
|
||||
target_link_libraries(drv_android PRIVATE xrt-interfaces aux_util aux_os ${ANDROID_LIBRARY})
|
||||
list(APPEND ENABLED_DRIVERS android)
|
||||
endif()
|
||||
|
||||
if(ENABLED_HEADSET_DRIVERS)
|
||||
set(ENABLED_DRIVERS ${ENABLED_HEADSET_DRIVERS} ${ENABLED_DRIVERS})
|
||||
list(SORT ENABLED_DRIVERS)
|
||||
|
|
91
src/xrt/drivers/android/android_prober.c
Normal file
91
src/xrt/drivers/android/android_prober.c
Normal file
|
@ -0,0 +1,91 @@
|
|||
// Copyright 2020, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Interface to Android sensors prober code.
|
||||
* @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
|
||||
* @ingroup drv_android
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "xrt/xrt_prober.h"
|
||||
|
||||
#include "util/u_misc.h"
|
||||
#include "util/u_debug.h"
|
||||
#include "util/u_logging.h"
|
||||
|
||||
#include "android_prober.h"
|
||||
#include "android_sensors.h"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Defines & structs.
|
||||
*
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Android prober struct.
|
||||
*
|
||||
* @ingroup drv_android
|
||||
* @implements xrt_auto_prober
|
||||
*/
|
||||
struct android_prober
|
||||
{
|
||||
struct xrt_auto_prober base;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Static functions.
|
||||
*
|
||||
*/
|
||||
|
||||
//! @private @memberof android_prober
|
||||
static inline struct android_prober *
|
||||
android_prober(struct xrt_auto_prober *p)
|
||||
{
|
||||
return (struct android_prober *)p;
|
||||
}
|
||||
|
||||
//! @public @memberof android_prober
|
||||
static void
|
||||
android_prober_destroy(struct xrt_auto_prober *p)
|
||||
{
|
||||
struct android_prober *pandroid = android_prober(p);
|
||||
free(pandroid);
|
||||
}
|
||||
|
||||
//! @public @memberof android_prober
|
||||
static struct xrt_device *
|
||||
android_prober_autoprobe(struct xrt_auto_prober *xap,
|
||||
cJSON *attached_data,
|
||||
bool no_hmds,
|
||||
struct xrt_prober *xp)
|
||||
{
|
||||
struct android_device *dd = android_device_create();
|
||||
return &dd->base;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Exported functions.
|
||||
*
|
||||
*/
|
||||
|
||||
struct xrt_auto_prober *
|
||||
android_create_auto_prober()
|
||||
{
|
||||
struct android_prober *p = U_TYPED_CALLOC(struct android_prober);
|
||||
p->base.name = "Android";
|
||||
p->base.destroy = android_prober_destroy;
|
||||
p->base.lelo_dallas_autoprobe = android_prober_autoprobe;
|
||||
|
||||
return &p->base;
|
||||
}
|
41
src/xrt/drivers/android/android_prober.h
Normal file
41
src/xrt/drivers/android/android_prober.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
// Copyright 2020, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Interface to Android sensors driver.
|
||||
* @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
|
||||
* @ingroup drv_android
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* @defgroup drv_android Android sensors driver
|
||||
* @ingroup drv
|
||||
*
|
||||
* @brief Generic driver for phone sensors.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Probing function for Android sensors.
|
||||
*
|
||||
* @ingroup drv_android
|
||||
*/
|
||||
struct xrt_auto_prober *
|
||||
android_create_auto_prober();
|
||||
|
||||
|
||||
/*!
|
||||
* @dir drivers/android
|
||||
*
|
||||
* @brief @ref drv_android files.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
260
src/xrt/drivers/android/android_sensors.c
Normal file
260
src/xrt/drivers/android/android_sensors.c
Normal file
|
@ -0,0 +1,260 @@
|
|||
// Copyright 2013, Fredrik Hultin.
|
||||
// Copyright 2013, Jakob Bornecrantz.
|
||||
// Copyright 2015, Joey Ferwerda.
|
||||
// Copyright 2020, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Android sensors driver code.
|
||||
* @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
|
||||
* @ingroup drv_android
|
||||
*/
|
||||
|
||||
#include "android_sensors.h"
|
||||
|
||||
#include "util/u_debug.h"
|
||||
#include "util/u_device.h"
|
||||
#include "util/u_var.h"
|
||||
|
||||
// 60 events per second (in us).
|
||||
#define POLL_RATE_USEC (1000L / 60) * 1000
|
||||
|
||||
|
||||
DEBUG_GET_ONCE_LOG_OPTION(android_log, "ANDROID_SENSORS_LOG", U_LOGGING_WARN)
|
||||
|
||||
static inline struct android_device *
|
||||
android_device(struct xrt_device *xdev)
|
||||
{
|
||||
return (struct android_device *)xdev;
|
||||
}
|
||||
|
||||
// Callback for the Android sensor event queue
|
||||
static int
|
||||
android_sensor_callback(int fd, int events, void *data)
|
||||
{
|
||||
struct android_device *d = (struct android_device *)data;
|
||||
|
||||
if (d->accelerometer == NULL || d->gyroscope == NULL)
|
||||
return 1;
|
||||
|
||||
ASensorEvent event;
|
||||
struct xrt_vec3 gyro;
|
||||
struct xrt_vec3 accel;
|
||||
while (ASensorEventQueue_getEvents(d->event_queue, &event, 1) > 0) {
|
||||
|
||||
switch (event.type) {
|
||||
case ASENSOR_TYPE_ACCELEROMETER: {
|
||||
accel.x = event.acceleration.y;
|
||||
accel.y = -event.acceleration.x;
|
||||
accel.z = event.acceleration.z;
|
||||
|
||||
ANDROID_TRACE(d, "accel %ld %.2f %.2f %.2f",
|
||||
event.timestamp, accel.x, accel.y,
|
||||
accel.z);
|
||||
break;
|
||||
}
|
||||
case ASENSOR_TYPE_GYROSCOPE: {
|
||||
gyro.x = -event.data[1];
|
||||
gyro.y = event.data[0];
|
||||
gyro.z = event.data[2];
|
||||
|
||||
ANDROID_TRACE(d, "gyro %ld %.2f %.2f %.2f",
|
||||
event.timestamp, gyro.x, gyro.y, gyro.z);
|
||||
|
||||
// TODO: Make filter handle accelerometer
|
||||
struct xrt_vec3 null_accel;
|
||||
|
||||
// Lock last and the fusion.
|
||||
os_mutex_lock(&d->lock);
|
||||
|
||||
m_imu_3dof_update(&d->fusion, event.timestamp,
|
||||
&null_accel, &gyro);
|
||||
|
||||
// Now done.
|
||||
os_mutex_unlock(&d->lock);
|
||||
}
|
||||
default:
|
||||
ANDROID_TRACE(d, "Unhandled event type %d", event.type);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void *
|
||||
android_run_thread(void *ptr)
|
||||
{
|
||||
struct android_device *d = (struct android_device *)ptr;
|
||||
|
||||
d->sensor_manager = ASensorManager_getInstance();
|
||||
d->accelerometer = ASensorManager_getDefaultSensor(
|
||||
d->sensor_manager, ASENSOR_TYPE_ACCELEROMETER);
|
||||
d->gyroscope = ASensorManager_getDefaultSensor(d->sensor_manager,
|
||||
ASENSOR_TYPE_GYROSCOPE);
|
||||
|
||||
ALooper *looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
|
||||
|
||||
d->event_queue = ASensorManager_createEventQueue(
|
||||
d->sensor_manager, looper, ALOOPER_POLL_CALLBACK,
|
||||
android_sensor_callback, (void *)d);
|
||||
|
||||
// Start sensors in case this was not done already.
|
||||
if (d->accelerometer != NULL) {
|
||||
ASensorEventQueue_enableSensor(d->event_queue,
|
||||
d->accelerometer);
|
||||
ASensorEventQueue_setEventRate(d->event_queue, d->accelerometer,
|
||||
POLL_RATE_USEC);
|
||||
}
|
||||
if (d->gyroscope != NULL) {
|
||||
ASensorEventQueue_enableSensor(d->event_queue, d->gyroscope);
|
||||
ASensorEventQueue_setEventRate(d->event_queue, d->gyroscope,
|
||||
POLL_RATE_USEC);
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
while (ret != ALOOPER_POLL_ERROR) {
|
||||
ret = ALooper_pollAll(0, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Device functions.
|
||||
*
|
||||
*/
|
||||
|
||||
static void
|
||||
android_device_destroy(struct xrt_device *xdev)
|
||||
{
|
||||
struct android_device *android = android_device(xdev);
|
||||
|
||||
// Destroy the thread object.
|
||||
os_thread_helper_destroy(&android->oth);
|
||||
|
||||
// Now that the thread is not running we can destroy the lock.
|
||||
os_mutex_destroy(&android->lock);
|
||||
|
||||
// Destroy the fusion.
|
||||
m_imu_3dof_close(&android->fusion);
|
||||
|
||||
// Remove the variable tracking.
|
||||
u_var_remove_root(android);
|
||||
|
||||
free(android);
|
||||
}
|
||||
|
||||
static void
|
||||
android_device_update_inputs(struct xrt_device *xdev)
|
||||
{
|
||||
// Empty
|
||||
}
|
||||
|
||||
static void
|
||||
android_device_get_tracked_pose(struct xrt_device *xdev,
|
||||
enum xrt_input_name name,
|
||||
uint64_t at_timestamp_ns,
|
||||
struct xrt_space_relation *out_relation)
|
||||
{
|
||||
(void)at_timestamp_ns;
|
||||
|
||||
struct android_device *d = android_device(xdev);
|
||||
out_relation->pose.orientation = d->fusion.rot;
|
||||
|
||||
//! @todo assuming that orientation is actually currently tracked.
|
||||
out_relation->relation_flags = (enum xrt_space_relation_flags)(
|
||||
XRT_SPACE_RELATION_ORIENTATION_VALID_BIT |
|
||||
XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT);
|
||||
}
|
||||
|
||||
static void
|
||||
android_device_get_view_pose(struct xrt_device *xdev,
|
||||
struct xrt_vec3 *eye_relation,
|
||||
uint32_t view_index,
|
||||
struct xrt_pose *out_pose)
|
||||
{
|
||||
struct xrt_pose pose = {{0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f}};
|
||||
bool adjust = view_index == 0;
|
||||
|
||||
pose.position.x = eye_relation->x / 2.0f;
|
||||
pose.position.y = eye_relation->y / 2.0f;
|
||||
pose.position.z = eye_relation->z / 2.0f;
|
||||
|
||||
// Adjust for left/right while also making sure there aren't any -0.f.
|
||||
if (pose.position.x > 0.0f && adjust) {
|
||||
pose.position.x = -pose.position.x;
|
||||
}
|
||||
if (pose.position.y > 0.0f && adjust) {
|
||||
pose.position.y = -pose.position.y;
|
||||
}
|
||||
if (pose.position.z > 0.0f && adjust) {
|
||||
pose.position.z = -pose.position.z;
|
||||
}
|
||||
|
||||
*out_pose = pose;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* Prober functions.
|
||||
*
|
||||
*/
|
||||
|
||||
struct android_device *
|
||||
android_device_create()
|
||||
{
|
||||
enum u_device_alloc_flags flags = (enum u_device_alloc_flags)(
|
||||
U_DEVICE_ALLOC_HMD | U_DEVICE_ALLOC_TRACKING_NONE);
|
||||
struct android_device *d =
|
||||
U_DEVICE_ALLOCATE(struct android_device, flags, 1, 0);
|
||||
|
||||
d->base.name = XRT_DEVICE_ANDROID;
|
||||
d->base.destroy = android_device_destroy;
|
||||
d->base.update_inputs = android_device_update_inputs;
|
||||
d->base.get_tracked_pose = android_device_get_tracked_pose;
|
||||
d->base.get_view_pose = android_device_get_view_pose;
|
||||
d->base.inputs[0].name = XRT_INPUT_GENERIC_HEAD_POSE;
|
||||
d->base.device_type = XRT_DEVICE_TYPE_HMD;
|
||||
|
||||
d->ll = debug_get_log_option_android_log();
|
||||
|
||||
m_imu_3dof_init(&d->fusion, M_IMU_3DOF_USE_GRAVITY_DUR_20MS);
|
||||
|
||||
// Everything done, finally start the thread.
|
||||
int ret = os_thread_helper_start(&d->oth, android_run_thread, d);
|
||||
if (ret != 0) {
|
||||
ANDROID_ERROR(d, "Failed to start thread!");
|
||||
android_device_destroy(&d->base);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Setup info.
|
||||
struct u_device_simple_info info;
|
||||
info.display.w_pixels = 1280;
|
||||
info.display.h_pixels = 720;
|
||||
info.display.w_meters = 0.13f;
|
||||
info.display.h_meters = 0.07f;
|
||||
info.lens_horizontal_separation_meters = 0.13f / 2.0f;
|
||||
info.lens_vertical_position_meters = 0.07f / 2.0f;
|
||||
info.views[0].fov = 85.0f * (M_PI / 180.0f);
|
||||
info.views[1].fov = 85.0f * (M_PI / 180.0f);
|
||||
|
||||
if (!u_device_setup_split_side_by_side(&d->base, &info)) {
|
||||
ANDROID_ERROR(d, "Failed to setup basic device info");
|
||||
android_device_destroy(&d->base);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u_var_add_root(d, "Android phone", true);
|
||||
u_var_add_ro_vec3_f32(d, &d->fusion.last.accel, "last.accel");
|
||||
u_var_add_ro_vec3_f32(d, &d->fusion.last.gyro, "last.gyro");
|
||||
|
||||
d->base.orientation_tracking_supported = true;
|
||||
d->base.position_tracking_supported = false;
|
||||
|
||||
ANDROID_DEBUG(d, "Created device!");
|
||||
|
||||
return d;
|
||||
}
|
70
src/xrt/drivers/android/android_sensors.h
Normal file
70
src/xrt/drivers/android/android_sensors.h
Normal file
|
@ -0,0 +1,70 @@
|
|||
// Copyright 2020, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Android sensors driver header.
|
||||
* @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
|
||||
* @ingroup drv_android
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <android/sensor.h>
|
||||
|
||||
#include "math/m_api.h"
|
||||
#include "math/m_imu_pre.h"
|
||||
#include "math/m_imu_3dof.h"
|
||||
|
||||
#include "xrt/xrt_device.h"
|
||||
|
||||
#include "os/os_threading.h"
|
||||
|
||||
#include "util/u_logging.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* @implements xrt_device
|
||||
*/
|
||||
struct android_device
|
||||
{
|
||||
struct xrt_device base;
|
||||
struct os_thread_helper oth;
|
||||
|
||||
ASensorManager *sensor_manager;
|
||||
const ASensor *accelerometer;
|
||||
const ASensor *gyroscope;
|
||||
ASensorEventQueue *event_queue;
|
||||
|
||||
struct
|
||||
{
|
||||
//! Lock for last and fusion.
|
||||
struct os_mutex lock;
|
||||
struct m_imu_3dof fusion;
|
||||
};
|
||||
|
||||
enum u_logging_level ll;
|
||||
};
|
||||
|
||||
|
||||
struct android_device *
|
||||
android_device_create();
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Printing functions.
|
||||
*
|
||||
*/
|
||||
|
||||
#define ANDROID_TRACE(d, ...) U_LOG_XDEV_IFL_T(&d->base, d->ll, __VA_ARGS__)
|
||||
#define ANDROID_DEBUG(d, ...) U_LOG_XDEV_IFL_D(&d->base, d->ll, __VA_ARGS__)
|
||||
#define ANDROID_INFO(d, ...) U_LOG_XDEV_IFL_I(&d->base, d->ll, __VA_ARGS__)
|
||||
#define ANDROID_WARN(d, ...) U_LOG_XDEV_IFL_W(&d->base, d->ll, __VA_ARGS__)
|
||||
#define ANDROID_ERROR(d, ...) U_LOG_XDEV_IFL_E(&d->base, d->ll, __VA_ARGS__)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -419,6 +419,7 @@ enum xrt_device_name
|
|||
XRT_DEVICE_VIVE_WAND,
|
||||
XRT_DEVICE_VIVE_TRACKER_GEN1,
|
||||
XRT_DEVICE_VIVE_TRACKER_GEN2,
|
||||
XRT_DEVICE_ANDROID
|
||||
};
|
||||
|
||||
/*!
|
||||
|
|
|
@ -76,6 +76,10 @@ if(XRT_BUILD_DRIVER_SURVIVE)
|
|||
target_link_libraries(target_lists PRIVATE drv_survive)
|
||||
endif()
|
||||
|
||||
if(XRT_BUILD_DRIVER_ANDROID)
|
||||
target_link_libraries(target_lists PRIVATE drv_android)
|
||||
endif()
|
||||
|
||||
####
|
||||
# Instance
|
||||
#
|
||||
|
|
|
@ -54,6 +54,10 @@
|
|||
#include "daydream/daydream_interface.h"
|
||||
#endif
|
||||
|
||||
#ifdef XRT_BUILD_DRIVER_ANDROID
|
||||
#include "android/android_prober.h"
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* Each entry should be a vendor ID (VID), product ID (PID), a "found" function,
|
||||
* and a string literal name.
|
||||
|
@ -134,6 +138,10 @@ xrt_auto_prober_creator target_auto_list[] = {
|
|||
ns_create_auto_prober,
|
||||
#endif
|
||||
|
||||
#ifdef XRT_BUILD_DRIVER_ANDROID
|
||||
android_create_auto_prober,
|
||||
#endif
|
||||
|
||||
#ifdef XRT_BUILD_DRIVER_DUMMY
|
||||
// Dummy headset driver last.
|
||||
dummy_create_auto_prober,
|
||||
|
|
Loading…
Reference in a new issue