The open source OpenXR runtime
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

d/ulv5: Add UltraLeap v5 driver

authored by

0y8w1x and committed by
Jakob Bornecrantz
66e8db5d fa06aa6c

+393
+4
CMakeLists.txt
··· 106 106 find_package(ZLIB MODULE) 107 107 find_package(cJSON MODULE) 108 108 find_package(LeapV2 MODULE) 109 + find_package(LeapSDK 5) 109 110 find_package(ONNXRuntime MODULE) 110 111 if(NOT WIN32) 111 112 find_package(EGL MODULE) ··· 346 347 option_with_deps(XRT_BUILD_DRIVER_STEAMVR_LIGHTHOUSE "Enable SteamVR Lighthouse driver" DEPENDS XRT_HAVE_LINUX XRT_HAVE_STEAM XRT_MODULE_AUX_VIVE) 347 348 option_with_deps(XRT_BUILD_DRIVER_SURVIVE "Enable libsurvive driver" DEPENDS SURVIVE_FOUND XRT_MODULE_AUX_VIVE) 348 349 option_with_deps(XRT_BUILD_DRIVER_ULV2 "Enable Ultraleap v2 driver" DEPENDS LeapV2_FOUND) 350 + option_with_deps(XRT_BUILD_DRIVER_ULV5 "Enable Ultraleap v5 driver" DEPENDS LeapSDK_FOUND) 349 351 option_with_deps(XRT_BUILD_DRIVER_VF "Build video frame driver (for video file support, uses gstreamer)" DEPENDS XRT_HAVE_GST) 350 352 option_with_deps(XRT_BUILD_DRIVER_VIVE "Enable driver for HTC Vive, Vive Pro, Valve Index, and their controllers" DEPENDS ZLIB_FOUND XRT_HAVE_LINUX XRT_MODULE_AUX_VIVE) 351 353 option_with_deps(XRT_BUILD_DRIVER_WMR "Enable Windows Mixed Reality driver" DEPENDS "NOT WIN32") ··· 461 463 "SURVIVE" 462 464 "V4L2" 463 465 "ULV2" 466 + "ULV5" 464 467 "VF" 465 468 "DEPTHAI" 466 469 "VIVE" ··· 675 678 message(STATUS "# DRIVER_SURVIVE: ${XRT_BUILD_DRIVER_SURVIVE}") 676 679 message(STATUS "# DRIVER_TWRAP: ${XRT_BUILD_DRIVER_TWRAP}") 677 680 message(STATUS "# DRIVER_ULV2: ${XRT_BUILD_DRIVER_ULV2}") 681 + message(STATUS "# DRIVER_ULV5: ${XRT_BUILD_DRIVER_ULV5}") 678 682 message(STATUS "# DRIVER_VF: ${XRT_BUILD_DRIVER_VF}") 679 683 message(STATUS "# DRIVER_VIVE: ${XRT_BUILD_DRIVER_VIVE}") 680 684 message(STATUS "# DRIVER_WMR: ${XRT_BUILD_DRIVER_WMR}")
+5
src/xrt/drivers/CMakeLists.txt
··· 127 127 target_link_libraries(drv_ulv2 PRIVATE xrt-interfaces aux_util aux_math LeapV2::LeapV2) 128 128 endif() 129 129 130 + if(XRT_BUILD_DRIVER_ULV5) 131 + add_library(drv_ulv5 STATIC ultraleap_v5/ulv5_driver.cpp ultraleap_v5/ulv5_interface.h) 132 + target_link_libraries(drv_ulv5 PRIVATE xrt-interfaces aux_util aux_math LeapSDK::LeapC) 133 + endif() 134 + 130 135 if(XRT_BUILD_DRIVER_OHMD) 131 136 add_library( 132 137 drv_ohmd STATIC ohmd/oh_device.c ohmd/oh_device.h ohmd/oh_interface.h
+336
src/xrt/drivers/ultraleap_v5/ulv5_driver.cpp
··· 1 + // Copyright 2023, Joseph Albers. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief Driver for Ultraleap's V5 API for the Leap Motion Controller. 6 + * @author Joseph Albers <joseph.albers@outlook.de> 7 + * @ingroup drv_ulv5 8 + */ 9 + 10 + #include "ulv5_interface.h" 11 + #include "util/u_device.h" 12 + #include "util/u_var.h" 13 + #include "util/u_debug.h" 14 + #include "math/m_space.h" 15 + #include "math/m_api.h" 16 + #include "util/u_time.h" 17 + #include "os/os_time.h" 18 + #include "os/os_threading.h" 19 + 20 + #include "LeapC.h" 21 + 22 + DEBUG_GET_ONCE_LOG_OPTION(ulv5_log, "ULV5_LOG", U_LOGGING_INFO) 23 + 24 + #define ULV5_TRACE(ulv5d, ...) U_LOG_XDEV_IFL_T(&ulv5d->base, ulv5d->log_level, __VA_ARGS__) 25 + #define ULV5_DEBUG(ulv5d, ...) U_LOG_XDEV_IFL_D(&ulv5d->base, ulv5d->log_level, __VA_ARGS__) 26 + #define ULV5_INFO(ulv5d, ...) U_LOG_XDEV_IFL_I(&ulv5d->base, ulv5d->log_level, __VA_ARGS__) 27 + #define ULV5_WARN(ulv5d, ...) U_LOG_XDEV_IFL_W(&ulv5d->base, ulv5d->log_level, __VA_ARGS__) 28 + #define ULV5_ERROR(ulv5d, ...) U_LOG_XDEV_IFL_E(&ulv5d->base, ulv5d->log_level, __VA_ARGS__) 29 + 30 + extern "C" { 31 + 32 + const char * 33 + leap_result_to_string(eLeapRS result) 34 + { 35 + switch (result) { 36 + case eLeapRS_Success: return "eLeapRS_Success"; 37 + case eLeapRS_UnknownError: return "eLeapRS_UnknownError"; 38 + case eLeapRS_InvalidArgument: return "eLeapRS_InvalidArgument"; 39 + case eLeapRS_InsufficientResources: return "eLeapRS_InsufficientResources"; 40 + case eLeapRS_InsufficientBuffer: return "eLeapRS_InsufficientBuffer"; 41 + case eLeapRS_Timeout: return "eLeapRS_Timeout"; 42 + case eLeapRS_NotConnected: return "eLeapRS_NotConnected"; 43 + case eLeapRS_HandshakeIncomplete: return "eLeapRS_HandshakeIncomplete"; 44 + case eLeapRS_BufferSizeOverflow: return "eLeapRS_BufferSizeOverflow"; 45 + case eLeapRS_ProtocolError: return "eLeapRS_ProtocolError"; 46 + case eLeapRS_InvalidClientID: return "eLeapRS_InvalidClientID"; 47 + case eLeapRS_UnexpectedClosed: return "eLeapRS_UnexpectedClosed"; 48 + case eLeapRS_UnknownImageFrameRequest: return "eLeapRS_UnknownImageFrameRequest"; 49 + case eLeapRS_UnknownTrackingFrameID: return "eLeapRS_UnknownTrackingFrameID"; 50 + case eLeapRS_RoutineIsNotSeer: return "eLeapRS_RoutineIsNotSeer"; 51 + case eLeapRS_TimestampTooEarly: return "eLeapRS_TimestampTooEarly"; 52 + case eLeapRS_ConcurrentPoll: return "eLeapRS_ConcurrentPoll"; 53 + case eLeapRS_NotAvailable: return "eLeapRS_NotAvailable"; 54 + case eLeapRS_NotStreaming: return "eLeapRS_NotStreaming"; 55 + case eLeapRS_CannotOpenDevice: return "eLeapRS_CannotOpenDevice"; 56 + default: return "unknown result type."; 57 + } 58 + } 59 + 60 + static const enum xrt_space_relation_flags valid_flags = (enum xrt_space_relation_flags)( 61 + XRT_SPACE_RELATION_ORIENTATION_VALID_BIT | XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT | 62 + XRT_SPACE_RELATION_POSITION_VALID_BIT | XRT_SPACE_RELATION_POSITION_TRACKED_BIT); 63 + 64 + 65 + struct ulv5_device 66 + { 67 + struct xrt_device base; 68 + 69 + struct xrt_tracking_origin tracking_origin; 70 + 71 + enum u_logging_level log_level; 72 + 73 + bool stop_frame_polling_thread; 74 + 75 + struct os_thread_helper oth; 76 + 77 + struct xrt_hand_joint_set joint_set[2]; 78 + 79 + bool hand_exists[2]; 80 + 81 + // LEAP_CONNECTION *leap_connection; 82 + }; 83 + 84 + inline struct ulv5_device * 85 + ulv5_device(struct xrt_device *xdev) 86 + { 87 + return (struct ulv5_device *)xdev; 88 + } 89 + 90 + static void 91 + ulv5_device_update_inputs(struct xrt_device *xdev) 92 + { 93 + // Empty 94 + } 95 + 96 + static void 97 + ulv5_device_get_hand_tracking(struct xrt_device *xdev, 98 + enum xrt_input_name name, 99 + uint64_t at_timestamp_ns, 100 + struct xrt_hand_joint_set *out_value, 101 + uint64_t *out_timestamp_ns) 102 + { 103 + struct ulv5_device *ulv5d = ulv5_device(xdev); 104 + 105 + if (name != XRT_INPUT_GENERIC_HAND_TRACKING_LEFT && name != XRT_INPUT_GENERIC_HAND_TRACKING_RIGHT) { 106 + ULV5_ERROR(ulv5d, "unknown input name for hand tracker"); 107 + return; 108 + } 109 + 110 + bool hand_index = (name == XRT_INPUT_GENERIC_HAND_TRACKING_RIGHT); // 0 if left, 1 if right. 111 + 112 + bool hand_valid = ulv5d->hand_exists[hand_index]; 113 + 114 + os_thread_helper_lock(&ulv5d->oth); 115 + memcpy(out_value, &ulv5d->joint_set[hand_index], sizeof(struct xrt_hand_joint_set)); 116 + hand_valid = ulv5d->hand_exists[hand_index]; 117 + os_thread_helper_unlock(&ulv5d->oth); 118 + m_space_relation_ident(&out_value->hand_pose); 119 + 120 + if (hand_valid) { 121 + out_value->is_active = true; 122 + out_value->hand_pose.relation_flags = valid_flags; 123 + } else { 124 + out_value->is_active = false; 125 + } 126 + // still a lie... 127 + *out_timestamp_ns = at_timestamp_ns; 128 + } 129 + 130 + // todo: cleanly shutdown the LEAP_CONNECTION 131 + static void 132 + ulv5_device_destroy(struct xrt_device *xdev) 133 + { 134 + struct ulv5_device *ulv5d = ulv5_device(xdev); 135 + 136 + ulv5d->stop_frame_polling_thread = true; 137 + 138 + // Destroy also stops the thread. 139 + os_thread_helper_destroy(&ulv5d->oth); 140 + 141 + // Remove the variable tracking. 142 + u_var_remove_root(ulv5d); 143 + 144 + u_device_free(&ulv5d->base); 145 + } 146 + 147 + static void 148 + ulv5_process_joint(LEAP_VECTOR joint_pos, 149 + LEAP_QUATERNION joint_orientation, 150 + float width, 151 + struct xrt_hand_joint_value *joint) 152 + { 153 + joint->radius = (width / 1000) / 2; 154 + 155 + struct xrt_space_relation *relation = &joint->relation; 156 + relation->pose.position.x = joint_pos.x * -1 / 1000.0; 157 + relation->pose.position.y = joint_pos.z * -1 / 1000.0; 158 + relation->pose.position.z = joint_pos.y * -1 / 1000.0; 159 + relation->relation_flags = valid_flags; 160 + } 161 + 162 + void 163 + ulv5_process_hand(LEAP_HAND hand, struct ulv5_device *ulv5d, int handedness) 164 + { 165 + struct xrt_hand_joint_set dummy_joint_set; 166 + // gives access to individual joints of the joint_set 167 + #define dummy_joint_set(y) &dummy_joint_set.values.hand_joint_set_default[XRT_HAND_JOINT_##y] 168 + 169 + ulv5_process_joint(hand.palm.position, hand.palm.orientation, hand.palm.width, dummy_joint_set(PALM)); 170 + // wrist is the next_joint of the arm 171 + ulv5_process_joint(hand.arm.next_joint, hand.arm.rotation, hand.arm.width, dummy_joint_set(WRIST)); 172 + // thumb 173 + ulv5_process_joint(hand.thumb.proximal.prev_joint, hand.thumb.proximal.rotation, hand.thumb.proximal.width, 174 + dummy_joint_set(THUMB_METACARPAL)); 175 + ulv5_process_joint(hand.thumb.intermediate.prev_joint, hand.thumb.intermediate.rotation, 176 + hand.thumb.intermediate.width, dummy_joint_set(THUMB_PROXIMAL)); 177 + ulv5_process_joint(hand.thumb.distal.prev_joint, hand.thumb.distal.rotation, hand.thumb.distal.width, 178 + dummy_joint_set(THUMB_DISTAL)); 179 + ulv5_process_joint(hand.thumb.distal.next_joint, hand.thumb.distal.rotation, hand.thumb.distal.width, 180 + dummy_joint_set(THUMB_TIP)); 181 + // index 182 + ulv5_process_joint(hand.index.metacarpal.prev_joint, hand.index.metacarpal.rotation, 183 + hand.index.metacarpal.width, dummy_joint_set(INDEX_METACARPAL)); 184 + ulv5_process_joint(hand.index.proximal.prev_joint, hand.index.proximal.rotation, hand.index.proximal.width, 185 + dummy_joint_set(INDEX_PROXIMAL)); 186 + ulv5_process_joint(hand.index.intermediate.prev_joint, hand.index.intermediate.rotation, 187 + hand.index.intermediate.width, dummy_joint_set(INDEX_INTERMEDIATE)); 188 + ulv5_process_joint(hand.index.distal.prev_joint, hand.index.distal.rotation, hand.index.distal.width, 189 + dummy_joint_set(INDEX_DISTAL)); 190 + ulv5_process_joint(hand.index.distal.next_joint, hand.index.distal.rotation, hand.index.distal.width, 191 + dummy_joint_set(INDEX_TIP)); 192 + // middle 193 + ulv5_process_joint(hand.middle.metacarpal.prev_joint, hand.middle.metacarpal.rotation, 194 + hand.middle.metacarpal.width, dummy_joint_set(MIDDLE_METACARPAL)); 195 + ulv5_process_joint(hand.middle.proximal.prev_joint, hand.middle.proximal.rotation, hand.middle.proximal.width, 196 + dummy_joint_set(MIDDLE_PROXIMAL)); 197 + ulv5_process_joint(hand.middle.intermediate.prev_joint, hand.middle.intermediate.rotation, 198 + hand.middle.intermediate.width, dummy_joint_set(MIDDLE_INTERMEDIATE)); 199 + ulv5_process_joint(hand.middle.distal.prev_joint, hand.middle.distal.rotation, hand.middle.distal.width, 200 + dummy_joint_set(MIDDLE_DISTAL)); 201 + ulv5_process_joint(hand.middle.distal.next_joint, hand.middle.distal.rotation, hand.middle.distal.width, 202 + dummy_joint_set(MIDDLE_TIP)); 203 + // ring 204 + ulv5_process_joint(hand.ring.metacarpal.prev_joint, hand.ring.metacarpal.rotation, hand.ring.metacarpal.width, 205 + dummy_joint_set(RING_METACARPAL)); 206 + ulv5_process_joint(hand.ring.proximal.prev_joint, hand.ring.proximal.rotation, hand.ring.proximal.width, 207 + dummy_joint_set(RING_PROXIMAL)); 208 + ulv5_process_joint(hand.ring.intermediate.prev_joint, hand.ring.intermediate.rotation, 209 + hand.ring.intermediate.width, dummy_joint_set(RING_INTERMEDIATE)); 210 + ulv5_process_joint(hand.ring.distal.prev_joint, hand.ring.distal.rotation, hand.ring.distal.width, 211 + dummy_joint_set(RING_DISTAL)); 212 + ulv5_process_joint(hand.ring.distal.next_joint, hand.ring.distal.rotation, hand.ring.distal.width, 213 + dummy_joint_set(RING_TIP)); 214 + // pinky 215 + ulv5_process_joint(hand.pinky.metacarpal.prev_joint, hand.pinky.metacarpal.rotation, 216 + hand.pinky.metacarpal.width, dummy_joint_set(LITTLE_METACARPAL)); 217 + ulv5_process_joint(hand.pinky.proximal.prev_joint, hand.pinky.proximal.rotation, hand.pinky.proximal.width, 218 + dummy_joint_set(LITTLE_PROXIMAL)); 219 + ulv5_process_joint(hand.pinky.intermediate.prev_joint, hand.pinky.intermediate.rotation, 220 + hand.pinky.intermediate.width, dummy_joint_set(LITTLE_INTERMEDIATE)); 221 + ulv5_process_joint(hand.pinky.distal.prev_joint, hand.pinky.distal.rotation, hand.pinky.distal.width, 222 + dummy_joint_set(LITTLE_DISTAL)); 223 + ulv5_process_joint(hand.pinky.distal.next_joint, hand.pinky.distal.rotation, hand.pinky.distal.width, 224 + dummy_joint_set(LITTLE_TIP)); 225 + 226 + // copy over to ulv5d joint set 227 + os_thread_helper_lock(&ulv5d->oth); 228 + memcpy(&ulv5d->joint_set[handedness], &dummy_joint_set, sizeof(struct xrt_hand_joint_set)); 229 + os_thread_helper_unlock(&ulv5d->oth); 230 + } 231 + 232 + void * 233 + leap_input_loop(void *ptr_to_xdev) 234 + { 235 + struct xrt_device *xdev = (struct xrt_device *)ptr_to_xdev; 236 + struct ulv5_device *ulv5d = ulv5_device(xdev); 237 + 238 + LEAP_CONNECTION connection; 239 + if (LeapCreateConnection(NULL, &connection) == eLeapRS_Success) 240 + ULV5_INFO(ulv5d, "created leap connection."); 241 + if (LeapOpenConnection(connection) == eLeapRS_Success) 242 + ULV5_INFO(ulv5d, "opened leap connection to background service."); 243 + if (LeapSetTrackingMode(connection, eLeapTrackingMode_HMD) == eLeapRS_Success) 244 + ULV5_INFO(ulv5d, "set tracking mode to HMD use."); 245 + 246 + // check if the leap hardware is connected 247 + uint32_t num_connected_devices = 0; 248 + for (int i = 0; i < 5; i++) { 249 + LEAP_CONNECTION_MESSAGE msg; 250 + LeapPollConnection(connection, 1000, &msg); 251 + LeapGetDeviceList(connection, NULL, &num_connected_devices); 252 + 253 + if (num_connected_devices > 0) { 254 + break; 255 + } 256 + 257 + ULV5_INFO(ulv5d, "waiting for leap USB connection..."); 258 + } 259 + if (num_connected_devices == 0) 260 + ULV5_ERROR(ulv5d, "leap hardware is physically not connected."); 261 + 262 + // main loop, polling the message queue of leap background service 263 + LEAP_CONNECTION_MESSAGE msg; 264 + const LEAP_TRACKING_EVENT *tracking_event; 265 + unsigned int timeout = 1000; 266 + eLeapRS result; 267 + while (!ulv5d->stop_frame_polling_thread) { 268 + result = LeapPollConnection(connection, timeout, &msg); 269 + 270 + if (result != eLeapRS_Success) 271 + ULV5_ERROR(ulv5d, 272 + "LeapPollConnection returned %s\n" 273 + "TIP: make sure you are connected to a full USB2.0 bandwidth port" 274 + "(not a HUB with multiple devices connected)", 275 + leap_result_to_string(result)); 276 + 277 + // only care about hand tracking data 278 + if (msg.type == eLeapEventType_Tracking) { 279 + tracking_event = msg.tracking_event; 280 + 281 + uint32_t num_hands = tracking_event->nHands; 282 + LEAP_HAND *hands = tracking_event->pHands; 283 + 284 + for (uint32_t i = 0; i < num_hands; i++) { 285 + int handedness = hands[i].type; 286 + ulv5_process_hand(hands[i], ulv5d, handedness); 287 + ulv5d->hand_exists[handedness] = true; 288 + } 289 + } 290 + } 291 + } 292 + 293 + xrt_result_t 294 + ulv5_create_device(struct xrt_device **out_xdev) 295 + { 296 + enum u_device_alloc_flags flags = U_DEVICE_ALLOC_NO_FLAGS; 297 + int num_hands = 2; 298 + 299 + struct ulv5_device *ulv5d = U_DEVICE_ALLOCATE(struct ulv5_device, flags, num_hands, 0); 300 + 301 + os_thread_helper_init(&ulv5d->oth); 302 + os_thread_helper_start(&ulv5d->oth, (&leap_input_loop), (void *)&ulv5d->base); 303 + 304 + ulv5d->base.tracking_origin = &ulv5d->tracking_origin; 305 + ulv5d->base.tracking_origin->type = XRT_TRACKING_TYPE_OTHER; 306 + 307 + math_pose_identity(&ulv5d->base.tracking_origin->offset); 308 + 309 + ulv5d->log_level = debug_get_log_option_ulv5_log(); 310 + 311 + ulv5d->base.update_inputs = ulv5_device_update_inputs; 312 + ulv5d->base.get_hand_tracking = ulv5_device_get_hand_tracking; 313 + ulv5d->base.destroy = ulv5_device_destroy; 314 + 315 + strncpy(ulv5d->base.str, "Leap Motion v5 driver", XRT_DEVICE_NAME_LEN); 316 + strncpy(ulv5d->base.serial, "Leap Motion v5 driver", XRT_DEVICE_NAME_LEN); 317 + 318 + ulv5d->base.inputs[0].name = XRT_INPUT_GENERIC_HAND_TRACKING_LEFT; 319 + ulv5d->base.inputs[1].name = XRT_INPUT_GENERIC_HAND_TRACKING_RIGHT; 320 + 321 + ulv5d->base.name = XRT_DEVICE_HAND_TRACKER; 322 + 323 + ulv5d->base.device_type = XRT_DEVICE_TYPE_HAND_TRACKER; 324 + ulv5d->base.hand_tracking_supported = true; 325 + 326 + u_var_add_root(ulv5d, "Leap Motion v5 driver", true); 327 + u_var_add_ro_text(ulv5d, ulv5d->base.str, "Name"); 328 + 329 + ULV5_INFO(ulv5d, "Hand Tracker initialized!"); 330 + 331 + out_xdev[0] = &ulv5d->base; 332 + 333 + return XRT_SUCCESS; 334 + } 335 + 336 + } // extern "C"
+40
src/xrt/drivers/ultraleap_v5/ulv5_interface.h
··· 1 + // Copyright 2023, Joseph Albers. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief Driver for Ultraleap's V5 API for the Leap Motion Controller. 6 + * @author Joseph Albers <joseph.albers@outlook.de> 7 + * @ingroup drv_ulv5 8 + */ 9 + 10 + #pragma once 11 + 12 + #include "math/m_api.h" 13 + #include "xrt/xrt_device.h" 14 + #include "xrt/xrt_prober.h" 15 + 16 + #ifdef __cplusplus 17 + extern "C" { 18 + #endif 19 + 20 + #define ULV5_VID 0x2936 21 + #define ULV5_PID 0x1202 22 + 23 + /*! 24 + * @defgroup drv_ulv5 Leap Motion Controller driver 25 + * @ingroup drv 26 + * 27 + * @brief Leap Motion Controller driver using Ultraleap's V5 API 28 + */ 29 + 30 + /*! 31 + * Probing function for Leap Motion Controller. 32 + * 33 + * @ingroup drv_ulv5 34 + * @see xrt_prober_found_func_t 35 + */ 36 + xrt_result_t 37 + ulv5_create_device(struct xrt_device **out_xdev); 38 + #ifdef __cplusplus 39 + } 40 + #endif
+4
src/xrt/targets/common/CMakeLists.txt
··· 109 109 target_link_libraries(target_lists PRIVATE drv_ulv2) 110 110 endif() 111 111 112 + if(XRT_BUILD_DRIVER_ULV5) 113 + target_link_libraries(target_lists PRIVATE drv_ulv5) 114 + endif() 115 + 112 116 if(XRT_BUILD_DRIVER_OHMD) 113 117 target_link_libraries(target_lists PRIVATE drv_ohmd) 114 118 endif()
+4
src/xrt/targets/common/target_lists.c
··· 72 72 #include "ultraleap_v2/ulv2_interface.h" 73 73 #endif 74 74 75 + #ifdef XRT_BUILD_DRIVER_ULV5 76 + #include "ultraleap_v5/ulv5_interface.h" 77 + #endif 78 + 75 79 #ifdef XRT_BUILD_DRIVER_DEPTHAI 76 80 #include "depthai/depthai_interface.h" 77 81 #endif