d/xreal_air: Rename nreal air to xreal air in driver, support xreal air 2 and xreal air 2 pro

This commit is contained in:
TheJackiMonster 2024-02-29 18:45:17 +01:00 committed by Tobias Frisch
parent ffb71af26f
commit 9f4f2541a6
11 changed files with 500 additions and 439 deletions

View file

@ -310,7 +310,6 @@ option_with_deps(XRT_BUILD_DRIVER_HDK "Enable HDK driver" DEPENDS XRT_HAVE_INTER
option_with_deps(XRT_BUILD_DRIVER_HYDRA "Enable Hydra driver" DEPENDS XRT_HAVE_INTERNAL_HID)
option_with_deps(XRT_BUILD_DRIVER_ILLIXR "Enable ILLIXR driver" DEPENDS ILLIXR_PATH)
option(XRT_BUILD_DRIVER_NS "Enable North Star driver" ON)
option_with_deps(XRT_BUILD_DRIVER_NA "Enable Nreal Air HMD driver" DEPENDS XRT_HAVE_HIDAPI)
option_with_deps(XRT_BUILD_DRIVER_OHMD "Enable OpenHMD driver" DEPENDS OPENHMD_FOUND)
option_with_deps(XRT_BUILD_DRIVER_OPENGLOVES "Enable OpenGloves driver" DEPENDS XRT_HAVE_LIBUDEV XRT_HAVE_BLUETOOTH)
option_with_deps(XRT_BUILD_DRIVER_PSMV "Enable Playstation Move driver" DEPENDS XRT_HAVE_INTERNAL_HID "NOT MSVC")
@ -328,6 +327,7 @@ option_with_deps(XRT_BUILD_DRIVER_ULV5 "Enable Ultraleap v5 driver" DEPENDS Leap
option_with_deps(XRT_BUILD_DRIVER_VF "Build video frame driver (for video file support, uses gstreamer)" DEPENDS XRT_HAVE_GST)
option_with_deps(XRT_BUILD_DRIVER_VIVE "Enable driver for HTC Vive, Vive Pro, Valve Index, and their controllers" DEPENDS ZLIB_FOUND XRT_HAVE_LINUX XRT_MODULE_AUX_VIVE)
option_with_deps(XRT_BUILD_DRIVER_WMR "Enable Windows Mixed Reality driver" DEPENDS "NOT WIN32")
option_with_deps(XRT_BUILD_DRIVER_XREAL_AIR "Enable Xreal Air HMD driver" DEPENDS XRT_HAVE_HIDAPI)
option_with_deps(XRT_BUILD_DRIVER_SIMULAVR "Enable simula driver" DEPENDS XRT_HAVE_REALSENSE)
option(XRT_BUILD_DRIVER_SIMULATED "Enable simulated driver" ON)
@ -663,7 +663,6 @@ message(STATUS "# DRIVER_HANDTRACKING: ${XRT_BUILD_DRIVER_HANDTRACKIN
message(STATUS "# DRIVER_HDK: ${XRT_BUILD_DRIVER_HDK}")
message(STATUS "# DRIVER_HYDRA: ${XRT_BUILD_DRIVER_HYDRA}")
message(STATUS "# DRIVER_ILLIXR: ${XRT_BUILD_DRIVER_ILLIXR}")
message(STATUS "# DRIVER_NA: ${XRT_BUILD_DRIVER_NA}")
message(STATUS "# DRIVER_NS: ${XRT_BUILD_DRIVER_NS}")
message(STATUS "# DRIVER_OHMD: ${XRT_BUILD_DRIVER_OHMD}")
message(STATUS "# DRIVER_OPENGLOVES: ${XRT_BUILD_DRIVER_OPENGLOVES}")
@ -684,6 +683,7 @@ message(STATUS "# DRIVER_ULV5: ${XRT_BUILD_DRIVER_ULV5}")
message(STATUS "# DRIVER_VF: ${XRT_BUILD_DRIVER_VF}")
message(STATUS "# DRIVER_VIVE: ${XRT_BUILD_DRIVER_VIVE}")
message(STATUS "# DRIVER_WMR: ${XRT_BUILD_DRIVER_WMR}")
message(STATUS "# DRIVER_XREAL_AIR: ${XRT_BUILD_DRIVER_XREAL_AIR}")
message(STATUS "# DRIVER_STEAMVR_LIGHTHOUSE: ${XRT_BUILD_DRIVER_STEAMVR_LIGHTHOUSE}")
message(STATUS "#####----- Config -----#####")
# cmake-format: on

View file

@ -110,16 +110,16 @@ if(XRT_BUILD_DRIVER_NS)
list(APPEND ENABLED_HEADSET_DRIVERS ns)
endif()
if(XRT_BUILD_DRIVER_NA)
if(XRT_BUILD_DRIVER_XREAL_AIR)
add_library(
drv_na STATIC nreal_air/na_hmd.h nreal_air/na_hmd.c nreal_air/na_interface.h
nreal_air/na_packet.c
drv_xreal_air STATIC xreal_air/xreal_air_hmd.h xreal_air/xreal_air_hmd.c
xreal_air/xreal_air_interface.h xreal_air/xreal_air_packet.c
)
target_link_libraries(
drv_na PRIVATE xrt-interfaces HIDAPI::hidapi aux_util xrt-external-cjson
drv_xreal_air PRIVATE xrt-interfaces HIDAPI::hidapi aux_util xrt-external-cjson
)
target_include_directories(drv_na PRIVATE ${HIDAPI_INCLUDE_DIRS})
list(APPEND ENABLED_HEADSET_DRIVERS na)
target_include_directories(drv_xreal_air PRIVATE ${HIDAPI_INCLUDE_DIRS})
list(APPEND ENABLED_HEADSET_DRIVERS xreal_air)
endif()
if(XRT_BUILD_DRIVER_ULV2)

View file

@ -1,166 +0,0 @@
// Copyright 2023, Tobias Frisch
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Nreal Air packet parsing implementation.
* @author Tobias Frisch <thejackimonster@gmail.com>
* @ingroup drv_na
*/
#pragma once
#include "xrt/xrt_device.h"
#include "xrt/xrt_prober.h"
#include "os/os_hid.h"
#include "util/u_logging.h"
#ifdef __cplusplus
extern "C" {
#endif
#define NA_HANDLE_IFACE 3
#define NA_CONTROL_IFACE 4
#define NA_MSG_R_BRIGHTNESS 0x03
#define NA_MSG_W_BRIGHTNESS 0x04
#define NA_MSG_R_DISP_MODE 0x07
#define NA_MSG_W_DISP_MODE 0x08
#define NA_MSG_P_START_HEARTBEAT 0x6c02
#define NA_MSG_P_BUTTON_PRESSED 0x6C05
#define NA_MSG_P_END_HEARTBEAT 0x6c12
#define NA_MSG_P_ASYNC_TEXT_LOG 0x6c09
#define NA_BUTTON_PHYS_DISPLAY_TOGGLE 0x1
#define NA_BUTTON_PHYS_BRIGHTNESS_UP 0x2
#define NA_BUTTON_PHYS_BRIGHTNESS_DOWN 0x3
#define NA_BUTTON_VIRT_DISPLAY_TOGGLE 0x1
#define NA_BUTTON_VIRT_MENU_TOGGLE 0x3
#define NA_BUTTON_VIRT_BRIGHTNESS_UP 0x6
#define NA_BUTTON_VIRT_BRIGHTNESS_DOWN 0x7
#define NA_BUTTON_VIRT_MODE_UP 0x8
#define NA_BUTTON_VIRT_MODE_DOWN 0x9
#define NA_BRIGHTNESS_MIN 0
#define NA_BRIGHTNESS_MAX 7
#define NA_DISPLAY_MODE_2D 0x1
#define NA_DISPLAY_MODE_3D 0x3
#define NA_TICKS_PER_SECOND (1000.0) // 1 KHz ticks
#define NA_NS_PER_TICK (1000000) // Each tick is a millisecond
#define NA_MSG_GET_CAL_DATA_LENGTH 0x14
#define NA_MSG_CAL_DATA_GET_NEXT_SEGMENT 0x15
#define NA_MSG_ALLOCATE_CAL_DATA_BUFFER 0x16
#define NA_MSG_WRITE_CAL_DATA_SEGMENT 0x17
#define NA_MSG_FREE_CAL_BUFFER 0x18
#define NA_MSG_START_IMU_DATA 0x19
#define NA_MSG_GET_STATIC_ID 0x1A
#define NA_MSG_UNKNOWN 0x1D
struct na_parsed_calibration
{
struct xrt_vec3 accel_bias;
struct xrt_quat accel_q_gyro;
struct xrt_vec3 gyro_bias;
struct xrt_quat gyro_q_mag;
struct xrt_vec3 mag_bias;
struct xrt_vec3 scale_accel;
struct xrt_vec3 scale_gyro;
struct xrt_vec3 scale_mag;
float imu_noises[4];
};
/*!
* A parsed single gyroscope, accelerometer and
* magnetometer sample with their corresponding
* factors for conversion from raw data.
*
* @ingroup drv_na
*/
struct na_parsed_sample
{
struct xrt_vec3_i32 accel;
struct xrt_vec3_i32 gyro;
struct xrt_vec3_i32 mag;
int16_t accel_multiplier;
int16_t gyro_multiplier;
int16_t mag_multiplier;
int32_t accel_divisor;
int32_t gyro_divisor;
int32_t mag_divisor;
};
/*!
* Over the wire sensor packet from the glasses.
*
* @ingroup drv_na
*/
struct na_parsed_sensor
{
int16_t temperature;
uint64_t timestamp;
struct na_parsed_sample sample;
};
/*!
* Over the wire sensor control data packet from the glasses.
*
* @ingroup drv_na
*/
struct na_parsed_sensor_control_data
{
uint16_t length;
uint8_t msgid;
uint8_t data[56];
};
/*!
* A control packet from the glasses in wire format.
*
* @ingroup drv_na
*/
struct na_parsed_control
{
uint16_t length;
uint64_t timestamp;
uint16_t action;
uint8_t data[42];
};
/*!
* Create Nreal Air glasses.
*
* @ingroup drv_na
*/
struct xrt_device *
na_hmd_create_device(struct os_hid_device *sensor_device,
struct os_hid_device *control_device,
enum u_logging_level log_level);
bool
na_parse_calibration_buffer(struct na_parsed_calibration *calibration, const char *buffer, size_t size);
bool
na_parse_sensor_packet(struct na_parsed_sensor *sensor, const uint8_t *buffer, int size);
bool
na_parse_sensor_control_data_packet(struct na_parsed_sensor_control_data *data, const uint8_t *buffer, int size);
bool
na_parse_control_packet(struct na_parsed_control *control, const uint8_t *buffer, int size);
#ifdef __cplusplus
}
#endif

View file

@ -1,53 +0,0 @@
// Copyright 2023, Tobias Frisch
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Nreal Air packet parsing implementation.
* @author Tobias Frisch <thejackimonster@gmail.com>
* @ingroup drv_na
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/*!
* @defgroup drv_na Nreal Air driver
* @ingroup drv
*
* @brief Driver for the Nreal Air HMD.
*/
/*!
* Vendor id for Nreal Air.
*
* @ingroup drv_na
*/
#define NA_VID 0x3318
/*!
* Product id for Nreal Air.
*
* @ingroup drv_na
*/
#define NA_PID 0x0424
/*!
* Builder setup for Nreal Air glasses.
*
* @ingroup drv_na
*/
struct xrt_builder *
nreal_air_builder_create(void);
/*!
* @dir drivers/nreal_air
*
* @brief nreal_air files.
*/
#ifdef __cplusplus
}
#endif

View file

@ -1,10 +1,10 @@
// Copyright 2023, Tobias Frisch
// Copyright 2023-2024, Tobias Frisch
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Nreal Air packet parsing implementation.
* @brief Xreal Air packet parsing implementation.
* @author Tobias Frisch <thejackimonster@gmail.com>
* @ingroup drv_na
* @ingroup drv_xreal_air
*/
#include "xrt/xrt_compiler.h"
@ -21,7 +21,7 @@
#include "util/u_trace_marker.h"
#include "util/u_var.h"
#include "na_hmd.h"
#include "xreal_air_hmd.h"
#include "math/m_mathinclude.h"
#include "math/m_relation_history.h"
@ -31,8 +31,8 @@
#include <stdint.h>
#include <stdbool.h>
#define NA_DEBUG(hmd, ...) U_LOG_XDEV_IFL_D(&hmd->base, hmd->log_level, __VA_ARGS__)
#define NA_ERROR(hmd, ...) U_LOG_XDEV_IFL_E(&hmd->base, hmd->log_level, __VA_ARGS__)
#define XREAL_AIR_DEBUG(hmd, ...) U_LOG_XDEV_IFL_D(&hmd->base, hmd->log_level, __VA_ARGS__)
#define XREAL_AIR_ERROR(hmd, ...) U_LOG_XDEV_IFL_E(&hmd->base, hmd->log_level, __VA_ARGS__)
#define SENSOR_BUFFER_SIZE 64
#define CONTROL_BUFFER_SIZE 64
@ -41,12 +41,12 @@
#define CONTROL_HEAD 0xFD
/*!
* Private struct for the nreal_air device.
* Private struct for the xreal_air device.
*
* @ingroup drv_na
* @ingroup drv_xreal_air
* @implements xrt_device
*/
struct na_hmd
struct xreal_air_hmd
{
struct xrt_device base;
@ -63,7 +63,7 @@ struct na_hmd
//! Only touched from the sensor thread.
timepoint_ns last_sensor_time;
struct na_parsed_sensor last;
struct xreal_air_parsed_sensor last;
struct
{
@ -97,7 +97,7 @@ struct na_hmd
char *calibration_buffer;
bool calibration_valid;
struct na_parsed_calibration calibration;
struct xreal_air_parsed_calibration calibration;
struct
{
@ -115,10 +115,10 @@ struct na_hmd
*
*/
static inline struct na_hmd *
na_hmd(struct xrt_device *dev)
static inline struct xreal_air_hmd *
xreal_air_hmd(struct xrt_device *dev)
{
return (struct na_hmd *)dev;
return (struct xreal_air_hmd *)dev;
}
const uint32_t crc32_table[256] = {
@ -167,7 +167,8 @@ crc32_checksum(const uint8_t *buf, uint32_t len)
static uint8_t
scale_brightness(uint8_t brightness)
{
float relative = ((float)brightness - NA_BRIGHTNESS_MIN) / (NA_BRIGHTNESS_MAX - NA_BRIGHTNESS_MIN);
float relative =
((float)brightness - XREAL_AIR_BRIGHTNESS_MIN) / (XREAL_AIR_BRIGHTNESS_MAX - XREAL_AIR_BRIGHTNESS_MIN);
relative = CLAMP(relative, 0.0f, 1.0f);
return (uint8_t)(relative * 100.0f);
}
@ -177,7 +178,7 @@ unscale_brightness(uint8_t scaled_brightness)
{
float relative = ((float)scaled_brightness) / 100.0f;
relative = CLAMP(relative, 0.0f, 1.0f);
return (uint8_t)(relative * (NA_BRIGHTNESS_MAX - NA_BRIGHTNESS_MIN)) + NA_BRIGHTNESS_MIN;
return (uint8_t)(relative * (XREAL_AIR_BRIGHTNESS_MAX - XREAL_AIR_BRIGHTNESS_MIN)) + XREAL_AIR_BRIGHTNESS_MIN;
}
/*
@ -187,7 +188,7 @@ unscale_brightness(uint8_t scaled_brightness)
*/
static bool
send_payload_to_sensor(struct na_hmd *hmd, uint8_t msgid, const uint8_t *data, uint8_t len)
send_payload_to_sensor(struct xreal_air_hmd *hmd, uint8_t msgid, const uint8_t *data, uint8_t len)
{
uint8_t payload[SENSOR_BUFFER_SIZE];
@ -229,8 +230,8 @@ post_biased_coordinate_system(const struct xrt_vec3 *in, struct xrt_vec3 *out)
}
static void
read_sample_and_apply_calibration(struct na_hmd *hmd,
struct na_parsed_sample *sample,
read_sample_and_apply_calibration(struct xreal_air_hmd *hmd,
struct xreal_air_parsed_sample *sample,
struct xrt_vec3 *out_accel,
struct xrt_vec3 *out_gyro,
struct xrt_vec3 *out_mag)
@ -302,14 +303,14 @@ read_sample_and_apply_calibration(struct na_hmd *hmd,
}
static void
update_fusion_locked(struct na_hmd *hmd, struct na_parsed_sample *sample, uint64_t timestamp_ns)
update_fusion_locked(struct xreal_air_hmd *hmd, struct xreal_air_parsed_sample *sample, uint64_t timestamp_ns)
{
read_sample_and_apply_calibration(hmd, sample, &hmd->read.accel, &hmd->read.gyro, &hmd->read.mag);
m_imu_3dof_update(&hmd->fusion, timestamp_ns, &hmd->read.accel, &hmd->read.gyro);
}
static void
update_fusion(struct na_hmd *hmd, struct na_parsed_sample *sample, uint64_t timestamp_ns)
update_fusion(struct xreal_air_hmd *hmd, struct xreal_air_parsed_sample *sample, uint64_t timestamp_ns)
{
struct xrt_space_relation rel;
U_ZERO(&rel); // Clear out the relation.
@ -339,7 +340,7 @@ calc_delta_and_handle_rollover(uint32_t next, uint32_t last)
}
static timepoint_ns
ensure_forward_progress_timestamps(struct na_hmd *hmd, timepoint_ns timestamp_ns)
ensure_forward_progress_timestamps(struct xreal_air_hmd *hmd, timepoint_ns timestamp_ns)
{
timepoint_ns t = timestamp_ns;
@ -356,48 +357,49 @@ ensure_forward_progress_timestamps(struct na_hmd *hmd, timepoint_ns timestamp_ns
}
static void
request_sensor_control_get_cal_data_length(struct na_hmd *hmd)
request_sensor_control_get_cal_data_length(struct xreal_air_hmd *hmd)
{
// Request calibration data length.
if (!send_payload_to_sensor(hmd, NA_MSG_GET_CAL_DATA_LENGTH, NULL, 0)) {
NA_ERROR(hmd, "Failed to send payload for receiving calibration data length!");
if (!send_payload_to_sensor(hmd, XREAL_AIR_MSG_GET_CAL_DATA_LENGTH, NULL, 0)) {
XREAL_AIR_ERROR(hmd, "Failed to send payload for receiving calibration data length!");
}
}
static void
request_sensor_control_cal_data_get_next_segment(struct na_hmd *hmd)
request_sensor_control_cal_data_get_next_segment(struct xreal_air_hmd *hmd)
{
// Request next segment of calibration data.
if (!send_payload_to_sensor(hmd, NA_MSG_CAL_DATA_GET_NEXT_SEGMENT, NULL, 0)) {
NA_ERROR(hmd, "Failed to send payload for receiving next calibration data segment! %d / %d",
hmd->calibration_buffer_pos, hmd->calibration_buffer_len);
if (!send_payload_to_sensor(hmd, XREAL_AIR_MSG_CAL_DATA_GET_NEXT_SEGMENT, NULL, 0)) {
XREAL_AIR_ERROR(hmd, "Failed to send payload for receiving next calibration data segment! %d / %d",
hmd->calibration_buffer_pos, hmd->calibration_buffer_len);
}
}
static void
request_sensor_control_get_static_id(struct na_hmd *hmd)
request_sensor_control_get_static_id(struct xreal_air_hmd *hmd)
{
// Request the static id.
if (!send_payload_to_sensor(hmd, NA_MSG_GET_STATIC_ID, NULL, 0)) {
NA_ERROR(hmd, "Failed to send payload for receiving static id!");
if (!send_payload_to_sensor(hmd, XREAL_AIR_MSG_GET_STATIC_ID, NULL, 0)) {
XREAL_AIR_ERROR(hmd, "Failed to send payload for receiving static id!");
}
}
static void
request_sensor_control_start_imu_data(struct na_hmd *hmd, uint8_t imu_stream_state)
request_sensor_control_start_imu_data(struct xreal_air_hmd *hmd, uint8_t imu_stream_state)
{
// Request to change the imu stream state.
if (!send_payload_to_sensor(hmd, NA_MSG_START_IMU_DATA, &imu_stream_state, 1)) {
NA_ERROR(hmd, "Failed to send payload for changing the imu stream state! %d", imu_stream_state);
if (!send_payload_to_sensor(hmd, XREAL_AIR_MSG_START_IMU_DATA, &imu_stream_state, 1)) {
XREAL_AIR_ERROR(hmd, "Failed to send payload for changing the imu stream state! %d", imu_stream_state);
}
}
static void
handle_sensor_control_get_cal_data_length(struct na_hmd *hmd, const struct na_parsed_sensor_control_data *data)
handle_sensor_control_get_cal_data_length(struct xreal_air_hmd *hmd,
const struct xreal_air_parsed_sensor_control_data *data)
{
// Read calibration data length.
const uint32_t calibration_data_length =
@ -421,7 +423,8 @@ handle_sensor_control_get_cal_data_length(struct na_hmd *hmd, const struct na_pa
}
static void
handle_sensor_control_cal_data_get_next_segment(struct na_hmd *hmd, const struct na_parsed_sensor_control_data *data)
handle_sensor_control_cal_data_get_next_segment(struct xreal_air_hmd *hmd,
const struct xreal_air_parsed_sensor_control_data *data)
{
if (hmd->calibration_buffer_len == 0) {
request_sensor_control_get_cal_data_length(hmd);
@ -429,8 +432,8 @@ handle_sensor_control_cal_data_get_next_segment(struct na_hmd *hmd, const struct
}
if (hmd->calibration_buffer_len <= hmd->calibration_buffer_pos) {
NA_ERROR(hmd, "Failed to receive next calibration data segment! %d / %d", hmd->calibration_buffer_pos,
hmd->calibration_buffer_len);
XREAL_AIR_ERROR(hmd, "Failed to receive next calibration data segment! %d / %d",
hmd->calibration_buffer_pos, hmd->calibration_buffer_len);
return;
}
@ -448,9 +451,9 @@ handle_sensor_control_cal_data_get_next_segment(struct na_hmd *hmd, const struct
if (hmd->calibration_buffer_pos == hmd->calibration_buffer_len) {
// Parse calibration data from raw json.
if (!na_parse_calibration_buffer(&hmd->calibration, hmd->calibration_buffer,
hmd->calibration_buffer_len)) {
NA_ERROR(hmd, "Failed parse calibration data!");
if (!xreal_air_parse_calibration_buffer(&hmd->calibration, hmd->calibration_buffer,
hmd->calibration_buffer_len)) {
XREAL_AIR_ERROR(hmd, "Failed parse calibration data!");
} else {
hmd->calibration_valid = true;
@ -469,7 +472,7 @@ handle_sensor_control_cal_data_get_next_segment(struct na_hmd *hmd, const struct
}
static void
handle_sensor_control_start_imu_data(struct na_hmd *hmd, const struct na_parsed_sensor_control_data *data)
handle_sensor_control_start_imu_data(struct xreal_air_hmd *hmd, const struct xreal_air_parsed_sensor_control_data *data)
{
// Read the imu stream state.
const uint8_t imu_stream_state = data->data[0];
@ -484,7 +487,7 @@ handle_sensor_control_start_imu_data(struct na_hmd *hmd, const struct na_parsed_
}
static void
handle_sensor_control_get_static_id(struct na_hmd *hmd, const struct na_parsed_sensor_control_data *data)
handle_sensor_control_get_static_id(struct xreal_air_hmd *hmd, const struct xreal_air_parsed_sensor_control_data *data)
{
// Read the static id.
const uint32_t static_id =
@ -498,30 +501,32 @@ handle_sensor_control_get_static_id(struct na_hmd *hmd, const struct na_parsed_s
}
static void
handle_sensor_control_data_msg(struct na_hmd *hmd, unsigned char *buffer, int size)
handle_sensor_control_data_msg(struct xreal_air_hmd *hmd, unsigned char *buffer, int size)
{
struct na_parsed_sensor_control_data data;
struct xreal_air_parsed_sensor_control_data data;
if (!na_parse_sensor_control_data_packet(&data, buffer, size)) {
NA_ERROR(hmd, "Could not decode sensor control data packet");
if (!xreal_air_parse_sensor_control_data_packet(&data, buffer, size)) {
XREAL_AIR_ERROR(hmd, "Could not decode sensor control data packet");
}
hmd->imu_stream_state = 0xAA;
switch (data.msgid) {
case NA_MSG_GET_CAL_DATA_LENGTH: handle_sensor_control_get_cal_data_length(hmd, &data); break;
case NA_MSG_CAL_DATA_GET_NEXT_SEGMENT: handle_sensor_control_cal_data_get_next_segment(hmd, &data); break;
case NA_MSG_ALLOCATE_CAL_DATA_BUFFER: break;
case NA_MSG_WRITE_CAL_DATA_SEGMENT: break;
case NA_MSG_FREE_CAL_BUFFER: break;
case NA_MSG_START_IMU_DATA: handle_sensor_control_start_imu_data(hmd, &data); break;
case NA_MSG_GET_STATIC_ID: handle_sensor_control_get_static_id(hmd, &data); break;
default: NA_ERROR(hmd, "Got unknown sensor control data msgid, 0x%02x", data.msgid); break;
case XREAL_AIR_MSG_GET_CAL_DATA_LENGTH: handle_sensor_control_get_cal_data_length(hmd, &data); break;
case XREAL_AIR_MSG_CAL_DATA_GET_NEXT_SEGMENT:
handle_sensor_control_cal_data_get_next_segment(hmd, &data);
break;
case XREAL_AIR_MSG_ALLOCATE_CAL_DATA_BUFFER: break;
case XREAL_AIR_MSG_WRITE_CAL_DATA_SEGMENT: break;
case XREAL_AIR_MSG_FREE_CAL_BUFFER: break;
case XREAL_AIR_MSG_START_IMU_DATA: handle_sensor_control_start_imu_data(hmd, &data); break;
case XREAL_AIR_MSG_GET_STATIC_ID: handle_sensor_control_get_static_id(hmd, &data); break;
default: XREAL_AIR_ERROR(hmd, "Got unknown sensor control data msgid, 0x%02x", data.msgid); break;
}
}
static void
handle_sensor_msg(struct na_hmd *hmd, unsigned char *buffer, int size)
handle_sensor_msg(struct xreal_air_hmd *hmd, unsigned char *buffer, int size)
{
if (buffer[0] == 0xAA) {
handle_sensor_control_data_msg(hmd, buffer, size);
@ -531,8 +536,8 @@ handle_sensor_msg(struct na_hmd *hmd, unsigned char *buffer, int size)
timepoint_ns now_ns = (timepoint_ns)os_monotonic_get_ns();
uint64_t last_timestamp = hmd->last.timestamp;
if (!na_parse_sensor_packet(&hmd->last, buffer, size)) {
NA_ERROR(hmd, "Could not decode sensor packet");
if (!xreal_air_parse_sensor_packet(&hmd->last, buffer, size)) {
XREAL_AIR_ERROR(hmd, "Could not decode sensor packet");
} else {
hmd->imu_stream_state = 0x1;
}
@ -541,7 +546,7 @@ handle_sensor_msg(struct na_hmd *hmd, unsigned char *buffer, int size)
request_sensor_control_start_imu_data(hmd, 0xAA);
}
struct na_parsed_sensor *s = &hmd->last;
struct xreal_air_parsed_sensor *s = &hmd->last;
// According to the ICM-42688-P datasheet: (offset: 25 °C, sensitivity: 132.48 LSB/°C)
hmd->read.temperature = ((float)s->temperature) / 132.48f + 25.0f;
@ -553,7 +558,7 @@ handle_sensor_msg(struct na_hmd *hmd, unsigned char *buffer, int size)
// If this is larger then one second something bad is going on.
if (hmd->fusion.state != M_IMU_3DOF_STATE_START &&
inter_sample_duration_ns >= (time_duration_ns)U_TIME_1S_IN_NS) {
NA_ERROR(hmd, "Drop packet (sensor too slow): %lu", inter_sample_duration_ns);
XREAL_AIR_ERROR(hmd, "Drop packet (sensor too slow): %lu", inter_sample_duration_ns);
return;
}
@ -568,7 +573,7 @@ handle_sensor_msg(struct na_hmd *hmd, unsigned char *buffer, int size)
}
static void
sensor_clear_queue(struct na_hmd *hmd)
sensor_clear_queue(struct xreal_air_hmd *hmd)
{
uint8_t buffer[SENSOR_BUFFER_SIZE];
@ -578,7 +583,7 @@ sensor_clear_queue(struct na_hmd *hmd)
}
static int
sensor_read_one_packet(struct na_hmd *hmd)
sensor_read_one_packet(struct xreal_air_hmd *hmd)
{
uint8_t buffer[SENSOR_BUFFER_SIZE];
@ -592,14 +597,14 @@ sensor_read_one_packet(struct na_hmd *hmd)
}
static int
read_one_control_packet(struct na_hmd *hmd);
read_one_control_packet(struct xreal_air_hmd *hmd);
static void *
read_thread(void *ptr)
{
U_TRACE_SET_THREAD_NAME("Nreal Air");
U_TRACE_SET_THREAD_NAME("Xreal Air");
struct na_hmd *hmd = (struct na_hmd *)ptr;
struct xreal_air_hmd *hmd = (struct xreal_air_hmd *)ptr;
int ret = 0;
os_thread_helper_lock(&hmd->oth);
@ -637,7 +642,7 @@ read_thread(void *ptr)
*
*/
static bool
send_payload_to_control(struct na_hmd *hmd, uint16_t msgid, const uint8_t *data, uint8_t len)
send_payload_to_control(struct xreal_air_hmd *hmd, uint16_t msgid, const uint8_t *data, uint8_t len)
{
uint8_t payload[CONTROL_BUFFER_SIZE];
@ -670,7 +675,7 @@ send_payload_to_control(struct na_hmd *hmd, uint16_t msgid, const uint8_t *data,
}
static void
handle_control_brightness(struct na_hmd *hmd, const struct na_parsed_control *control)
handle_control_brightness(struct xreal_air_hmd *hmd, const struct xreal_air_parsed_control *control)
{
// Check status
if (control->data[0] != 0) {
@ -685,7 +690,7 @@ handle_control_brightness(struct na_hmd *hmd, const struct na_parsed_control *co
}
static void
handle_control_display_mode(struct na_hmd *hmd, const struct na_parsed_control *control)
handle_control_display_mode(struct xreal_air_hmd *hmd, const struct xreal_air_parsed_control *control)
{
// Check status
if (control->data[0] != 0) {
@ -700,13 +705,13 @@ handle_control_display_mode(struct na_hmd *hmd, const struct na_parsed_control *
}
static void
handle_control_heartbeat_start(struct na_hmd *hmd, const struct na_parsed_control *control)
handle_control_heartbeat_start(struct xreal_air_hmd *hmd, const struct xreal_air_parsed_control *control)
{
// TODO
}
static void
handle_control_button(struct na_hmd *hmd, const struct na_parsed_control *control)
handle_control_button(struct xreal_air_hmd *hmd, const struct xreal_air_parsed_control *control)
{
// Physical button
const uint8_t phys_button = control->data[0];
@ -718,82 +723,82 @@ handle_control_button(struct na_hmd *hmd, const struct na_parsed_control *contro
const uint8_t value = control->data[8];
switch (virt_button) {
case NA_BUTTON_VIRT_DISPLAY_TOGGLE: {
case XREAL_AIR_BUTTON_VIRT_DISPLAY_TOGGLE: {
hmd->display_on = value;
break;
}
case NA_BUTTON_VIRT_MENU_TOGGLE: break;
case NA_BUTTON_VIRT_BRIGHTNESS_UP:
case NA_BUTTON_VIRT_BRIGHTNESS_DOWN: {
case XREAL_AIR_BUTTON_VIRT_MENU_TOGGLE: break;
case XREAL_AIR_BUTTON_VIRT_BRIGHTNESS_UP:
case XREAL_AIR_BUTTON_VIRT_BRIGHTNESS_DOWN: {
const uint8_t brightness = scale_brightness(value);
hmd->state.brightness = brightness;
hmd->wants.brightness = brightness;
break;
}
case NA_BUTTON_VIRT_MODE_UP: {
case XREAL_AIR_BUTTON_VIRT_MODE_UP: {
const uint8_t display_mode = hmd->state.display_mode;
if (display_mode == NA_DISPLAY_MODE_2D) {
hmd->wants.display_mode = NA_DISPLAY_MODE_3D;
if (display_mode == XREAL_AIR_DISPLAY_MODE_2D) {
hmd->wants.display_mode = XREAL_AIR_DISPLAY_MODE_3D;
}
break;
}
case NA_BUTTON_VIRT_MODE_DOWN: {
case XREAL_AIR_BUTTON_VIRT_MODE_DOWN: {
const uint8_t display_mode = hmd->state.display_mode;
if (display_mode == NA_DISPLAY_MODE_3D) {
hmd->wants.display_mode = NA_DISPLAY_MODE_2D;
if (display_mode == XREAL_AIR_DISPLAY_MODE_3D) {
hmd->wants.display_mode = XREAL_AIR_DISPLAY_MODE_2D;
}
break;
}
default: {
NA_ERROR(hmd, "Got unknown button pressed, 0x%02x (0x%02x)", virt_button, phys_button);
XREAL_AIR_ERROR(hmd, "Got unknown button pressed, 0x%02x (0x%02x)", virt_button, phys_button);
break;
}
}
}
static void
handle_control_async_text(struct na_hmd *hmd, const struct na_parsed_control *control)
handle_control_async_text(struct xreal_air_hmd *hmd, const struct xreal_air_parsed_control *control)
{
// Event only appears if the display is active!
hmd->display_on = true;
NA_DEBUG(hmd, "Control message: %s", (const char *)control->data);
XREAL_AIR_DEBUG(hmd, "Control message: %s", (const char *)control->data);
}
static void
handle_control_heartbeat_end(struct na_hmd *hmd, const struct na_parsed_control *control)
handle_control_heartbeat_end(struct xreal_air_hmd *hmd, const struct xreal_air_parsed_control *control)
{
// TODO
}
static void
handle_control_action_locked(struct na_hmd *hmd, const struct na_parsed_control *control)
handle_control_action_locked(struct xreal_air_hmd *hmd, const struct xreal_air_parsed_control *control)
{
switch (control->action) {
case NA_MSG_R_BRIGHTNESS: handle_control_brightness(hmd, control); break;
case NA_MSG_W_BRIGHTNESS: break;
case NA_MSG_R_DISP_MODE: handle_control_display_mode(hmd, control); break;
case NA_MSG_W_DISP_MODE: break;
case NA_MSG_P_START_HEARTBEAT: handle_control_heartbeat_start(hmd, control); break;
case NA_MSG_P_BUTTON_PRESSED: handle_control_button(hmd, control); break;
case NA_MSG_P_ASYNC_TEXT_LOG: handle_control_async_text(hmd, control); break;
case NA_MSG_P_END_HEARTBEAT: handle_control_heartbeat_end(hmd, control); break;
default: NA_ERROR(hmd, "Got unknown control action, 0x%02x", control->action); break;
case XREAL_AIR_MSG_R_BRIGHTNESS: handle_control_brightness(hmd, control); break;
case XREAL_AIR_MSG_W_BRIGHTNESS: break;
case XREAL_AIR_MSG_R_DISP_MODE: handle_control_display_mode(hmd, control); break;
case XREAL_AIR_MSG_W_DISP_MODE: break;
case XREAL_AIR_MSG_P_START_HEARTBEAT: handle_control_heartbeat_start(hmd, control); break;
case XREAL_AIR_MSG_P_BUTTON_PRESSED: handle_control_button(hmd, control); break;
case XREAL_AIR_MSG_P_ASYNC_TEXT_LOG: handle_control_async_text(hmd, control); break;
case XREAL_AIR_MSG_P_END_HEARTBEAT: handle_control_heartbeat_end(hmd, control); break;
default: XREAL_AIR_ERROR(hmd, "Got unknown control action, 0x%02x", control->action); break;
}
}
static void
handle_control_msg(struct na_hmd *hmd, unsigned char *buffer, int size)
handle_control_msg(struct xreal_air_hmd *hmd, unsigned char *buffer, int size)
{
struct na_parsed_control control;
struct xreal_air_parsed_control control;
if (!na_parse_control_packet(&control, buffer, size)) {
NA_ERROR(hmd, "Could not decode control packet");
if (!xreal_air_parse_control_packet(&control, buffer, size)) {
XREAL_AIR_ERROR(hmd, "Could not decode control packet");
}
os_mutex_lock(&hmd->device_mutex);
@ -802,7 +807,7 @@ handle_control_msg(struct na_hmd *hmd, unsigned char *buffer, int size)
}
static void
control_clear_queue(struct na_hmd *hmd)
control_clear_queue(struct xreal_air_hmd *hmd)
{
uint8_t buffer[CONTROL_BUFFER_SIZE];
@ -812,7 +817,7 @@ control_clear_queue(struct na_hmd *hmd)
}
static int
read_one_control_packet(struct na_hmd *hmd)
read_one_control_packet(struct xreal_air_hmd *hmd)
{
static uint8_t buffer[CONTROL_BUFFER_SIZE];
int size = 0;
@ -830,7 +835,7 @@ read_one_control_packet(struct na_hmd *hmd)
}
static bool
wait_for_brightness(struct na_hmd *hmd)
wait_for_brightness(struct xreal_air_hmd *hmd)
{
for (int i = 0; i < 5000; i++) {
read_one_control_packet(hmd);
@ -846,13 +851,13 @@ wait_for_brightness(struct na_hmd *hmd)
}
static bool
wait_for_display_mode(struct na_hmd *hmd)
wait_for_display_mode(struct xreal_air_hmd *hmd)
{
for (int i = 0; i < 5000; i++) {
read_one_control_packet(hmd);
if ((hmd->state.display_mode == NA_DISPLAY_MODE_2D) ||
(hmd->state.display_mode == NA_DISPLAY_MODE_3D)) {
if ((hmd->state.display_mode == XREAL_AIR_DISPLAY_MODE_2D) ||
(hmd->state.display_mode == XREAL_AIR_DISPLAY_MODE_3D)) {
return true;
}
@ -863,15 +868,15 @@ wait_for_display_mode(struct na_hmd *hmd)
}
static bool
control_brightness(struct na_hmd *hmd)
control_brightness(struct xreal_air_hmd *hmd)
{
if (!send_payload_to_control(hmd, NA_MSG_R_BRIGHTNESS, NULL, 0)) {
NA_ERROR(hmd, "Failed to send payload for initial brightness value!");
if (!send_payload_to_control(hmd, XREAL_AIR_MSG_R_BRIGHTNESS, NULL, 0)) {
XREAL_AIR_ERROR(hmd, "Failed to send payload for initial brightness value!");
return false;
}
if (!wait_for_brightness(hmd)) {
NA_ERROR(hmd, "Failed to wait for valid brightness value!");
XREAL_AIR_ERROR(hmd, "Failed to wait for valid brightness value!");
return false;
}
@ -879,15 +884,15 @@ control_brightness(struct na_hmd *hmd)
}
static bool
control_display_mode(struct na_hmd *hmd)
control_display_mode(struct xreal_air_hmd *hmd)
{
if (!send_payload_to_control(hmd, NA_MSG_R_DISP_MODE, NULL, 0)) {
NA_ERROR(hmd, "Failed to send payload for initial display mode!");
if (!send_payload_to_control(hmd, XREAL_AIR_MSG_R_DISP_MODE, NULL, 0)) {
XREAL_AIR_ERROR(hmd, "Failed to send payload for initial display mode!");
return false;
}
if (!wait_for_display_mode(hmd)) {
NA_ERROR(hmd, "Failed to wait for valid display mode!");
XREAL_AIR_ERROR(hmd, "Failed to wait for valid display mode!");
return false;
}
@ -895,9 +900,9 @@ control_display_mode(struct na_hmd *hmd)
}
static bool
switch_display_mode(struct na_hmd *hmd, uint8_t display_mode)
switch_display_mode(struct xreal_air_hmd *hmd, uint8_t display_mode)
{
if ((display_mode != NA_DISPLAY_MODE_2D) && (display_mode > NA_DISPLAY_MODE_3D)) {
if ((display_mode != XREAL_AIR_DISPLAY_MODE_2D) && (display_mode > XREAL_AIR_DISPLAY_MODE_3D)) {
return false;
}
@ -912,7 +917,7 @@ switch_display_mode(struct na_hmd *hmd, uint8_t display_mode)
info.display.w_meters *= 2.0f;
info.lens_horizontal_separation_meters *= 2.0f;
if (display_mode == NA_DISPLAY_MODE_3D) {
if (display_mode == XREAL_AIR_DISPLAY_MODE_3D) {
info.display.w_pixels *= 2;
}
@ -920,11 +925,11 @@ switch_display_mode(struct na_hmd *hmd, uint8_t display_mode)
info.fov[1] = (float)(46.0 * (M_PI / 180.0));
if (!u_device_setup_split_side_by_side(&hmd->base, &info)) {
NA_ERROR(hmd, "Failed to setup basic device info");
XREAL_AIR_ERROR(hmd, "Failed to setup basic device info");
return false;
}
if (display_mode == NA_DISPLAY_MODE_2D) {
if (display_mode == XREAL_AIR_DISPLAY_MODE_2D) {
hmd->base.hmd->views[0].display.w_pixels = info.display.w_pixels;
hmd->base.hmd->views[0].viewport.w_pixels = info.display.w_pixels;
@ -945,7 +950,7 @@ switch_display_mode(struct na_hmd *hmd, uint8_t display_mode)
*/
static void
teardown(struct na_hmd *hmd)
teardown(struct xreal_air_hmd *hmd)
{
// Stop the variable tracking.
u_var_remove_root(hmd);
@ -973,7 +978,7 @@ teardown(struct na_hmd *hmd)
}
static void
adjust_brightness(struct na_hmd *hmd)
adjust_brightness(struct xreal_air_hmd *hmd)
{
if (hmd->wants.brightness > 100) {
return;
@ -990,8 +995,8 @@ adjust_brightness(struct na_hmd *hmd)
return;
}
if (!send_payload_to_control(hmd, NA_MSG_W_BRIGHTNESS, &raw_brightness, 1)) {
NA_ERROR(hmd, "Failed to send payload setting custom brightness value!");
if (!send_payload_to_control(hmd, XREAL_AIR_MSG_W_BRIGHTNESS, &raw_brightness, 1)) {
XREAL_AIR_ERROR(hmd, "Failed to send payload setting custom brightness value!");
return;
}
@ -999,9 +1004,10 @@ adjust_brightness(struct na_hmd *hmd)
}
static void
adjust_display_mode(struct na_hmd *hmd)
adjust_display_mode(struct xreal_air_hmd *hmd)
{
if ((hmd->wants.display_mode != NA_DISPLAY_MODE_2D) && (hmd->wants.display_mode != NA_DISPLAY_MODE_3D)) {
if ((hmd->wants.display_mode != XREAL_AIR_DISPLAY_MODE_2D) &&
(hmd->wants.display_mode != XREAL_AIR_DISPLAY_MODE_3D)) {
return;
}
@ -1011,8 +1017,8 @@ adjust_display_mode(struct na_hmd *hmd)
const uint8_t display_mode = hmd->wants.display_mode;
if (!send_payload_to_control(hmd, NA_MSG_W_DISP_MODE, &display_mode, 1)) {
NA_ERROR(hmd, "Failed to send payload setting custom display mode!");
if (!send_payload_to_control(hmd, XREAL_AIR_MSG_W_DISP_MODE, &display_mode, 1)) {
XREAL_AIR_ERROR(hmd, "Failed to send payload setting custom display mode!");
return;
}
@ -1026,9 +1032,9 @@ adjust_display_mode(struct na_hmd *hmd)
*/
static void
na_hmd_update_inputs(struct xrt_device *xdev)
xreal_air_hmd_update_inputs(struct xrt_device *xdev)
{
struct na_hmd *hmd = na_hmd(xdev);
struct xreal_air_hmd *hmd = xreal_air_hmd(xdev);
os_mutex_lock(&hmd->device_mutex);
@ -1042,15 +1048,15 @@ na_hmd_update_inputs(struct xrt_device *xdev)
}
static void
na_hmd_get_tracked_pose(struct xrt_device *xdev,
enum xrt_input_name name,
uint64_t at_timestamp_ns,
struct xrt_space_relation *out_relation)
xreal_air_hmd_get_tracked_pose(struct xrt_device *xdev,
enum xrt_input_name name,
uint64_t at_timestamp_ns,
struct xrt_space_relation *out_relation)
{
struct na_hmd *hmd = na_hmd(xdev);
struct xreal_air_hmd *hmd = xreal_air_hmd(xdev);
if (name != XRT_INPUT_GENERIC_HEAD_POSE) {
NA_ERROR(hmd, "unknown input name");
XREAL_AIR_ERROR(hmd, "unknown input name");
return;
}
@ -1071,16 +1077,17 @@ na_hmd_get_tracked_pose(struct xrt_device *xdev,
}
static void
na_hmd_destroy(struct xrt_device *xdev)
xreal_air_hmd_destroy(struct xrt_device *xdev)
{
struct na_hmd *hmd = na_hmd(xdev);
struct xreal_air_hmd *hmd = xreal_air_hmd(xdev);
teardown(hmd);
u_device_free(&hmd->base);
}
static bool
na_hmd_compute_distortion(struct xrt_device *xdev, uint32_t view, float u, float v, struct xrt_uv_triplet *result)
xreal_air_hmd_compute_distortion(
struct xrt_device *xdev, uint32_t view, float u, float v, struct xrt_uv_triplet *result)
{
return u_compute_distortion_none(u, v, result);
}
@ -1092,21 +1099,21 @@ na_hmd_compute_distortion(struct xrt_device *xdev, uint32_t view, float u, float
*/
struct xrt_device *
na_hmd_create_device(struct os_hid_device *sensor_device,
struct os_hid_device *control_device,
enum u_logging_level log_level)
xreal_air_hmd_create_device(struct os_hid_device *sensor_device,
struct os_hid_device *control_device,
enum u_logging_level log_level)
{
enum u_device_alloc_flags flags =
(enum u_device_alloc_flags)(U_DEVICE_ALLOC_HMD | U_DEVICE_ALLOC_TRACKING_NONE);
struct na_hmd *hmd = U_DEVICE_ALLOCATE(struct na_hmd, flags, 1, 0);
struct xreal_air_hmd *hmd = U_DEVICE_ALLOCATE(struct xreal_air_hmd, flags, 1, 0);
int ret;
hmd->log_level = log_level;
hmd->base.update_inputs = na_hmd_update_inputs;
hmd->base.get_tracked_pose = na_hmd_get_tracked_pose;
hmd->base.update_inputs = xreal_air_hmd_update_inputs;
hmd->base.get_tracked_pose = xreal_air_hmd_get_tracked_pose;
hmd->base.get_view_poses = u_device_get_view_poses;
hmd->base.compute_distortion = na_hmd_compute_distortion;
hmd->base.destroy = na_hmd_destroy;
hmd->base.compute_distortion = xreal_air_hmd_compute_distortion;
hmd->base.destroy = xreal_air_hmd_destroy;
hmd->base.name = XRT_DEVICE_GENERIC_HMD;
hmd->base.device_type = XRT_DEVICE_TYPE_HMD;
hmd->base.inputs[0].name = XRT_INPUT_GENERIC_HEAD_POSE;
@ -1140,8 +1147,8 @@ na_hmd_create_device(struct os_hid_device *sensor_device,
hmd->last.timestamp = 0xFFFFFFFF;
// Print name
snprintf(hmd->base.str, XRT_DEVICE_NAME_LEN, "Nreal Air Glasses");
snprintf(hmd->base.serial, XRT_DEVICE_NAME_LEN, "Nreal Air Glasses");
snprintf(hmd->base.str, XRT_DEVICE_NAME_LEN, "Xreal Air Glasses");
snprintf(hmd->base.serial, XRT_DEVICE_NAME_LEN, "Xreal Air Glasses");
// Do mutex and thread init before any call to teardown happens.
os_mutex_init(&hmd->device_mutex);
@ -1186,7 +1193,7 @@ na_hmd_create_device(struct os_hid_device *sensor_device,
* Setup variable.
*/
u_var_add_root(hmd, "Nreal Air Glasses", true);
u_var_add_root(hmd, "Xreal Air Glasses", true);
u_var_add_u8(hmd, &hmd->wants.brightness, "Brightness");
u_var_add_u8(hmd, &hmd->wants.display_mode, "Display mode");
u_var_add_gui_header(hmd, &hmd->gui.last_frame, "Last data");
@ -1208,15 +1215,15 @@ na_hmd_create_device(struct os_hid_device *sensor_device,
*/
if (hmd->log_level <= U_LOGGING_DEBUG) {
u_device_dump_config(&hmd->base, __func__, "Nreal Air");
u_device_dump_config(&hmd->base, __func__, "Xreal Air");
}
NA_DEBUG(hmd, "YES!");
XREAL_AIR_DEBUG(hmd, "YES!");
return &hmd->base;
cleanup:
NA_DEBUG(hmd, "NO! :(");
XREAL_AIR_DEBUG(hmd, "NO! :(");
if (hmd->calibration_buffer) {
free(hmd->calibration_buffer);

View file

@ -0,0 +1,168 @@
// Copyright 2023-2024, Tobias Frisch
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Xreal Air packet parsing implementation.
* @author Tobias Frisch <thejackimonster@gmail.com>
* @ingroup drv_xreal_air
*/
#pragma once
#include "xrt/xrt_device.h"
#include "xrt/xrt_prober.h"
#include "os/os_hid.h"
#include "util/u_logging.h"
#ifdef __cplusplus
extern "C" {
#endif
#define XREAL_AIR_HANDLE_IFACE 3
#define XREAL_AIR_CONTROL_IFACE 4
#define XREAL_AIR_MSG_R_BRIGHTNESS 0x03
#define XREAL_AIR_MSG_W_BRIGHTNESS 0x04
#define XREAL_AIR_MSG_R_DISP_MODE 0x07
#define XREAL_AIR_MSG_W_DISP_MODE 0x08
#define XREAL_AIR_MSG_P_START_HEARTBEAT 0x6c02
#define XREAL_AIR_MSG_P_BUTTON_PRESSED 0x6C05
#define XREAL_AIR_MSG_P_END_HEARTBEAT 0x6c12
#define XREAL_AIR_MSG_P_ASYNC_TEXT_LOG 0x6c09
#define XREAL_AIR_BUTTON_PHYS_DISPLAY_TOGGLE 0x1
#define XREAL_AIR_BUTTON_PHYS_BRIGHTNESS_UP 0x2
#define XREAL_AIR_BUTTON_PHYS_BRIGHTNESS_DOWN 0x3
#define XREAL_AIR_BUTTON_VIRT_DISPLAY_TOGGLE 0x1
#define XREAL_AIR_BUTTON_VIRT_MENU_TOGGLE 0x3
#define XREAL_AIR_BUTTON_VIRT_BRIGHTNESS_UP 0x6
#define XREAL_AIR_BUTTON_VIRT_BRIGHTNESS_DOWN 0x7
#define XREAL_AIR_BUTTON_VIRT_MODE_UP 0x8
#define XREAL_AIR_BUTTON_VIRT_MODE_DOWN 0x9
#define XREAL_AIR_BRIGHTNESS_MIN 0
#define XREAL_AIR_BRIGHTNESS_MAX 7
#define XREAL_AIR_DISPLAY_MODE_2D 0x1
#define XREAL_AIR_DISPLAY_MODE_3D 0x3
#define XREAL_AIR_TICKS_PER_SECOND (1000.0) // 1 KHz ticks
#define XREAL_AIR_NS_PER_TICK (1000000) // Each tick is a millisecond
#define XREAL_AIR_MSG_GET_CAL_DATA_LENGTH 0x14
#define XREAL_AIR_MSG_CAL_DATA_GET_NEXT_SEGMENT 0x15
#define XREAL_AIR_MSG_ALLOCATE_CAL_DATA_BUFFER 0x16
#define XREAL_AIR_MSG_WRITE_CAL_DATA_SEGMENT 0x17
#define XREAL_AIR_MSG_FREE_CAL_BUFFER 0x18
#define XREAL_AIR_MSG_START_IMU_DATA 0x19
#define XREAL_AIR_MSG_GET_STATIC_ID 0x1A
#define XREAL_AIR_MSG_UNKNOWN 0x1D
struct xreal_air_parsed_calibration
{
struct xrt_vec3 accel_bias;
struct xrt_quat accel_q_gyro;
struct xrt_vec3 gyro_bias;
struct xrt_quat gyro_q_mag;
struct xrt_vec3 mag_bias;
struct xrt_vec3 scale_accel;
struct xrt_vec3 scale_gyro;
struct xrt_vec3 scale_mag;
float imu_noises[4];
};
/*!
* A parsed single gyroscope, accelerometer and
* magnetometer sample with their corresponding
* factors for conversion from raw data.
*
* @ingroup drv_xreal_air
*/
struct xreal_air_parsed_sample
{
struct xrt_vec3_i32 accel;
struct xrt_vec3_i32 gyro;
struct xrt_vec3_i32 mag;
int16_t accel_multiplier;
int16_t gyro_multiplier;
int16_t mag_multiplier;
int32_t accel_divisor;
int32_t gyro_divisor;
int32_t mag_divisor;
};
/*!
* Over the wire sensor packet from the glasses.
*
* @ingroup drv_xreal_air
*/
struct xreal_air_parsed_sensor
{
int16_t temperature;
uint64_t timestamp;
struct xreal_air_parsed_sample sample;
};
/*!
* Over the wire sensor control data packet from the glasses.
*
* @ingroup drv_xreal_air
*/
struct xreal_air_parsed_sensor_control_data
{
uint16_t length;
uint8_t msgid;
uint8_t data[56];
};
/*!
* A control packet from the glasses in wire format.
*
* @ingroup drv_xreal_air
*/
struct xreal_air_parsed_control
{
uint16_t length;
uint64_t timestamp;
uint16_t action;
uint8_t data[42];
};
/*!
* Create Xreal Air glasses.
*
* @ingroup drv_xreal_air
*/
struct xrt_device *
xreal_air_hmd_create_device(struct os_hid_device *sensor_device,
struct os_hid_device *control_device,
enum u_logging_level log_level);
bool
xreal_air_parse_calibration_buffer(struct xreal_air_parsed_calibration *calibration, const char *buffer, size_t size);
bool
xreal_air_parse_sensor_packet(struct xreal_air_parsed_sensor *sensor, const uint8_t *buffer, int size);
bool
xreal_air_parse_sensor_control_data_packet(struct xreal_air_parsed_sensor_control_data *data,
const uint8_t *buffer,
int size);
bool
xreal_air_parse_control_packet(struct xreal_air_parsed_control *control, const uint8_t *buffer, int size);
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,67 @@
// Copyright 2023-2024, Tobias Frisch
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Xreal Air packet parsing implementation.
* @author Tobias Frisch <thejackimonster@gmail.com>
* @ingroup drv_xreal_air
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/*!
* @defgroup drv_xreal_air Xreal Air driver
* @ingroup drv
*
* @brief Driver for the Xreal Air HMD.
*/
/*!
* Vendor id for Xreal Air.
*
* @ingroup drv_xreal_air
*/
#define XREAL_AIR_VID 0x3318
/*!
* Product id for Xreal Air.
*
* @ingroup drv_xreal_air
*/
#define XREAL_AIR_PID 0x0424
/*!
* Product id for Xreal Air 2.
*
* @ingroup drv_xreal_air
*/
#define XREAL_AIR_2_PID 0x0428
/*!
* Product id for Xreal Air 2 Pro.
*
* @ingroup drv_xreal_air
*/
#define XREAL_AIR_2_PRO_PID 0x0432
/*!
* Builder setup for Xreal Air glasses.
*
* @ingroup drv_xreal_air
*/
struct xrt_builder *
xreal_air_builder_create(void);
/*!
* @dir drivers/xreal_air
*
* @brief xreal_air files.
*/
#ifdef __cplusplus
}
#endif

View file

@ -1,15 +1,15 @@
// Copyright 2023, Tobias Frisch
// Copyright 2023-2024, Tobias Frisch
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Nreal Air packet parsing implementation.
* @brief Xreal Air packet parsing implementation.
* @author Tobias Frisch <thejackimonster@gmail.com>
* @ingroup drv_na
* @ingroup drv_xreal_air
*/
#include "xrt/xrt_compiler.h"
#include "na_hmd.h"
#include "xreal_air_hmd.h"
#include <cjson/cJSON.h>
#include <string.h>
@ -203,7 +203,7 @@ read_json_array(cJSON *object, const char *const string, int size, float *out_ar
*/
static void
read_sample(const uint8_t **buffer, struct na_parsed_sample *sample)
read_sample(const uint8_t **buffer, struct xreal_air_parsed_sample *sample)
{
read_i16(buffer, &sample->gyro_multiplier);
read_i32(buffer, &sample->gyro_divisor);
@ -235,7 +235,7 @@ read_sample(const uint8_t **buffer, struct na_parsed_sample *sample)
*/
bool
na_parse_calibration_buffer(struct na_parsed_calibration *calibration, const char *buffer, size_t size)
xreal_air_parse_calibration_buffer(struct xreal_air_parsed_calibration *calibration, const char *buffer, size_t size)
{
cJSON *root = cJSON_ParseWithLength(buffer, size);
@ -259,7 +259,7 @@ na_parse_calibration_buffer(struct na_parsed_calibration *calibration, const cha
}
bool
na_parse_sensor_packet(struct na_parsed_sensor *sensor, const uint8_t *buffer, int size)
xreal_air_parse_sensor_packet(struct xreal_air_parsed_sensor *sensor, const uint8_t *buffer, int size)
{
const uint8_t *start = buffer;
@ -293,7 +293,9 @@ na_parse_sensor_packet(struct na_parsed_sensor *sensor, const uint8_t *buffer, i
}
bool
na_parse_sensor_control_data_packet(struct na_parsed_sensor_control_data *data, const uint8_t *buffer, int size)
xreal_air_parse_sensor_control_data_packet(struct xreal_air_parsed_sensor_control_data *data,
const uint8_t *buffer,
int size)
{
const uint8_t *start = buffer;
@ -320,7 +322,7 @@ na_parse_sensor_control_data_packet(struct na_parsed_sensor_control_data *data,
}
bool
na_parse_control_packet(struct na_parsed_control *control, const uint8_t *buffer, int size)
xreal_air_parse_control_packet(struct xreal_air_parsed_control *control, const uint8_t *buffer, int size)
{
const uint8_t *start = buffer;

View file

@ -44,11 +44,6 @@ if(XRT_BUILD_DRIVER_SIMULAVR)
target_sources(target_lists PRIVATE target_builder_simulavr.c)
endif()
if(XRT_BUILD_DRIVER_NA)
target_sources(target_lists PRIVATE target_builder_nreal_air.c)
target_link_libraries(target_lists PRIVATE drv_na)
endif()
if(XRT_BUILD_DRIVER_NS)
target_sources(target_lists PRIVATE target_builder_north_star.c)
target_link_libraries(target_lists PRIVATE drv_ns)
@ -64,6 +59,11 @@ if(XRT_BUILD_DRIVER_QWERTY)
target_link_libraries(target_lists PRIVATE drv_qwerty)
endif()
if(XRT_BUILD_DRIVER_XREAL_AIR)
target_sources(target_lists PRIVATE target_builder_xreal_air.c)
target_link_libraries(target_lists PRIVATE drv_xreal_air)
endif()
###
# Drivers
#
@ -94,10 +94,6 @@ if(XRT_BUILD_DRIVER_HYDRA)
target_link_libraries(target_lists PRIVATE drv_hydra)
endif()
if(XRT_BUILD_DRIVER_NA)
target_link_libraries(target_lists PRIVATE drv_na)
endif()
if(XRT_BUILD_DRIVER_NS)
target_link_libraries(target_lists PRIVATE drv_ns)
endif()
@ -193,6 +189,10 @@ if(XRT_BUILD_DRIVER_WMR)
target_link_libraries(target_lists PRIVATE drv_wmr)
endif()
if(XRT_BUILD_DRIVER_XREAL_AIR)
target_link_libraries(target_lists PRIVATE drv_xreal_air)
endif()
if(XRT_BUILD_DRIVER_EUROC)
target_link_libraries(target_lists PRIVATE drv_euroc)
endif()

View file

@ -1,13 +1,14 @@
// Copyright 2023, Tobias Frisch
// Copyright 2023-2024, Tobias Frisch
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Nreal Air prober code.
* @brief Xreal Air prober code.
* @author Tobias Frisch <thejackimonster@gmail.com>
* @ingroup drv_na
* @ingroup drv_xreal_air
*/
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
@ -24,13 +25,13 @@
#include "util/u_system_helpers.h"
#include "util/u_trace_marker.h"
#include "nreal_air/na_hmd.h"
#include "nreal_air/na_interface.h"
#include "xreal_air/xreal_air_hmd.h"
#include "xreal_air/xreal_air_interface.h"
enum u_logging_level nreal_air_log_level;
enum u_logging_level xreal_air_log_level;
#define NA_WARN(...) U_LOG_IFL_W(nreal_air_log_level, __VA_ARGS__)
#define NA_ERROR(...) U_LOG_IFL_E(nreal_air_log_level, __VA_ARGS__)
#define XREAL_AIR_WARN(...) U_LOG_IFL_W(xreal_air_log_level, __VA_ARGS__)
#define XREAL_AIR_ERROR(...) U_LOG_IFL_E(xreal_air_log_level, __VA_ARGS__)
/*
@ -39,10 +40,18 @@ enum u_logging_level nreal_air_log_level;
*
*/
DEBUG_GET_ONCE_LOG_OPTION(nreal_air_log, "NA_LOG", U_LOGGING_WARN)
DEBUG_GET_ONCE_LOG_OPTION(xreal_air_log, "XREAL_AIR_LOG", U_LOGGING_WARN)
static const char *driver_list[] = {
"nreal_air",
"xreal_air",
};
#define XREAL_AIR_DRIVER_PRODUCT_IDS 3
static const uint16_t driver_product_ids[XREAL_AIR_DRIVER_PRODUCT_IDS] = {
XREAL_AIR_PID,
XREAL_AIR_2_PID,
XREAL_AIR_2_PRO_PID,
};
@ -53,7 +62,7 @@ static const char *driver_list[] = {
*/
static xrt_result_t
nreal_air_estimate_system(struct xrt_builder *xb,
xreal_air_estimate_system(struct xrt_builder *xb,
cJSON *config,
struct xrt_prober *xp,
struct xrt_builder_estimate *estimate)
@ -65,12 +74,24 @@ nreal_air_estimate_system(struct xrt_builder *xb,
U_ZERO(estimate);
xret = xrt_prober_lock_list(xp, &xpdevs, &xpdev_count);
if (xret != XRT_SUCCESS) {
return xret;
}
struct xrt_prober_device *dev =
u_builder_find_prober_device(xpdevs, xpdev_count, NA_VID, NA_PID, XRT_BUS_TYPE_USB);
struct xrt_prober_device *dev = NULL;
uint16_t product_index = 0;
while (product_index < XREAL_AIR_DRIVER_PRODUCT_IDS) {
dev = u_builder_find_prober_device(xpdevs, xpdev_count, XREAL_AIR_VID,
driver_product_ids[product_index], XRT_BUS_TYPE_USB);
if (dev != NULL)
break;
product_index++;
}
if (dev != NULL) {
estimate->certain.head = true;
}
@ -82,7 +103,7 @@ nreal_air_estimate_system(struct xrt_builder *xb,
}
static xrt_result_t
nreal_air_open_system_impl(struct xrt_builder *xb,
xreal_air_open_system_impl(struct xrt_builder *xb,
cJSON *config,
struct xrt_prober *xp,
struct xrt_tracking_origin *origin,
@ -96,39 +117,53 @@ nreal_air_open_system_impl(struct xrt_builder *xb,
DRV_TRACE_MARKER();
nreal_air_log_level = debug_get_log_option_nreal_air_log();
xreal_air_log_level = debug_get_log_option_xreal_air_log();
xret = xrt_prober_lock_list(xp, &xpdevs, &xpdev_count);
if (xret != XRT_SUCCESS) {
goto unlock_and_fail;
}
struct xrt_prober_device *dev_hmd =
u_builder_find_prober_device(xpdevs, xpdev_count, NA_VID, NA_PID, XRT_BUS_TYPE_USB);
struct xrt_prober_device *dev_hmd = NULL;
uint16_t product_index = 0;
while (product_index < XREAL_AIR_DRIVER_PRODUCT_IDS) {
dev_hmd = u_builder_find_prober_device(xpdevs, xpdev_count, XREAL_AIR_VID,
driver_product_ids[product_index], XRT_BUS_TYPE_USB);
if (dev_hmd != NULL)
break;
product_index++;
}
if (dev_hmd == NULL) {
goto unlock_and_fail;
}
struct os_hid_device *hid_handle = NULL;
int result = xrt_prober_open_hid_interface(xp, dev_hmd, NA_HANDLE_IFACE, &hid_handle);
int result = xrt_prober_open_hid_interface(xp, dev_hmd, XREAL_AIR_HANDLE_IFACE, &hid_handle);
if (result != 0) {
NA_ERROR("Failed to open Nreal Air handle interface");
XREAL_AIR_ERROR("Failed to open Xreal Air handle interface");
goto unlock_and_fail;
}
struct os_hid_device *hid_control = NULL;
result = xrt_prober_open_hid_interface(xp, dev_hmd, NA_CONTROL_IFACE, &hid_control);
result = xrt_prober_open_hid_interface(xp, dev_hmd, XREAL_AIR_CONTROL_IFACE, &hid_control);
if (result != 0) {
os_hid_destroy(hid_handle);
NA_ERROR("Failed to open Nreal Air control interface");
XREAL_AIR_ERROR("Failed to open Xreal Air control interface");
goto unlock_and_fail;
}
unsigned char hmd_serial_no[XRT_DEVICE_NAME_LEN];
result = xrt_prober_get_string_descriptor(xp, dev_hmd, XRT_PROBER_STRING_SERIAL_NUMBER, hmd_serial_no,
XRT_DEVICE_NAME_LEN);
if (result < 0) {
NA_WARN("Could not read Nreal Air serial number from USB");
XREAL_AIR_WARN("Could not read Xreal Air serial number from USB");
snprintf((char *)hmd_serial_no, XRT_DEVICE_NAME_LEN, "Unknown");
}
@ -137,17 +172,18 @@ nreal_air_open_system_impl(struct xrt_builder *xb,
goto fail;
}
struct xrt_device *na_device = na_hmd_create_device(hid_handle, hid_control, nreal_air_log_level);
if (na_device == NULL) {
NA_ERROR("Failed to initialise Nreal Air driver");
struct xrt_device *xreal_air_device = xreal_air_hmd_create_device(hid_handle, hid_control, xreal_air_log_level);
if (xreal_air_device == NULL) {
XREAL_AIR_ERROR("Failed to initialise Xreal Air driver");
goto fail;
}
// Add to device list.
xsysd->xdevs[xsysd->xdev_count++] = na_device;
xsysd->xdevs[xsysd->xdev_count++] = xreal_air_device;
// Assign to role(s).
ubrh->head = na_device;
ubrh->head = xreal_air_device;
return XRT_SUCCESS;
@ -168,7 +204,7 @@ fail:
}
static void
nreal_air_destroy(struct xrt_builder *xb)
xreal_air_destroy(struct xrt_builder *xb)
{
free(xb);
}
@ -181,21 +217,21 @@ nreal_air_destroy(struct xrt_builder *xb)
*/
struct xrt_builder *
nreal_air_builder_create(void)
xreal_air_builder_create(void)
{
struct u_builder *ub = U_TYPED_CALLOC(struct u_builder);
// xrt_builder fields.
ub->base.estimate_system = nreal_air_estimate_system;
ub->base.estimate_system = xreal_air_estimate_system;
ub->base.open_system = u_builder_open_system_static_roles;
ub->base.destroy = nreal_air_destroy;
ub->base.identifier = "nreal_air";
ub->base.name = "Nreal Air";
ub->base.destroy = xreal_air_destroy;
ub->base.identifier = "xreal_air";
ub->base.name = "Xreal Air";
ub->base.driver_identifiers = driver_list;
ub->base.driver_identifier_count = ARRAY_SIZE(driver_list);
// u_builder fields.
ub->open_system_static_roles = nreal_air_open_system_impl;
ub->open_system_static_roles = xreal_air_open_system_impl;
return &ub->base;
}

View file

@ -1,4 +1,4 @@
// Copyright 2019-2023, Collabora, Ltd.
// Copyright 2019-2024, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
@ -80,15 +80,15 @@
#include "depthai/depthai_interface.h"
#endif
#ifdef XRT_BUILD_DRIVER_NA
#include "nreal_air/na_interface.h"
#endif
#ifdef XRT_BUILD_DRIVER_WMR
#include "wmr/wmr_interface.h"
#include "wmr/wmr_common.h"
#endif
#ifdef XRT_BUILD_DRIVER_XREAL_AIR
#include "xreal_air/xreal_air_interface.h"
#endif
#ifdef XRT_BUILD_DRIVER_EUROC
#include "euroc/euroc_interface.h"
#endif
@ -136,10 +136,6 @@ xrt_builder_create_func_t target_builder_list[] = {
t_builder_lighthouse_create,
#endif // T_BUILDER_LIGHTHOUSE
#ifdef XRT_BUILD_DRIVER_NA
nreal_air_builder_create,
#endif // T_BUILDER_NA
#ifdef T_BUILDER_NS
t_builder_north_star_create,
#endif // T_BUILDER_NS
@ -148,6 +144,10 @@ xrt_builder_create_func_t target_builder_list[] = {
t_builder_wmr_create,
#endif // T_BUILDER_WMR
#ifdef XRT_BUILD_DRIVER_XREAL_AIR
xreal_air_builder_create,
#endif // T_BUILDER_XREAL_AIR
#ifdef T_BUILDER_LEGACY
t_builder_legacy_create,
#endif // T_BUILDER_LEGACY