The open source OpenXR runtime
1// Copyright 2020-2021, N Madsen.
2// Copyright 2020-2023, Collabora, Ltd.
3// Copyright 2020-2023, Jan Schmidt
4// SPDX-License-Identifier: BSL-1.0
5/*!
6 * @file
7 * @brief Driver for WMR Controllers.
8 * @author Jan Schmidt <jan@centricular.com>
9 * @ingroup drv_wmr
10 */
11#include "math/m_api.h"
12
13#include "util/u_device.h"
14#include "util/u_trace_marker.h"
15#include "util/u_var.h"
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <assert.h>
21#include <errno.h>
22
23#include "wmr_common.h"
24#include "wmr_controller.h"
25
26#ifdef XRT_DOXYGEN
27#define WMR_PACKED
28#else
29#define WMR_PACKED __attribute__((packed))
30#endif
31
32/*!
33 * Indices in input list of each input.
34 */
35enum wmr_controller_og_input_index
36{
37 WMR_CONTROLLER_INDEX_MENU_CLICK,
38 WMR_CONTROLLER_INDEX_HOME_CLICK,
39 WMR_CONTROLLER_INDEX_SQUEEZE_CLICK,
40 WMR_CONTROLLER_INDEX_TRIGGER_VALUE,
41 WMR_CONTROLLER_INDEX_THUMBSTICK_CLICK,
42 WMR_CONTROLLER_INDEX_THUMBSTICK,
43 WMR_CONTROLLER_INDEX_TRACKPAD_CLICK,
44 WMR_CONTROLLER_INDEX_TRACKPAD_TOUCH,
45 WMR_CONTROLLER_INDEX_TRACKPAD,
46 WMR_CONTROLLER_INDEX_GRIP_POSE,
47 WMR_CONTROLLER_INDEX_AIM_POSE,
48};
49
50#define SET_WMR_INPUT(wcb, NAME) (wcb->base.inputs[WMR_CONTROLLER_INDEX_##NAME].name = XRT_INPUT_WMR_##NAME)
51#define SET_ODYSSEY_INPUT(wcb, NAME) \
52 (wcb->base.inputs[WMR_CONTROLLER_INDEX_##NAME].name = XRT_INPUT_ODYSSEY_CONTROLLER_##NAME)
53
54/*
55 *
56 * Bindings
57 *
58 */
59
60static struct xrt_binding_input_pair simple_inputs_og[4] = {
61 {XRT_INPUT_SIMPLE_SELECT_CLICK, XRT_INPUT_WMR_TRIGGER_VALUE},
62 {XRT_INPUT_SIMPLE_MENU_CLICK, XRT_INPUT_WMR_MENU_CLICK},
63 {XRT_INPUT_SIMPLE_GRIP_POSE, XRT_INPUT_WMR_GRIP_POSE},
64 {XRT_INPUT_SIMPLE_AIM_POSE, XRT_INPUT_WMR_AIM_POSE},
65};
66
67static struct xrt_binding_output_pair simple_outputs_og[1] = {
68 {XRT_OUTPUT_NAME_SIMPLE_VIBRATION, XRT_OUTPUT_NAME_WMR_HAPTIC},
69};
70
71static struct xrt_binding_input_pair vive_inputs_og[10] = {
72 {XRT_INPUT_VIVE_SYSTEM_CLICK, XRT_INPUT_WMR_HOME_CLICK},
73 {XRT_INPUT_VIVE_SQUEEZE_CLICK, XRT_INPUT_WMR_SQUEEZE_CLICK},
74 {XRT_INPUT_VIVE_MENU_CLICK, XRT_INPUT_WMR_MENU_CLICK},
75 {XRT_INPUT_VIVE_TRIGGER_CLICK, XRT_INPUT_WMR_TRIGGER_VALUE},
76 {XRT_INPUT_VIVE_TRIGGER_VALUE, XRT_INPUT_WMR_TRIGGER_VALUE},
77 {XRT_INPUT_VIVE_TRACKPAD, XRT_INPUT_WMR_TRACKPAD},
78 {XRT_INPUT_VIVE_TRACKPAD_CLICK, XRT_INPUT_WMR_TRACKPAD_CLICK},
79 {XRT_INPUT_VIVE_TRACKPAD_TOUCH, XRT_INPUT_WMR_TRACKPAD_TOUCH},
80 {XRT_INPUT_VIVE_GRIP_POSE, XRT_INPUT_WMR_GRIP_POSE},
81 {XRT_INPUT_VIVE_AIM_POSE, XRT_INPUT_WMR_AIM_POSE},
82};
83
84static struct xrt_binding_output_pair vive_outputs_og[1] = {
85 {XRT_OUTPUT_NAME_VIVE_HAPTIC, XRT_OUTPUT_NAME_WMR_HAPTIC},
86};
87
88static struct xrt_binding_profile binding_profiles_og[2] = {
89 {
90 .name = XRT_DEVICE_VIVE_WAND,
91 .inputs = vive_inputs_og,
92 .input_count = ARRAY_SIZE(vive_inputs_og),
93 .outputs = vive_outputs_og,
94 .output_count = ARRAY_SIZE(vive_outputs_og),
95 },
96 {
97 .name = XRT_DEVICE_SIMPLE_CONTROLLER,
98 .inputs = simple_inputs_og,
99 .input_count = ARRAY_SIZE(simple_inputs_og),
100 .outputs = simple_outputs_og,
101 .output_count = ARRAY_SIZE(simple_outputs_og),
102 },
103};
104
105static struct xrt_binding_input_pair simple_inputs_odyssey[4] = {
106 {XRT_INPUT_SIMPLE_SELECT_CLICK, XRT_INPUT_ODYSSEY_CONTROLLER_TRIGGER_VALUE},
107 {XRT_INPUT_SIMPLE_MENU_CLICK, XRT_INPUT_ODYSSEY_CONTROLLER_MENU_CLICK},
108 {XRT_INPUT_SIMPLE_GRIP_POSE, XRT_INPUT_ODYSSEY_CONTROLLER_GRIP_POSE},
109 {XRT_INPUT_SIMPLE_AIM_POSE, XRT_INPUT_ODYSSEY_CONTROLLER_AIM_POSE},
110};
111
112static struct xrt_binding_output_pair simple_outputs_odyssey[1] = {
113 {XRT_OUTPUT_NAME_SIMPLE_VIBRATION, XRT_OUTPUT_NAME_ODYSSEY_CONTROLLER_HAPTIC},
114};
115
116static struct xrt_binding_input_pair wmr_inputs_odyssey[11] = {
117 {XRT_INPUT_WMR_MENU_CLICK, XRT_INPUT_ODYSSEY_CONTROLLER_MENU_CLICK},
118 {XRT_INPUT_WMR_SQUEEZE_CLICK, XRT_INPUT_ODYSSEY_CONTROLLER_SQUEEZE_CLICK},
119 {XRT_INPUT_WMR_TRIGGER_VALUE, XRT_INPUT_ODYSSEY_CONTROLLER_TRIGGER_VALUE},
120 {XRT_INPUT_WMR_THUMBSTICK_CLICK, XRT_INPUT_ODYSSEY_CONTROLLER_THUMBSTICK_CLICK},
121 {XRT_INPUT_WMR_THUMBSTICK, XRT_INPUT_ODYSSEY_CONTROLLER_THUMBSTICK},
122 {XRT_INPUT_WMR_TRACKPAD_CLICK, XRT_INPUT_ODYSSEY_CONTROLLER_TRACKPAD_CLICK},
123 {XRT_INPUT_WMR_TRACKPAD_TOUCH, XRT_INPUT_ODYSSEY_CONTROLLER_TRACKPAD_TOUCH},
124 {XRT_INPUT_WMR_TRACKPAD, XRT_INPUT_ODYSSEY_CONTROLLER_TRACKPAD},
125 {XRT_INPUT_WMR_GRIP_POSE, XRT_INPUT_ODYSSEY_CONTROLLER_GRIP_POSE},
126 {XRT_INPUT_WMR_AIM_POSE, XRT_INPUT_ODYSSEY_CONTROLLER_AIM_POSE},
127 {XRT_INPUT_WMR_HOME_CLICK, XRT_INPUT_ODYSSEY_CONTROLLER_HOME_CLICK},
128};
129
130static struct xrt_binding_output_pair wmr_outputs_odyssey[1] = {
131 {XRT_OUTPUT_NAME_WMR_HAPTIC, XRT_OUTPUT_NAME_ODYSSEY_CONTROLLER_HAPTIC},
132};
133
134static struct xrt_binding_input_pair vive_inputs_odyssey[10] = {
135 {XRT_INPUT_VIVE_SYSTEM_CLICK, XRT_INPUT_ODYSSEY_CONTROLLER_HOME_CLICK},
136 {XRT_INPUT_VIVE_SQUEEZE_CLICK, XRT_INPUT_ODYSSEY_CONTROLLER_SQUEEZE_CLICK},
137 {XRT_INPUT_VIVE_MENU_CLICK, XRT_INPUT_ODYSSEY_CONTROLLER_MENU_CLICK},
138 {XRT_INPUT_VIVE_TRIGGER_CLICK, XRT_INPUT_ODYSSEY_CONTROLLER_TRIGGER_VALUE},
139 {XRT_INPUT_VIVE_TRIGGER_VALUE, XRT_INPUT_ODYSSEY_CONTROLLER_TRIGGER_VALUE},
140 {XRT_INPUT_VIVE_TRACKPAD, XRT_INPUT_ODYSSEY_CONTROLLER_TRACKPAD},
141 {XRT_INPUT_VIVE_TRACKPAD_CLICK, XRT_INPUT_ODYSSEY_CONTROLLER_TRACKPAD_CLICK},
142 {XRT_INPUT_VIVE_TRACKPAD_TOUCH, XRT_INPUT_ODYSSEY_CONTROLLER_TRACKPAD_TOUCH},
143 {XRT_INPUT_VIVE_GRIP_POSE, XRT_INPUT_ODYSSEY_CONTROLLER_GRIP_POSE},
144 {XRT_INPUT_VIVE_AIM_POSE, XRT_INPUT_ODYSSEY_CONTROLLER_AIM_POSE},
145};
146
147static struct xrt_binding_output_pair vive_outputs_odyssey[1] = {
148 {XRT_OUTPUT_NAME_VIVE_HAPTIC, XRT_OUTPUT_NAME_ODYSSEY_CONTROLLER_HAPTIC},
149};
150
151static struct xrt_binding_profile binding_profiles_odyssey[3] = {
152 {
153 .name = XRT_DEVICE_WMR_CONTROLLER,
154 .inputs = wmr_inputs_odyssey,
155 .input_count = ARRAY_SIZE(wmr_inputs_odyssey),
156 .outputs = wmr_outputs_odyssey,
157 .output_count = ARRAY_SIZE(wmr_outputs_odyssey),
158 },
159 {
160 .name = XRT_DEVICE_VIVE_WAND,
161 .inputs = vive_inputs_odyssey,
162 .input_count = ARRAY_SIZE(vive_inputs_odyssey),
163 .outputs = vive_outputs_odyssey,
164 .output_count = ARRAY_SIZE(vive_outputs_odyssey),
165 },
166 {
167 .name = XRT_DEVICE_SIMPLE_CONTROLLER,
168 .inputs = simple_inputs_odyssey,
169 .input_count = ARRAY_SIZE(simple_inputs_odyssey),
170 .outputs = simple_outputs_odyssey,
171 .output_count = ARRAY_SIZE(simple_outputs_odyssey),
172 },
173};
174
175
176/* OG WMR Controller inputs struct */
177struct wmr_controller_og_input
178{
179 // buttons clicked
180 bool menu;
181 bool home;
182 bool bt_pairing;
183 bool squeeze; // Actually a "squeeze" click
184
185 float trigger;
186
187 struct
188 {
189 bool click;
190 struct xrt_vec2 values;
191 } thumbstick;
192 struct
193 {
194 bool click;
195 bool touch;
196 struct xrt_vec2 values;
197 } trackpad;
198
199 uint8_t battery;
200
201 struct
202 {
203 uint64_t timestamp_ticks;
204 struct xrt_vec3 acc;
205 struct xrt_vec3 gyro;
206 int32_t temperature;
207 } imu;
208};
209#undef WMR_PACKED
210
211/* OG WMR Controller device struct */
212struct wmr_controller_og
213{
214 struct wmr_controller_base base;
215
216 //! The last decoded package of IMU and button data
217 struct wmr_controller_og_input last_inputs;
218};
219
220/*
221 *
222 * WMR Motion Controller protocol helpers
223 *
224 */
225
226static inline void
227vec3_from_wmr_controller_accel(const int32_t sample[3], struct xrt_vec3 *out_vec)
228{
229 // Reverb G1 observation: 1g is approximately 490,000.
230
231 out_vec->x = (float)sample[0] / (98000 / 2);
232 out_vec->y = (float)sample[1] / (98000 / 2);
233 out_vec->z = (float)sample[2] / (98000 / 2);
234}
235
236
237static inline void
238vec3_from_wmr_controller_gyro(const int32_t sample[3], struct xrt_vec3 *out_vec)
239{
240 out_vec->x = (float)sample[0] * 0.00001f;
241 out_vec->y = (float)sample[1] * 0.00001f;
242 out_vec->z = (float)sample[2] * 0.00001f;
243}
244
245static bool
246wmr_controller_og_packet_parse(struct wmr_controller_og *ctrl, const unsigned char *buffer, size_t len)
247{
248 struct wmr_controller_og_input *last_input = &ctrl->last_inputs;
249 struct wmr_controller_base *wcb = (struct wmr_controller_base *)(ctrl);
250
251 if (len != 44) {
252 U_LOG_IFL_E(wcb->log_level, "WMR Controller: unexpected message length: %zd", len);
253 return false;
254 }
255
256 const unsigned char *p = buffer;
257
258 // Read buttons
259 uint8_t buttons = read8(&p);
260 last_input->thumbstick.click = buttons & 0x01;
261 last_input->home = buttons & 0x02;
262 last_input->menu = buttons & 0x04;
263 last_input->squeeze = buttons & 0x08; // squeeze-click
264 last_input->trackpad.click = buttons & 0x10;
265 last_input->bt_pairing = buttons & 0x20;
266 last_input->trackpad.touch = buttons & 0x40;
267
268
269 // Read thumbstick coordinates (12 bit resolution)
270 int16_t stick_x = read8(&p);
271 uint8_t nibbles = read8(&p);
272 stick_x += ((nibbles & 0x0F) << 8);
273 int16_t stick_y = (nibbles >> 4);
274 stick_y += (read8(&p) << 4);
275
276 last_input->thumbstick.values.x = (float)(stick_x - 0x07FF) / 0x07FF;
277 if (last_input->thumbstick.values.x > 1.0f) {
278 last_input->thumbstick.values.x = 1.0f;
279 }
280
281 last_input->thumbstick.values.y = (float)(stick_y - 0x07FF) / 0x07FF;
282 if (last_input->thumbstick.values.y > 1.0f) {
283 last_input->thumbstick.values.y = 1.0f;
284 }
285
286 // Read trigger value (0x00 - 0xFF)
287 last_input->trigger = (float)read8(&p) / 0xFF;
288
289 // Read trackpad coordinates (0x00 - 0x64. Both are 0xFF when untouched)
290 uint8_t trackpad_x = read8(&p);
291 uint8_t trackpad_y = read8(&p);
292 last_input->trackpad.values.x = (trackpad_x == 0xFF) ? 0.0f : (float)(trackpad_x - 0x32) / 0x32;
293 last_input->trackpad.values.y = (trackpad_y == 0xFF) ? 0.0f : (float)(trackpad_y - 0x32) / 0x32;
294
295 last_input->battery = read8(&p);
296
297 int32_t acc[3];
298 acc[0] = read24(&p); // x
299 acc[1] = read24(&p); // y
300 acc[2] = read24(&p); // z
301 vec3_from_wmr_controller_accel(acc, &last_input->imu.acc);
302 math_matrix_3x3_transform_vec3(&wcb->config.sensors.accel.mix_matrix, &last_input->imu.acc,
303 &last_input->imu.acc);
304 math_vec3_accum(&wcb->config.sensors.accel.bias_offsets, &last_input->imu.acc);
305 math_quat_rotate_vec3(&wcb->config.sensors.transforms.P_oxr_acc.orientation, &last_input->imu.acc,
306 &last_input->imu.acc);
307
308 U_LOG_IFL_T(wcb->log_level, "Accel [m/s^2] : %f",
309 sqrtf(last_input->imu.acc.x * last_input->imu.acc.x +
310 last_input->imu.acc.y * last_input->imu.acc.y +
311 last_input->imu.acc.z * last_input->imu.acc.z));
312
313
314 last_input->imu.temperature = read16(&p);
315
316 int32_t gyro[3];
317 gyro[0] = read24(&p);
318 gyro[1] = read24(&p);
319 gyro[2] = read24(&p);
320 vec3_from_wmr_controller_gyro(gyro, &last_input->imu.gyro);
321 math_matrix_3x3_transform_vec3(&wcb->config.sensors.gyro.mix_matrix, &last_input->imu.gyro,
322 &last_input->imu.gyro);
323 math_vec3_accum(&wcb->config.sensors.gyro.bias_offsets, &last_input->imu.gyro);
324 math_quat_rotate_vec3(&wcb->config.sensors.transforms.P_oxr_gyr.orientation, &last_input->imu.gyro,
325 &last_input->imu.gyro);
326
327
328 uint32_t prev_ticks = last_input->imu.timestamp_ticks & UINT32_C(0xFFFFFFFF);
329
330 // Write the new ticks value into the lower half of timestamp_ticks
331 last_input->imu.timestamp_ticks &= (UINT64_C(0xFFFFFFFF) << 32u);
332 last_input->imu.timestamp_ticks += (uint32_t)read32(&p);
333
334 if ((last_input->imu.timestamp_ticks & UINT64_C(0xFFFFFFFF)) < prev_ticks) {
335 // Timer overflow, so increment the upper half of timestamp_ticks
336 last_input->imu.timestamp_ticks += (UINT64_C(0x1) << 32u);
337 }
338
339 /* Todo: More decoding here
340 read16(&p); // Unknown. Seems to depend on controller orientation (probably mag)
341 read32(&p); // Unknown.
342 read16(&p); // Unknown. Device state, etc.
343 read16(&p);
344 read16(&p);
345 */
346
347 return true;
348}
349
350static bool
351handle_input_packet(struct wmr_controller_base *wcb, uint64_t time_ns, uint8_t *buffer, uint32_t buf_size)
352{
353 struct wmr_controller_og *ctrl = (struct wmr_controller_og *)(wcb);
354 bool b = wmr_controller_og_packet_parse(ctrl, buffer, buf_size);
355 if (b) {
356 m_imu_3dof_update(&wcb->fusion,
357 ctrl->last_inputs.imu.timestamp_ticks * WMR_MOTION_CONTROLLER_NS_PER_TICK,
358 &ctrl->last_inputs.imu.acc, &ctrl->last_inputs.imu.gyro);
359
360 wcb->last_imu_timestamp_ns = time_ns;
361 wcb->last_angular_velocity = ctrl->last_inputs.imu.gyro;
362 }
363
364 return b;
365}
366
367static xrt_result_t
368wmr_controller_og_update_inputs(struct xrt_device *xdev)
369{
370 DRV_TRACE_MARKER();
371
372 struct wmr_controller_og *ctrl = (struct wmr_controller_og *)(xdev);
373 struct wmr_controller_base *wcb = (struct wmr_controller_base *)(xdev);
374
375 os_mutex_lock(&wcb->data_lock);
376
377 struct xrt_input *xrt_inputs = xdev->inputs;
378 struct wmr_controller_og_input *cur_inputs = &ctrl->last_inputs;
379
380 xrt_inputs[WMR_CONTROLLER_INDEX_MENU_CLICK].value.boolean = cur_inputs->menu;
381 xrt_inputs[WMR_CONTROLLER_INDEX_HOME_CLICK].value.boolean = cur_inputs->home;
382 xrt_inputs[WMR_CONTROLLER_INDEX_SQUEEZE_CLICK].value.boolean = cur_inputs->squeeze;
383 xrt_inputs[WMR_CONTROLLER_INDEX_TRIGGER_VALUE].value.vec1.x = cur_inputs->trigger;
384 xrt_inputs[WMR_CONTROLLER_INDEX_THUMBSTICK_CLICK].value.boolean = cur_inputs->thumbstick.click;
385 xrt_inputs[WMR_CONTROLLER_INDEX_THUMBSTICK].value.vec2 = cur_inputs->thumbstick.values;
386 xrt_inputs[WMR_CONTROLLER_INDEX_TRACKPAD_CLICK].value.boolean = cur_inputs->trackpad.click;
387 xrt_inputs[WMR_CONTROLLER_INDEX_TRACKPAD_TOUCH].value.boolean = cur_inputs->trackpad.touch;
388 xrt_inputs[WMR_CONTROLLER_INDEX_TRACKPAD].value.vec2 = cur_inputs->trackpad.values;
389
390 os_mutex_unlock(&wcb->data_lock);
391
392 return XRT_SUCCESS;
393}
394
395static void
396wmr_controller_og_destroy(struct xrt_device *xdev)
397{
398 struct wmr_controller_base *wcb = (struct wmr_controller_base *)(xdev);
399
400 wmr_controller_base_deinit(wcb);
401 free(wcb);
402}
403
404struct wmr_controller_base *
405wmr_controller_og_create(struct wmr_controller_connection *conn,
406 enum xrt_device_type controller_type,
407 uint16_t pid,
408 enum u_logging_level log_level)
409{
410 DRV_TRACE_MARKER();
411
412 enum u_device_alloc_flags flags = U_DEVICE_ALLOC_TRACKING_NONE;
413 struct wmr_controller_og *ctrl = U_DEVICE_ALLOCATE(struct wmr_controller_og, flags, 11, 1);
414 struct wmr_controller_base *wcb = (struct wmr_controller_base *)(ctrl);
415
416 if (!wmr_controller_base_init(wcb, conn, controller_type, log_level, wmr_controller_og_destroy)) {
417 wmr_controller_og_destroy(&wcb->base);
418 return NULL;
419 }
420
421 wcb->handle_input_packet = handle_input_packet;
422
423 // Only set those we want to overwrite.
424 wcb->base.update_inputs = wmr_controller_og_update_inputs;
425
426 if (pid == ODYSSEY_CONTROLLER_PID) {
427 wcb->base.name = XRT_DEVICE_SAMSUNG_ODYSSEY_CONTROLLER;
428 } else {
429 wcb->base.name = XRT_DEVICE_WMR_CONTROLLER;
430 }
431
432 if (pid == ODYSSEY_CONTROLLER_PID) {
433 SET_ODYSSEY_INPUT(wcb, MENU_CLICK);
434 SET_ODYSSEY_INPUT(wcb, HOME_CLICK);
435 SET_ODYSSEY_INPUT(wcb, SQUEEZE_CLICK);
436 SET_ODYSSEY_INPUT(wcb, TRIGGER_VALUE);
437 SET_ODYSSEY_INPUT(wcb, THUMBSTICK_CLICK);
438 SET_ODYSSEY_INPUT(wcb, THUMBSTICK);
439 SET_ODYSSEY_INPUT(wcb, TRACKPAD_CLICK);
440 SET_ODYSSEY_INPUT(wcb, TRACKPAD_TOUCH);
441 SET_ODYSSEY_INPUT(wcb, TRACKPAD);
442 SET_ODYSSEY_INPUT(wcb, GRIP_POSE);
443 SET_ODYSSEY_INPUT(wcb, AIM_POSE);
444
445 wcb->base.outputs[0].name = XRT_OUTPUT_NAME_ODYSSEY_CONTROLLER_HAPTIC;
446
447 wcb->base.binding_profiles = binding_profiles_odyssey;
448 wcb->base.binding_profile_count = ARRAY_SIZE(binding_profiles_odyssey);
449 } else {
450 SET_WMR_INPUT(wcb, MENU_CLICK);
451 SET_WMR_INPUT(wcb, HOME_CLICK);
452 SET_WMR_INPUT(wcb, SQUEEZE_CLICK);
453 SET_WMR_INPUT(wcb, TRIGGER_VALUE);
454 SET_WMR_INPUT(wcb, THUMBSTICK_CLICK);
455 SET_WMR_INPUT(wcb, THUMBSTICK);
456 SET_WMR_INPUT(wcb, TRACKPAD_CLICK);
457 SET_WMR_INPUT(wcb, TRACKPAD_TOUCH);
458 SET_WMR_INPUT(wcb, TRACKPAD);
459 SET_WMR_INPUT(wcb, GRIP_POSE);
460 SET_WMR_INPUT(wcb, AIM_POSE);
461
462 wcb->base.outputs[0].name = XRT_OUTPUT_NAME_WMR_HAPTIC;
463
464 wcb->base.binding_profiles = binding_profiles_og;
465 wcb->base.binding_profile_count = ARRAY_SIZE(binding_profiles_og);
466 }
467
468 for (uint32_t i = 0; i < wcb->base.input_count; i++) {
469 wcb->base.inputs[0].active = true;
470 }
471
472 ctrl->last_inputs.imu.timestamp_ticks = 0;
473
474 u_var_add_bool(wcb, &ctrl->last_inputs.menu, "input.menu");
475 u_var_add_bool(wcb, &ctrl->last_inputs.home, "input.home");
476 u_var_add_bool(wcb, &ctrl->last_inputs.bt_pairing, "input.bt_pairing");
477 u_var_add_bool(wcb, &ctrl->last_inputs.squeeze, "input.squeeze");
478 u_var_add_f32(wcb, &ctrl->last_inputs.trigger, "input.trigger");
479 u_var_add_u8(wcb, &ctrl->last_inputs.battery, "input.battery");
480 u_var_add_bool(wcb, &ctrl->last_inputs.thumbstick.click, "input.thumbstick.click");
481 u_var_add_f32(wcb, &ctrl->last_inputs.thumbstick.values.x, "input.thumbstick.values.y");
482 u_var_add_f32(wcb, &ctrl->last_inputs.thumbstick.values.y, "input.thumbstick.values.x");
483 u_var_add_bool(wcb, &ctrl->last_inputs.trackpad.click, "input.trackpad.click");
484 u_var_add_bool(wcb, &ctrl->last_inputs.trackpad.touch, "input.trackpad.touch");
485 u_var_add_f32(wcb, &ctrl->last_inputs.trackpad.values.x, "input.trackpad.values.x");
486 u_var_add_f32(wcb, &ctrl->last_inputs.trackpad.values.y, "input.trackpad.values.y");
487 u_var_add_ro_vec3_f32(wcb, &ctrl->last_inputs.imu.acc, "imu.acc");
488 u_var_add_ro_vec3_f32(wcb, &ctrl->last_inputs.imu.gyro, "imu.gyro");
489 u_var_add_i32(wcb, &ctrl->last_inputs.imu.temperature, "imu.temperature");
490
491 return wcb;
492}