The open source OpenXR runtime

drivers: add all of opengloves driver

danwillm fd61dd08 0943ce10

+1385
+3
CMakeLists.txt
··· 285 285 option_with_deps(XRT_BUILD_DRIVER_ILLIXR "Enable ILLIXR driver" DEPENDS ILLIXR_PATH) 286 286 option_with_deps(XRT_BUILD_DRIVER_NS "Enable North Star driver" DEPENDS XRT_HAVE_INTERNAL_HID) 287 287 option_with_deps(XRT_BUILD_DRIVER_OHMD "Enable OpenHMD driver" DEPENDS OPENHMD_FOUND) 288 + option_with_deps(XRT_BUILD_DRIVER_OPENGLOVES "Enable OpenGloves driver" DEPENDS XRT_HAVE_LIBUDEV XRT_HAVE_BLUETOOTH) 288 289 option_with_deps(XRT_BUILD_DRIVER_PSMV "Enable Playstation Move driver" DEPENDS XRT_HAVE_INTERNAL_HID) 289 290 option_with_deps(XRT_BUILD_DRIVER_PSVR "Enable PSVR HMD driver" DEPENDS XRT_HAVE_HIDAPI) 290 291 option_with_deps(XRT_BUILD_DRIVER_QWERTY "Enable Qwerty driver" DEPENDS XRT_HAVE_SDL2) ··· 336 337 "ILLIXR" 337 338 "NS" 338 339 "OHMD" 340 + "OPENGLOVES" 339 341 "PSMV" 340 342 "PSVR" 341 343 "REALSENSE" ··· 504 506 message(STATUS "# DRIVER_ILLIXR: ${XRT_BUILD_DRIVER_ILLIXR}") 505 507 message(STATUS "# DRIVER_NS: ${XRT_BUILD_DRIVER_NS}") 506 508 message(STATUS "# DRIVER_OHMD: ${XRT_BUILD_DRIVER_OHMD}") 509 + message(STATUS "# DRIVER_OPENGLOVES: ${XRT_BUILD_DRIVER_OPENGLOVES}") 507 510 message(STATUS "# DRIVER_PSMV: ${XRT_BUILD_DRIVER_PSMV}") 508 511 message(STATUS "# DRIVER_PSVR: ${XRT_BUILD_DRIVER_PSVR}") 509 512 message(STATUS "# DRIVER_QWERTY: ${XRT_BUILD_DRIVER_QWERTY}")
+15
src/xrt/drivers/CMakeLists.txt
··· 113 113 list(APPEND ENABLED_HEADSET_DRIVERS openhmd) 114 114 endif() 115 115 116 + if(XRT_BUILD_DRIVER_OPENGLOVES) 117 + add_library( 118 + drv_opengloves STATIC 119 + opengloves/opengloves_interface.h opengloves/opengloves_device.c opengloves/opengloves_prober.c opengloves/opengloves_device.h opengloves/communication/serial/opengloves_serial.h opengloves/communication/serial/opengloves_serial.c opengloves/encoding/alpha_encoding.h opengloves/encoding/alpha_encoding.cpp opengloves/encoding/encoding.h opengloves/communication/bluetooth/opengloves_bt_serial.h opengloves/communication/bluetooth/opengloves_bt_serial.c opengloves/communication/opengloves_communication.h opengloves/communication/serial/opengloves_prober_serial.h opengloves/communication/serial/opengloves_prober_serial.c opengloves/communication/bluetooth/opengloves_prober_bt.h opengloves/communication/bluetooth/opengloves_prober_bt.c) 120 + target_link_libraries(drv_opengloves 121 + PRIVATE 122 + xrt-interfaces 123 + aux_util 124 + aux_os 125 + bluetooth 126 + ) 127 + list(APPEND ENABLED_DRIVERS opengloves) 128 + 129 + endif() 130 + 116 131 if(XRT_BUILD_DRIVER_PSMV) 117 132 add_library(drv_psmv STATIC psmv/psmv_driver.c psmv/psmv_interface.h) 118 133 target_link_libraries(
+91
src/xrt/drivers/opengloves/communication/bluetooth/opengloves_bt_serial.c
··· 1 + // Copyright 2022, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief OpenGloves bluetooth serial implementation 6 + * @author Daniel Willmott <web@dan-w.com> 7 + * @ingroup drv_opengloves 8 + */ 9 + 10 + #include <unistd.h> 11 + #include <errno.h> 12 + #include <bluetooth/bluetooth.h> 13 + #include <bluetooth/rfcomm.h> 14 + 15 + #include "util/u_misc.h" 16 + #include "util/u_debug.h" 17 + 18 + #include "opengloves_bt_serial.h" 19 + 20 + #define OPENGLOVES_PROBER_LOG_LEVEL U_LOGGING_TRACE 21 + 22 + #define OPENGLOVES_ERROR(...) U_LOG_IFL_E(OPENGLOVES_PROBER_LOG_LEVEL, __VA_ARGS__) 23 + #define OPENGLOVES_WARN(...) U_LOG_IFL_W(OPENGLOVES_PROBER_LOG_LEVEL, __VA_ARGS__) 24 + #define OPENGLOVES_INFO(...) U_LOG_IFL_I(OPENGLOVES_PROBER_LOG_LEVEL, __VA_ARGS__) 25 + 26 + static void 27 + opengloves_bt_close(struct opengloves_bt_device *btdev) 28 + { 29 + if (btdev->sock != 0) { 30 + close(btdev->sock); 31 + btdev->sock = 0; 32 + } 33 + } 34 + 35 + static int 36 + opengloves_bt_read(struct opengloves_communication_device *ocdev, char *data, size_t length) 37 + { 38 + struct opengloves_bt_device *obdev = (struct opengloves_bt_device *)ocdev; 39 + 40 + return read(obdev->sock, data, length); 41 + } 42 + 43 + static int 44 + opengloves_bt_write(struct opengloves_communication_device *ocdev, const uint8_t *data, size_t length) 45 + { 46 + struct opengloves_bt_device *obdev = (struct opengloves_bt_device *)obdev; 47 + 48 + return write(obdev->sock, data, length); 49 + } 50 + 51 + static void 52 + opengloves_bt_destroy(struct opengloves_communication_device *ocdev) 53 + { 54 + struct opengloves_bt_device *obdev = (struct opengloves_bt_device *)obdev; 55 + 56 + opengloves_bt_close(obdev); 57 + free(obdev); 58 + } 59 + 60 + 61 + 62 + int 63 + opengloves_bt_open(const char *btaddr, struct opengloves_communication_device **out_comm_dev) 64 + { 65 + struct opengloves_bt_device *obdev = U_TYPED_CALLOC(struct opengloves_bt_device); 66 + 67 + obdev->base.read = opengloves_bt_read; 68 + obdev->base.write = opengloves_bt_write; 69 + obdev->base.destroy = opengloves_bt_destroy; 70 + 71 + // allocate a socket 72 + obdev->sock = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); 73 + 74 + // set the connection parameters (who to connect to) 75 + struct sockaddr_rc addr = {0}; 76 + addr.rc_family = AF_BLUETOOTH; 77 + addr.rc_channel = (uint8_t)1; 78 + str2ba(btaddr, &addr.rc_bdaddr); 79 + 80 + // connect to server 81 + int ret = connect(obdev->sock, (struct sockaddr *)&addr, sizeof(addr)); 82 + 83 + if (ret < 0) { 84 + OPENGLOVES_ERROR("Failed to connect to device! %s", strerror(errno)); 85 + return ret; 86 + } 87 + 88 + *out_comm_dev = &obdev->base; 89 + 90 + return 0; 91 + }
+31
src/xrt/drivers/opengloves/communication/bluetooth/opengloves_bt_serial.h
··· 1 + // Copyright 2019-2022, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief Bluetooth Serial interface for OpenGloves. 6 + * @author Daniel Willmott <web@dan-w.com> 7 + * @ingroup drv_opengloves 8 + */ 9 + 10 + #pragma once 11 + 12 + #include "../opengloves_communication.h" 13 + 14 + 15 + #ifdef __cplusplus 16 + extern "C" { 17 + #endif 18 + 19 + 20 + struct opengloves_bt_device 21 + { 22 + struct opengloves_communication_device base; 23 + int sock; 24 + }; 25 + 26 + int 27 + opengloves_bt_open(const char *btaddr, struct opengloves_communication_device **out_comm_dev); 28 + 29 + #ifdef __cplusplus 30 + } 31 + #endif
+81
src/xrt/drivers/opengloves/communication/bluetooth/opengloves_prober_bt.c
··· 1 + // Copyright 2019-2022, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief OpenGloves bluetooth prober implementation. 6 + * @author Daniel Willmott <web@dan-w.com> 7 + * @ingroup drv_opengloves 8 + */ 9 + 10 + #include <stdlib.h> 11 + 12 + #include <bluetooth/bluetooth.h> 13 + #include <bluetooth/hci.h> 14 + #include <bluetooth/hci_lib.h> 15 + #include <unistd.h> 16 + 17 + #include "util/u_debug.h" 18 + #include "xrt/xrt_defines.h" 19 + 20 + #include "opengloves_bt_serial.h" 21 + #include "opengloves_prober_bt.h" 22 + #include "util/u_misc.h" 23 + 24 + #define OPENGLOVES_PROBER_LOG_LEVEL U_LOGGING_TRACE 25 + 26 + #define OPENGLOVES_ERROR(...) U_LOG_IFL_E(OPENGLOVES_PROBER_LOG_LEVEL, __VA_ARGS__) 27 + #define OPENGLOVES_WARN(...) U_LOG_IFL_W(OPENGLOVES_PROBER_LOG_LEVEL, __VA_ARGS__) 28 + #define OPENGLOVES_INFO(...) U_LOG_IFL_I(OPENGLOVES_PROBER_LOG_LEVEL, __VA_ARGS__) 29 + 30 + #define OPENGLOVES_BT_MAX_ADDRESS_LEN 19 31 + #define OPENGLOVES_BT_MAX_NAME_LEN 248 32 + #define OPENGLOVES_BT_MAX_DEVICES 255 33 + 34 + int 35 + opengloves_get_bt_devices(const char *bt_name, struct opengloves_communication_device **out_ocd) 36 + { 37 + char addr[OPENGLOVES_BT_MAX_ADDRESS_LEN] = {0}; 38 + char name[OPENGLOVES_BT_MAX_NAME_LEN] = {0}; 39 + 40 + int dev_id = hci_get_route(NULL); 41 + int sock = hci_open_dev(dev_id); 42 + 43 + if (dev_id < 0 || sock < 0) { 44 + OPENGLOVES_ERROR("Failed to open socket!"); 45 + 46 + return -1; 47 + } 48 + 49 + int max_rsp = OPENGLOVES_BT_MAX_DEVICES; // maximum devices to find 50 + inquiry_info *ii = U_TYPED_ARRAY_CALLOC(inquiry_info, max_rsp); 51 + 52 + int num_rsp = hci_inquiry(dev_id, 1, max_rsp, NULL, &ii, IREQ_CACHE_FLUSH); 53 + 54 + if (num_rsp < 0) { 55 + OPENGLOVES_ERROR("device inquiry failed!"); 56 + 57 + free(ii); 58 + close(sock); 59 + 60 + return -1; 61 + } 62 + 63 + for (int i = 0; i < num_rsp; i++) { 64 + ba2str(&(ii + i)->bdaddr, addr); 65 + memset(name, 0, sizeof(name)); 66 + 67 + hci_read_remote_name(sock, &(ii + i)->bdaddr, sizeof(name), name, 0); 68 + 69 + if (!strcmp(name, bt_name) && *out_ocd == NULL) { 70 + OPENGLOVES_INFO("Found bt device! %s", name); 71 + 72 + opengloves_bt_open(addr, out_ocd); 73 + 74 + break; 75 + } 76 + } 77 + 78 + free(ii); 79 + close(sock); 80 + return 0; 81 + }
+26
src/xrt/drivers/opengloves/communication/bluetooth/opengloves_prober_bt.h
··· 1 + // Copyright 2019-2022, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief OpenGloves bluetooth prober. 6 + * @author Daniel Willmott <web@dan-w.com> 7 + * @ingroup drv_opengloves 8 + */ 9 + 10 + #pragma once 11 + 12 + #include "../opengloves_communication.h" 13 + 14 + #define LUCIDGLOVES_BT_L_NAME "lucidgloves-left" 15 + #define LUCIDGLOVES_BT_R_NAME "lucidgloves-right" 16 + 17 + #ifdef __cplusplus 18 + extern "C" { 19 + #endif 20 + 21 + int 22 + opengloves_get_bt_devices(const char *bt_name, struct opengloves_communication_device **out_ocd); 23 + 24 + #ifdef __cplusplus 25 + } 26 + #endif
+58
src/xrt/drivers/opengloves/communication/opengloves_communication.h
··· 1 + // Copyright 2019-2022, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief Communication structures for OpenGloves 6 + * @author Daniel Willmott <web@dan-w.com> 7 + * @ingroup drv_opengloves 8 + */ 9 + 10 + #pragma once 11 + #include <stdint.h> 12 + #include <stddef.h> 13 + 14 + #ifdef __cplusplus 15 + extern "C" { 16 + #endif 17 + 18 + /*! 19 + * @interface opengloves_communication_device 20 + * 21 + * Interface for a communication method 22 + * 23 + * @ingroup drv_opengloves 24 + */ 25 + struct opengloves_communication_device 26 + { 27 + int (*read)(struct opengloves_communication_device *comm_dev, char *data, size_t size); 28 + 29 + int (*write)(struct opengloves_communication_device *comm_dev, const uint8_t *data, size_t size); 30 + 31 + void (*destroy)(struct opengloves_communication_device *comm_dev); 32 + }; 33 + 34 + static inline int 35 + opengloves_communication_device_read(struct opengloves_communication_device *comm_dev, char *data, size_t size) 36 + { 37 + return comm_dev->read(comm_dev, data, size); 38 + } 39 + 40 + static inline int 41 + opengloves_communication_device_write(struct opengloves_communication_device *comm_dev, 42 + const uint8_t *data, 43 + size_t size) 44 + { 45 + return comm_dev->write(comm_dev, data, size); 46 + } 47 + 48 + 49 + static inline void 50 + opengloves_communication_device_destory(struct opengloves_communication_device *comm_dev) 51 + { 52 + comm_dev->destroy(comm_dev); 53 + } 54 + 55 + 56 + #ifdef __cplusplus 57 + } 58 + #endif
+107
src/xrt/drivers/opengloves/communication/serial/opengloves_prober_serial.c
··· 1 + // Copyright 2019-2022, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief OpenGloves serial prober implementation. 6 + * @author Daniel Willmott <web@dan-w.com> 7 + * @ingroup drv_opengloves 8 + */ 9 + 10 + #include <libudev.h> 11 + #include <stdlib.h> 12 + #include <string.h> 13 + #include <stdio.h> 14 + 15 + #include "util/u_debug.h" 16 + #include "xrt/xrt_defines.h" 17 + 18 + #include "opengloves_prober_serial.h" 19 + #include "opengloves_serial.h" 20 + 21 + #define OPENGLOVES_PROBER_LOG_LEVEL U_LOGGING_TRACE 22 + 23 + #define OPENGLOVES_ERROR(...) U_LOG_IFL_E(OPENGLOVES_PROBER_LOG_LEVEL, __VA_ARGS__) 24 + #define OPENGLOVES_INFO(...) U_LOG_IFL_I(OPENGLOVES_PROBER_LOG_LEVEL, __VA_ARGS__) 25 + 26 + #define OPENGLOVES_TTY_PATH_SIZE 14 27 + 28 + static int 29 + opengloves_udev_get_sysattr_u16_base16(struct udev_device *dev, const char *name, uint16_t *out_value) 30 + { 31 + const char *str = udev_device_get_sysattr_value(dev, name); 32 + if (str == NULL) { 33 + return -1; 34 + } 35 + 36 + *out_value = (uint16_t)strtol(str, NULL, 16); 37 + 38 + return 0; 39 + } 40 + 41 + static int 42 + opengloves_serial_device_found(const char *sysfs_path, struct opengloves_communication_device **ocdev) 43 + { 44 + // ttyUSBx comes after the last / in sysfs_path 45 + const char *tty_name = strrchr(sysfs_path, '/') + 1; 46 + 47 + char tty_path[OPENGLOVES_TTY_PATH_SIZE] = {0}; 48 + int cx = snprintf(tty_path, OPENGLOVES_TTY_PATH_SIZE, "/dev/%s", tty_name); 49 + 50 + if (cx < 0) { 51 + OPENGLOVES_ERROR("Failed to create tty path!"); 52 + return 0; 53 + } 54 + 55 + OPENGLOVES_INFO("Device discovered! Attempting connection to %s", tty_path); 56 + 57 + int ret = opengloves_serial_open(tty_path, ocdev); 58 + if (ret < 0) { 59 + OPENGLOVES_ERROR("Failed to connect to serial device, %s", strerror(-ret)); 60 + return 0; 61 + } 62 + 63 + OPENGLOVES_INFO("Successfully connected to device"); 64 + 65 + return 1; 66 + } 67 + 68 + int 69 + opengloves_get_serial_devices(uint16_t vid, uint16_t pid, struct opengloves_communication_device **out_ocd) 70 + { 71 + struct udev *ud = udev_new(); 72 + 73 + struct udev_enumerate *tty_enumerate = udev_enumerate_new(ud); 74 + 75 + udev_enumerate_add_match_subsystem(tty_enumerate, "tty"); 76 + udev_enumerate_scan_devices(tty_enumerate); 77 + 78 + struct udev_list_entry *tty_devices; 79 + tty_devices = udev_enumerate_get_list_entry(tty_enumerate); 80 + 81 + struct udev_list_entry *tty_dev_list_entry; 82 + 83 + int dev_count = 0; 84 + udev_list_entry_foreach(tty_dev_list_entry, tty_devices) 85 + { 86 + const char *sysfs_path = udev_list_entry_get_name(tty_dev_list_entry); 87 + struct udev_device *raw_dev = udev_device_new_from_syspath(ud, sysfs_path); 88 + 89 + struct udev_device *parent_dev = raw_dev; 90 + while (parent_dev != NULL) { 91 + uint16_t vendor_id; 92 + uint16_t product_id; 93 + opengloves_udev_get_sysattr_u16_base16(parent_dev, "idVendor", &vendor_id); 94 + opengloves_udev_get_sysattr_u16_base16(parent_dev, "idProduct", &product_id); 95 + 96 + // if vendor and product id match what was requested 97 + if (vendor_id == vid && product_id == pid && *out_ocd == NULL) 98 + dev_count = dev_count + opengloves_serial_device_found(sysfs_path, out_ocd); 99 + 100 + parent_dev = udev_device_get_parent(parent_dev); 101 + } 102 + } 103 + 104 + udev_enumerate_unref(tty_enumerate); 105 + 106 + return dev_count; 107 + }
+27
src/xrt/drivers/opengloves/communication/serial/opengloves_prober_serial.h
··· 1 + // Copyright 2019-2022, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief Serial prober interface for OpenGloves. 6 + * @author Daniel Willmott <web@dan-w.com> 7 + * @ingroup drv_opengloves 8 + */ 9 + 10 + #pragma once 11 + 12 + #include "../opengloves_communication.h" 13 + 14 + #define LUCIDGLOVES_USB_VID 0x1a86 15 + #define LUCIDGLOVES_USB_L_PID 0x7523 // left hand pid 16 + #define LUCIDGLOVES_USB_R_PID 0x7524 // right hand pid 17 + #ifdef __cplusplus 18 + extern "C" { 19 + #endif 20 + 21 + 22 + int 23 + opengloves_get_serial_devices(uint16_t vid, uint16_t pid, struct opengloves_communication_device **out_ocd); 24 + 25 + #ifdef __cplusplus 26 + } 27 + #endif
+106
src/xrt/drivers/opengloves/communication/serial/opengloves_serial.c
··· 1 + // Copyright 2019-2022, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief USB Serial implementation for OpenGloves. 6 + * @author Daniel Willmott <web@dan-w.com> 7 + * @ingroup drv_opengloves 8 + */ 9 + 10 + #include <stdio.h> 11 + #include <string.h> 12 + #include <unistd.h> 13 + 14 + #include <fcntl.h> 15 + #include <errno.h> 16 + #include <termios.h> 17 + #include <sys/ioctl.h> 18 + 19 + #include "opengloves_serial.h" 20 + 21 + #include "util/u_misc.h" 22 + 23 + 24 + static int 25 + opengloves_serial_read(struct opengloves_communication_device *ocdev, char *data, size_t length) 26 + { 27 + struct opengloves_serial_device *osdev = (struct opengloves_serial_device *)ocdev; 28 + int ret = read(osdev->fd, data, length); 29 + 30 + return ret; 31 + } 32 + 33 + static int 34 + opengloves_serial_write(struct opengloves_communication_device *ocdev, const uint8_t *data, size_t length) 35 + { 36 + struct opengloves_serial_device *osdev = (struct opengloves_serial_device *)ocdev; 37 + 38 + return write(osdev->fd, data, length); 39 + } 40 + 41 + static void 42 + opengloves_serial_destroy(struct opengloves_communication_device *ocdev) 43 + { 44 + struct opengloves_serial_device *osdev = (struct opengloves_serial_device *)ocdev; 45 + 46 + close(osdev->fd); 47 + free(osdev); 48 + } 49 + 50 + int 51 + opengloves_serial_open(const char *path, struct opengloves_communication_device **out_comm_dev) 52 + { 53 + int fd = open(path, O_RDWR); 54 + 55 + // error opening file 56 + if (fd < 0) { 57 + return -errno; 58 + } 59 + 60 + // read existing settings 61 + struct termios tty; 62 + if (tcgetattr(fd, &tty) != 0) { 63 + return -errno; 64 + } 65 + 66 + tty.c_cflag &= ~PARENB; 67 + tty.c_cflag &= ~CSTOPB; 68 + tty.c_cflag &= ~CSIZE; 69 + tty.c_cflag |= CS8; 70 + tty.c_cflag |= CREAD | CLOCAL; 71 + tty.c_cflag &= ~CRTSCTS; 72 + 73 + tty.c_lflag &= ~ICANON; 74 + tty.c_lflag &= ~ECHO; 75 + tty.c_lflag &= ~ECHOE; 76 + tty.c_lflag &= ~ECHONL; 77 + tty.c_lflag &= ~ISIG; 78 + tty.c_iflag &= ~(IXON | IXOFF | IXANY); 79 + tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL); 80 + 81 + tty.c_oflag &= ~OPOST; 82 + tty.c_oflag &= ~ONLCR; 83 + 84 + tty.c_cc[VTIME] = 10; 85 + tty.c_cc[VMIN] = 0; 86 + 87 + // baud rates 88 + cfsetispeed(&tty, B115200); 89 + cfsetospeed(&tty, B115200); 90 + 91 + if (tcsetattr(fd, TCSANOW, &tty) != 0) { 92 + return -errno; 93 + } 94 + 95 + struct opengloves_serial_device *osdev = U_TYPED_CALLOC(struct opengloves_serial_device); 96 + 97 + osdev->base.read = opengloves_serial_read; 98 + osdev->base.write = opengloves_serial_write; 99 + osdev->base.destroy = opengloves_serial_destroy; 100 + 101 + osdev->fd = fd; 102 + 103 + *out_comm_dev = &osdev->base; 104 + 105 + return 0; 106 + }
+31
src/xrt/drivers/opengloves/communication/serial/opengloves_serial.h
··· 1 + // Copyright 2019-2022, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief USB Serial interface for OpenGloves. 6 + * @author Daniel Willmott <web@dan-w.com> 7 + * @ingroup drv_opengloves 8 + */ 9 + 10 + #pragma once 11 + #include <stdint.h> 12 + #include <stddef.h> 13 + 14 + #include "../opengloves_communication.h" 15 + 16 + #ifdef __cplusplus 17 + extern "C" { 18 + #endif 19 + 20 + struct opengloves_serial_device 21 + { 22 + struct opengloves_communication_device base; 23 + int fd; 24 + }; 25 + 26 + int 27 + opengloves_serial_open(const char *path, struct opengloves_communication_device **out_comm_dev); 28 + 29 + #ifdef __cplusplus 30 + } 31 + #endif
+250
src/xrt/drivers/opengloves/encoding/alpha_encoding.cpp
··· 1 + // Copyright 2019-2022, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief OpenGloves Alpha Encoding Decoding implementation. 6 + * @author Daniel Willmott <web@dan-w.com> 7 + * @ingroup drv_opengloves 8 + */ 9 + 10 + #include <string> 11 + #include <stdexcept> 12 + 13 + #include <map> 14 + #include "util/u_logging.h" 15 + 16 + #include "alpha_encoding.h" 17 + #include "encoding.h" 18 + 19 + enum opengloves_alpha_encoding_key 20 + { 21 + OPENGLOVES_ALPHA_ENCODING_FinThumb, 22 + OPENGLOVES_ALPHA_ENCODING_FinSplayThumb, 23 + 24 + OPENGLOVES_ALPHA_ENCODING_FinIndex, 25 + OPENGLOVES_ALPHA_ENCODING_FinSplayIndex, 26 + 27 + OPENGLOVES_ALPHA_ENCODING_FinMiddle, 28 + OPENGLOVES_ALPHA_ENCODING_FinSplayMiddle, 29 + 30 + OPENGLOVES_ALPHA_ENCODING_FinRing, 31 + OPENGLOVES_ALPHA_ENCODING_FinSplayRing, 32 + 33 + OPENGLOVES_ALPHA_ENCODING_FinPinky, 34 + OPENGLOVES_ALPHA_ENCODING_FinSplayPinky, 35 + 36 + OPENGLOVES_ALPHA_ENCODING_FinJointThumb0, 37 + OPENGLOVES_ALPHA_ENCODING_FinJointThumb1, 38 + OPENGLOVES_ALPHA_ENCODING_FinJointThumb2, 39 + OPENGLOVES_ALPHA_ENCODING_FinJointThumb3, // unused in input but used for parity to other fingers in the array 40 + 41 + 42 + OPENGLOVES_ALPHA_ENCODING_FinJointIndex0, 43 + OPENGLOVES_ALPHA_ENCODING_FinJointIndex1, 44 + OPENGLOVES_ALPHA_ENCODING_FinJointIndex2, 45 + OPENGLOVES_ALPHA_ENCODING_FinJointIndex3, 46 + 47 + 48 + OPENGLOVES_ALPHA_ENCODING_FinJointMiddle0, 49 + OPENGLOVES_ALPHA_ENCODING_FinJointMiddle1, 50 + OPENGLOVES_ALPHA_ENCODING_FinJointMiddle2, 51 + OPENGLOVES_ALPHA_ENCODING_FinJointMiddle3, 52 + 53 + 54 + OPENGLOVES_ALPHA_ENCODING_FinJointRing0, 55 + OPENGLOVES_ALPHA_ENCODING_FinJointRing1, 56 + OPENGLOVES_ALPHA_ENCODING_FinJointRing2, 57 + OPENGLOVES_ALPHA_ENCODING_FinJointRing3, 58 + 59 + 60 + OPENGLOVES_ALPHA_ENCODING_FinJointPinky0, 61 + OPENGLOVES_ALPHA_ENCODING_FinJointPinky1, 62 + OPENGLOVES_ALPHA_ENCODING_FinJointPinky2, 63 + OPENGLOVES_ALPHA_ENCODING_FinJointPinky3, 64 + 65 + OPENGLOVES_ALPHA_ENCODING_JoyX, 66 + OPENGLOVES_ALPHA_ENCODING_JoyY, 67 + OPENGLOVES_ALPHA_ENCODING_JoyBtn, 68 + 69 + OPENGLOVES_ALPHA_ENCODING_TrgValue, 70 + OPENGLOVES_ALPHA_ENCODING_BtnTrg, 71 + OPENGLOVES_ALPHA_ENCODING_BtnA, 72 + OPENGLOVES_ALPHA_ENCODING_BtnB, 73 + 74 + OPENGLOVES_ALPHA_ENCODING_GesGrab, 75 + OPENGLOVES_ALPHA_ENCODING_GesPinch, 76 + 77 + OPENGLOVES_ALPHA_ENCODING_BtnMenu, 78 + OPENGLOVES_ALPHA_ENCODING_BtnCalib, 79 + 80 + OPENGLOVES_ALPHA_ENCODING_MAX 81 + }; 82 + 83 + #define OPENGLOVES_ALPHA_ENCODING_VAL_IN_MAP_E_0 84 + 85 + static const std::string opengloves_alpha_encoding_key_characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ()"; 86 + 87 + static bool 88 + opengloves_alpha_encoding_is_key_character(const char character) 89 + { 90 + return opengloves_alpha_encoding_key_characters.find(character) != std::string::npos; 91 + } 92 + 93 + static const std::map<std::string, int> opengloves_alpha_encoding_key_string{ 94 + {"A", OPENGLOVES_ALPHA_ENCODING_FinThumb}, // whole thumb curl (default curl value for thumb joints) 95 + {"(AB)", OPENGLOVES_ALPHA_ENCODING_FinSplayThumb}, // whole thumb splay thumb joint 3 (doesn't exist, but keeps 96 + // consistency with the other fingers 97 + {"B", OPENGLOVES_ALPHA_ENCODING_FinIndex}, // whole index curl (default curl value for index joints) 98 + {"(BB)", OPENGLOVES_ALPHA_ENCODING_FinSplayIndex}, // whole index splay 99 + 100 + {"C", OPENGLOVES_ALPHA_ENCODING_FinMiddle}, // whole middle curl (default curl value for middle joints) 101 + {"(CB)", OPENGLOVES_ALPHA_ENCODING_FinSplayMiddle}, // whole middle splay 102 + 103 + {"D", OPENGLOVES_ALPHA_ENCODING_FinRing}, // whole ring curl (default curl value for 104 + {"(DB)", OPENGLOVES_ALPHA_ENCODING_FinSplayRing}, // whole ring splay 105 + // ring joints) 106 + {"E", OPENGLOVES_ALPHA_ENCODING_FinPinky}, // whole pinky curl (default curl value 107 + {"(EB)", OPENGLOVES_ALPHA_ENCODING_FinSplayPinky}, // whole pinky splay 108 + // for pinky joints 109 + {"(AAA)", OPENGLOVES_ALPHA_ENCODING_FinJointThumb0}, // thumb joint 0 110 + {"(AAB)", OPENGLOVES_ALPHA_ENCODING_FinJointThumb1}, // thumb joint 1 111 + {"(AAC)", OPENGLOVES_ALPHA_ENCODING_FinJointThumb2}, // thumb joint 2 112 + {"(AAD)", OPENGLOVES_ALPHA_ENCODING_FinJointThumb3}, 113 + {"(BAA)", OPENGLOVES_ALPHA_ENCODING_FinJointIndex0}, // index joint 0 114 + {"(BAB)", OPENGLOVES_ALPHA_ENCODING_FinJointIndex1}, // index joint 1 115 + {"(BAC)", OPENGLOVES_ALPHA_ENCODING_FinJointIndex2}, // index joint 2 116 + {"(BAD)", OPENGLOVES_ALPHA_ENCODING_FinJointIndex3}, // index joint 3 117 + {"(CAA)", OPENGLOVES_ALPHA_ENCODING_FinJointMiddle0}, // middle joint 0 118 + {"(CAB)", OPENGLOVES_ALPHA_ENCODING_FinJointMiddle1}, // middle joint 1 119 + {"(CAC)", OPENGLOVES_ALPHA_ENCODING_FinJointMiddle2}, // middle joint 2 120 + {"(CAD)", OPENGLOVES_ALPHA_ENCODING_FinJointMiddle3}, // middle joint 3 121 + {"(DAA)", OPENGLOVES_ALPHA_ENCODING_FinJointRing0}, // ring joint 0 122 + {"(DAB)", OPENGLOVES_ALPHA_ENCODING_FinJointRing1}, // ring joint 1 123 + {"(DAC)", OPENGLOVES_ALPHA_ENCODING_FinJointRing2}, // ring joint 2 124 + {"(DAD)", OPENGLOVES_ALPHA_ENCODING_FinJointRing3}, // ring joint 3 125 + {"(EAA)", OPENGLOVES_ALPHA_ENCODING_FinJointPinky0}, // pinky joint 0 126 + {"(EAB)", OPENGLOVES_ALPHA_ENCODING_FinJointPinky1}, // pinky joint 1 127 + {"(EAC)", OPENGLOVES_ALPHA_ENCODING_FinJointPinky2}, // pinky joint 2 128 + {"(EAD)", OPENGLOVES_ALPHA_ENCODING_FinJointPinky3}, // pinky joint 3 129 + {"F", OPENGLOVES_ALPHA_ENCODING_JoyX}, // joystick x component 130 + {"G", OPENGLOVES_ALPHA_ENCODING_JoyY}, // joystick y component 131 + {"H", OPENGLOVES_ALPHA_ENCODING_JoyBtn}, // joystick button 132 + {"I", OPENGLOVES_ALPHA_ENCODING_BtnTrg}, // trigger button 133 + {"J", OPENGLOVES_ALPHA_ENCODING_BtnA}, // A button 134 + {"K", OPENGLOVES_ALPHA_ENCODING_BtnB}, // B button 135 + {"L", OPENGLOVES_ALPHA_ENCODING_GesGrab}, // grab gesture (boolean) 136 + {"M", OPENGLOVES_ALPHA_ENCODING_GesPinch}, // pinch gesture (boolean) 137 + {"N", OPENGLOVES_ALPHA_ENCODING_BtnMenu}, // system button pressed (opens SteamVR menu) 138 + {"O", OPENGLOVES_ALPHA_ENCODING_BtnCalib}, // calibration button 139 + {"P", OPENGLOVES_ALPHA_ENCODING_TrgValue}, // analog trigger value 140 + {"", OPENGLOVES_ALPHA_ENCODING_MAX} // Junk key 141 + }; 142 + 143 + static std::map<int, std::string> 144 + opengloves_alpha_encoding_parse_to_map(const std::string &str) 145 + { 146 + std::map<int, std::string> result; 147 + 148 + size_t i = 0; 149 + while (i < str.length()) { 150 + // Advance until we get an alphabetic character (no point in looking at values that don't have a key 151 + // associated with them) 152 + 153 + if (str[i] >= 0 && opengloves_alpha_encoding_is_key_character(str[i])) { 154 + std::string key = {str[i]}; 155 + i++; 156 + 157 + // we're going to be parsing a "long key", i.e. (AB) for thumb finger splay. Long keys must 158 + // always be enclosed in brackets 159 + if (key[0] == '(') { 160 + while (str[i] >= 0 && opengloves_alpha_encoding_is_key_character(str[i]) && 161 + i < str.length()) { 162 + key += str[i]; 163 + i++; 164 + } 165 + } 166 + 167 + std::string value; 168 + while (str[i] >= 0 && isdigit(str[i]) && i < str.length()) { 169 + value += str[i]; 170 + i++; 171 + } 172 + 173 + // Even if the value is empty we still want to use the key, it means that we have a button that 174 + // is pressed (it only appears in the packet if it is) 175 + if (opengloves_alpha_encoding_key_string.find(key) != 176 + opengloves_alpha_encoding_key_string.end()) 177 + result.insert_or_assign(opengloves_alpha_encoding_key_string.at(key), value); 178 + else 179 + U_LOG_W("Unable to insert key: %s into input map as it was not found", key.c_str()); 180 + } else 181 + i++; 182 + } 183 + 184 + return result; 185 + } 186 + 187 + 188 + void 189 + opengloves_alpha_encoding_decode(const char *data, struct opengloves_input *out) 190 + { 191 + std::map<int, std::string> input_map = opengloves_alpha_encoding_parse_to_map(data); 192 + 193 + try { 194 + // five fingers, 2 (curl + splay) 195 + for (int i = 0; i < 5; i++) { 196 + int enum_position = i * 2; 197 + // curls 198 + if (input_map.find(enum_position) != input_map.end()) { 199 + float fin_curl_value = std::stof(input_map.at(enum_position)); 200 + std::fill(std::begin(out->flexion[i]), std::begin(out->flexion[i]) + 4, 201 + fin_curl_value / OPENGLOVES_ENCODING_MAX_ANALOG_VALUE); 202 + } 203 + 204 + // splay 205 + if (input_map.find(enum_position + 1) != input_map.end()) 206 + out->splay[i] = 207 + (std::stof(input_map.at(enum_position + 1)) / OPENGLOVES_ENCODING_MAX_ANALOG_VALUE - 208 + 0.5f) * 209 + 2.0f; 210 + } 211 + 212 + int current_finger_joint = OPENGLOVES_ALPHA_ENCODING_FinJointThumb0; 213 + for (int i = 0; i < 5; i++) { 214 + for (int j = 0; j < 4; j++) { 215 + // individual joint curls 216 + out->flexion[i][j] = input_map.find(current_finger_joint) != input_map.end() 217 + ? (std::stof(input_map.at(current_finger_joint)) / 218 + OPENGLOVES_ENCODING_MAX_ANALOG_VALUE) 219 + // use the curl of the previous joint 220 + : out->flexion[i][j > 0 ? j - 1 : 0]; 221 + current_finger_joint++; 222 + } 223 + } 224 + 225 + // joysticks 226 + if (input_map.find(OPENGLOVES_ALPHA_ENCODING_JoyX) != input_map.end()) 227 + out->joysticks.main.x = 2 * std::stof(input_map.at(OPENGLOVES_ALPHA_ENCODING_JoyX)) / 228 + OPENGLOVES_ENCODING_MAX_ANALOG_VALUE - 229 + 1; 230 + if (input_map.find(OPENGLOVES_ALPHA_ENCODING_JoyY) != input_map.end()) 231 + out->joysticks.main.y = 2 * std::stof(input_map.at(OPENGLOVES_ALPHA_ENCODING_JoyY)) / 232 + OPENGLOVES_ENCODING_MAX_ANALOG_VALUE - 233 + 1; 234 + out->joysticks.main.pressed = input_map.find(OPENGLOVES_ALPHA_ENCODING_JoyBtn) != input_map.end(); 235 + 236 + } catch (std::invalid_argument &e) { 237 + U_LOG_E("Error parsing input string: %s", e.what()); 238 + } 239 + 240 + if (input_map.find(OPENGLOVES_ALPHA_ENCODING_TrgValue) != input_map.end()) 241 + out->buttons.trigger.value = 242 + std::stof(input_map.at(OPENGLOVES_ALPHA_ENCODING_TrgValue)) / OPENGLOVES_ENCODING_MAX_ANALOG_VALUE; 243 + out->buttons.trigger.pressed = input_map.find(OPENGLOVES_ALPHA_ENCODING_BtnTrg) != input_map.end(); 244 + 245 + out->buttons.A.pressed = input_map.find(OPENGLOVES_ALPHA_ENCODING_BtnA) != input_map.end(); 246 + out->buttons.B.pressed = input_map.find(OPENGLOVES_ALPHA_ENCODING_BtnB) != input_map.end(); 247 + out->gestures.grab.activated = input_map.find(OPENGLOVES_ALPHA_ENCODING_GesGrab) != input_map.end(); 248 + out->gestures.pinch.activated = input_map.find(OPENGLOVES_ALPHA_ENCODING_GesPinch) != input_map.end(); 249 + out->buttons.menu.pressed = input_map.find(OPENGLOVES_ALPHA_ENCODING_BtnMenu) != input_map.end(); 250 + }
+22
src/xrt/drivers/opengloves/encoding/alpha_encoding.h
··· 1 + // Copyright 2019-2022, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief OpenGloves Alpha Encoding Decoding interface. 6 + * @author Daniel Willmott <web@dan-w.com> 7 + * @ingroup drv_opengloves 8 + */ 9 + 10 + #pragma once 11 + #include "encoding.h" 12 + 13 + #ifdef __cplusplus 14 + extern "C" { 15 + #endif 16 + 17 + void 18 + opengloves_alpha_encoding_decode(const char *data, struct opengloves_input *out_kv); 19 + 20 + #ifdef __cplusplus 21 + } 22 + #endif
+71
src/xrt/drivers/opengloves/encoding/encoding.h
··· 1 + // Copyright 2019-2022, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief Defines for OpenGloves internal inputs 6 + * @author Daniel Willmott <web@dan-w.com> 7 + * @ingroup drv_opengloves 8 + */ 9 + 10 + #pragma once 11 + #include <stdbool.h> 12 + 13 + #define OPENGLOVES_ENCODING_MAX_ANALOG_VALUE 1023.0f 14 + #define OPENGLOVES_ENCODING_MAX_PACKET_SIZE 150 15 + 16 + #ifdef __cplusplus 17 + extern "C" { 18 + #endif 19 + 20 + 21 + struct opengloves_input_button 22 + { 23 + float value; 24 + bool pressed; 25 + }; 26 + 27 + struct opengloves_input_joystick 28 + { 29 + float x; 30 + float y; 31 + bool pressed; 32 + }; 33 + 34 + struct opengloves_input_gesture 35 + { 36 + bool activated; 37 + }; 38 + 39 + struct opengloves_input_buttons 40 + { 41 + struct opengloves_input_button A; 42 + struct opengloves_input_button B; 43 + struct opengloves_input_button trigger; 44 + struct opengloves_input_button menu; 45 + }; 46 + 47 + struct opengloves_input_joysticks 48 + { 49 + struct opengloves_input_joystick main; 50 + }; 51 + 52 + struct opengloves_input_gestures 53 + { 54 + struct opengloves_input_gesture grab; 55 + struct opengloves_input_gesture pinch; 56 + }; 57 + 58 + 59 + struct opengloves_input 60 + { 61 + float flexion[5][5]; 62 + float splay[5]; 63 + 64 + struct opengloves_input_joysticks joysticks; 65 + struct opengloves_input_buttons buttons; 66 + struct opengloves_input_gestures gestures; 67 + }; 68 + 69 + #ifdef __cplusplus 70 + } 71 + #endif
+290
src/xrt/drivers/opengloves/opengloves_device.c
··· 1 + // Copyright 2019-2022, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief OpenGloves device implementation. 6 + * @author Daniel Willmott <web@dan-w.com> 7 + * @ingroup drv_opengloves 8 + */ 9 + 10 + #include <stdio.h> 11 + 12 + #include "xrt/xrt_device.h" 13 + #include "xrt/xrt_defines.h" 14 + 15 + #include "util/u_device.h" 16 + #include "util/u_debug.h" 17 + #include "util/u_hand_tracking.h" 18 + #include "util/u_logging.h" 19 + #include "util/u_misc.h" 20 + #include "util/u_var.h" 21 + 22 + #include "opengloves_device.h" 23 + 24 + #include "communication/opengloves_communication.h" 25 + #include "encoding/alpha_encoding.h" 26 + 27 + DEBUG_GET_ONCE_LOG_OPTION(opengloves_log, "OPENGLOVES_LOG", U_LOGGING_INFO) 28 + 29 + 30 + #include "os/os_threading.h" 31 + 32 + #define OPENGLOVES_TRACE(d, ...) U_LOG_XDEV_IFL_T(&d->base, d->log_level, __VA_ARGS__) 33 + #define OPENGLOVES_DEBUG(d, ...) U_LOG_XDEV_IFL_D(&d->base, d->log_level, __VA_ARGS__) 34 + #define OPENGLOVES_INFO(d, ...) U_LOG_XDEV_IFL_I(&d->base, d->log_level, __VA_ARGS__) 35 + #define OPENGLOVES_WARN(d, ...) U_LOG_XDEV_IFL_W(&d->base, d->log_level, __VA_ARGS__) 36 + #define OPENGLOVES_ERROR(d, ...) U_LOG_XDEV_IFL_E(&d->base, d->log_level, __VA_ARGS__) 37 + 38 + enum opengloves_input_index 39 + { 40 + OPENGLOVES_INDEX_HAND_TRACKING, 41 + 42 + OPENGLOVES_INDEX_TRIGGER_CLICK, 43 + OPENGLOVES_INDEX_TRIGGER_VALUE, 44 + 45 + OPENGLOVES_INDEX_A_CLICK, 46 + OPENGLOVES_INDEX_B_CLICK, 47 + 48 + OPENGLOVES_INDEX_JOYSTICK_MAIN, 49 + OPENGLOVES_INDEX_JOYSTICK_MAIN_CLICK, 50 + 51 + OPENGLOVES_INDEX_COUNT 52 + }; 53 + 54 + /*! 55 + * @implements xrt_device 56 + */ 57 + struct opengloves_device 58 + { 59 + struct xrt_device base; 60 + struct opengloves_communication_device *ocd; 61 + 62 + struct os_thread_helper oth; 63 + struct os_mutex lock; 64 + 65 + struct opengloves_input *last_input; 66 + 67 + enum xrt_hand hand; 68 + 69 + struct u_hand_tracking hand_tracking; 70 + 71 + enum u_logging_level log_level; 72 + }; 73 + 74 + static inline struct opengloves_device * 75 + opengloves_device(struct xrt_device *xdev) 76 + { 77 + return (struct opengloves_device *)xdev; 78 + } 79 + 80 + static void 81 + opengloves_device_get_hand_tracking(struct xrt_device *xdev, 82 + enum xrt_input_name name, 83 + uint64_t requested_timestamp_ns, 84 + struct xrt_hand_joint_set *out_joint_set, 85 + uint64_t *out_timestamp_ns) 86 + { 87 + struct opengloves_device *od = opengloves_device(xdev); 88 + 89 + enum xrt_hand hand = od->hand; 90 + 91 + struct xrt_vec3 static_offset = {0, 0, 0}; 92 + struct u_hand_tracking_values values = {.little = 93 + { 94 + .splay = od->last_input->splay[4], 95 + .joint_count = 5, 96 + }, 97 + .ring = 98 + { 99 + .splay = od->last_input->splay[3], 100 + .joint_count = 5, 101 + }, 102 + .middle = 103 + { 104 + .splay = od->last_input->splay[2], 105 + .joint_count = 5, 106 + }, 107 + .index = 108 + { 109 + .splay = od->last_input->splay[1], 110 + .joint_count = 5, 111 + }, 112 + .thumb = { 113 + .splay = od->last_input->splay[0], 114 + .joint_count = 4, 115 + }}; 116 + // copy in the curls 117 + memcpy(values.little.joint_curls, od->last_input->flexion[4], sizeof(od->last_input->flexion[4])); 118 + memcpy(values.ring.joint_curls, od->last_input->flexion[3], sizeof(od->last_input->flexion[3])); 119 + memcpy(values.middle.joint_curls, od->last_input->flexion[2], sizeof(od->last_input->flexion[2])); 120 + memcpy(values.index.joint_curls, od->last_input->flexion[1], sizeof(od->last_input->flexion[1])); 121 + memcpy(values.thumb.joint_curls, od->last_input->flexion[0], sizeof(od->last_input->flexion[0])); 122 + 123 + u_hand_joints_update(&od->hand_tracking, hand, requested_timestamp_ns, &values); 124 + 125 + struct xrt_space_relation controller_relation = {.pose = {.orientation.w = 1.0f, .position = {0, 0, 0}}}; 126 + controller_relation.relation_flags = XRT_SPACE_RELATION_ORIENTATION_VALID_BIT | 127 + XRT_SPACE_RELATION_ORIENTATION_VALID_BIT | 128 + XRT_SPACE_RELATION_POSITION_VALID_BIT; 129 + 130 + struct xrt_pose hand_on_handle_pose; 131 + u_hand_joints_offset_valve_index_controller(hand, &static_offset, &hand_on_handle_pose); 132 + u_hand_joints_set_out_data(&od->hand_tracking, hand, &controller_relation, &hand_on_handle_pose, out_joint_set); 133 + 134 + 135 + *out_timestamp_ns = requested_timestamp_ns; 136 + out_joint_set->is_active = true; 137 + } 138 + 139 + static void 140 + opengloves_device_update_inputs(struct xrt_device *xdev) 141 + { 142 + struct opengloves_device *od = opengloves_device(xdev); 143 + 144 + os_mutex_lock(&od->lock); 145 + 146 + od->base.inputs[OPENGLOVES_INDEX_A_CLICK].value.boolean = od->last_input->buttons.A.pressed; 147 + od->base.inputs[OPENGLOVES_INDEX_B_CLICK].value.boolean = od->last_input->buttons.B.pressed; 148 + 149 + od->base.inputs[OPENGLOVES_INDEX_TRIGGER_CLICK].value.boolean = od->last_input->buttons.trigger.pressed; 150 + od->base.inputs[OPENGLOVES_INDEX_TRIGGER_VALUE].value.vec1.x = od->last_input->buttons.trigger.value; 151 + 152 + od->base.inputs[OPENGLOVES_INDEX_JOYSTICK_MAIN].value.vec2.x = od->last_input->joysticks.main.x; 153 + od->base.inputs[OPENGLOVES_INDEX_JOYSTICK_MAIN].value.vec2.y = od->last_input->joysticks.main.y; 154 + od->base.inputs[OPENGLOVES_INDEX_JOYSTICK_MAIN_CLICK].value.boolean = od->last_input->joysticks.main.pressed; 155 + 156 + os_mutex_unlock(&od->lock); 157 + } 158 + 159 + static void 160 + opengloves_device_destroy(struct xrt_device *xdev) 161 + { 162 + struct opengloves_device *od = opengloves_device(xdev); 163 + 164 + os_thread_helper_destroy(&od->oth); 165 + 166 + os_mutex_destroy(&od->lock); 167 + 168 + opengloves_communication_device_destory(od->ocd); 169 + 170 + free(od->last_input); 171 + free(od); 172 + } 173 + 174 + 175 + /*! 176 + * Reads the next packet from the device, finishing successfully when reaching a newline 177 + * Returns true if finished at a newline, or false if there was an error 178 + */ 179 + static bool 180 + opengloves_read_next_packet(struct opengloves_device *od, char *buffer, int buffer_len) 181 + { 182 + os_thread_helper_lock(&od->oth); 183 + 184 + char next_char = 0; 185 + int i = 0; 186 + do { 187 + // try read one byte 188 + int ret = opengloves_communication_device_read(od->ocd, &next_char, 1); 189 + if (ret < 0) { 190 + OPENGLOVES_ERROR(od, "Failed to read from device! %s", strerror(ret)); 191 + os_thread_helper_unlock(&od->oth); 192 + return false; 193 + } 194 + 195 + if (next_char == 0 || next_char == '\n') 196 + continue; 197 + 198 + buffer[i++] = next_char; 199 + } while (next_char != '\n' && i < buffer_len); 200 + 201 + // null terminate 202 + buffer[i] = '\0'; 203 + 204 + OPENGLOVES_DEBUG(od, "%s -> len %i", buffer, i); 205 + 206 + os_thread_helper_unlock(&od->oth); 207 + 208 + return true; 209 + } 210 + 211 + /*! 212 + * Main thread for reading data from the device 213 + */ 214 + static void * 215 + opengloves_run_thread(void *ptr) 216 + { 217 + struct opengloves_device *od = (struct opengloves_device *)ptr; 218 + 219 + char buffer[OPENGLOVES_ENCODING_MAX_PACKET_SIZE]; 220 + 221 + while (opengloves_read_next_packet(od, buffer, OPENGLOVES_ENCODING_MAX_PACKET_SIZE) && 222 + os_thread_helper_is_running(&od->oth)) { 223 + os_mutex_lock(&od->lock); 224 + opengloves_alpha_encoding_decode(buffer, od->last_input); 225 + os_mutex_unlock(&od->lock); 226 + } 227 + 228 + return 0; 229 + } 230 + 231 + struct xrt_device * 232 + opengloves_device_create(struct opengloves_communication_device *ocd, enum xrt_hand hand) 233 + { 234 + enum u_device_alloc_flags flags = (enum u_device_alloc_flags)(U_DEVICE_ALLOC_TRACKING_NONE); 235 + struct opengloves_device *od = U_DEVICE_ALLOCATE(struct opengloves_device, flags, 8, 0); 236 + 237 + od->base.name = XRT_DEVICE_HAND_TRACKER; 238 + od->base.device_type = XRT_DEVICE_TYPE_HAND_TRACKER; 239 + od->hand = hand; 240 + 241 + od->ocd = ocd; 242 + od->base.destroy = opengloves_device_destroy; 243 + os_mutex_init(&od->lock); 244 + 245 + // hand tracking 246 + od->base.get_hand_tracking = opengloves_device_get_hand_tracking; 247 + od->base.inputs[OPENGLOVES_INDEX_HAND_TRACKING].name = 248 + od->hand == XRT_HAND_LEFT ? XRT_INPUT_GENERIC_HAND_TRACKING_LEFT : XRT_INPUT_GENERIC_HAND_TRACKING_RIGHT; 249 + 250 + u_hand_joints_init_default_set(&od->hand_tracking, hand, XRT_HAND_TRACKING_MODEL_INTRINSIC, 1.0); 251 + od->base.hand_tracking_supported = true; 252 + 253 + // inputs 254 + od->base.update_inputs = opengloves_device_update_inputs; 255 + od->last_input = U_TYPED_CALLOC(struct opengloves_input); 256 + 257 + 258 + od->base.inputs[OPENGLOVES_INDEX_A_CLICK].name = XRT_INPUT_INDEX_A_CLICK; 259 + od->base.inputs[OPENGLOVES_INDEX_B_CLICK].name = XRT_INPUT_INDEX_B_CLICK; 260 + 261 + od->base.inputs[OPENGLOVES_INDEX_TRIGGER_VALUE].name = XRT_INPUT_INDEX_TRIGGER_VALUE; 262 + od->base.inputs[OPENGLOVES_INDEX_TRIGGER_CLICK].name = XRT_INPUT_INDEX_TRIGGER_CLICK; 263 + 264 + od->base.inputs[OPENGLOVES_INDEX_JOYSTICK_MAIN].name = XRT_INPUT_INDEX_THUMBSTICK; 265 + od->base.inputs[OPENGLOVES_INDEX_JOYSTICK_MAIN_CLICK].name = XRT_INPUT_INDEX_THUMBSTICK_CLICK; 266 + 267 + // startup thread 268 + int ret = os_thread_helper_init(&od->oth); 269 + if (ret != 0) { 270 + OPENGLOVES_ERROR(od, "Failed to initialise threading!"); 271 + opengloves_device_destroy(&od->base); 272 + return NULL; 273 + } 274 + 275 + ret = os_thread_helper_start(&od->oth, opengloves_run_thread, od); 276 + if (ret != 0) { 277 + OPENGLOVES_ERROR(od, "Failed to start thread!"); 278 + opengloves_device_destroy(&od->base); 279 + 280 + return 0; 281 + } 282 + 283 + u_var_add_root(od, "OpenGloves VR glove device", true); 284 + snprintf(od->base.serial, XRT_DEVICE_NAME_LEN, "OpenGloves %s", hand == XRT_HAND_LEFT ? "Left" : "Right"); 285 + 286 + od->log_level = debug_get_log_option_opengloves_log(); 287 + 288 + 289 + return &od->base; 290 + }
+24
src/xrt/drivers/opengloves/opengloves_device.h
··· 1 + // Copyright 2019-2022, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief OpenGloves device. 6 + * @author Daniel Willmott <web@dan-w.com> 7 + * @ingroup drv_opengloves 8 + */ 9 + 10 + #pragma once 11 + #include "util/u_logging.h" 12 + #include "xrt/xrt_device.h" 13 + #include "communication/opengloves_communication.h" 14 + 15 + #ifdef __cplusplus 16 + extern "C" { 17 + #endif 18 + 19 + struct xrt_device * 20 + opengloves_device_create(struct opengloves_communication_device *ocd, enum xrt_hand hand); 21 + 22 + #ifdef __cplusplus 23 + } 24 + #endif
+36
src/xrt/drivers/opengloves/opengloves_interface.h
··· 1 + // Copyright 2019-2022, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief OpenGloves device interface. 6 + * @author Daniel Willmott <web@dan-w.com> 7 + * @ingroup drv_opengloves 8 + */ 9 + 10 + #pragma once 11 + 12 + #ifdef __cplusplus 13 + extern "C" { 14 + #endif 15 + 16 + struct u_system_devices; 17 + 18 + /*! 19 + * @defgroup drv_opengloves OpenGloves Driver for VR Gloves 20 + * @ingroup drv 21 + * 22 + * @brief Driver for OpenGloves VR Gloves Devices 23 + */ 24 + 25 + int 26 + opengloves_create_devices(struct xrt_device **out_xdevs, const struct xrt_system_devices *sysdevs); 27 + 28 + /*! 29 + * @dir drivers/opengloves 30 + * 31 + * @brief @ref drv_opengloves files. 32 + */ 33 + 34 + #ifdef __cplusplus 35 + } 36 + #endif
+116
src/xrt/drivers/opengloves/opengloves_prober.c
··· 1 + // Copyright 2019-2022, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief OpenGloves prober implementation. 6 + * @author Daniel Willmott <web@dan-w.com> 7 + * @ingroup drv_opengloves 8 + */ 9 + 10 + #include "xrt/xrt_prober.h" 11 + #include "xrt/xrt_defines.h" 12 + 13 + #include "util/u_config_json.h" 14 + #include "util/u_debug.h" 15 + #include "util/u_system_helpers.h" 16 + 17 + 18 + #include "opengloves_interface.h" 19 + #include "opengloves_device.h" 20 + 21 + #include "communication/serial/opengloves_prober_serial.h" 22 + #include "communication/bluetooth/opengloves_prober_bt.h" 23 + 24 + #include "../multi_wrapper/multi.h" 25 + 26 + #define OPENGLOVES_PROBER_LOG_LEVEL U_LOGGING_TRACE 27 + 28 + #define OPENGLOVES_ERROR(...) U_LOG_IFL_E(OPENGLOVES_PROBER_LOG_LEVEL, __VA_ARGS__) 29 + #define OPENGLOVES_INFO(...) U_LOG_IFL_I(OPENGLOVES_PROBER_LOG_LEVEL, __VA_ARGS__) 30 + 31 + #define JSON_VEC3(a, b, c) u_json_get_vec3_array(u_json_get(a, b), c) 32 + #define JSON_QUAT(a, b, c) u_json_get_quat(u_json_get(a, b), c) 33 + 34 + 35 + static const cJSON * 36 + opengloves_load_config_file(struct u_config_json config_json) 37 + { 38 + u_config_json_open_or_create_main_file(&config_json); 39 + if (!config_json.file_loaded) { 40 + OPENGLOVES_ERROR("Failed to load config file"); 41 + return NULL; 42 + } 43 + 44 + const cJSON *out_config_json = u_json_get(config_json.root, "config_opengloves"); 45 + if (out_config_json == NULL) { 46 + return NULL; 47 + } 48 + 49 + return out_config_json; 50 + } 51 + 52 + int 53 + opengloves_create_devices(struct xrt_device **out_xdevs, const struct xrt_system_devices *sysdevs) 54 + { 55 + struct xrt_device *dev_left = NULL; 56 + struct xrt_device *dev_right = NULL; 57 + 58 + // first check for serial devices 59 + struct opengloves_communication_device *ocd_left = NULL; 60 + struct opengloves_communication_device *ocd_right = NULL; 61 + 62 + // try to find serial devices 63 + opengloves_get_serial_devices(LUCIDGLOVES_USB_VID, LUCIDGLOVES_USB_L_PID, &ocd_left); 64 + opengloves_get_serial_devices(LUCIDGLOVES_USB_VID, LUCIDGLOVES_USB_R_PID, &ocd_right); 65 + 66 + 67 + // if comm device is still null try search for bluetooth devices to fill it 68 + if (ocd_left == NULL) 69 + opengloves_get_bt_devices(LUCIDGLOVES_BT_L_NAME, &ocd_left); 70 + if (ocd_right == NULL) 71 + opengloves_get_bt_devices(LUCIDGLOVES_BT_R_NAME, &ocd_right); 72 + 73 + // now try to create the device if we've found a communication device 74 + if (ocd_left != NULL) 75 + dev_left = opengloves_device_create(ocd_left, XRT_HAND_LEFT); 76 + if (ocd_right != NULL) 77 + dev_right = opengloves_device_create(ocd_right, XRT_HAND_RIGHT); 78 + 79 + // load config 80 + struct u_config_json config_json = {0}; 81 + const cJSON *opengloves_config_json = opengloves_load_config_file(config_json); 82 + 83 + // set up tracking overrides 84 + int cur_dev = 0; 85 + if (dev_left != NULL && sysdevs->roles.left != NULL) { 86 + struct xrt_quat rot = XRT_QUAT_IDENTITY; 87 + struct xrt_vec3 pos = XRT_VEC3_ZERO; 88 + JSON_QUAT(opengloves_config_json, "offset_rot_right", &rot); 89 + JSON_VEC3(opengloves_config_json, "offset_pos_right", &pos); 90 + 91 + struct xrt_pose offset_pose = {.orientation = rot, .position = pos}; 92 + 93 + struct xrt_device *dev_wrap = 94 + multi_create_tracking_override(XRT_TRACKING_OVERRIDE_DIRECT, dev_left, sysdevs->roles.left, 95 + XRT_INPUT_GENERIC_TRACKER_POSE, &offset_pose); 96 + 97 + out_xdevs[cur_dev++] = dev_wrap; 98 + } 99 + 100 + if (dev_right != NULL && sysdevs->roles.right != NULL) { 101 + struct xrt_quat rot = XRT_QUAT_IDENTITY; 102 + struct xrt_vec3 pos = XRT_VEC3_ZERO; 103 + JSON_QUAT(opengloves_config_json, "offset_rot_right", &rot); 104 + JSON_VEC3(opengloves_config_json, "offset_pos_right", &pos); 105 + 106 + struct xrt_pose offset_pose = {.orientation = rot, .position = pos}; 107 + 108 + struct xrt_device *dev_wrap = 109 + multi_create_tracking_override(XRT_TRACKING_OVERRIDE_DIRECT, dev_left, sysdevs->roles.left, 110 + XRT_INPUT_GENERIC_TRACKER_POSE, &offset_pose); 111 + 112 + out_xdevs[cur_dev++] = dev_wrap; 113 + } 114 + 115 + return cur_dev; 116 + }