The open source OpenXR runtime
at main 1016 lines 35 kB view raw
1// Copyright 2023, Collabora, Ltd. 2// Copyright 2023, Jarett Millard 3// SPDX-License-Identifier: BSL-1.0 4/*! 5 * @file 6 * @brief PlayStation Sense controller prober and driver code. 7 * @author Jarett Millard <jarett.millard@gmail.com> 8 * @ingroup drv_pssense 9 */ 10 11#include "xrt/xrt_prober.h" 12 13#include "os/os_threading.h" 14#include "os/os_hid.h" 15#include "os/os_time.h" 16 17#include "math/m_api.h" 18 19#include "tracking/t_imu.h" 20 21#include "util/u_var.h" 22#include "util/u_debug.h" 23#include "util/u_device.h" 24#include "util/u_logging.h" 25#include "util/u_trace_marker.h" 26 27#include "pssense_interface.h" 28#include "math/m_mathinclude.h" 29#include "math/m_space.h" 30#include "math/m_imu_3dof.h" 31 32#include <stdio.h> 33 34/*! 35 * @addtogroup drv_pssense 36 * @{ 37 */ 38 39#define PSSENSE_TRACE(p, ...) U_LOG_XDEV_IFL_T(&p->base, p->log_level, __VA_ARGS__) 40#define PSSENSE_DEBUG(p, ...) U_LOG_XDEV_IFL_D(&p->base, p->log_level, __VA_ARGS__) 41#define PSSENSE_WARN(p, ...) U_LOG_XDEV_IFL_W(&p->base, p->log_level, __VA_ARGS__) 42#define PSSENSE_ERROR(p, ...) U_LOG_XDEV_IFL_E(&p->base, p->log_level, __VA_ARGS__) 43 44DEBUG_GET_ONCE_LOG_OPTION(pssense_log, "PSSENSE_LOG", U_LOGGING_INFO) 45 46static struct xrt_binding_input_pair simple_inputs_pssense[4] = { 47 {XRT_INPUT_SIMPLE_SELECT_CLICK, XRT_INPUT_PSSENSE_TRIGGER_VALUE}, 48 {XRT_INPUT_SIMPLE_MENU_CLICK, XRT_INPUT_PSSENSE_OPTIONS_CLICK}, 49 {XRT_INPUT_SIMPLE_GRIP_POSE, XRT_INPUT_PSSENSE_GRIP_POSE}, 50 {XRT_INPUT_SIMPLE_AIM_POSE, XRT_INPUT_PSSENSE_AIM_POSE}, 51}; 52 53static struct xrt_binding_output_pair simple_outputs_pssense[1] = { 54 {XRT_OUTPUT_NAME_SIMPLE_VIBRATION, XRT_OUTPUT_NAME_PSSENSE_VIBRATION}, 55}; 56 57static struct xrt_binding_profile binding_profiles_pssense[1] = { 58 { 59 .name = XRT_DEVICE_SIMPLE_CONTROLLER, 60 .inputs = simple_inputs_pssense, 61 .input_count = ARRAY_SIZE(simple_inputs_pssense), 62 .outputs = simple_outputs_pssense, 63 .output_count = ARRAY_SIZE(simple_outputs_pssense), 64 }, 65}; 66 67/*! 68 * Indices where each input is in the input list. 69 */ 70enum pssense_input_index 71{ 72 PSSENSE_INDEX_PS_CLICK, 73 PSSENSE_INDEX_SHARE_CLICK, 74 PSSENSE_INDEX_OPTIONS_CLICK, 75 PSSENSE_INDEX_SQUARE_CLICK, 76 PSSENSE_INDEX_SQUARE_TOUCH, 77 PSSENSE_INDEX_TRIANGLE_CLICK, 78 PSSENSE_INDEX_TRIANGLE_TOUCH, 79 PSSENSE_INDEX_CROSS_CLICK, 80 PSSENSE_INDEX_CROSS_TOUCH, 81 PSSENSE_INDEX_CIRCLE_CLICK, 82 PSSENSE_INDEX_CIRCLE_TOUCH, 83 PSSENSE_INDEX_SQUEEZE_CLICK, 84 PSSENSE_INDEX_SQUEEZE_TOUCH, 85 PSSENSE_INDEX_SQUEEZE_PROXIMITY_FLOAT, 86 PSSENSE_INDEX_TRIGGER_CLICK, 87 PSSENSE_INDEX_TRIGGER_TOUCH, 88 PSSENSE_INDEX_TRIGGER_VALUE, 89 PSSENSE_INDEX_TRIGGER_PROXIMITY_FLOAT, 90 PSSENSE_INDEX_THUMBSTICK, 91 PSSENSE_INDEX_THUMBSTICK_CLICK, 92 PSSENSE_INDEX_THUMBSTICK_TOUCH, 93 PSSENSE_INDEX_GRIP_POSE, 94 PSSENSE_INDEX_AIM_POSE, 95}; 96 97const uint8_t INPUT_REPORT_ID = 0x31; 98const uint8_t OUTPUT_REPORT_ID = 0x31; 99const uint8_t OUTPUT_REPORT_TAG = 0x10; 100const uint8_t CALIBRATION_DATA_FEATURE_REPORT_ID = 0x05; 101const uint8_t CALIBRATION_DATA_PART_ID_1 = 0; 102const uint8_t CALIBRATION_DATA_PART_ID_2 = 0x81; 103 104const uint8_t INPUT_REPORT_CRC32_SEED = 0xa1; 105const uint8_t OUTPUT_REPORT_CRC32_SEED = 0xa2; 106const uint8_t FEATURE_REPORT_CRC32_SEED = 0xa3; 107 108//! Gyro read value range is +-32768. 109const double PSSENSE_GYRO_SCALE_DEG = 180.0 / 1024; 110//! Accelerometer read value range is +-32768 and covers +-8 g. 111const double PSSENSE_ACCEL_SCALE = MATH_GRAVITY_M_S2 / 4096; 112 113//! Flag bits to enable setting vibration in an output report 114const uint8_t VIBRATE_ENABLE_BITS = 0x03; 115//! Pure 120Hz vibration 116const uint8_t VIBRATE_MODE_HIGH_120HZ = 0x00; 117//! Pure 60Hz vibration 118const uint8_t VIBRATE_MODE_LOW_60HZ = 0x20; 119//! Emulates a legacy vibration motor 120const uint8_t VIBRATE_MODE_CLASSIC_RUMBLE = 0x40; 121//! Softer rumble emulation, like an engine running 122const uint8_t VIBRATE_MODE_DIET_RUMBLE = 0x60; 123 124//! Flag bits to enable setting trigger feedback in an output report 125const uint8_t TRIGGER_FEEDBACK_ENABLE_BITS = 0x04; 126//! Clear the trigger feedback setting 127const uint8_t TRIGGER_FEEDBACK_MODE_NONE = 0x00; 128//! Constant resistance throughout the trigger movement 129const uint8_t TRIGGER_FEEDBACK_MODE_CONSTANT = 0x01; 130//! A single point of resistance at the beginning of the trigger, right before the click flag is activated 131const uint8_t TRIGGER_FEEDBACK_MODE_CATCH = 0x02; 132 133const uint8_t CHARGE_STATE_DISCHARGING = 0x00; 134const uint8_t CHARGE_STATE_CHARGING = 0x01; 135const uint8_t CHARGE_STATE_FULL = 0x02; 136const uint8_t CHARGE_STATE_ABNORMAL_VOLTAGE = 0x0A; 137const uint8_t CHARGE_STATE_ABNORMAL_TEMP = 0x0B; 138const uint8_t CHARGE_STATE_CHARGING_ERROR = 0x0F; 139 140/** 141 * 16-bit little-endian int 142 */ 143struct pssense_i16_le 144{ 145 uint8_t low; 146 uint8_t high; 147}; 148 149/** 150 * 32-bit little-endian int 151 */ 152struct pssense_i32_le 153{ 154 uint8_t lowest; 155 uint8_t lower; 156 uint8_t higher; 157 uint8_t highest; 158}; 159 160#define INPUT_REPORT_LENGTH 78 161/*! 162 * HID input report data packet. 163 */ 164struct pssense_input_report 165{ 166 uint8_t report_id; 167 uint8_t bt_header; 168 uint8_t thumbstick_x; 169 uint8_t thumbstick_y; 170 uint8_t trigger_value; 171 uint8_t trigger_proximity; 172 uint8_t squeeze_proximity; 173 uint8_t unknown1[2]; // Always 0x0001 174 uint8_t buttons[3]; 175 uint8_t unknown2; // Always 0x00 176 struct pssense_i32_le seq_no; 177 struct pssense_i16_le gyro[3]; 178 struct pssense_i16_le accel[3]; 179 struct pssense_i32_le imu_ticks; 180 uint8_t temperature; 181 uint8_t unknown3[9]; 182 uint8_t battery_state; // High bits charge level 0x00-0x0a, low bits battery state 183 uint8_t plug_state; // Flags for USB data and/or power connected 184 struct pssense_i32_le host_timestamp; 185 struct pssense_i32_le device_timestamp; 186 uint8_t unknown4[4]; 187 uint8_t aes_cmac[8]; 188 uint8_t unknown5; 189 uint8_t crc_failure_count; 190 uint8_t padding[7]; 191 struct pssense_i32_le crc; 192}; 193static_assert(sizeof(struct pssense_input_report) == INPUT_REPORT_LENGTH, "Incorrect input report struct length"); 194 195#define OUTPUT_REPORT_LENGTH 78 196/** 197 * HID output report data packet. 198 */ 199struct pssense_output_report 200{ 201 uint8_t report_id; 202 uint8_t bt_seq_no; // High bits only; low bits are always 0 203 uint8_t tag; // Needs to be 0x10 for this report 204 uint8_t feedback_flags; // Vibrate mode and enable flags to set vibrate and trigger feedback in this report 205 uint8_t unknown; 206 uint8_t vibration_amplitude; // Vibration amplitude from 0x00-0xff. Sending 0 turns vibration off. 207 uint8_t unknown2; 208 uint8_t trigger_feedback_mode; // Constant or sticky trigger resistance 209 uint8_t ffb[10]; 210 struct pssense_i32_le host_timestamp; 211 uint8_t unknown3[19]; 212 uint8_t counter; 213 uint8_t haptics[32]; 214 struct pssense_i32_le crc; 215}; 216static_assert(sizeof(struct pssense_output_report) == OUTPUT_REPORT_LENGTH, "Incorrect output report struct length"); 217 218#define FEATURE_REPORT_LENGTH 64 219#define CALIBRATION_DATA_LENGTH 116 220/** 221 * HID output report data packet. 222 */ 223struct pssense_feature_report 224{ 225 uint8_t report_id; 226 uint8_t part_id; 227 uint8_t data[CALIBRATION_DATA_LENGTH / 2]; 228 struct pssense_i32_le crc; 229}; 230static_assert(sizeof(struct pssense_feature_report) == FEATURE_REPORT_LENGTH, "Incorrect feature report struct length"); 231 232/*! 233 * PlayStation Sense state parsed from a data packet. 234 */ 235struct pssense_input_state 236{ 237 uint64_t timestamp_ns; 238 uint32_t seq_no; 239 240 bool ps_click; 241 bool share_click; 242 bool options_click; 243 bool square_click; 244 bool square_touch; 245 bool triangle_click; 246 bool triangle_touch; 247 bool cross_click; 248 bool cross_touch; 249 bool circle_click; 250 bool circle_touch; 251 bool squeeze_click; 252 bool squeeze_touch; 253 float squeeze_proximity; 254 bool trigger_click; 255 bool trigger_touch; 256 float trigger_value; 257 float trigger_proximity; 258 bool thumbstick_click; 259 bool thumbstick_touch; 260 struct xrt_vec2 thumbstick; 261 262 uint32_t imu_ticks_last; 263 uint64_t imu_ticks_total; 264 struct xrt_vec3_i32 gyro_raw; 265 struct xrt_vec3_i32 accel_raw; 266 267 bool battery_state_valid; 268 bool battery_charging; 269 //! 0..1 270 float battery_charge_percent; 271}; 272 273/*! 274 * A single PlayStation Sense Controller. 275 * 276 * @implements xrt_device 277 */ 278struct pssense_device 279{ 280 struct xrt_device base; 281 282 struct os_hid_device *hid; 283 struct os_thread_helper controller_thread; 284 struct os_mutex lock; 285 286 enum 287 { 288 PSSENSE_HAND_LEFT, 289 PSSENSE_HAND_RIGHT 290 } hand; 291 292 enum u_logging_level log_level; 293 294 //! Input state parsed from most recent packet 295 struct pssense_input_state state; 296 //! Pending output state to send to device 297 struct 298 { 299 uint8_t next_seq_no; 300 bool send_vibration; 301 uint8_t vibration_amplitude; 302 uint8_t vibration_mode; 303 uint64_t vibration_end_timestamp_ns; 304 uint64_t vibration_resend_timestamp_ns; 305 bool send_trigger_feedback; 306 uint8_t trigger_feedback_mode; 307 } output; 308 309 struct m_imu_3dof fusion; 310 struct xrt_pose pose; 311 312 struct 313 { 314 bool button_states; 315 bool tracking; 316 } gui; 317}; 318 319static uint32_t 320pssense_i32_le_to_u32(const struct pssense_i32_le *from) 321{ 322 return (uint32_t)(from->lowest | from->lower << 8 | from->higher << 16 | from->highest << 24); 323} 324 325static struct pssense_i32_le 326pssense_u32_to_i32_le(uint32_t from) 327{ 328 struct pssense_i32_le ret = { 329 .lowest = (from >> 0) & 0x0ff, 330 .lower = (from >> 8) & 0x0ff, 331 .higher = (from >> 16) & 0x0ff, 332 .highest = (from >> 24) & 0x0ff, 333 }; 334 335 return ret; 336} 337 338static int16_t 339pssense_i16_le_to_i16(const struct pssense_i16_le *from) 340{ 341 // The cast is important, sign extend properly. 342 return (int16_t)(from->low | from->high << 8); 343} 344 345const uint32_t CRC_POLYNOMIAL = 0xedb88320; 346static uint32_t 347crc32_le(uint32_t crc, uint8_t const *p, size_t len) 348{ 349 int i; 350 crc ^= 0xffffffff; 351 while (len--) { 352 crc ^= *p++; 353 for (i = 0; i < 8; i++) 354 crc = (crc >> 1) ^ ((crc & 1) ? CRC_POLYNOMIAL : 0); 355 } 356 return crc ^ 0xffffffff; 357} 358 359/*! 360 * Reads one packet from the device, handles time out, locking and checking if 361 * the thread has been told to shut down. 362 */ 363static bool 364pssense_read_one_packet(struct pssense_device *pssense, uint8_t *buffer, size_t size, bool check_size) 365{ 366 os_thread_helper_lock(&pssense->controller_thread); 367 368 while (os_thread_helper_is_running_locked(&pssense->controller_thread)) { 369 os_thread_helper_unlock(&pssense->controller_thread); 370 371 int ret = os_hid_read(pssense->hid, buffer, size, 1000); 372 373 if (ret == 0) { 374 PSSENSE_DEBUG(pssense, "Timeout"); 375 376 // Must lock thread before check in a while. 377 os_thread_helper_lock(&pssense->controller_thread); 378 continue; 379 } 380 if (ret < 0) { 381 PSSENSE_ERROR(pssense, "Failed to read device '%i'!", ret); 382 return false; 383 } 384 // Skip this check if we haven't flushed all the compat mode packets yet, since they're shorter. 385 if (check_size && ret != (int)size) { 386 PSSENSE_ERROR(pssense, "Unexpected HID packet size %i (expected %zu)", ret, size); 387 return false; 388 } 389 390 return true; 391 } 392 393 return false; 394} 395 396static bool 397pssense_parse_packet(struct pssense_device *pssense, 398 struct pssense_input_report *data, 399 struct pssense_input_state *input) 400{ 401 if (data->report_id != INPUT_REPORT_ID) { 402 PSSENSE_WARN(pssense, "Unrecognized HID report id %u", data->report_id); 403 return false; 404 } 405 406 uint32_t expected_crc = pssense_i32_le_to_u32(&data->crc); 407 uint32_t crc = crc32_le(0, &INPUT_REPORT_CRC32_SEED, 1); 408 crc = crc32_le(crc, (uint8_t *)data, sizeof(struct pssense_input_report) - 4); 409 if (crc != expected_crc) { 410 PSSENSE_WARN(pssense, "CRC mismatch; skipping input. Expected %08X but got %08X", expected_crc, crc); 411 return false; 412 } 413 414 input->timestamp_ns = os_monotonic_get_ns(); 415 416 uint32_t seq_no = pssense_i32_le_to_u32(&data->seq_no); 417 if (input->seq_no != 0 && seq_no != input->seq_no + 1) { 418 PSSENSE_WARN(pssense, "Missed seq no %u. Previous was %u", seq_no, input->seq_no); 419 } 420 input->seq_no = seq_no; 421 422 input->ps_click = (data->buttons[1] & 16) != 0; 423 input->squeeze_touch = (data->buttons[2] & 8) != 0; 424 input->squeeze_proximity = data->squeeze_proximity / 255.0f; 425 input->trigger_touch = (data->buttons[1] & 128) != 0; 426 input->trigger_value = data->trigger_value / 255.0f; 427 input->trigger_proximity = data->trigger_proximity / 255.0f; 428 input->thumbstick.x = (data->thumbstick_x - 128) / 128.0f; 429 input->thumbstick.y = (data->thumbstick_y - 128) / -128.0f; 430 input->thumbstick_touch = (data->buttons[2] & 4) != 0; 431 432 if (pssense->hand == PSSENSE_HAND_LEFT) { 433 input->share_click = (data->buttons[1] & 1) != 0; 434 input->square_click = (data->buttons[0] & 1) != 0; 435 input->square_touch = (data->buttons[2] & 2) != 0; 436 input->triangle_click = (data->buttons[0] & 8) != 0; 437 input->triangle_touch = (data->buttons[2] & 1) != 0; 438 input->squeeze_click = (data->buttons[0] & 16) != 0; 439 input->trigger_click = (data->buttons[0] & 64) != 0; 440 input->thumbstick_click = (data->buttons[1] & 4) != 0; 441 } else if (pssense->hand == PSSENSE_HAND_RIGHT) { 442 input->options_click = (data->buttons[1] & 2) != 0; 443 input->cross_click = (data->buttons[0] & 2) != 0; 444 input->cross_touch = (data->buttons[2] & 2) != 0; 445 input->circle_click = (data->buttons[0] & 4) != 0; 446 input->circle_touch = (data->buttons[2] & 1) != 0; 447 input->squeeze_click = (data->buttons[0] & 32) != 0; 448 input->trigger_click = (data->buttons[0] & 128) != 0; 449 input->thumbstick_click = (data->buttons[1] & 8) != 0; 450 } 451 452 uint32_t imu_ticks = pssense_i32_le_to_u32(&data->imu_ticks); 453 int64_t imu_ticks_delta = imu_ticks - input->imu_ticks_last; 454 if (imu_ticks_delta >= 0) { 455 input->imu_ticks_total += imu_ticks_delta; 456 input->imu_ticks_last = imu_ticks; 457 458 input->gyro_raw.x = pssense_i16_le_to_i16(&data->gyro[0]); 459 input->gyro_raw.y = pssense_i16_le_to_i16(&data->gyro[1]); 460 input->gyro_raw.z = pssense_i16_le_to_i16(&data->gyro[2]); 461 462 input->accel_raw.x = pssense_i16_le_to_i16(&data->accel[0]); 463 input->accel_raw.y = pssense_i16_le_to_i16(&data->accel[1]); 464 input->accel_raw.z = pssense_i16_le_to_i16(&data->accel[2]); 465 } else { 466 PSSENSE_WARN(pssense, "Time went backwards. Check your play area for black holes."); 467 } 468 469 uint8_t battery_state = data->battery_state >> 4; 470 // Charge values go from 0..10, so add 5% and cap at 100% so we never show 0% charge 471 float battery_percent = MIN(1.0f, (data->battery_state & 0xf) * .1f + .05); 472 bool valid, charging; 473 if (battery_state == CHARGE_STATE_DISCHARGING) { 474 valid = true; 475 charging = false; 476 } else if (battery_state == CHARGE_STATE_CHARGING) { 477 valid = true; 478 charging = true; 479 } else if (battery_state == CHARGE_STATE_FULL) { 480 valid = true; 481 charging = true; 482 battery_percent = 1.0f; 483 } else if (battery_state == CHARGE_STATE_ABNORMAL_VOLTAGE) { 484 valid = false; 485 PSSENSE_WARN(pssense, "Unable to determine charge state: abnormal voltage"); 486 } else if (battery_state == CHARGE_STATE_ABNORMAL_TEMP) { 487 valid = false; 488 PSSENSE_WARN(pssense, "Unable to determine charge state: abnormal temp"); 489 } else if (battery_state == CHARGE_STATE_CHARGING_ERROR) { 490 valid = false; 491 PSSENSE_WARN(pssense, "Unable to determine charge state: charging error"); 492 } else { 493 valid = false; 494 PSSENSE_WARN(pssense, "Unable to determine charge state: unknown reason"); 495 } 496 497 input->battery_state_valid = valid; 498 if (valid) { 499 if (charging != input->battery_charging || battery_percent != input->battery_charge_percent) { 500 PSSENSE_DEBUG(pssense, "Battery at %.f%%, %s", battery_percent * 100, 501 charging ? "charging" : "discharging"); 502 } 503 input->battery_charging = charging; 504 input->battery_charge_percent = battery_percent; 505 } 506 507 return true; 508} 509 510static void 511pssense_update_fusion(struct pssense_device *pssense) 512{ 513 struct xrt_vec3 gyro; 514 gyro.x = DEG_TO_RAD(pssense->state.gyro_raw.x * PSSENSE_GYRO_SCALE_DEG); 515 gyro.y = DEG_TO_RAD(pssense->state.gyro_raw.y * PSSENSE_GYRO_SCALE_DEG); 516 gyro.z = DEG_TO_RAD(pssense->state.gyro_raw.z * PSSENSE_GYRO_SCALE_DEG); 517 518 struct xrt_vec3 accel; 519 accel.x = pssense->state.accel_raw.x * PSSENSE_ACCEL_SCALE; 520 accel.y = pssense->state.accel_raw.y * PSSENSE_ACCEL_SCALE; 521 accel.z = pssense->state.accel_raw.z * PSSENSE_ACCEL_SCALE; 522 523 // TODO: Apply correction from calibration data 524 525 // Each IMU tick is .33μs 526 m_imu_3dof_update(&pssense->fusion, pssense->state.imu_ticks_total * 333, &accel, &gyro); 527 pssense->pose.orientation = pssense->fusion.rot; 528} 529 530static void 531pssense_send_output_report_locked(struct pssense_device *pssense) 532{ 533 uint64_t timestamp_ns = os_monotonic_get_ns(); 534 535 struct pssense_output_report report = {0}; 536 report.report_id = OUTPUT_REPORT_ID; 537 report.bt_seq_no = pssense->output.next_seq_no << 4; 538 report.tag = OUTPUT_REPORT_TAG; 539 540 if (timestamp_ns >= pssense->output.vibration_end_timestamp_ns) { 541 pssense->output.vibration_amplitude = 0; 542 } 543 544 if (pssense->output.send_vibration) { 545 report.feedback_flags = pssense->output.vibration_mode | VIBRATE_ENABLE_BITS; 546 report.vibration_amplitude = pssense->output.vibration_amplitude; 547 pssense->output.send_vibration = pssense->output.vibration_amplitude > 0; 548 } 549 550 if (pssense->output.send_trigger_feedback) { 551 report.feedback_flags |= TRIGGER_FEEDBACK_ENABLE_BITS; 552 report.trigger_feedback_mode = pssense->output.trigger_feedback_mode; 553 pssense->output.send_trigger_feedback = false; 554 } 555 556 pssense->output.next_seq_no = (pssense->output.next_seq_no + 1) % 16; 557 558 uint32_t crc = crc32_le(0, &OUTPUT_REPORT_CRC32_SEED, 1); 559 crc = crc32_le(crc, (uint8_t *)&report, sizeof(struct pssense_output_report) - 4); 560 report.crc = pssense_u32_to_i32_le(crc); 561 562 PSSENSE_DEBUG(pssense, "Setting vibration amplitude: %u, mode: %02X, trigger feedback mode: %02X", 563 pssense->output.vibration_amplitude, pssense->output.vibration_mode, 564 pssense->output.trigger_feedback_mode); 565 int ret = os_hid_write(pssense->hid, (uint8_t *)&report, sizeof(struct pssense_output_report)); 566 if (ret == sizeof(struct pssense_output_report)) { 567 // Controller will vibrate for 5 sec unless we resend the output report. Resend every 2 sec to be safe. 568 pssense->output.vibration_resend_timestamp_ns = timestamp_ns + 2000000000; 569 if (pssense->output.vibration_resend_timestamp_ns > pssense->output.vibration_end_timestamp_ns) { 570 pssense->output.vibration_resend_timestamp_ns = pssense->output.vibration_end_timestamp_ns; 571 } 572 } else { 573 PSSENSE_WARN(pssense, "Failed to send output report: %d", ret); 574 pssense->output.vibration_resend_timestamp_ns = timestamp_ns; 575 } 576} 577 578static void * 579pssense_run_thread(void *ptr) 580{ 581 U_TRACE_SET_THREAD_NAME("PS Sense"); 582 583 struct pssense_device *pssense = (struct pssense_device *)ptr; 584 585 union { 586 uint8_t buffer[sizeof(struct pssense_input_report)]; 587 struct pssense_input_report report; 588 } data; 589 struct pssense_input_state input_state = {0}; 590 591 // The Sense controller starts in compat mode with a different HID report ID and format. 592 // We need to discard packets until we get a correct report. 593 while (pssense_read_one_packet(pssense, data.buffer, sizeof(data), false) && 594 data.report.report_id != INPUT_REPORT_ID) { 595 PSSENSE_DEBUG(pssense, "Discarding compat mode HID report"); 596 } 597 598 while (pssense_read_one_packet(pssense, data.buffer, sizeof(data), true)) { 599 if (pssense_parse_packet(pssense, &data.report, &input_state)) { 600 os_mutex_lock(&pssense->lock); 601 pssense->state = input_state; 602 pssense_update_fusion(pssense); 603 if (pssense->output.send_vibration && 604 pssense->state.timestamp_ns >= pssense->output.vibration_resend_timestamp_ns) { 605 pssense_send_output_report_locked(pssense); 606 } 607 os_mutex_unlock(&pssense->lock); 608 } 609 } 610 611 return NULL; 612} 613 614static void 615pssense_device_destroy(struct xrt_device *xdev) 616{ 617 struct pssense_device *pssense = (struct pssense_device *)xdev; 618 619 // Destroy the thread object. 620 os_thread_helper_destroy(&pssense->controller_thread); 621 622 // Now that the thread is not running we can destroy the lock. 623 os_mutex_destroy(&pssense->lock); 624 625 m_imu_3dof_close(&pssense->fusion); 626 627 // Remove the variable tracking. 628 u_var_remove_root(pssense); 629 630 if (pssense->hid != NULL) { 631 os_hid_destroy(pssense->hid); 632 pssense->hid = NULL; 633 } 634 635 free(pssense); 636} 637 638static xrt_result_t 639pssense_device_update_inputs(struct xrt_device *xdev) 640{ 641 struct pssense_device *pssense = (struct pssense_device *)xdev; 642 643 // Lock the data. 644 os_mutex_lock(&pssense->lock); 645 646 for (uint32_t i = 0; i < (uint32_t)sizeof(enum pssense_input_index); i++) { 647 pssense->base.inputs[i].timestamp = (int64_t)pssense->state.timestamp_ns; 648 } 649 pssense->base.inputs[PSSENSE_INDEX_PS_CLICK].value.boolean = pssense->state.ps_click; 650 pssense->base.inputs[PSSENSE_INDEX_SHARE_CLICK].value.boolean = pssense->state.share_click; 651 pssense->base.inputs[PSSENSE_INDEX_OPTIONS_CLICK].value.boolean = pssense->state.options_click; 652 pssense->base.inputs[PSSENSE_INDEX_SQUARE_CLICK].value.boolean = pssense->state.square_click; 653 pssense->base.inputs[PSSENSE_INDEX_SQUARE_TOUCH].value.boolean = pssense->state.square_touch; 654 pssense->base.inputs[PSSENSE_INDEX_TRIANGLE_CLICK].value.boolean = pssense->state.triangle_click; 655 pssense->base.inputs[PSSENSE_INDEX_TRIANGLE_TOUCH].value.boolean = pssense->state.triangle_touch; 656 pssense->base.inputs[PSSENSE_INDEX_CROSS_CLICK].value.boolean = pssense->state.cross_click; 657 pssense->base.inputs[PSSENSE_INDEX_CROSS_TOUCH].value.boolean = pssense->state.cross_touch; 658 pssense->base.inputs[PSSENSE_INDEX_CIRCLE_CLICK].value.boolean = pssense->state.circle_click; 659 pssense->base.inputs[PSSENSE_INDEX_CIRCLE_TOUCH].value.boolean = pssense->state.circle_touch; 660 pssense->base.inputs[PSSENSE_INDEX_SQUEEZE_CLICK].value.boolean = pssense->state.squeeze_click; 661 pssense->base.inputs[PSSENSE_INDEX_SQUEEZE_TOUCH].value.boolean = pssense->state.squeeze_touch; 662 pssense->base.inputs[PSSENSE_INDEX_SQUEEZE_PROXIMITY_FLOAT].value.vec1.x = pssense->state.squeeze_proximity; 663 pssense->base.inputs[PSSENSE_INDEX_TRIGGER_CLICK].value.boolean = pssense->state.trigger_click; 664 pssense->base.inputs[PSSENSE_INDEX_TRIGGER_TOUCH].value.boolean = pssense->state.trigger_touch; 665 pssense->base.inputs[PSSENSE_INDEX_TRIGGER_VALUE].value.vec1.x = pssense->state.trigger_value; 666 pssense->base.inputs[PSSENSE_INDEX_TRIGGER_PROXIMITY_FLOAT].value.vec1.x = pssense->state.trigger_proximity; 667 pssense->base.inputs[PSSENSE_INDEX_THUMBSTICK].value.vec2 = pssense->state.thumbstick; 668 pssense->base.inputs[PSSENSE_INDEX_THUMBSTICK_CLICK].value.boolean = pssense->state.thumbstick_click; 669 pssense->base.inputs[PSSENSE_INDEX_THUMBSTICK_TOUCH].value.boolean = pssense->state.thumbstick_touch; 670 671 // Done now. 672 os_mutex_unlock(&pssense->lock); 673 674 return XRT_SUCCESS; 675} 676 677static xrt_result_t 678pssense_set_output(struct xrt_device *xdev, enum xrt_output_name name, const struct xrt_output_value *value) 679{ 680 struct pssense_device *pssense = (struct pssense_device *)xdev; 681 682 bool send_vibration = false; 683 uint8_t vibration_amplitude; 684 uint8_t vibration_mode; 685 bool send_trigger_feedback = false; 686 uint8_t trigger_feedback_mode; 687 if (name == XRT_OUTPUT_NAME_PSSENSE_VIBRATION) { 688 send_vibration = true; 689 vibration_amplitude = (uint8_t)(value->vibration.amplitude * 255.0f); 690 vibration_mode = VIBRATE_MODE_CLASSIC_RUMBLE; 691 if (value->vibration.frequency != XRT_FREQUENCY_UNSPECIFIED) { 692 if (value->vibration.frequency <= 70) { 693 vibration_mode = VIBRATE_MODE_LOW_60HZ; 694 } else if (value->vibration.frequency >= 110) { 695 vibration_mode = VIBRATE_MODE_HIGH_120HZ; 696 } 697 } 698 } else if (name == XRT_OUTPUT_NAME_PSSENSE_TRIGGER_FEEDBACK) { 699 for (uint64_t i = 0; i < value->force_feedback.force_feedback_location_count; i++) { 700 if (value->force_feedback.force_feedback[i].location == 701 XRT_FORCE_FEEDBACK_LOCATION_LEFT_INDEX) { 702 send_trigger_feedback = true; 703 if (value->force_feedback.force_feedback[i].value > 0) { 704 trigger_feedback_mode = TRIGGER_FEEDBACK_MODE_CONSTANT; 705 } else { 706 trigger_feedback_mode = TRIGGER_FEEDBACK_MODE_NONE; 707 } 708 } 709 } 710 } else { 711 U_LOG_XDEV_UNSUPPORTED_OUTPUT(&pssense->base, pssense->log_level, name); 712 return XRT_ERROR_OUTPUT_UNSUPPORTED; 713 } 714 715 os_mutex_lock(&pssense->lock); 716 if (send_vibration && (vibration_amplitude != pssense->output.vibration_amplitude || 717 vibration_mode != pssense->output.vibration_mode)) { 718 pssense->output.send_vibration = true; 719 pssense->output.vibration_amplitude = vibration_amplitude; 720 pssense->output.vibration_mode = vibration_mode; 721 pssense->output.vibration_end_timestamp_ns = os_monotonic_get_ns() + value->vibration.duration_ns; 722 } 723 if (send_trigger_feedback && trigger_feedback_mode != pssense->output.trigger_feedback_mode) { 724 pssense->output.send_trigger_feedback = true; 725 pssense->output.trigger_feedback_mode = trigger_feedback_mode; 726 } 727 if (pssense->output.send_vibration || pssense->output.send_trigger_feedback) { 728 pssense_send_output_report_locked(pssense); 729 } 730 os_mutex_unlock(&pssense->lock); 731 732 return XRT_SUCCESS; 733} 734 735static void 736pssense_get_fusion_pose(struct pssense_device *pssense, 737 enum xrt_input_name name, 738 int64_t at_timestamp_ns, 739 struct xrt_space_relation *out_relation) 740{ 741 out_relation->pose = pssense->pose; 742 out_relation->linear_velocity.x = 0.0f; 743 out_relation->linear_velocity.y = 0.0f; 744 out_relation->linear_velocity.z = 0.0f; 745 746 /*! 747 * @todo This is hack, fusion reports angvel relative to the device but 748 * it needs to be in relation to the base space. Rotating it with the 749 * device orientation is enough to get it into the right space, angular 750 * velocity is a derivative so needs a special rotation. 751 */ 752 math_quat_rotate_derivative(&pssense->pose.orientation, &pssense->fusion.last.gyro, 753 &out_relation->angular_velocity); 754 755 out_relation->relation_flags = (enum xrt_space_relation_flags)( 756 XRT_SPACE_RELATION_ORIENTATION_VALID_BIT | XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT | 757 XRT_SPACE_RELATION_ANGULAR_VELOCITY_VALID_BIT | XRT_SPACE_RELATION_LINEAR_VELOCITY_VALID_BIT); 758} 759 760static xrt_result_t 761pssense_get_tracked_pose(struct xrt_device *xdev, 762 enum xrt_input_name name, 763 int64_t at_timestamp_ns, 764 struct xrt_space_relation *out_relation) 765{ 766 struct pssense_device *pssense = (struct pssense_device *)xdev; 767 768 if (name != XRT_INPUT_PSSENSE_AIM_POSE && name != XRT_INPUT_PSSENSE_GRIP_POSE) { 769 U_LOG_XDEV_UNSUPPORTED_INPUT(&pssense->base, pssense->log_level, name); 770 return XRT_ERROR_INPUT_UNSUPPORTED; 771 } 772 773 struct xrt_relation_chain xrc = {0}; 774 struct xrt_pose pose_correction = {0}; 775 776 // Rotate the grip/aim pose up by 60 degrees around the X axis 777 struct xrt_vec3 axis = {1.0, 0, 0}; 778 math_quat_from_angle_vector(DEG_TO_RAD(60), &axis, &pose_correction.orientation); 779 m_relation_chain_push_pose(&xrc, &pose_correction); 780 781 struct xrt_space_relation *rel = m_relation_chain_reserve(&xrc); 782 783 os_mutex_lock(&pssense->lock); 784 pssense_get_fusion_pose(pssense, name, at_timestamp_ns, rel); 785 os_mutex_unlock(&pssense->lock); 786 787 m_relation_chain_resolve(&xrc, out_relation); 788 789 return XRT_SUCCESS; 790} 791 792static xrt_result_t 793pssense_get_battery_status(struct xrt_device *xdev, bool *out_present, bool *out_charging, float *out_charge) 794{ 795 struct pssense_device *pssense = (struct pssense_device *)xdev; 796 if (!pssense->state.battery_state_valid) { 797 *out_present = false; 798 return XRT_SUCCESS; 799 } 800 801 *out_present = true; 802 *out_charging = pssense->state.battery_charging; 803 *out_charge = pssense->state.battery_charge_percent; 804 return XRT_SUCCESS; 805} 806 807/** 808 * Retrieving the calibration data report will switch the Sense controller from compat mode into full mode. 809 */ 810bool 811pssense_get_calibration_data(struct pssense_device *pssense) 812{ 813 int ret; 814 uint8_t buffer[sizeof(struct pssense_feature_report)]; 815 uint8_t data[CALIBRATION_DATA_LENGTH] = {0}; 816 bool invalid_crc; 817 do { 818 invalid_crc = false; 819 for (int i = 0; i < 2; i++) { 820 ret = os_hid_get_feature(pssense->hid, CALIBRATION_DATA_FEATURE_REPORT_ID, buffer, 821 sizeof(buffer)); 822 if (ret < 0) { 823 PSSENSE_ERROR(pssense, "Failed to retrieve calibration report: %d", ret); 824 return false; 825 } 826 if (ret != sizeof(buffer)) { 827 PSSENSE_ERROR(pssense, "Invalid byte count transferred, expected %zu got %d", 828 sizeof(buffer), ret); 829 return false; 830 } 831 struct pssense_feature_report *report = (struct pssense_feature_report *)buffer; 832 if (report->part_id == CALIBRATION_DATA_PART_ID_1) { 833 memcpy(data, report->data, sizeof(report->data)); 834 } else if (report->part_id == CALIBRATION_DATA_PART_ID_2) { 835 memcpy(data + sizeof(report->data), report->data, sizeof(report->data)); 836 } else { 837 PSSENSE_ERROR(pssense, "Unknown calibration data part ID %u", report->part_id); 838 return false; 839 } 840 841 uint32_t crc = crc32_le(0, &FEATURE_REPORT_CRC32_SEED, 1); 842 crc = crc32_le(crc, (uint8_t *)&buffer, sizeof(buffer) - 4); 843 uint32_t expected_crc = pssense_i32_le_to_u32(&report->crc); 844 if (crc != expected_crc) { 845 PSSENSE_WARN(pssense, "Invalid feature report CRC. Expected 0x%08X, actual 0x%08X", 846 expected_crc, crc); 847 invalid_crc = true; 848 } 849 } 850 } while (invalid_crc); 851 852 // TODO: Parse calibration data into prefiler 853 854 return true; 855} 856 857#define SET_INPUT(NAME) (pssense->base.inputs[PSSENSE_INDEX_##NAME].name = XRT_INPUT_PSSENSE_##NAME) 858 859int 860pssense_found(struct xrt_prober *xp, 861 struct xrt_prober_device **devices, 862 size_t device_count, 863 size_t index, 864 cJSON *attached_data, 865 struct xrt_device **out_xdevs) 866{ 867 struct os_hid_device *hid = NULL; 868 int ret; 869 870 ret = xrt_prober_open_hid_interface(xp, devices[index], 0, &hid); 871 if (ret != 0) { 872 return -1; 873 } 874 875 unsigned char product_name[128]; 876 ret = xrt_prober_get_string_descriptor( // 877 xp, // 878 devices[index], // 879 XRT_PROBER_STRING_PRODUCT, // 880 product_name, // 881 sizeof(product_name)); // 882 if (ret <= 0) { 883 U_LOG_E("Failed to get product name from Bluetooth device!"); 884 return -1; 885 } 886 887 enum u_device_alloc_flags flags = U_DEVICE_ALLOC_TRACKING_NONE; 888 struct pssense_device *pssense = U_DEVICE_ALLOCATE(struct pssense_device, flags, 23, 2); 889 PSSENSE_DEBUG(pssense, "PlayStation Sense controller found"); 890 891 pssense->base.name = XRT_DEVICE_PSSENSE; 892 snprintf(pssense->base.str, XRT_DEVICE_NAME_LEN, "%s", product_name); 893 pssense->base.update_inputs = pssense_device_update_inputs; 894 pssense->base.set_output = pssense_set_output; 895 pssense->base.get_tracked_pose = pssense_get_tracked_pose; 896 pssense->base.get_battery_status = pssense_get_battery_status; 897 pssense->base.destroy = pssense_device_destroy; 898 pssense->base.supported.orientation_tracking = true; 899 pssense->base.supported.battery_status = true; 900 901 pssense->base.binding_profiles = binding_profiles_pssense; 902 pssense->base.binding_profile_count = ARRAY_SIZE(binding_profiles_pssense); 903 904 m_imu_3dof_init(&pssense->fusion, M_IMU_3DOF_USE_GRAVITY_DUR_20MS); 905 906 pssense->log_level = debug_get_log_option_pssense_log(); 907 pssense->hid = hid; 908 909 if (devices[index]->product_id == PSSENSE_PID_LEFT) { 910 pssense->base.device_type = XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER; 911 pssense->hand = PSSENSE_HAND_LEFT; 912 } else if (devices[index]->product_id == PSSENSE_PID_RIGHT) { 913 pssense->base.device_type = XRT_DEVICE_TYPE_RIGHT_HAND_CONTROLLER; 914 pssense->hand = PSSENSE_HAND_RIGHT; 915 } else { 916 PSSENSE_ERROR(pssense, "Unable to determine controller type"); 917 pssense_device_destroy(&pssense->base); 918 return -1; 919 } 920 921 SET_INPUT(PS_CLICK); 922 SET_INPUT(SHARE_CLICK); 923 SET_INPUT(OPTIONS_CLICK); 924 SET_INPUT(SQUARE_CLICK); 925 SET_INPUT(SQUARE_TOUCH); 926 SET_INPUT(TRIANGLE_CLICK); 927 SET_INPUT(TRIANGLE_TOUCH); 928 SET_INPUT(CROSS_CLICK); 929 SET_INPUT(CROSS_TOUCH); 930 SET_INPUT(CIRCLE_CLICK); 931 SET_INPUT(CIRCLE_TOUCH); 932 SET_INPUT(SQUEEZE_CLICK); 933 SET_INPUT(SQUEEZE_TOUCH); 934 SET_INPUT(SQUEEZE_PROXIMITY_FLOAT); 935 SET_INPUT(TRIGGER_CLICK); 936 SET_INPUT(TRIGGER_TOUCH); 937 SET_INPUT(TRIGGER_VALUE); 938 SET_INPUT(TRIGGER_PROXIMITY_FLOAT); 939 SET_INPUT(THUMBSTICK); 940 SET_INPUT(THUMBSTICK_CLICK); 941 SET_INPUT(THUMBSTICK_TOUCH); 942 SET_INPUT(GRIP_POSE); 943 SET_INPUT(AIM_POSE); 944 945 pssense->base.outputs[0].name = XRT_OUTPUT_NAME_PSSENSE_VIBRATION; 946 pssense->base.outputs[1].name = XRT_OUTPUT_NAME_PSSENSE_TRIGGER_FEEDBACK; 947 948 ret = os_mutex_init(&pssense->lock); 949 if (ret != 0) { 950 PSSENSE_ERROR(pssense, "Failed to init mutex!"); 951 pssense_device_destroy(&pssense->base); 952 return -1; 953 } 954 955 ret = os_thread_helper_init(&pssense->controller_thread); 956 if (ret != 0) { 957 PSSENSE_ERROR(pssense, "Failed to init threading!"); 958 pssense_device_destroy(&pssense->base); 959 return -1; 960 } 961 962 ret = os_thread_helper_start(&pssense->controller_thread, pssense_run_thread, pssense); 963 if (ret != 0) { 964 PSSENSE_ERROR(pssense, "Failed to start thread!"); 965 pssense_device_destroy(&pssense->base); 966 return -1; 967 } 968 969 if (!pssense_get_calibration_data(pssense)) { 970 PSSENSE_ERROR(pssense, "Failed to retrieve calibration data"); 971 pssense_device_destroy(&pssense->base); 972 return -1; 973 } 974 975 u_var_add_root(pssense, pssense->base.str, false); 976 u_var_add_log_level(pssense, &pssense->log_level, "Log level"); 977 978 u_var_add_gui_header(pssense, &pssense->gui.button_states, "Button States"); 979 u_var_add_bool(pssense, &pssense->state.ps_click, "PS Click"); 980 if (pssense->hand == PSSENSE_HAND_LEFT) { 981 u_var_add_bool(pssense, &pssense->state.share_click, "Share Click"); 982 u_var_add_bool(pssense, &pssense->state.square_click, "Square Click"); 983 u_var_add_bool(pssense, &pssense->state.square_touch, "Square Touch"); 984 u_var_add_bool(pssense, &pssense->state.triangle_click, "Triangle Click"); 985 u_var_add_bool(pssense, &pssense->state.triangle_touch, "Triangle Touch"); 986 } else if (pssense->hand == PSSENSE_HAND_RIGHT) { 987 u_var_add_bool(pssense, &pssense->state.options_click, "Options Click"); 988 u_var_add_bool(pssense, &pssense->state.cross_click, "Cross Click"); 989 u_var_add_bool(pssense, &pssense->state.cross_touch, "Cross Touch"); 990 u_var_add_bool(pssense, &pssense->state.circle_click, "Circle Click"); 991 u_var_add_bool(pssense, &pssense->state.circle_touch, "Circle Touch"); 992 } 993 u_var_add_bool(pssense, &pssense->state.squeeze_click, "Squeeze Click"); 994 u_var_add_bool(pssense, &pssense->state.squeeze_touch, "Squeeze Touch"); 995 u_var_add_ro_f32(pssense, &pssense->state.squeeze_proximity, "Squeeze Proximity"); 996 u_var_add_bool(pssense, &pssense->state.trigger_click, "Trigger Click"); 997 u_var_add_bool(pssense, &pssense->state.trigger_touch, "Trigger Touch"); 998 u_var_add_ro_f32(pssense, &pssense->state.trigger_value, "Trigger"); 999 u_var_add_ro_f32(pssense, &pssense->state.trigger_proximity, "Trigger Proximity"); 1000 u_var_add_ro_f32(pssense, &pssense->state.thumbstick.x, "Thumbstick X"); 1001 u_var_add_ro_f32(pssense, &pssense->state.thumbstick.y, "Thumbstick Y"); 1002 u_var_add_bool(pssense, &pssense->state.thumbstick_click, "Thumbstick Click"); 1003 u_var_add_bool(pssense, &pssense->state.thumbstick_touch, "Thumbstick Touch"); 1004 1005 u_var_add_gui_header(pssense, &pssense->gui.tracking, "Tracking"); 1006 u_var_add_ro_vec3_i32(pssense, &pssense->state.gyro_raw, "Raw Gyro"); 1007 u_var_add_ro_vec3_i32(pssense, &pssense->state.accel_raw, "Raw Accel"); 1008 u_var_add_pose(pssense, &pssense->pose, "Pose"); 1009 1010 out_xdevs[0] = &pssense->base; 1011 return 1; 1012} 1013 1014/*! 1015 * @} 1016 */