Commit 42cddb25 authored by Jakob Bornecrantz's avatar Jakob Bornecrantz Committed by Ryan Pavlik

d/psvr: Add a experimental PSVR driver

Hidden behind a env variable.
parent 74165d7e
......@@ -54,7 +54,7 @@ set(BUILD_WITH_LIBUSB TRUE)
cmake_dependent_option(BUILD_WITH_OPENCV "Enable OpenCV backend" ON "OpenCV_FOUND" OFF)
cmake_dependent_option(BUILD_WITH_LIBUVC "Enable libuvc video driver" ON "LIBUVC_FOUND" OFF)
cmake_dependent_option(BUILD_WITH_FFMPEG "Enable ffmpeg testing video driver" ON "FFMPEG_FOUND" OFF)
cmake_dependent_option(BUILD_WITH_HIDAPI "Enable HIDAPI-based driver(s) (OSVR HDK)" ON "HIDAPI_FOUND" OFF)
cmake_dependent_option(BUILD_WITH_HIDAPI "Enable HIDAPI-based driver(s) (OSVR HDK, PSVR)" ON "HIDAPI_FOUND" OFF)
cmake_dependent_option(BUILD_WITH_OPENHMD "Enable OpenHMD driver" ON "OPENHMD_FOUND" OFF)
......@@ -105,6 +105,8 @@ if(BUILD_WITH_HIDAPI)
# Drivers enabled with hidapi.
add_definitions(-DXRT_BUILD_HDK)
set(BUILD_DRIVER_HDK TRUE)
add_definitions(-DXRT_BUILD_PSVR)
set(BUILD_DRIVER_PSVR TRUE)
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic -Wall -Wextra -Wno-unused-parameter")
......
......@@ -40,3 +40,21 @@ if(BUILD_DRIVER_OHMD)
PRIVATE ${OPENHMD_INCLUDE_DIRS}
)
endif()
if(BUILD_DRIVER_PSVR)
set(PSVR_SOURCE_FILES
psvr/psvr_device.c
psvr/psvr_device.h
psvr/psvr_interface.h
psvr/psvr_packet.c
psvr/psvr_prober.c
)
# Use OBJECT to not create a archive, since it just gets in the way.
add_library(drv_psvr OBJECT ${PSVR_SOURCE_FILES})
set_property(TARGET drv_psvr PROPERTY POSITION_INDEPENDENT_CODE ON)
target_include_directories(drv_psvr SYSTEM
PRIVATE ${HIDAPI_INCLUDE_DIRS}
)
endif()
This diff is collapsed.
// Copyright 2016, Joey Ferwerda.
// Copyright 2019, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief PSVR device header, imported from OpenHMD.
* @author Joey Ferwerda <joeyferweda@gmail.com>
* @author Philipp Zabel <philipp.zabel@gmail.com>
* @author Jakob Bornecrantz <jakob@collabora.com>
* @ingroup drv_psvr
*/
#pragma once
#include "xrt/xrt_device.h"
#include <hidapi.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
*
* Defines
*
*/
#define PSVR_VID 0x054c
#define PSVR_PID 0x09af
#define PSVR_HANDLE_IFACE 4
#define PSVR_CONTROL_IFACE 5
enum psvr_status_bits
{
// clang-format off
PSVR_STATUS_BIT_POWER = (1 << 0),
PSVR_STATUS_BIT_HMD_WORN = (1 << 1),
PSVR_STATUS_BIT_CINEMATIC_MODE = (1 << 2),
PSVR_STATUS_BIT_UNKNOWN_BIT_3 = (1 << 3),
PSVR_STATUS_BIT_HEADPHONES_CONNECTED = (1 << 4),
PSVR_STATUS_BIT_MUTE_ENABLED = (1 << 5),
PSVR_STATUS_BIT_UNKNOWN_BIT_6 = (1 << 6),
PSVR_STATUS_BIT_UNKNOWN_BIT_7 = (1 << 7),
// clang-format on
};
#define PSVR_STATUS_VR_MODE_OFF 0
#define PSVR_STATUS_VR_MODE_ON 1
#define PSVR_TICK_PERIOD (1.0f / 1000000.0f) // 1 MHz ticks
#define PSVR_PKG_STATUS 0xF0
#define PSVR_PKG_0xA0 0xA0
/*
*
* Structs
*
*/
/*!
* A single gyro, accel and tick sample.
*
* @ingroup drv_psvr
*/
struct psvr_sensor_sample
{
int16_t accel[3];
int16_t gyro[3];
uint32_t tick;
};
/*!
* A parsed sensor packet from the headset.
*
* @ingroup drv_psvr
*/
struct psvr_sensor_packet
{
uint8_t buttons;
uint8_t state;
uint16_t volume;
struct psvr_sensor_sample samples[2];
uint16_t button_raw;
uint16_t proximity;
uint8_t seq;
};
/*!
* A parsed status packet from the headset.
*
* @ingroup drv_psvr
*/
struct psvr_status_packet
{
uint8_t status;
uint8_t volume;
uint8_t display_time;
uint8_t vr_mode;
};
/*
*
* Functions
*
*/
struct xrt_device *
psvr_device_create(struct hid_device_info *hmd_handle_info,
struct hid_device_info *hmd_control_info,
bool print_spew,
bool print_debug);
bool
psvr_parse_sensor_packet(struct psvr_sensor_packet *packet,
const uint8_t *buffer,
int size);
bool
psvr_parse_status_packet(struct psvr_status_packet *packet,
const uint8_t *buffer,
int size);
/*
*
* Printing functions.
*
*/
#define PSVR_SPEW(p, ...) \
do { \
if (p->print_spew) { \
fprintf(stderr, "%s - ", __func__); \
fprintf(stderr, __VA_ARGS__); \
fprintf(stderr, "\n"); \
} \
} while (false)
#define PSVR_DEBUG(p, ...) \
do { \
if (p->print_debug) { \
fprintf(stderr, "%s - ", __func__); \
fprintf(stderr, __VA_ARGS__); \
fprintf(stderr, "\n"); \
} \
} while (false)
#define PSVR_ERROR(p, ...) \
do { \
fprintf(stderr, "%s - ", __func__); \
fprintf(stderr, __VA_ARGS__); \
fprintf(stderr, "\n"); \
} while (false)
#ifdef __cplusplus
}
#endif
// Copyright 2019, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Interface to @ref drv_psvr.
* @author Jakob Bornecrantz <jakob@collabora.com>
* @ingroup drv_psvr
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/*!
* @defgroup drv_psvr PSVR driver
* @ingroup drv
*
* @brief Driver for the Sony PSVR hmd.
*/
/*!
* Create a proble for PSVR devices.
*
* @ingroup drv_psvr
*/
struct xrt_auto_prober*
psvr_create_auto_prober();
/*!
* @dir drivers/psvr
*
* @brief @ref drv_psvr files.
*/
#ifdef __cplusplus
}
#endif
// Copyright 2016, Joey Ferwerda.
// Copyright 2019, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief PSVR packet parsing implementation, imported from OpenHMD.
* @author Joey Ferwerda <joeyferweda@gmail.com>
* @author Philipp Zabel <philipp.zabel@gmail.com>
* @author Jakob Bornecrantz <jakob@collabora.com>
* @ingroup drv_psvr
*/
#include "xrt/xrt_compiler.h"
#include "util/u_misc.h"
#include "util/u_debug.h"
#include "psvr_device.h"
#include <stdio.h>
/*
*
* Helper functions
*
*/
inline static void
skip(const uint8_t **buffer, size_t num)
{
*buffer += num;
}
inline static void
read_u8(const uint8_t **buffer, uint8_t *out_value)
{
*out_value = **buffer;
*buffer += 1;
}
inline static void
read_u16(const uint8_t **buffer, uint16_t *out_value)
{
*out_value = (*(*buffer + 0) << 0) | // Byte 0
(*(*buffer + 1) << 8); // Byte 1
*buffer += 2;
}
inline static void
read_i16(const uint8_t **buffer, int16_t *out_value)
{
*out_value = (*(*buffer + 0) << 0) | // Byte 0
(*(*buffer + 1) << 8); // Byte 1
*buffer += 2;
}
inline static void
read_u32(const uint8_t **buffer, uint32_t *out_value)
{
*out_value = (*(*buffer + 0) << 0) | // Byte 0
(*(*buffer + 1) << 8) | // Byte 1
(*(*buffer + 2) << 16) | // Byte 2
(*(*buffer + 3) << 24); // Byte 3
*buffer += 4;
}
static void
read_sensor(const uint8_t **buffer, struct psvr_sensor_sample *sample)
{
// Tick.
read_u32(buffer, &sample->tick);
// Rotation.
read_i16(buffer, &sample->gyro[0]);
read_i16(buffer, &sample->gyro[1]);
read_i16(buffer, &sample->gyro[2]);
// Acceleration.
read_i16(buffer, &sample->accel[0]);
read_i16(buffer, &sample->accel[1]);
read_i16(buffer, &sample->accel[2]);
}
/*
*
* Exported functions
*
*/
bool
psvr_parse_sensor_packet(struct psvr_sensor_packet *packet,
const uint8_t *buffer,
int size)
{
const uint8_t *start = buffer;
if (size != 64) {
return false;
}
// Buttons.
read_u8(&buffer, &packet->buttons);
// Unknown, skip 1 bytes.
skip(&buffer, 1);
// Volume.
read_u16(&buffer, &packet->volume);
// Unknown, skip 1 bytes.
skip(&buffer, 1);
// State.
read_u8(&buffer, &packet->state);
// Unknown, skip 10 bytes.
skip(&buffer, 10);
// Two sensors.
read_sensor(&buffer, &packet->samples[0]);
read_sensor(&buffer, &packet->samples[1]);
// unknown, skip 5 bytes.
skip(&buffer, 5);
// Raw button data.
read_u16(&buffer, &packet->button_raw);
// Proximity, ~150 (nothing) to 1023 (headset is on).
read_u16(&buffer, &packet->proximity);
// Unknown, skip 6 bytes.
skip(&buffer, 6);
// Finally a sequence number.
read_u8(&buffer, &packet->seq);
return (size_t)buffer - (size_t)start == 64;
}
bool
psvr_parse_status_packet(struct psvr_status_packet *packet,
const uint8_t *buffer,
int size)
{
const uint8_t *start = buffer;
if (size != 20) {
return false;
}
// Header.
skip(&buffer, 4);
// Status bits.
read_u8(&buffer, &packet->status);
// Volume.
read_u8(&buffer, &packet->volume);
// Unknown, 0x00, 0x00.
skip(&buffer, 2);
// Display time in minutes.
read_u8(&buffer, &packet->display_time);
// Unknown, 0xFF, 0x00.
skip(&buffer, 2);
// VR Mode Active.
read_u8(&buffer, &packet->vr_mode);
// Unknown, 0x12, 0x00...
skip(&buffer, 8);
return (size_t)buffer - (size_t)start == 20;
}
// Copyright 2019, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief PSVR prober code.
* @author Jakob Bornecrantz <jakob@collabora.com>
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
* @ingroup drv_psvr
*/
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include <hidapi.h>
#include "xrt/xrt_prober.h"
#include "util/u_misc.h"
#include "util/u_debug.h"
#include "psvr_interface.h"
#include "psvr_device.h"
/*
*
* Defines & structs.
*
*/
// Should the experimental PSVR driver be enabled.
DEBUG_GET_ONCE_BOOL_OPTION(psvr_enable, "PSVR_ENABLE", false)
DEBUG_GET_ONCE_BOOL_OPTION(psvr_spew, "PSVR_PRINT_SPEW", false)
DEBUG_GET_ONCE_BOOL_OPTION(psvr_debug, "PSVR_PRINT_DEBUG", false)
/*!
* PSVR prober struct.
*
* @ingroup drv_psvr
*/
struct psvr_prober
{
struct xrt_auto_prober base;
bool print_spew;
bool print_debug;
bool enabled;
};
/*
*
* Static functions.
*
*/
static inline struct psvr_prober *
psvr_prober(struct xrt_auto_prober *p)
{
return (struct psvr_prober *)p;
}
static void
psvr_prober_destroy(struct xrt_auto_prober *p)
{
struct psvr_prober *ppsvr = psvr_prober(p);
free(ppsvr);
}
static struct xrt_device *
psvr_prober_autoprobe(struct xrt_auto_prober *p)
{
struct psvr_prober *ppsvr = psvr_prober(p);
struct hid_device_info *info_control = NULL;
struct hid_device_info *info_handle = NULL;
struct hid_device_info *cur_dev = NULL;
struct hid_device_info *devs = NULL;
struct xrt_device *dev = NULL;
devs = hid_enumerate(PSVR_VID, PSVR_PID);
cur_dev = devs;
for (; cur_dev != NULL; cur_dev = cur_dev->next) {
switch (cur_dev->interface_number) {
case PSVR_HANDLE_IFACE: info_handle = cur_dev; break;
case PSVR_CONTROL_IFACE: info_control = cur_dev; break;
default: break;
}
}
if (info_control != NULL && info_handle != NULL) {
if (ppsvr->enabled) {
dev = psvr_device_create(info_handle, info_control,
ppsvr->print_spew,
ppsvr->print_debug);
} else {
PSVR_DEBUG(ppsvr,
"Found a PSVR hmd but driver is disabled");
}
}
hid_free_enumeration(devs);
return dev;
}
/*
*
* Exported functions.
*
*/
struct xrt_auto_prober *
psvr_create_auto_prober()
{
struct psvr_prober *ppsvr = U_TYPED_CALLOC(struct psvr_prober);
ppsvr->base.destroy = psvr_prober_destroy;
ppsvr->base.lelo_dallas_autoprobe = psvr_prober_autoprobe;
ppsvr->enabled = debug_get_bool_option_psvr_enable();
ppsvr->print_spew = debug_get_bool_option_psvr_spew();
ppsvr->print_debug = debug_get_bool_option_psvr_debug();
return &ppsvr->base;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment