d/android: Add Android sensors driver.

This commit is contained in:
Lubosz Sarnecki 2020-10-23 10:28:50 +02:00 committed by Ryan Pavlik
parent ad42bbff9e
commit f4113ef15b
10 changed files with 493 additions and 1 deletions

View file

@ -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}")

View file

@ -0,0 +1 @@
Add initial "Cardboard" phone-holder driver for Android.

View file

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

View 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;
}

View 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

View 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;
}

View 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

View file

@ -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
};
/*!

View file

@ -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
#

View file

@ -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,