Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions include/XLink/XLink.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,21 @@ XLinkError_t XLinkSearchForDevices(const deviceDesc_t in_deviceRequirements,


/**
* @brief Connects to specific device, starts dispatcher and pings remote
* @brief Connects to specific device, starts dispatcher and pings remote.
* Uses XLINK_CONNECT_TIMEOUT as the default timeout for the ping handshake.
* @param[in,out] handler - XLink communication parameters (file path name for underlying layer)
* @return Status code of the operation: X_LINK_SUCCESS (0) for success
*/
XLinkError_t XLinkConnect(XLinkHandler_t* handler);

/**
* @brief Connects to specific device with a configurable timeout for the ping handshake.
* @param[in,out] handler - XLink communication parameters (file path name for underlying layer)
* @param[in] timeoutMs - timeout in milliseconds for the ping round-trip. Use XLINK_NO_RW_TIMEOUT for infinite wait.
* @return Status code of the operation: X_LINK_SUCCESS (0) for success, X_LINK_TIMEOUT on timeout
*/
XLinkError_t XLinkConnectWithTimeout(XLinkHandler_t* handler, unsigned int timeoutMs);

/**
* @brief Puts device into bootloader mode
* @param deviceDesc - device description structure, obtained from XLinkFind* functions call
Expand Down Expand Up @@ -214,15 +223,27 @@ XLinkError_t XLinkGetProfilingData(linkId_t id, XLinkProf_t* prof);
// ------------------------------------

/**
* @brief Opens a stream in the remote that can be written to by the local
* Allocates stream_write_size (aligned up to 64 bytes) for that stream
* @brief Opens a stream in the remote that can be written to by the local.
* Allocates stream_write_size (aligned up to 64 bytes) for that stream.
* Uses XLINK_OPEN_STREAM_TIMEOUT as the default timeout.
* @param[in] id - link Id obtained from XLinkConnect in the handler parameter
* @param[in] name - stream name
* @param[in] stream_write_size - stream buffer size
* @return Link Id: INVALID_STREAM_ID for failure
*/
streamId_t XLinkOpenStream(linkId_t id, const char* name, int stream_write_size);

/**
* @brief Opens a stream with a configurable timeout.
* Allocates stream_write_size (aligned up to 64 bytes) for that stream.
* @param[in] id - link Id obtained from XLinkConnect in the handler parameter
* @param[in] name - stream name
* @param[in] stream_write_size - stream buffer size
* @param[in] timeoutMs - timeout in milliseconds. Use XLINK_NO_RW_TIMEOUT for infinite wait.
* @return Link Id: INVALID_STREAM_ID for failure (including timeout)
*/
streamId_t XLinkOpenStreamWithTimeout(linkId_t id, const char* name, int stream_write_size, unsigned int timeoutMs);

/**
* @brief Closes stream for any further data transfer
* Stream will be deallocated when all pending data has been released
Expand Down
2 changes: 2 additions & 0 deletions include/XLink/XLinkPublicDefines.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ extern "C"
#endif
#define XLINK_MAX_PACKETS_PER_STREAM 64
#define XLINK_NO_RW_TIMEOUT 0xFFFFFFFF
#define XLINK_CONNECT_TIMEOUT 5000 /* 5s default timeout for XLinkConnect ping handshake */
#define XLINK_OPEN_STREAM_TIMEOUT 5000 /* 5s default timeout for XLinkOpenStream */


typedef enum {
Expand Down
14 changes: 10 additions & 4 deletions src/shared/XLinkData.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,17 @@ static XLinkError_t getLinkByStreamId(streamId_t streamId, xLinkDesc_t** out_lin
// ------------------------------------

streamId_t XLinkOpenStream(linkId_t id, const char* name, int stream_write_size)
{
return XLinkOpenStreamWithTimeout(id, name, stream_write_size, XLINK_OPEN_STREAM_TIMEOUT);
}

streamId_t XLinkOpenStreamWithTimeout(linkId_t id, const char* name, int stream_write_size, unsigned int timeoutMs)
{
XLINK_RET_ERR_IF(name == NULL, INVALID_STREAM_ID);
XLINK_RET_ERR_IF(stream_write_size < 0, INVALID_STREAM_ID);

xLinkDesc_t* link = getLinkById(id);
mvLog(MVLOG_DEBUG,"%s() id %d link %p\n", __func__, id, link);
mvLog(MVLOG_DEBUG,"%s() id %d link %p timeout %u\n", __func__, id, link, timeoutMs);
XLINK_RET_ERR_IF(link == NULL, INVALID_STREAM_ID);
XLINK_RET_ERR_IF(getXLinkState(link) != XLINK_UP, INVALID_STREAM_ID);
XLINK_RET_ERR_IF(strlen(name) >= MAX_STREAM_NAME_LENGTH, INVALID_STREAM_ID);
Expand All @@ -65,9 +70,10 @@ streamId_t XLinkOpenStream(linkId_t id, const char* name, int stream_write_size)
name, MAX_STREAM_NAME_LENGTH - 1);

DispatcherAddEvent(EVENT_LOCAL, &event);
XLINK_RET_ERR_IF(
DispatcherWaitEventComplete(&link->deviceHandle, XLINK_NO_RW_TIMEOUT),
INVALID_STREAM_ID);
if (DispatcherWaitEventComplete(&link->deviceHandle, timeoutMs)) {
mvLog(MVLOG_ERROR, "Open stream \"%s\" timed out after %u ms", name, timeoutMs);
return INVALID_STREAM_ID;
}

#ifndef __DEVICE__
XLinkError_t eventStatus = checkEventHeader(event.header);
Expand Down
11 changes: 9 additions & 2 deletions src/shared/XLinkDevice.c
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,12 @@ XLinkError_t XLinkSearchForDevices(const deviceDesc_t in_deviceRequirements,

//Called only from app - per device
XLinkError_t XLinkConnect(XLinkHandler_t* handler)
{
return XLinkConnectWithTimeout(handler, XLINK_CONNECT_TIMEOUT);
}

//Called only from app - per device, with configurable timeout
XLinkError_t XLinkConnectWithTimeout(XLinkHandler_t* handler, unsigned int timeoutMs)
{
XLINK_RET_IF(handler == NULL);
if (strnlen(handler->devicePath, MAX_PATH_LENGTH) < 2) {
Expand All @@ -235,7 +241,7 @@ XLinkError_t XLinkConnect(XLinkHandler_t* handler)

xLinkDesc_t* link = getNextAvailableLink();
XLINK_RET_IF(link == NULL);
mvLog(MVLOG_DEBUG,"%s() device name %s glHandler %p protocol %d\n", __func__, handler->devicePath, glHandler, handler->protocol);
mvLog(MVLOG_DEBUG,"%s() device name %s glHandler %p protocol %d timeout %u\n", __func__, handler->devicePath, glHandler, handler->protocol, timeoutMs);

link->deviceHandle.protocol = handler->protocol;
int connectStatus = XLinkPlatformConnect(handler->devicePath2, handler->devicePath,
Expand Down Expand Up @@ -263,7 +269,8 @@ XLinkError_t XLinkConnect(XLinkHandler_t* handler)
event.deviceHandle = link->deviceHandle;
DispatcherAddEvent(EVENT_LOCAL, &event);

if (DispatcherWaitEventComplete(&link->deviceHandle, XLINK_NO_RW_TIMEOUT)) {
if (DispatcherWaitEventComplete(&link->deviceHandle, timeoutMs)) {
mvLog(MVLOG_ERROR, "Ping handshake timed out after %u ms", timeoutMs);
DispatcherClean(&link->deviceHandle);
return X_LINK_TIMEOUT;
}
Expand Down
26 changes: 19 additions & 7 deletions src/shared/XLinkDispatcher.c
Original file line number Diff line number Diff line change
Expand Up @@ -417,19 +417,31 @@ int DispatcherWaitEventComplete(xLinkDeviceHandle_t *deviceHandle, unsigned int

int rc = 0;
if (timeoutMs != XLINK_NO_RW_TIMEOUT) {
// This is a workaround for sem_timedwait being influenced by the system clock change.
// This is a temporary solution. TODO: replace this with something more efficient.
while (timeoutMs--) {
// Use monotonic clock to measure elapsed time accurately.
// This replaces the previous iteration-counting workaround that was added
// because sem_timedwait uses CLOCK_REALTIME (affected by NTP/clock jumps).
// steady_clock/CLOCK_MONOTONIC is immune to system clock changes.
XLinkTimespec start;
getMonotonicTimestamp(&start);
uint64_t startMs = start.tv_sec * 1000 + start.tv_nsec / 1000000;

while (1) {
rc = XLink_sem_trywait(id);
if (!rc) {
break;
} else {
}
XLinkTimespec now;
getMonotonicTimestamp(&now);
uint64_t nowMs = now.tv_sec * 1000 + now.tv_nsec / 1000000;
if (nowMs - startMs >= timeoutMs) {
rc = -1;
break;
}
#if (defined(_WIN32) || defined(_WIN64) )
Sleep(1);
Sleep(1);
#else
usleep(1000);
usleep(1000);
#endif
}
}
} else {
while(((rc = XLink_sem_wait(id)) == -1) && errno == EINTR)
Expand Down