mirror of
https://gitlab.freedesktop.org/monado/monado.git
synced 2025-01-28 17:38:27 +00:00
316 lines
8.6 KiB
C
316 lines
8.6 KiB
C
// 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"
|
|
#include "util/u_distortion_mesh.h"
|
|
|
|
#include "android/android_globals.h"
|
|
#include "android/android_custom_surface.h"
|
|
|
|
#include <xrt/xrt_config_android.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;
|
|
|
|
#if __ANDROID_API__ >= 26
|
|
d->sensor_manager =
|
|
ASensorManager_getInstanceForPackage(XRT_ANDROID_PACKAGE);
|
|
#else
|
|
d->sensor_manager = ASensorManager_getInstance();
|
|
#endif
|
|
|
|
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.
|
|
*
|
|
*/
|
|
|
|
static bool
|
|
android_device_compute_distortion(struct xrt_device *xdev,
|
|
int view,
|
|
float u,
|
|
float v,
|
|
struct xrt_uv_triplet *result)
|
|
{
|
|
struct android_device *d = android_device(xdev);
|
|
return u_compute_distortion_cardboard(&d->cardboard.values[view], u, v,
|
|
result);
|
|
}
|
|
|
|
|
|
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_GENERIC_HMD;
|
|
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.compute_distortion = android_device_compute_distortion;
|
|
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;
|
|
}
|
|
|
|
struct xrt_android_display_metrics metrics;
|
|
if (!android_custom_surface_get_display_metrics(
|
|
android_globals_get_vm(), android_globals_get_activity(),
|
|
&metrics)) {
|
|
U_LOG_E("Could not get Android display metrics.");
|
|
/* Fallback to default values (Pixel 3) */
|
|
metrics.width_pixels = 2960;
|
|
metrics.height_pixels = 1440;
|
|
metrics.density_dpi = 572;
|
|
}
|
|
|
|
const uint32_t w_pixels = metrics.width_pixels;
|
|
const uint32_t h_pixels = metrics.height_pixels;
|
|
const uint32_t ppi = metrics.density_dpi;
|
|
|
|
const float angle = 45 * M_PI / 180.0; // 0.698132; // 40Deg in rads
|
|
const float w_meters = ((float)w_pixels / (float)ppi) * 0.0254f;
|
|
const float h_meters = ((float)h_pixels / (float)ppi) * 0.0254f;
|
|
|
|
struct u_cardboard_distortion_arguments args = {
|
|
.distortion_k = {0.441f, 0.156f, 0.f, 0.f, 0.f},
|
|
.screen =
|
|
{
|
|
.w_pixels = w_pixels,
|
|
.h_pixels = h_pixels,
|
|
.w_meters = w_meters,
|
|
.h_meters = h_meters,
|
|
},
|
|
.inter_lens_distance_meters = 0.06f,
|
|
.lens_y_center_on_screen_meters = h_meters / 2.0f,
|
|
.screen_to_lens_distance_meters = 0.042f,
|
|
.fov =
|
|
{
|
|
.angle_left = -angle,
|
|
.angle_right = angle,
|
|
.angle_up = angle,
|
|
.angle_down = -angle,
|
|
},
|
|
};
|
|
|
|
u_distortion_cardboard_calculate(&args, d->base.hmd, &d->cardboard);
|
|
|
|
|
|
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;
|
|
|
|
// Distortion information.
|
|
u_distortion_mesh_fill_in_compute(&d->base);
|
|
|
|
ANDROID_DEBUG(d, "Created device!");
|
|
|
|
return d;
|
|
}
|