diff --git a/CMakeLists.txt b/CMakeLists.txt index c701e44..e19c493 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,12 @@ include(cmake/XLinkDependencies.cmake) # Link to libusb target_link_libraries(${TARGET_NAME} PRIVATE usb-1.0) +if(WIN32 AND NOT MINGW) + # needs minor fixes so that target_link_options/STATIC_LIBRARY_OPTIONS + # only puts the options on the thing that "contains" XLink executable bytes + target_link_libraries(${TARGET_NAME} PRIVATE delayimp.lib Pathcch.lib) + target_link_options(${TARGET_NAME} PUBLIC "/DELAYLOAD:libusb-1.0$<$:d>.dll") +endif() if(WIN32) target_compile_definitions(${TARGET_NAME} PRIVATE WIN32_LEAN_AND_MEAN) diff --git a/cmake/XLink.cmake b/cmake/XLink.cmake index 19573c1..fc0ccee 100644 --- a/cmake/XLink.cmake +++ b/cmake/XLink.cmake @@ -16,7 +16,8 @@ if(WIN32) set(XLINK_PLATFORM_INCLUDE ${XLINK_ROOT_DIR}/src/pc/Win/include) file(GLOB XLINK_PLATFORM_SRC "${XLINK_ROOT_DIR}/src/pc/Win/src/*.c") - list(APPEND XLINK_SOURCES ${XLINK_PLATFORM_SRC}) + file(GLOB XLINK_PLATFORM_SRC_CPP "${XLINK_ROOT_DIR}/src/pc/Win/src/*.cpp") + list(APPEND XLINK_SOURCES ${XLINK_PLATFORM_SRC} ${XLINK_PLATFORM_SRC_CPP}) endif() if(APPLE) diff --git a/include/XLink/XLinkPlatform.h b/include/XLink/XLinkPlatform.h index 70007b3..e22f600 100644 --- a/include/XLink/XLinkPlatform.h +++ b/include/XLink/XLinkPlatform.h @@ -38,7 +38,7 @@ typedef enum { // Device management. Begin. // ------------------------------------ -void XLinkPlatformInit(void* options); +xLinkPlatformErrorCode_t XLinkPlatformInit(void* options); #ifndef __DEVICE__ /** diff --git a/src/pc/PlatformDeviceControl.c b/src/pc/PlatformDeviceControl.c index 8462f8d..2932ee3 100644 --- a/src/pc/PlatformDeviceControl.c +++ b/src/pc/PlatformDeviceControl.c @@ -85,9 +85,11 @@ static int tcpipPlatformBootFirmware(const deviceDesc_t* deviceDesc, const char* // XLinkPlatform API implementation. Begin. // ------------------------------------ -void XLinkPlatformInit(void* options) +xLinkPlatformErrorCode_t XLinkPlatformInit(void* options) { - usbInitialize(options); + // check for failed initialization; LIBUSB_SUCCESS = 0 + if (usbInitialize(options) != 0) + return X_LINK_PLATFORM_DRIVER_NOT_LOADED; // TODO(themarpe) - move to tcpip_host //tcpipInitialize(); @@ -95,6 +97,7 @@ void XLinkPlatformInit(void* options) WSADATA wsa_data; WSAStartup(MAKEWORD(2,2), &wsa_data); #endif + return X_LINK_PLATFORM_SUCCESS; } diff --git a/src/pc/Win/src/win_usb_host.cpp b/src/pc/Win/src/win_usb_host.cpp new file mode 100755 index 0000000..2f0215e --- /dev/null +++ b/src/pc/Win/src/win_usb_host.cpp @@ -0,0 +1,74 @@ +// Win32 api and MSVC only; not mingw, *nix, etc. +#if defined(_WIN32) && defined(_MSC_VER) + +// project +#define MVLOG_UNIT_NAME xLinkUsb + +// libraries +#ifdef XLINK_LIBUSB_LOCAL +#include +#else +#include +#endif + +#include "XLink/XLinkLog.h" +#include "usb_host.h" + +// std +#include +#include + +int usbInitialize_customdir(void** hContext) { + // get handle to the module containing a XLink static function/var + // can not use GetModuleFileNameW(nullptr) because when the main depthai app is a DLL (e.g. plugin), + // then it returns the main EXE which is usually wrong + HMODULE hXLink = nullptr; + if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCWSTR)&MVLOGLEVEL(global), &hXLink) == 0) { + return LIBUSB_ERROR_OVERFLOW; + } + + // get path to that module + std::array rawPath = {}; + const auto len = GetModuleFileNameW(hXLink, rawPath.data(), static_cast(rawPath.size())); + if ((len == 0) || (len == rawPath.size())) { + return LIBUSB_ERROR_OVERFLOW; + } + + // remove filename with string::find_last_of(), _wsplitpath_s(), PathCchRemoveFileSpec() + // using PathCchRemoveFileSpec() as it handles special cases + if (PathCchRemoveFileSpec(rawPath.data(), rawPath.size()) != S_OK) { + return LIBUSB_ERROR_OVERFLOW; + } + + // persist existing custom DLL load path + bool oldGetError = false; + std::array oldDllDir = {}; + if (GetDllDirectoryW(static_cast(oldDllDir.size()), oldDllDir.data())) { + // nothing + } + else { + // SetDllDirectoryW() previously unused, or an error + oldGetError = true; + } + + // set custom dll load directory + if (SetDllDirectoryW(rawPath.data()) == 0) { + return LIBUSB_ERROR_OVERFLOW; + } + + // initialize libusb + int initResult = LIBUSB_SUCCESS; + __try { + initResult = libusb_init((libusb_context**)hContext); + } + __except (EXCEPTION_EXECUTE_HANDLER) { + initResult = LIBUSB_ERROR_OVERFLOW; + } + + // restore custom dll load directory + SetDllDirectoryW(oldGetError ? nullptr : oldDllDir.data()); + + return initResult; +} + +#endif // defined(_WIN32) && defined(_MSC_VER) diff --git a/src/pc/protocols/usb_host.cpp b/src/pc/protocols/usb_host.cpp index 4fb892a..b9793f0 100644 --- a/src/pc/protocols/usb_host.cpp +++ b/src/pc/protocols/usb_host.cpp @@ -75,6 +75,9 @@ int usbInitialize(void* options){ // // Debug // mvLogLevelSet(MVLOG_DEBUG); + #if defined(_WIN32) && defined(_MSC_VER) + return usbInitialize_customdir((void**)&context); + #endif return libusb_init(&context); } diff --git a/src/pc/protocols/usb_host.h b/src/pc/protocols/usb_host.h index a567b66..0ec906f 100644 --- a/src/pc/protocols/usb_host.h +++ b/src/pc/protocols/usb_host.h @@ -36,6 +36,7 @@ typedef enum usbBootError { } usbBootError_t; int usbInitialize(void* options); +int usbInitialize_customdir(void** hContext); int usb_boot(const char *addr, const void *mvcmd, unsigned size); int get_pid_by_name(const char* name); diff --git a/src/shared/XLinkDevice.c b/src/shared/XLinkDevice.c index 4c53719..c8c7e43 100644 --- a/src/shared/XLinkDevice.c +++ b/src/shared/XLinkDevice.c @@ -75,18 +75,18 @@ static XLinkError_t parsePlatformError(xLinkPlatformErrorCode_t rc); XLinkError_t XLinkInitialize(XLinkGlobalHandler_t* globalHandler) { + XLINK_RET_IF(globalHandler == NULL); XLINK_RET_ERR_IF(pthread_mutex_lock(&init_mutex), X_LINK_ERROR); if(init_once){ + pthread_mutex_unlock(&init_mutex); return X_LINK_SUCCESS; } - init_once = 1; #ifdef __DEVICE__ mvLogLevelSet(MVLOG_FATAL); mvLogDefaultLevelSet(MVLOG_FATAL); #endif - XLINK_RET_IF(globalHandler == NULL); ASSERT_XLINK(XLINK_MAX_STREAMS <= MAX_POOLS_ALLOC); glHandler = globalHandler; if (sem_init(&pingSem,0,0)) { @@ -94,7 +94,10 @@ XLinkError_t XLinkInitialize(XLinkGlobalHandler_t* globalHandler) } int i; - XLinkPlatformInit(globalHandler->options); + if (XLinkPlatformInit(globalHandler->options) != X_LINK_PLATFORM_SUCCESS) { + pthread_mutex_unlock(&init_mutex); + return X_LINK_ERROR; + } //Using deprecated fields. Begin. int loglevel = globalHandler->loglevel; @@ -115,7 +118,11 @@ XLinkError_t XLinkInitialize(XLinkGlobalHandler_t* globalHandler) controlFunctionTbl.closeLink = &dispatcherCloseLink; controlFunctionTbl.closeDeviceFd = &dispatcherCloseDeviceFd; - XLINK_RET_IF(DispatcherInitialize(&controlFunctionTbl)); + if (DispatcherInitialize(&controlFunctionTbl)) { + mvLog(MVLOG_ERROR, "Condition failed: DispatcherInitialize(&controlFunctionTbl)"); + pthread_mutex_unlock(&init_mutex); + return X_LINK_ERROR; + } //initialize availableStreams memset(availableXLinks, 0, sizeof(availableXLinks)); @@ -134,23 +141,34 @@ XLinkError_t XLinkInitialize(XLinkGlobalHandler_t* globalHandler) #ifdef __DEVICE__ link = getNextAvailableLink(); - if (link == NULL) + if (link == NULL) { + pthread_mutex_unlock(&init_mutex); return X_LINK_COMMUNICATION_NOT_OPEN; + } link->peerState = XLINK_UP; link->deviceHandle.xLinkFD = NULL; link->deviceHandle.protocol = globalHandler->protocol; xLinkDeviceHandle_t temp = {0}; temp.protocol = globalHandler->protocol; - XLINK_RET_IF_FAIL(DispatcherStart(&temp)); //myriad has one + { + int rc; + if (rc = DispatcherStart(&temp)) { //myriad has one + mvLog(MVLOG_ERROR, " DispatcherStart(&temp) method call failed with an error: %d", rc); + pthread_mutex_unlock(&init_mutex); + return rc; + } + } while(((sem_wait(&pingSem) == -1) && errno == EINTR) continue; #endif + init_once = 1; int status = pthread_mutex_unlock(&init_mutex); if(status){ + // rare and unstable scenario; xlink is technically initialized yet mutex unlock failed return X_LINK_ERROR; }