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