The open source OpenXR runtime
1// Copyright 2020-2021, N Madsen.
2// Copyright 2020-2021, Collabora, Ltd.
3// Copyright 2021-2023, Jan Schmidt
4// SPDX-License-Identifier: BSL-1.0
5//
6/*!
7 * @file
8 * @brief Common implementation for WMR controllers, handling
9 * shared behaviour such as communication, configuration reading,
10 * IMU integration.
11 * @author Jan Schmidt <jan@centricular.com>
12 * @author Nis Madsen <nima_zero_one@protonmail.com>
13 * @ingroup drv_wmr
14 */
15#pragma once
16
17#include "os/os_threading.h"
18#include "math/m_imu_3dof.h"
19#include "util/u_device.h"
20#include "util/u_logging.h"
21#include "xrt/xrt_device.h"
22
23#include "wmr_controller_protocol.h"
24#include "wmr_config.h"
25
26#ifdef __cplusplus
27extern "C" {
28#endif
29
30struct wmr_controller_base;
31
32/*!
33 * A connection for communicating with the controller.
34 * The mechanism is implementation specific, so there are
35 * two variants for either communicating directly with a
36 * controller via bluetooth, and another for talking
37 * to a controller through a headset tunnelled mapping.
38 *
39 * The controller implementation doesn't need to care how
40 * the communication is implemented.
41 *
42 * The HMD-tunnelled version of the connection is reference
43 * counted and mutex protected, as both the controller and
44 * the HMD need to hold a reference to it to clean up safely.
45 * For bluetooth controllers, destruction of the controller
46 * xrt_device calls disconnect and destroys the connection
47 * object (and bluetooth listener) immediately.
48 */
49struct wmr_controller_connection
50{
51 //! The controller this connection is talking to.
52 struct wmr_controller_base *wcb;
53
54 bool (*send_bytes)(struct wmr_controller_connection *wcc, const uint8_t *buffer, uint32_t buf_size);
55 void (*receive_bytes)(struct wmr_controller_connection *wcc,
56 uint64_t time_ns,
57 uint8_t *buffer,
58 uint32_t buf_size);
59 int (*read_sync)(struct wmr_controller_connection *wcc, uint8_t *buffer, uint32_t buf_size, int timeout_ms);
60
61 void (*disconnect)(struct wmr_controller_connection *wcc);
62};
63
64static inline bool
65wmr_controller_connection_send_bytes(struct wmr_controller_connection *wcc, const uint8_t *buffer, uint32_t buf_size)
66{
67 assert(wcc->send_bytes != NULL);
68 return wcc->send_bytes(wcc, buffer, buf_size);
69}
70
71static inline int
72wmr_controller_connection_read_sync(struct wmr_controller_connection *wcc,
73 uint8_t *buffer,
74 uint32_t buf_size,
75 int timeout_ms)
76{
77 return wcc->read_sync(wcc, buffer, buf_size, timeout_ms);
78}
79
80static inline void
81wmr_controller_connection_disconnect(struct wmr_controller_connection *wcc)
82{
83 wcc->disconnect(wcc);
84}
85
86/*!
87 * Common base for all WMR controllers.
88 *
89 * @ingroup drv_wmr
90 * @implements xrt_device
91 */
92struct wmr_controller_base
93{
94 //! Base struct.
95 struct xrt_device base;
96
97 //! Mutex protects the controller connection
98 struct os_mutex conn_lock;
99
100 //! The connection for this controller.
101 struct wmr_controller_connection *wcc;
102
103 //! Callback from the connection when a packet has been received.
104 void (*receive_bytes)(struct wmr_controller_base *wcb, uint64_t time_ns, uint8_t *buffer, uint32_t buf_size);
105
106 enum u_logging_level log_level;
107
108 //! Mutex protects shared data used from OpenXR callbacks
109 struct os_mutex data_lock;
110
111 //! Callback to parse a controller update packet and update the input / imu info. Called with the
112 // data lock held.
113 bool (*handle_input_packet)(struct wmr_controller_base *wcb,
114 uint64_t time_ns,
115 uint8_t *buffer,
116 uint32_t buf_size);
117
118 /* firmware configuration block */
119 struct wmr_controller_config config;
120
121 //! Time of last IMU sample, in CPU time.
122 uint64_t last_imu_timestamp_ns;
123 //! Main fusion calculator.
124 struct m_imu_3dof fusion;
125 //! The last angular velocity from the IMU, for prediction.
126 struct xrt_vec3 last_angular_velocity;
127};
128
129bool
130wmr_controller_base_init(struct wmr_controller_base *wcb,
131 struct wmr_controller_connection *conn,
132 enum xrt_device_type controller_type,
133 enum u_logging_level log_level,
134 u_device_destroy_function_t destroy_fn);
135
136void
137wmr_controller_base_deinit(struct wmr_controller_base *wcb);
138
139static inline void
140wmr_controller_connection_receive_bytes(struct wmr_controller_connection *wcc,
141 uint64_t time_ns,
142 uint8_t *buffer,
143 uint32_t buf_size)
144{
145
146 if (wcc->receive_bytes != NULL) {
147 wcc->receive_bytes(wcc, time_ns, buffer, buf_size);
148 } else {
149 /* Default: deliver directly to the controller instance */
150 struct wmr_controller_base *wcb = wcc->wcb;
151 assert(wcb->receive_bytes != NULL);
152 wcb->receive_bytes(wcb, time_ns, buffer, buf_size);
153 }
154}
155
156#ifdef __cplusplus
157}
158#endif