2021-11-13 02:35:13 +00:00
|
|
|
// Copyright 2020-2021, N Madsen.
|
|
|
|
// Copyright 2020-2021, Collabora, Ltd.
|
|
|
|
// SPDX-License-Identifier: BSL-1.0
|
|
|
|
/*!
|
|
|
|
* @file
|
|
|
|
* @brief Driver for Bluetooth based WMR Controller.
|
|
|
|
* @author Nis Madsen <nima_zero_one@protonmail.com>
|
|
|
|
* @ingroup drv_wmr
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "os/os_time.h"
|
|
|
|
#include "os/os_hid.h"
|
|
|
|
|
|
|
|
#include "math/m_mathinclude.h"
|
|
|
|
#include "math/m_api.h"
|
|
|
|
#include "math/m_vec2.h"
|
|
|
|
#include "math/m_predict.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 "wmr_common.h"
|
2021-11-15 01:05:19 +00:00
|
|
|
#include "wmr_bt_controller.h"
|
2021-11-13 02:35:13 +00:00
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#ifndef XRT_OS_WINDOWS
|
|
|
|
#include <unistd.h> // for sleep()
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define WMR_TRACE(d, ...) U_LOG_XDEV_IFL_T(&d->base, d->ll, __VA_ARGS__)
|
|
|
|
#define WMR_DEBUG(d, ...) U_LOG_XDEV_IFL_D(&d->base, d->ll, __VA_ARGS__)
|
|
|
|
#define WMR_INFO(d, ...) U_LOG_XDEV_IFL_I(&d->base, d->ll, __VA_ARGS__)
|
|
|
|
#define WMR_WARN(d, ...) U_LOG_XDEV_IFL_W(&d->base, d->ll, __VA_ARGS__)
|
|
|
|
#define WMR_ERROR(d, ...) U_LOG_XDEV_IFL_E(&d->base, d->ll, __VA_ARGS__)
|
|
|
|
|
|
|
|
|
|
|
|
static inline struct wmr_bt_controller *
|
|
|
|
wmr_bt_controller(struct xrt_device *p)
|
|
|
|
{
|
|
|
|
return (struct wmr_bt_controller *)p;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2021-11-15 01:05:19 +00:00
|
|
|
read_packets(struct wmr_bt_controller *d)
|
2021-11-13 02:35:13 +00:00
|
|
|
{
|
2021-11-15 01:05:19 +00:00
|
|
|
unsigned char buffer[WMR_MOTION_CONTROLLER_MSG_BUFFER_SIZE];
|
2021-11-13 02:35:13 +00:00
|
|
|
|
|
|
|
// Do not block
|
|
|
|
int size = os_hid_read(d->controller_hid, buffer, sizeof(buffer), 0);
|
|
|
|
|
|
|
|
if (size < 0) {
|
2021-11-15 01:05:19 +00:00
|
|
|
WMR_ERROR(d, "WMR Controller (Bluetooth): Error reading from device");
|
2021-11-13 02:35:13 +00:00
|
|
|
return false;
|
|
|
|
} else if (size == 0) {
|
2021-11-15 01:05:19 +00:00
|
|
|
WMR_TRACE(d, "WMR Controller (Bluetooth): No data to read from device");
|
2021-11-13 02:35:13 +00:00
|
|
|
return true; // No more messages, return.
|
|
|
|
} else {
|
2021-11-15 01:05:19 +00:00
|
|
|
WMR_DEBUG(d, "WMR Controller (Bluetooth): Read %u bytes from device", size);
|
2021-11-13 02:35:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (buffer[0]) {
|
2021-11-15 01:05:19 +00:00
|
|
|
case WMR_BT_MOTION_CONTROLLER_MSG:
|
|
|
|
// Note: skipping msg type byte
|
|
|
|
if (!wmr_controller_packet_parse(&buffer[1], (size_t)size - 1, &d->controller_message, d->ll)) {
|
|
|
|
WMR_ERROR(d, "WMR Controller (Bluetooth): Failed parsing message type: %02x, size: %i",
|
|
|
|
buffer[0], size);
|
2021-11-13 02:35:13 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
break;
|
2021-11-15 01:05:19 +00:00
|
|
|
default:
|
|
|
|
WMR_DEBUG(d, "WMR Controller (Bluetooth): Unknown message type: %02x, size: %i", buffer[0], size);
|
2021-11-13 02:35:13 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
wmr_bt_controller_set_output(struct xrt_device *xdev, enum xrt_output_name name, union xrt_output_value *value)
|
|
|
|
{
|
|
|
|
// struct wmr_bt_controller *d = wmr_bt_controller(xdev);
|
|
|
|
// Todo: implement
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
wmr_bt_controller_get_tracked_pose(struct xrt_device *xdev,
|
|
|
|
enum xrt_input_name name,
|
|
|
|
uint64_t at_timestamp_ns,
|
|
|
|
struct xrt_space_relation *out_relation)
|
|
|
|
{
|
|
|
|
// struct wmr_bt_controller *d = wmr_bt_controller(xdev);
|
|
|
|
// Todo: implement
|
2021-11-19 17:27:17 +00:00
|
|
|
struct xrt_pose pose = {{0, 0, 0, 1}, {0, 1.2, -0.5}};
|
|
|
|
if (xdev->device_type == XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER) {
|
|
|
|
pose.position.x = -0.2;
|
|
|
|
} else {
|
|
|
|
pose.position.x = 0.2;
|
|
|
|
}
|
|
|
|
|
|
|
|
out_relation->pose = pose;
|
|
|
|
out_relation->relation_flags = (enum xrt_space_relation_flags)(
|
|
|
|
XRT_SPACE_RELATION_ORIENTATION_VALID_BIT | XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT |
|
|
|
|
XRT_SPACE_RELATION_ANGULAR_VELOCITY_VALID_BIT | XRT_SPACE_RELATION_LINEAR_VELOCITY_VALID_BIT);
|
2021-11-13 02:35:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
wmr_bt_controller_update_inputs(struct xrt_device *xdev)
|
|
|
|
{
|
|
|
|
// struct wmr_bt_controller *d = wmr_bt_controller(xdev);
|
|
|
|
// Todo: implement
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *
|
|
|
|
wmr_bt_controller_run_thread(void *ptr)
|
|
|
|
{
|
|
|
|
struct wmr_bt_controller *d = wmr_bt_controller(ptr);
|
|
|
|
|
|
|
|
|
|
|
|
os_thread_helper_lock(&d->controller_thread);
|
|
|
|
while (os_thread_helper_is_running_locked(&d->controller_thread)) {
|
|
|
|
os_thread_helper_unlock(&d->controller_thread);
|
|
|
|
|
|
|
|
// Does not block.
|
2021-11-15 01:05:19 +00:00
|
|
|
if (!read_packets(d)) {
|
2021-11-13 02:35:13 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-15 01:05:19 +00:00
|
|
|
WMR_DEBUG(d, "WMR Controller (Bluetooth): Exiting reading thread.");
|
2021-11-13 02:35:13 +00:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
wmr_bt_controller_destroy(struct xrt_device *xdev)
|
|
|
|
{
|
|
|
|
struct wmr_bt_controller *d = wmr_bt_controller(xdev);
|
|
|
|
|
|
|
|
// Destroy the thread object.
|
|
|
|
os_thread_helper_destroy(&d->controller_thread);
|
|
|
|
|
|
|
|
|
|
|
|
if (d->controller_hid != NULL) {
|
|
|
|
os_hid_destroy(d->controller_hid);
|
|
|
|
d->controller_hid = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Destroy the fusion.
|
|
|
|
m_imu_3dof_close(&d->fusion);
|
|
|
|
|
|
|
|
free(d);
|
|
|
|
}
|
|
|
|
|
2021-11-19 17:27:17 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Bindings
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
static struct xrt_binding_input_pair simple_inputs[4] = {
|
|
|
|
{XRT_INPUT_SIMPLE_SELECT_CLICK, XRT_INPUT_WMR_TRIGGER_VALUE},
|
|
|
|
{XRT_INPUT_SIMPLE_MENU_CLICK, XRT_INPUT_WMR_MENU_CLICK},
|
|
|
|
{XRT_INPUT_SIMPLE_GRIP_POSE, XRT_INPUT_WMR_GRIP_POSE},
|
|
|
|
{XRT_INPUT_SIMPLE_AIM_POSE, XRT_INPUT_WMR_AIM_POSE},
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct xrt_binding_output_pair simple_outputs[1] = {
|
|
|
|
{XRT_OUTPUT_NAME_SIMPLE_VIBRATION, XRT_OUTPUT_NAME_WMR_HAPTIC},
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct xrt_binding_profile binding_profiles[1] = {
|
|
|
|
{
|
|
|
|
.name = XRT_DEVICE_SIMPLE_CONTROLLER,
|
|
|
|
.inputs = simple_inputs,
|
|
|
|
.input_count = ARRAY_SIZE(simple_inputs),
|
|
|
|
.outputs = simple_outputs,
|
|
|
|
.output_count = ARRAY_SIZE(simple_outputs),
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
* 'Exported' functions.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2021-11-13 02:35:13 +00:00
|
|
|
struct xrt_device *
|
|
|
|
wmr_bt_controller_create(struct os_hid_device *controller_hid,
|
|
|
|
enum xrt_device_type controller_type,
|
|
|
|
enum u_logging_level ll)
|
|
|
|
{
|
|
|
|
|
|
|
|
enum u_device_alloc_flags flags = U_DEVICE_ALLOC_TRACKING_NONE;
|
2021-11-19 17:27:17 +00:00
|
|
|
struct wmr_bt_controller *d = U_DEVICE_ALLOCATE(struct wmr_bt_controller, flags, 2, 0);
|
2021-11-13 02:35:13 +00:00
|
|
|
|
|
|
|
d->ll = ll;
|
|
|
|
d->controller_hid = controller_hid;
|
|
|
|
|
2021-11-19 17:27:17 +00:00
|
|
|
if (controller_type == XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER) {
|
|
|
|
snprintf(d->base.str, ARRAY_SIZE(d->base.str), "WMR Left Controller");
|
|
|
|
} else {
|
|
|
|
snprintf(d->base.str, ARRAY_SIZE(d->base.str), "WMR Right Controller");
|
|
|
|
}
|
|
|
|
|
2021-11-13 02:35:13 +00:00
|
|
|
d->base.destroy = wmr_bt_controller_destroy;
|
|
|
|
d->base.get_tracked_pose = wmr_bt_controller_get_tracked_pose;
|
|
|
|
d->base.set_output = wmr_bt_controller_set_output;
|
|
|
|
d->base.update_inputs = wmr_bt_controller_update_inputs;
|
|
|
|
|
2021-11-19 17:27:17 +00:00
|
|
|
d->base.inputs[0].name = XRT_INPUT_WMR_GRIP_POSE;
|
|
|
|
d->base.inputs[0].active = true;
|
|
|
|
d->base.inputs[1].name = XRT_INPUT_WMR_AIM_POSE;
|
|
|
|
d->base.inputs[1].active = true;
|
|
|
|
d->base.binding_profiles = binding_profiles;
|
|
|
|
d->base.binding_profile_count = ARRAY_SIZE(binding_profiles);
|
2021-11-13 02:35:13 +00:00
|
|
|
|
|
|
|
d->base.name = XRT_DEVICE_WMR_CONTROLLER;
|
|
|
|
d->base.device_type = controller_type;
|
|
|
|
d->base.orientation_tracking_supported = true;
|
|
|
|
d->base.position_tracking_supported = false;
|
|
|
|
d->base.hand_tracking_supported = true;
|
|
|
|
|
|
|
|
m_imu_3dof_init(&d->fusion, M_IMU_3DOF_USE_GRAVITY_DUR_20MS);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int ret = 0;
|
|
|
|
|
2021-11-15 01:05:19 +00:00
|
|
|
// Todo: Read config file from controller if possible.
|
2021-11-13 02:35:13 +00:00
|
|
|
|
|
|
|
// Thread and other state.
|
|
|
|
ret = os_thread_helper_init(&d->controller_thread);
|
|
|
|
if (ret != 0) {
|
2021-11-15 01:05:19 +00:00
|
|
|
WMR_ERROR(d, "WMR Controller (Bluetooth): Failed to init controller threading!");
|
2021-11-13 02:35:13 +00:00
|
|
|
wmr_bt_controller_destroy(&d->base);
|
|
|
|
d = NULL;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Hand over controller device to reading thread.
|
|
|
|
ret = os_thread_helper_start(&d->controller_thread, wmr_bt_controller_run_thread, d);
|
|
|
|
if (ret != 0) {
|
2021-11-15 01:05:19 +00:00
|
|
|
WMR_ERROR(d, "WMR Controller (Bluetooth): Failed to start controller thread!");
|
2021-11-13 02:35:13 +00:00
|
|
|
wmr_bt_controller_destroy(&d->base);
|
|
|
|
d = NULL;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return &d->base;
|
|
|
|
}
|