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