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 16, 2022
1 parent af820e6 commit 6a71de5
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 10 deletions.
9 changes: 9 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,15 @@ 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)
# BUGBUG private fails...it does not put /delayload on tests or examples
# interface and public both cascade up and put it on things "higher" than xlink and depthai-core
# I think this is a bug in depthai-core cmake
target_link_options(${TARGET_NAME} PUBLIC "/DELAYLOAD:libusb-1.0$<$<CONFIG:Debug>:d>.dll")
endif()

if(WIN32)
target_compile_definitions(${TARGET_NAME} PRIVATE WIN32_LEAN_AND_MEAN)
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
65 changes: 64 additions & 1 deletion src/pc/protocols/usb_host.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
#include <thread>
#include <chrono>
#include <cstring>
#include <array>
#if defined(_WIN32) && defined(_MSC_VER)
#include <pathcch.h>
#endif

constexpr static int MAXIMUM_PORT_NUMBERS = 7;
using VidPid = std::pair<uint16_t, uint16_t>;
Expand Down Expand Up @@ -75,7 +79,66 @@ int usbInitialize(void* options){
// // Debug
// mvLogLevelSet(MVLOG_DEBUG);

return libusb_init(&context);
// Windows and Win32 api only; not mingw, *nix, etc.
#if defined(_WIN32) && defined(_MSC_VER)
// 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, 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;
}
mvLog(MVLOG_INFO, "dale path: %S", rawPath.data());

// 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;
}
mvLog(MVLOG_INFO, "dale dir: %S", rawPath.data());

// persist existing custom DLL load path
bool oldGetError = false;
std::array<wchar_t, 2048> oldDllDir = {};
if (GetDllDirectoryW(static_cast<DWORD>(oldDllDir.size()), oldDllDir.data())) {
mvLog(MVLOG_INFO, "dale old: %S", oldDllDir.data());
}
else {
// SetDllDirectoryW() previously unused, or an error
mvLog(MVLOG_INFO, "dale old unused or error");
oldGetError = true;
}

// set custom dll load directory
//const wchar_t hack[] = L"C:\\.hunter\\_Base\\9b4e732\\f33d64c\\8f81e86\\Install\\bin";
//if (SetDllDirectoryW(hack) == 0) {
if (SetDllDirectoryW(rawPath.data()) == 0) {
return LIBUSB_ERROR_OVERFLOW;
}

// initialize libusb
int initResult = LIBUSB_SUCCESS;
__try {
initResult = libusb_init(&context);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
initResult = LIBUSB_ERROR_OVERFLOW;
}

// restore custom dll load directory
SetDllDirectoryW(oldGetError ? nullptr : oldDllDir.data());

return initResult;
#else
return libusb_init(&context);
#endif
}

struct pair_hash {
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 6a71de5

Please sign in to comment.