Skip to content

Commit

Permalink
xlink init: fix mutex, result vals, libusb load dir
Browse files Browse the repository at this point in the history
* load libusb from same dir as depthai-core on Windows
* add xlink init error handling
* add return success to XLinkPlatformInit()
* xlink init unlocks mutex on errors + allows retry
  • Loading branch information
diablodale committed May 17, 2022
1 parent af820e6 commit 489b2bf
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 10 deletions.
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ include(cmake/XLinkDependencies.cmake)

# Link to libusb
target_link_libraries(${TARGET_NAME} PRIVATE usb-1.0)
if(WIN32 AND NOT MINGW)
target_link_libraries(${TARGET_NAME} PRIVATE delayimp.lib Pathcch.lib)
# workaround https://gitlab.kitware.com/cmake/cmake/-/issues/20022
target_link_options(${TARGET_NAME} PUBLIC "$<LINK_ONLY:/DELAYLOAD:libusb-1.0$<$<CONFIG:Debug>:d>.dll>")
endif()

if(WIN32)
target_compile_definitions(${TARGET_NAME} PRIVATE WIN32_LEAN_AND_MEAN)
Expand Down
3 changes: 2 additions & 1 deletion cmake/XLink.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion include/XLink/XLinkPlatform.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ typedef enum {
// Device management. Begin.
// ------------------------------------

void XLinkPlatformInit(void* options);
xLinkPlatformErrorCode_t XLinkPlatformInit(void* options);

#ifndef __DEVICE__
/**
Expand Down
7 changes: 5 additions & 2 deletions src/pc/PlatformDeviceControl.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,16 +85,19 @@ 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();
#if (defined(_WIN32) || defined(_WIN64)) && defined(USE_TCP_IP)
WSADATA wsa_data;
WSAStartup(MAKEWORD(2,2), &wsa_data);
#endif
return X_LINK_PLATFORM_SUCCESS;
}


Expand Down
74 changes: 74 additions & 0 deletions src/pc/Win/src/win_usb_host.cpp
Original file line number Diff line number Diff line change
@@ -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 <libusb.h>
#else
#include <libusb-1.0/libusb.h>
#endif

#include "XLink/XLinkLog.h"
#include "usb_host.h"

// std
#include <array>
#include <pathcch.h>

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<wchar_t, 2048> rawPath = {};
const auto len = GetModuleFileNameW(hXLink, rawPath.data(), static_cast<DWORD>(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<wchar_t, 2048> oldDllDir = {};
if (GetDllDirectoryW(static_cast<DWORD>(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)
3 changes: 3 additions & 0 deletions src/pc/protocols/usb_host.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
1 change: 1 addition & 0 deletions src/pc/protocols/usb_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
30 changes: 24 additions & 6 deletions src/shared/XLinkDevice.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,26 +75,29 @@ 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)) {
mvLog(MVLOG_ERROR, "Can't create semaphore\n");
}
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;
Expand All @@ -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));
Expand All @@ -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;
}

Expand Down

0 comments on commit 489b2bf

Please sign in to comment.