diff --git a/CMakeLists.txt b/CMakeLists.txt index 0650dc67..78709498 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,7 @@ option(XLINK_BUILD_EXAMPLES "Build XLink examples" OFF) option(XLINK_BUILD_TESTS "Build XLink tests" OFF) add_library(${TARGET_NAME} ${XLINK_SOURCES}) +add_default_flags(${TARGET_NAME}) add_flag_source(src/shared/XLinkDevice.c "-Werror=switch-enum") if(WIN32) diff --git a/cmake/Flags.cmake b/cmake/Flags.cmake index 23b4b527..08c1e2fc 100644 --- a/cmake/Flags.cmake +++ b/cmake/Flags.cmake @@ -18,7 +18,7 @@ endfunction() function(add_default_flags target) if ("${CMAKE_C_COMPILER_ID}" MATCHES "^(AppleClang|Clang|GNU)$") # enable those flags - add_flag(${target} -Woverloaded-virtual) # warn if you overload (not override) a virtual function + # add_flag(${target} -Woverloaded-virtual) # warn if you overload (not override) a virtual function add_flag(${target} -Wformat=2) # warn on security issues around functions that format output (ie printf) add_flag(${target} -Wmisleading-indentation) # (only in GCC >= 6.0) warn if indentation implies blocks where blocks do not exist add_flag(${target} -Wduplicated-cond) # (only in GCC >= 6.0) warn if if / else chain has duplicated conditions @@ -37,9 +37,9 @@ function(add_default_flags target) add_flag(${target} -Werror=self-assign-field) # error if self assign - bugprone add_flag(${target} -Werror=unused-lambda-capture) # error if lambda capture is unused add_flag(${target} -Werror=return-type) # warning: control reaches end of non-void function [-Wreturn-type] - add_flag(${target} -Werror=non-virtual-dtor) # warn the user if a class with virtual functions has a non-virtual destructor. This helps catch hard to track down memory errors + # add_flag(${target} -Werror=non-virtual-dtor) # warn the user if a class with virtual functions has a non-virtual destructor. This helps catch hard to track down memory errors add_flag(${target} -Werror=sign-compare) # warn the user if they compare a signed and unsigned numbers - add_flag(${target} -Werror=reorder) # field '$1' will be initialized after field '$2' + # add_flag(${target} -Werror=reorder) # field '$1' will be initialized after field '$2' elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC") # using Visual Studio C++ diff --git a/include/XLink/XLink.h b/include/XLink/XLink.h index d4731248..679d4ef9 100644 --- a/include/XLink/XLink.h +++ b/include/XLink/XLink.h @@ -74,6 +74,15 @@ XLinkError_t XLinkFindAllSuitableDevices(XLinkDeviceState_t state, */ XLinkError_t XLinkConnect(XLinkHandler_t* handler); +/** + * TODO(themarpe) - doesn't work well yet... + * @brief Connects to specific device with a timeout, starts dispatcher and pings remote + * @param[in,out] handler - XLink communication parameters (file path name for underlying layer) + * @param[in] msTimeout – time in milliseconds after which operation times out + * @return Status code of the operation: X_LINK_SUCCESS (0) for success +XLinkError_t XLinkConnectWithTimeout(XLinkHandler_t* handler, const unsigned int msTimeout); +*/ + /** * @brief Puts device into bootloader mode * @param deviceDesc - device description structure, obtained from XLinkFind* functions call @@ -114,22 +123,17 @@ XLinkError_t XLinkBootFirmware(const deviceDesc_t* deviceDesc, const char* firmw * @return Status code of the operation: X_LINK_SUCCESS (0) for success */ -XLinkError_t XLinkResetRemote(linkId_t id); +XLinkError_t XLinkResetRemote(const linkId_t id); /** * @brief Resets the remote device and close all open local handles for this device * @warning This function should be used in a host application * @param[in] id - link Id obtained from XLinkConnect in the handler parameter + * @param[in] msTimeout – time in milliseconds after which operation times out * @return Status code of the operation: X_LINK_SUCCESS (0) for success */ -XLinkError_t XLinkResetRemoteTimeout(linkId_t id, int timeoutMs); - -/** - * @brief Closes all and release all memory - * @return Status code of the operation: X_LINK_SUCCESS (0) for success - */ -XLinkError_t XLinkResetAll(); +XLinkError_t XLinkResetRemoteTimeout(const linkId_t id, const unsigned int msTimeout); /** * @brief Retrieves USB speed of certain connected device @@ -303,10 +307,10 @@ XLinkError_t XLinkReleaseData(streamId_t const streamId); * data. Should be fixed for the next release. * @param[in] streamId – stream link Id obtained from XLinkOpenStream call * @param[out] packet – structure containing output data buffer and received size - * @param[in] timeoutMs – timeout for a read operation in milliseconds + * @param[in] msTimeout – timeout for a read operation in milliseconds * @return Status code of the operation: X_LINK_SUCCESS (0) for success */ -XLinkError_t XLinkReadDataWithTimeout(streamId_t streamId, streamPacketDesc_t** packet, unsigned int timeoutMs); +XLinkError_t XLinkReadDataWithTimeout(streamId_t streamId, streamPacketDesc_t** packet, unsigned int msTimeout); /** * @brief Sends a package to initiate the writing of data to a remote stream with timeout in ms @@ -315,10 +319,10 @@ XLinkError_t XLinkReadDataWithTimeout(streamId_t streamId, streamPacketDesc_t** * @param[in] streamId – stream link Id obtained from XLinkOpenStream call * @param[in] buffer – data buffer to be transmitted * @param[in] size – size of the data to be transmitted - * @param[in] timeoutMs – timeout for a write operation in milliseconds + * @param[in] msTimeout – timeout for a write operation in milliseconds * @return Status code of the operation: X_LINK_SUCCESS (0) for success */ -XLinkError_t XLinkWriteDataWithTimeout(streamId_t streamId, const uint8_t* buffer, int size, unsigned int timeoutMs); +XLinkError_t XLinkWriteDataWithTimeout(streamId_t streamId, const uint8_t* buffer, int size, unsigned int msTimeout); // ------------------------------------ // Device streams management. End. @@ -346,8 +350,12 @@ XLinkError_t XLinkAsyncWriteData(); XLinkError_t XLinkSetDeviceOpenTimeOutMsec(unsigned int msec); XLinkError_t XLinkSetCommonTimeOutMsec(unsigned int msec); -// unsafe -XLinkError_t XLinkGetFillLevel(streamId_t const streamId, int isRemote, int* fillLevel); +/** + * Deprecated - issues + * @brief Closes all and release all memory + * @return Status code of the operation: X_LINK_SUCCESS (0) for success + */ +XLinkError_t XLinkResetAll(); #endif // __PC__ diff --git a/include/XLink/XLinkPrivateFields.h b/include/XLink/XLinkPrivateFields.h index 0e831374..68a3a894 100644 --- a/include/XLink/XLinkPrivateFields.h +++ b/include/XLink/XLinkPrivateFields.h @@ -40,8 +40,10 @@ extern sem_t pingSem; //to b used by myriad xLinkDesc_t* getLinkById(linkId_t id); xLinkDesc_t* getLink(void* fd); +xLinkDesc_t* getLinkUnsafe(void* fd); xLinkState_t getXLinkState(xLinkDesc_t* link); - +XLinkError_t getLinkUpDeviceHandleByLinkId(linkId_t const linkId, xLinkDeviceHandle_t* const out_handle); +XLinkError_t getLinkUpDeviceHandleByStreamId(streamId_t const streamId, xLinkDeviceHandle_t* const out_handle); streamId_t getStreamIdByName(xLinkDesc_t* link, const char* name); diff --git a/src/pc/PlatformData.c b/src/pc/PlatformData.c index 3fb852ce..76bc4885 100644 --- a/src/pc/PlatformData.c +++ b/src/pc/PlatformData.c @@ -169,7 +169,7 @@ void XLinkPlatformDeallocateData(void *ptr, uint32_t size, uint32_t alignment) // Wrappers implementation. Begin. // ------------------------------------ -int usbPlatformRead(void* fd, void* data, int size) +int usbPlatformRead(void* fdKey, void* data, int size) { int rc = 0; #ifndef USE_USB_VSC @@ -209,12 +209,20 @@ int usbPlatformRead(void* fd, void* data, int size) } #endif /*USE_LINK_JTAG*/ #else - rc = usb_read((libusb_device_handle *) fd, data, size); + + void* tmpUsbHandle = NULL; + if(getPlatformDeviceFdFromKey(fdKey, &tmpUsbHandle)){ + mvLog(MVLOG_FATAL, "Cannot find file descriptor by key: %" PRIxPTR, (uintptr_t) fdKey); + return -1; + } + libusb_device_handle* usbHandle = (libusb_device_handle*) tmpUsbHandle; + + rc = usb_read(usbHandle, data, size); #endif /*USE_USB_VSC*/ return rc; } -int usbPlatformWrite(void *fd, void *data, int size) +int usbPlatformWrite(void *fdKey, void *data, int size) { int rc = 0; #ifndef USE_USB_VSC @@ -257,7 +265,15 @@ int usbPlatformWrite(void *fd, void *data, int size) } #endif /*USE_LINK_JTAG*/ #else - rc = usb_write((libusb_device_handle *) fd, data, size); + + void* tmpUsbHandle = NULL; + if(getPlatformDeviceFdFromKey(fdKey, &tmpUsbHandle)){ + mvLog(MVLOG_FATAL, "Cannot find file descriptor by key: %" PRIxPTR, (uintptr_t) fdKey); + return -1; + } + libusb_device_handle* usbHandle = (libusb_device_handle*) tmpUsbHandle; + + rc = usb_write(usbHandle, data, size); #endif /*USE_USB_VSC*/ return rc; } @@ -277,7 +293,7 @@ int pciePlatformWrite(void *f, void *data, int size) { write_pending = 1; - size_t chunk = size < CHUNK_SIZE_BYTES ? size : CHUNK_SIZE_BYTES; + size_t chunk = (size_t)size < CHUNK_SIZE_BYTES ? (size_t)size : CHUNK_SIZE_BYTES; int num_written = pcie_write(f, data, chunk); write_pending = 0; diff --git a/src/pc/PlatformDeviceControl.c b/src/pc/PlatformDeviceControl.c index 550d8673..d778654b 100644 --- a/src/pc/PlatformDeviceControl.c +++ b/src/pc/PlatformDeviceControl.c @@ -47,7 +47,7 @@ int usbFdRead = -1; static UsbSpeed_t usb_speed_enum = X_LINK_USB_SPEED_UNKNOWN; static char mx_serial[XLINK_MAX_MX_ID_SIZE] = { 0 }; #ifdef USE_USB_VSC -static int statuswaittimeout = 5; +static const int statuswaittimeout = 5; #endif typedef struct { @@ -617,18 +617,21 @@ int usbPlatformConnect(const char *devPathRead, const char *devPathWrite, void * return 0; #endif /*USE_LINK_JTAG*/ #else - *fd = usbLinkOpen(devPathWrite); - if (*fd == 0) + void* usbHandle = usbLinkOpen(devPathWrite); + + if (usbHandle == 0) { /* could fail due to port name change */ return -1; } - if(*fd) - return 0; - else - return -1; + // Store the usb handle and create a "unique" key instead + // (as file descriptors are reused and can cause a clash with lookups between scheduler and link) + *fd = createPlatformDeviceFdKey(usbHandle); + #endif /*USE_USB_VSC*/ + + return 0; } int pciePlatformConnect(UNUSED const char *devPathRead, @@ -642,14 +645,23 @@ int pciePlatformConnect(UNUSED const char *devPathRead, int tcpipPlatformConnect(const char *devPathRead, const char *devPathWrite, void **fd) { #if defined(USE_TCP_IP) - if (!devPathWrite || !fd) + if (!devPathWrite || !fd) { return X_LINK_PLATFORM_INVALID_PARAMETERS; + } + TCPIP_SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); + +#if (defined(_WIN32) || defined(_WIN64) ) + if(sock == INVALID_SOCKET) + { + return TCPIP_HOST_ERROR; + } +#else if(sock < 0) { - tcpip_close_socket(sock); - return -1; + return TCPIP_HOST_ERROR; } +#endif // Disable sigpipe reception on send #if defined(SO_NOSIGPIPE) @@ -724,7 +736,7 @@ int tcpipPlatformBootBootloader(const char *name) return tcpip_boot_bootloader(name); } -int usbPlatformClose(void *fd) +int usbPlatformClose(void *fdKey) { #ifndef USE_USB_VSC @@ -741,7 +753,19 @@ int usbPlatformClose(void *fd) } #endif /*USE_LINK_JTAG*/ #else - usbLinkClose((libusb_device_handle *) fd); + + void* tmpUsbHandle = NULL; + if(getPlatformDeviceFdFromKey(fdKey, &tmpUsbHandle)){ + mvLog(MVLOG_FATAL, "Cannot find USB Handle by key"); + return -1; + } + usbLinkClose((libusb_device_handle *) tmpUsbHandle); + + if(destroyPlatformDeviceFdKey(fdKey)){ + mvLog(MVLOG_FATAL, "Cannot destroy USB Handle key"); + return -1; + } + #endif /*USE_USB_VSC*/ return -1; } @@ -794,7 +818,7 @@ int tcpipPlatformClose(void *fdKey) #endif if(destroyPlatformDeviceFdKey(fdKey)){ - mvLog(MVLOG_FATAL, "Cannot destory file descriptor key"); + mvLog(MVLOG_FATAL, "Cannot destroy file descriptor key"); return -1; } diff --git a/src/pc/Win/src/win_semaphore.c b/src/pc/Win/src/win_semaphore.c index dc9ad6fb..34bc572e 100644 --- a/src/pc/Win/src/win_semaphore.c +++ b/src/pc/Win/src/win_semaphore.c @@ -94,10 +94,15 @@ int sem_trywait(sem_t *sem){ return ls_set_errno(EINVAL); } sem_t s = *sem; - if (WaitForSingleObject(s->handle, 0) != WAIT_OBJECT_0) { + + DWORD ret = WaitForSingleObject(s->handle, 0); + if (ret == WAIT_OBJECT_0) { + return 0; + } else if(ret == WAIT_TIMEOUT) { + return ls_set_errno(ETIMEDOUT); + } else { return ls_set_errno(EINVAL); } - return 0; } diff --git a/src/pc/Win/src/win_usb.c b/src/pc/Win/src/win_usb.c index 10a9a636..b5b069c3 100644 --- a/src/pc/Win/src/win_usb.c +++ b/src/pc/Win/src/win_usb.c @@ -19,6 +19,7 @@ #include "usb_boot.h" #include "usb_mx_id.h" #include "stdbool.h" +#include "win_pthread.h" #define MVLOG_UNIT_NAME xLinkWinUsb #include "XLinkLog.h" @@ -76,6 +77,7 @@ static size_t errmsg_buff_len = 0; static int MX_ID_TIMEOUT = 100; // 100ms +static pthread_mutex_t globalMutex = PTHREAD_MUTEX_INITIALIZER; static const char* gen_addr_mx_id(HDEVINFO devInfo, SP_DEVINFO_DATA* devInfoData, int pid, char** refDevicePath); @@ -464,7 +466,7 @@ int usb_bulk_write(usb_hwnd han, uint8_t ep, const void *buffer, size_t sz, uint if(han == NULL) return USB_ERR_INVALID; - if(timeout_ms != han->eps[USB_DIR_OUT].last_timeout) { + if(timeout_ms != (long) han->eps[USB_DIR_OUT].last_timeout) { han->eps[USB_DIR_OUT].last_timeout = timeout_ms; if(!WinUsb_SetPipePolicy(han->winUsbHan, ep, PIPE_TRANSFER_TIMEOUT, sizeof(ULONG), &han->eps[USB_DIR_OUT].last_timeout)) { @@ -494,7 +496,7 @@ int usb_bulk_read(usb_hwnd han, uint8_t ep, void *buffer, size_t sz, uint32_t *r if(han == NULL) return USB_ERR_INVALID; - if(timeout_ms != han->eps[USB_DIR_IN].last_timeout) { + if(timeout_ms != (long) han->eps[USB_DIR_IN].last_timeout) { han->eps[USB_DIR_IN].last_timeout = timeout_ms; if(!WinUsb_SetPipePolicy(han->winUsbHan, ep, PIPE_TRANSFER_TIMEOUT, sizeof(ULONG), &han->eps[USB_DIR_IN].last_timeout)) { @@ -729,7 +731,7 @@ static const char* gen_addr_mx_id(HDEVINFO devInfo, SP_DEVINFO_DATA* devInfoData rbuf[8] &= 0xF0; // Convert to HEX presentation and store into mx_id - for (uint32_t i = 0; i < expectedMxIdReadSize; i++) + for (int i = 0; i < expectedMxIdReadSize; i++) { sprintf(mx_id + (2 * (uintptr_t)i), "%02X", rbuf[i]); } @@ -894,7 +896,11 @@ int win_usb_find_device(unsigned idx, char* addr, unsigned addrsize, void** devi if (strlen(addr) > 1) specificDevice = 1; - // TODO There is no global mutex as in linux version + if (pthread_mutex_lock(&globalMutex)) { + mvLog(MVLOG_ERROR, "globalMutex lock failed"); + return USB_BOOT_ERROR; + } + int res; static usb_dev_list* devs = NULL; @@ -909,6 +915,10 @@ int win_usb_find_device(unsigned idx, char* addr, unsigned addrsize, void** devi } if ((res = usb_get_device_list(&devs)) < 0) { mvLog(MVLOG_DEBUG, "Unable to get USB device list: %s", libusb_strerror(res)); + + if (pthread_mutex_unlock(&globalMutex)) { + mvLog(MVLOG_ERROR, "globalMutex unlock failed"); + } return USB_BOOT_ERROR; } devs_cnt = res; @@ -954,6 +964,10 @@ int win_usb_find_device(unsigned idx, char* addr, unsigned addrsize, void** devi // Create a copy of device path string. It should be freed by usb_free_device() *device = _strdup(devicePath); devs_cnt = 0; + + if (pthread_mutex_unlock(&globalMutex)) { + mvLog(MVLOG_ERROR, "globalMutex unlock failed"); + } return USB_BOOT_SUCCESS; } } @@ -962,25 +976,37 @@ int win_usb_find_device(unsigned idx, char* addr, unsigned addrsize, void** devi // gen addr const char* caddr = gen_addr_mx_id(devs->devInfo, devs->infos + i, idProduct, NULL); - if (strncmp(addr, caddr, XLINK_MAX_NAME_SIZE) == 0) + if (addr && caddr && strncmp(addr, caddr, XLINK_MAX_NAME_SIZE) == 0) { mvLog(MVLOG_DEBUG, "Found Address: %s - VID/PID %04x:%04x", caddr, idVendor, idProduct, NULL); + + if (pthread_mutex_unlock(&globalMutex)) { + mvLog(MVLOG_ERROR, "globalMutex unlock failed"); + } return USB_BOOT_SUCCESS; } } - else if (idx == count) + else if ((int) idx == count) { // gen addr const char* caddr = gen_addr_mx_id(devs->devInfo, devs->infos + i, idProduct, NULL); mvLog(MVLOG_DEBUG, "Device %d Address: %s - VID/PID %04x:%04x", idx, caddr, idVendor, idProduct); mv_strncpy(addr, addrsize, caddr, addrsize - 1); + + if (pthread_mutex_unlock(&globalMutex)) { + mvLog(MVLOG_ERROR, "globalMutex unlock failed"); + } return USB_BOOT_SUCCESS; } count++; } } devs_cnt = 0; + + if (pthread_mutex_unlock(&globalMutex)) { + mvLog(MVLOG_ERROR, "globalMutex unlock failed"); + } return USB_BOOT_DEVICE_NOT_FOUND; } #endif diff --git a/src/pc/protocols/tcpip_host.c b/src/pc/protocols/tcpip_host.c index 30539ac9..b1a57270 100644 --- a/src/pc/protocols/tcpip_host.c +++ b/src/pc/protocols/tcpip_host.c @@ -313,7 +313,7 @@ xLinkPlatformErrorCode_t tcpip_get_devices(XLinkDeviceState_t state, deviceDesc_ // Loop through all sockets and received messages that arrived double t1 = seconds(); do { - if(num_devices_match >= devices_size){ + if(num_devices_match >= (long) devices_size){ // Enough devices matched, exit the loop break; } @@ -321,8 +321,12 @@ xLinkPlatformErrorCode_t tcpip_get_devices(XLinkDeviceState_t state, deviceDesc_ char ip_addr[INET_ADDRSTRLEN] = {0}; tcpipHostDeviceDiscoveryResp_t recv_buffer = {0}; struct sockaddr_in dev_addr; - uint32_t len = sizeof(dev_addr); - + #if (defined(_WIN32) || defined(_WIN64) ) + int len = sizeof(dev_addr); + #else + socklen_t len = sizeof(dev_addr); + #endif + int ret = recvfrom(sock, (char *) &recv_buffer, sizeof(recv_buffer), 0, (struct sockaddr*) & dev_addr, &len); if(ret > 0) { @@ -354,8 +358,29 @@ xLinkPlatformErrorCode_t tcpip_get_devices(XLinkDeviceState_t state, deviceDesc_ tcpip_close_socket(sock); + // Filter out duplicates - routing table will decide through which interface the packets will traverse + // TODO(themarpe) - properly separate interfaces. + // Either bind to interface addr, or SO_BINDTODEVICE Linux, IP_BOUND_IF macOS, and prefix interface name + int write_index = 0; + for(int i = 0; i < num_devices_match; i++){ + bool duplicate = false; + for(int j = i - 1; j >= 0; j--){ + // Check if duplicate + + // TODO(themarpe) - merge with device search improvements + // to have mxid available as well + if(strcmp(devices[i].name, devices[j].name) == 0){ + duplicate = true; + break; + } + } + if(!duplicate){ + devices[write_index] = devices[i]; + write_index++; + } + } // return total device found - *device_count = num_devices_match; + *device_count = write_index; // if at least one device matched, return OK otherwise return not found if(num_devices_match <= 0) diff --git a/src/shared/XLinkData.c b/src/shared/XLinkData.c index f02b8a4f..73d310a9 100644 --- a/src/shared/XLinkData.c +++ b/src/shared/XLinkData.c @@ -36,9 +36,7 @@ static XLinkError_t checkEventHeader(xLinkEventHeader_t header); static float timespec_diff(struct timespec *start, struct timespec *stop); static XLinkError_t addEvent(xLinkEvent_t *event, unsigned int timeoutMs); static XLinkError_t addEventWithPerf(xLinkEvent_t *event, float* opTime, unsigned int timeoutMs); -static XLinkError_t addEventWithPerfTimeout(xLinkEvent_t *event, float* opTime, unsigned int msTimeout); static XLinkError_t getLinkByStreamId(streamId_t streamId, xLinkDesc_t** out_link); - // ------------------------------------ // Helpers declaration. End. // ------------------------------------ @@ -106,13 +104,13 @@ streamId_t XLinkOpenStream(linkId_t id, const char* name, int stream_write_size) // and on the remote side we are freeing the read buffer XLinkError_t XLinkCloseStream(streamId_t const streamId) { - xLinkDesc_t* link = NULL; - XLINK_RET_IF(getLinkByStreamId(streamId, &link)); + xLinkDeviceHandle_t deviceHandle; + XLINK_RET_IF(getLinkUpDeviceHandleByStreamId(streamId, &deviceHandle)); streamId_t streamIdOnly = EXTRACT_STREAM_ID(streamId); xLinkEvent_t event = {0}; XLINK_INIT_EVENT(event, streamIdOnly, XLINK_CLOSE_STREAM_REQ, - 0, NULL, link->deviceHandle); + 0, NULL, deviceHandle); XLINK_RET_IF(addEvent(&event, XLINK_NO_RW_TIMEOUT)); return X_LINK_SUCCESS; @@ -124,13 +122,13 @@ XLinkError_t XLinkWriteData(streamId_t const streamId, const uint8_t* buffer, XLINK_RET_IF(buffer == NULL); float opTime = 0.0f; - xLinkDesc_t* link = NULL; - XLINK_RET_IF(getLinkByStreamId(streamId, &link)); + xLinkDeviceHandle_t deviceHandle; + XLINK_RET_IF(getLinkUpDeviceHandleByStreamId(streamId, &deviceHandle)); streamId_t streamIdOnly = EXTRACT_STREAM_ID(streamId); xLinkEvent_t event = {0}; XLINK_INIT_EVENT(event, streamIdOnly, XLINK_WRITE_REQ, - size,(void*)buffer, link->deviceHandle); + size,(void*)buffer, deviceHandle); XLINK_RET_IF(addEventWithPerf(&event, &opTime, XLINK_NO_RW_TIMEOUT)); @@ -147,13 +145,13 @@ XLinkError_t XLinkReadData(streamId_t const streamId, streamPacketDesc_t** packe XLINK_RET_IF(packet == NULL); float opTime = 0.0f; - xLinkDesc_t* link = NULL; - XLINK_RET_IF(getLinkByStreamId(streamId, &link)); + xLinkDeviceHandle_t deviceHandle; + XLINK_RET_IF(getLinkUpDeviceHandleByStreamId(streamId, &deviceHandle)); streamId_t streamIdOnly = EXTRACT_STREAM_ID(streamId); xLinkEvent_t event = {0}; XLINK_INIT_EVENT(event, streamIdOnly, XLINK_READ_REQ, - 0, NULL, link->deviceHandle); + 0, NULL, deviceHandle); XLINK_RET_IF(addEventWithPerf(&event, &opTime, XLINK_NO_RW_TIMEOUT)); @@ -176,13 +174,13 @@ XLinkError_t XLinkWriteDataWithTimeout(streamId_t const streamId, const uint8_t* XLINK_RET_IF(buffer == NULL); float opTime = 0.0f; - xLinkDesc_t* link = NULL; - XLINK_RET_IF(getLinkByStreamId(streamId, &link)); + xLinkDeviceHandle_t deviceHandle; + XLINK_RET_IF(getLinkUpDeviceHandleByStreamId(streamId, &deviceHandle)); streamId_t streamIdOnly = EXTRACT_STREAM_ID(streamId); xLinkEvent_t event = {0}; XLINK_INIT_EVENT(event, streamIdOnly, XLINK_WRITE_REQ, - size,(void*)buffer, link->deviceHandle); + size,(void*)buffer, deviceHandle); mvLog(MVLOG_WARN,"XLinkWriteDataWithTimeout is not fully supported yet. The XLinkWriteData method is called instead. Desired timeout = %d\n", timeoutMs); XLINK_RET_IF_FAIL(addEventWithPerf(&event, &opTime, timeoutMs)); @@ -200,13 +198,13 @@ XLinkError_t XLinkReadDataWithTimeout(streamId_t streamId, streamPacketDesc_t** XLINK_RET_IF(packet == NULL); float opTime = 0.0f; - xLinkDesc_t* link = NULL; - XLINK_RET_IF(getLinkByStreamId(streamId, &link)); + xLinkDeviceHandle_t deviceHandle; + XLINK_RET_IF(getLinkUpDeviceHandleByStreamId(streamId, &deviceHandle)); streamId_t streamIdOnly = EXTRACT_STREAM_ID(streamId); xLinkEvent_t event = {0}; XLINK_INIT_EVENT(event, streamId, XLINK_READ_REQ, - 0, NULL, link->deviceHandle); + 0, NULL, deviceHandle); XLINK_RET_IF_FAIL(addEventWithPerf(&event, &opTime, timeoutMs)); @@ -228,13 +226,13 @@ XLinkError_t XLinkReadMoveData(streamId_t const streamId, streamPacketDesc_t* co XLINK_RET_IF(packet == NULL); float opTime = 0; - xLinkDesc_t *link = NULL; - XLINK_RET_IF(getLinkByStreamId(streamId, &link)); + xLinkDeviceHandle_t deviceHandle; + XLINK_RET_IF(getLinkUpDeviceHandleByStreamId(streamId, &deviceHandle)); streamId_t streamIdOnly = EXTRACT_STREAM_ID(streamId); xLinkEvent_t event = {0}; XLINK_INIT_EVENT(event, streamIdOnly, XLINK_READ_REQ, - 0, NULL, link->deviceHandle); + 0, NULL, deviceHandle); event.header.flags.bitField.moveSemantic = 1; XLINK_RET_IF(addEventWithPerf(&event, &opTime, XLINK_NO_RW_TIMEOUT)); @@ -269,16 +267,16 @@ XLinkError_t XLinkReadMoveDataWithTimeout(streamId_t const streamId, streamPacke XLINK_RET_IF(packet == NULL); float opTime = 0; - xLinkDesc_t *link = NULL; - XLINK_RET_IF(getLinkByStreamId(streamId, &link)); + xLinkDeviceHandle_t deviceHandle; + XLINK_RET_IF(getLinkUpDeviceHandleByStreamId(streamId, &deviceHandle)); streamId_t streamIdOnly = EXTRACT_STREAM_ID(streamId); xLinkEvent_t event = {0}; XLINK_INIT_EVENT(event, streamIdOnly, XLINK_READ_REQ, - 0, NULL, link->deviceHandle); + 0, NULL, deviceHandle); event.header.flags.bitField.moveSemantic = 1; - const XLinkError_t rc = addEventWithPerfTimeout(&event, &opTime, msTimeout); + const XLinkError_t rc = addEventWithPerf(&event, &opTime, msTimeout); if(rc == X_LINK_TIMEOUT) return rc; else XLINK_RET_IF(rc); @@ -314,13 +312,13 @@ void XLinkDeallocateMoveData(void* const data, const uint32_t length) { XLinkError_t XLinkReleaseData(streamId_t const streamId) { - xLinkDesc_t* link = NULL; - XLINK_RET_IF(getLinkByStreamId(streamId, &link)); + xLinkDeviceHandle_t deviceHandle; + XLINK_RET_IF(getLinkUpDeviceHandleByStreamId(streamId, &deviceHandle)); streamId_t streamIdOnly = EXTRACT_STREAM_ID(streamId); xLinkEvent_t event = {0}; XLINK_INIT_EVENT(event, streamIdOnly, XLINK_READ_REL_REQ, - 0, NULL, link->deviceHandle); + 0, NULL, deviceHandle); XLINK_RET_IF(addEvent(&event, XLINK_NO_RW_TIMEOUT)); @@ -342,27 +340,6 @@ XLinkError_t XLinkReleaseSpecificData(streamId_t streamId, streamPacketDesc_t* p return X_LINK_SUCCESS; } -XLinkError_t XLinkGetFillLevel(streamId_t const streamId, int isRemote, int* fillLevel) -{ - xLinkDesc_t* link = NULL; - XLINK_RET_IF(getLinkByStreamId(streamId, &link)); - streamId_t streamIdOnly = EXTRACT_STREAM_ID(streamId); - - streamDesc_t* stream = - getStreamById(link->deviceHandle.xLinkFD, streamIdOnly); - ASSERT_XLINK(stream); - - if (isRemote) { - *fillLevel = stream->remoteFillLevel; - } - else { - *fillLevel = stream->localFillLevel; - } - - releaseStream(stream); - return X_LINK_SUCCESS; -} - // ------------------------------------ // Helpers declaration. Begin. // ------------------------------------ @@ -468,52 +445,6 @@ XLinkError_t addEventWithPerf(xLinkEvent_t *event, float* opTime, unsigned int t return X_LINK_SUCCESS; } -XLinkError_t addEventTimeout(xLinkEvent_t *event, struct timespec abstime) -{ - ASSERT_XLINK(event); - - xLinkEvent_t* ev = DispatcherAddEvent(EVENT_LOCAL, event); - if(ev == NULL) { - mvLog(MVLOG_ERROR, "Dispatcher failed on adding event. type: %s, id: %d, stream name: %s\n", - TypeToStr(event->header.type), event->header.id, event->header.streamName); - return X_LINK_ERROR; - } - - if (DispatcherWaitEventCompleteTimeout(&event->deviceHandle, abstime)) { - return X_LINK_TIMEOUT; - } - - XLINK_RET_ERR_IF( - event->header.flags.bitField.ack != 1, - X_LINK_COMMUNICATION_FAIL); - - return X_LINK_SUCCESS; -} - -XLinkError_t addEventWithPerfTimeout(xLinkEvent_t *event, float* opTime, unsigned int msTimeout) -{ - ASSERT_XLINK(opTime); - - struct timespec start, end; - clock_gettime(CLOCK_REALTIME, &start); - - struct timespec absTimeout = start; - int64_t sec = msTimeout / 1000; - absTimeout.tv_sec += sec; - absTimeout.tv_nsec += (long)((msTimeout - (sec * 1000)) * 1000000); - int64_t secOver = absTimeout.tv_nsec / 1000000000; - absTimeout.tv_nsec -= (long)(secOver * 1000000000); - absTimeout.tv_sec += secOver; - - int rc = addEventTimeout(event, absTimeout); - if(rc != X_LINK_SUCCESS) return rc; - - clock_gettime(CLOCK_REALTIME, &end); - *opTime = timespec_diff(&start, &end); - - return X_LINK_SUCCESS; -} - static XLinkError_t getLinkByStreamId(streamId_t streamId, xLinkDesc_t** out_link) { ASSERT_XLINK(out_link != NULL); diff --git a/src/shared/XLinkDevice.c b/src/shared/XLinkDevice.c index 7e33610e..924498ed 100644 --- a/src/shared/XLinkDevice.c +++ b/src/shared/XLinkDevice.c @@ -179,7 +179,14 @@ XLinkError_t XLinkFindAllSuitableDevices(XLinkDeviceState_t state, } //Called only from app - per device +XLinkError_t XLinkConnectWithTimeout(XLinkHandler_t* handler, const unsigned int msTimeout); XLinkError_t XLinkConnect(XLinkHandler_t* handler) +{ + return XLinkConnectWithTimeout(handler, XLINK_NO_RW_TIMEOUT); +} + +//Called only from app - per device +XLinkError_t XLinkConnectWithTimeout(XLinkHandler_t* handler, const unsigned int msTimeout) { XLINK_RET_IF(handler == NULL); if (strnlen(handler->devicePath, MAX_PATH_LENGTH) < 2) { @@ -217,8 +224,10 @@ 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, msTimeout)) { DispatcherClean(&link->deviceHandle); + // TODO(themarpe) - cleaner exit in case of timeout... + // DispatcherDeviceFdDown(&link->deviceHandle); return X_LINK_TIMEOUT; } @@ -280,88 +289,45 @@ XLinkError_t XLinkBootFirmware(const deviceDesc_t* deviceDesc, const char* firmw return X_LINK_COMMUNICATION_FAIL; } -XLinkError_t XLinkResetRemote(linkId_t id) +XLinkError_t XLinkResetRemote(const linkId_t id) { - xLinkDesc_t* link = getLinkById(id); - XLINK_RET_IF(link == NULL); - - if (getXLinkState(link) != XLINK_UP) { - mvLog(MVLOG_WARN, "Link is down, close connection to device without reset"); - XLinkPlatformCloseRemote(&link->deviceHandle); - return X_LINK_COMMUNICATION_NOT_OPEN; - } - - // Add event to reset device. After sending it, dispatcher will close fd link - xLinkEvent_t event = {0}; - event.header.type = XLINK_RESET_REQ; - event.deviceHandle = link->deviceHandle; - mvLog(MVLOG_DEBUG, "sending reset remote event\n"); - DispatcherAddEvent(EVENT_LOCAL, &event); - XLINK_RET_ERR_IF(DispatcherWaitEventComplete(&link->deviceHandle, XLINK_NO_RW_TIMEOUT), - X_LINK_TIMEOUT); - - int rc; - while(((rc = XLink_sem_wait(&link->dispatcherClosedSem)) == -1) && errno == EINTR) - continue; - if(rc) { - mvLog(MVLOG_ERROR,"can't wait dispatcherClosedSem\n"); - return X_LINK_ERROR; - } - - return X_LINK_SUCCESS; + return XLinkResetRemoteTimeout(id, XLINK_NO_RW_TIMEOUT); } - -XLinkError_t XLinkResetRemoteTimeout(linkId_t id, int timeoutMs) +XLinkError_t XLinkResetRemoteTimeout(const linkId_t id, const unsigned int msTimeout) { + // TODO(themarpe) + // xLinkDeviceHandle_t deviceHandle; + // XLINK_RET_IF(getLinkUpDeviceHandleByLinkId(id, &deviceHandle)); + xLinkDesc_t* link = getLinkById(id); XLINK_RET_IF(link == NULL); - - if (getXLinkState(link) != XLINK_UP) { - mvLog(MVLOG_WARN, "Link is down, close connection to device without reset"); - XLinkPlatformCloseRemote(&link->deviceHandle); - return X_LINK_COMMUNICATION_NOT_OPEN; - } - // Add event to reset device. After sending it, dispatcher will close fd link xLinkEvent_t event = {0}; event.header.type = XLINK_RESET_REQ; + // event.deviceHandle = deviceHandle; event.deviceHandle = link->deviceHandle; mvLog(MVLOG_DEBUG, "sending reset remote event\n"); + DispatcherAddEvent(EVENT_LOCAL, &event); + // XLinkError_t ret = DispatcherWaitEventComplete(&deviceHandle, msTimeout); + XLinkError_t ret = DispatcherWaitEventComplete(&link->deviceHandle, msTimeout); - struct timespec start; - clock_gettime(CLOCK_REALTIME, &start); - - struct timespec absTimeout = start; - int64_t sec = timeoutMs / 1000; - absTimeout.tv_sec += sec; - absTimeout.tv_nsec += (long)((timeoutMs - (sec * 1000)) * 1000000); - int64_t secOver = absTimeout.tv_nsec / 1000000000; - absTimeout.tv_nsec -= (long)(secOver * 1000000000); - absTimeout.tv_sec += secOver; - - xLinkEvent_t* ev = DispatcherAddEvent(EVENT_LOCAL, &event); - if(ev == NULL) { - mvLog(MVLOG_ERROR, "Dispatcher failed on adding event. type: %s, id: %d, stream name: %s\n", - TypeToStr(event.header.type), event.header.id, event.header.streamName); - return X_LINK_ERROR; - } - - XLinkError_t ret = DispatcherWaitEventCompleteTimeout(&link->deviceHandle, absTimeout); if(ret != X_LINK_SUCCESS){ // Closing device link unblocks any blocked events // Afterwards the dispatcher can properly cleanup in its own thread + // DispatcherDeviceFdDown(&deviceHandle); DispatcherDeviceFdDown(&link->deviceHandle); } - // Wait for dispatcher to be closed - if(XLink_sem_wait(&link->dispatcherClosedSem)) { + int rc; + while(((rc = XLink_sem_wait(&link->dispatcherClosedSem)) == -1) && errno == EINTR) + continue; + if(rc) { mvLog(MVLOG_ERROR,"can't wait dispatcherClosedSem\n"); return X_LINK_ERROR; } return ret; - } XLinkError_t XLinkResetAll() diff --git a/src/shared/XLinkDispatcher.c b/src/shared/XLinkDispatcher.c index 3b6526b5..804270a2 100644 --- a/src/shared/XLinkDispatcher.c +++ b/src/shared/XLinkDispatcher.c @@ -118,6 +118,7 @@ int numSchedulers; xLinkSchedulerState_t schedulerState[MAX_SCHEDULERS]; sem_t addSchedulerSem; +static pthread_mutex_t unique_id_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t clean_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t reset_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t num_schedulers_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -420,14 +421,21 @@ int DispatcherWaitEventComplete(xLinkDeviceHandle_t *deviceHandle, unsigned int // This is a temporary solution. TODO: replace this with something more efficient. while (timeoutMs--) { rc = XLink_sem_trywait(id); - if (!rc) { + int tmpErrno = errno; + if (rc == 0) { + // Success break; } else { + if(tmpErrno == ETIMEDOUT) { #if (defined(_WIN32) || defined(_WIN64) ) - Sleep(1); + Sleep(1); #else - usleep(1000); + usleep(1000); #endif + } else { + // error, exit + break; + } } } } else { @@ -446,53 +454,19 @@ int DispatcherWaitEventComplete(xLinkDeviceHandle_t *deviceHandle, unsigned int while(((rc = XLink_sem_wait(id)) == -1) && errno == EINTR) continue; if (id == NULL || rc) { - // Calling non-thread safe dispatcherReset from external thread - // TODO - investigate further and resolve - dispatcherReset(curr); - } - } -#endif - - return rc; -} - -int DispatcherWaitEventCompleteTimeout(xLinkDeviceHandle_t *deviceHandle, struct timespec abstime) -{ - xLinkSchedulerState_t* curr = findCorrespondingScheduler(deviceHandle->xLinkFD); - ASSERT_XLINK(curr != NULL); - - XLink_sem_t* id = getSem(pthread_self(), curr); - if (id == NULL) { - return -1; - } + // // graceful link shutdown instead + // dispatcherDeviceFdDown(curr); - int rc = XLink_sem_timedwait(id, &abstime); - int err = errno; - -#ifdef __PC__ - if (rc) { - if(err == ETIMEDOUT){ - return X_LINK_TIMEOUT; - } else { - xLinkEvent_t event = {0}; - event.header.type = XLINK_RESET_REQ; - event.deviceHandle = *deviceHandle; - mvLog(MVLOG_ERROR,"waiting is timeout, sending reset remote event"); - DispatcherAddEvent(EVENT_LOCAL, &event); - id = getSem(pthread_self(), curr); - if (id == NULL || XLink_sem_wait(id)) { // Calling non-thread safe dispatcherReset from external thread // TODO - investigate further and resolve dispatcherReset(curr); } } - } #endif return rc; } - char* TypeToStr(int type) { switch(type) @@ -831,8 +805,17 @@ static void postAndMarkEventServed(xLinkEventPriv_t *event) static int createUniqueID() { - static int id = 0xa; - return id++; + static eventId_t id = 0xa; + eventId_t idCopy = 0; + XLINK_RET_ERR_IF(pthread_mutex_lock(&unique_id_mutex) != 0, -1); + id++; + if(id >= INT32_MAX){ + id = 0xa; + } + idCopy = id; + XLINK_RET_ERR_IF(pthread_mutex_unlock(&unique_id_mutex) != 0, -1); + + return idCopy; } int findAvailableScheduler() diff --git a/src/shared/XLinkDispatcherImpl.c b/src/shared/XLinkDispatcherImpl.c index 05c3a46a..13f9955b 100644 --- a/src/shared/XLinkDispatcherImpl.c +++ b/src/shared/XLinkDispatcherImpl.c @@ -70,31 +70,32 @@ int dispatcherEventSend(xLinkEvent_t *event) } int dispatcherEventReceive(xLinkEvent_t* event){ - static xLinkEvent_t prevEvent = {0}; + // static xLinkEvent_t prevEvent = {0}; int rc = XLinkPlatformRead(&event->deviceHandle, &event->header, sizeof(event->header)); - mvLog(MVLOG_DEBUG,"Incoming event %p: %s %d %p prevEvent: %s %d %p\n", - event, - TypeToStr(event->header.type), - (int)event->header.id, - event->deviceHandle.xLinkFD, - TypeToStr(prevEvent.header.type), - (int)prevEvent.header.id, - prevEvent.deviceHandle.xLinkFD); + // mvLog(MVLOG_DEBUG,"Incoming event %p: %s %d %p prevEvent: %s %d %p\n", + // event, + // TypeToStr(event->header.type), + // (int)event->header.id, + // event->deviceHandle.xLinkFD, + // TypeToStr(prevEvent.header.type), + // (int)prevEvent.header.id, + // prevEvent.deviceHandle.xLinkFD); if(rc < 0) { mvLog(MVLOG_DEBUG,"%s() Read failed %d\n", __func__, (int)rc); return rc; } - if (prevEvent.header.id == event->header.id && - prevEvent.header.type == event->header.type && - prevEvent.deviceHandle.xLinkFD == event->deviceHandle.xLinkFD) { - mvLog(MVLOG_FATAL,"Duplicate id detected. \n"); - } + // TODO(themarpe) - reimplement duplicate ID detection + // if (prevEvent.header.id == event->header.id && + // prevEvent.header.type == event->header.type && + // prevEvent.deviceHandle.xLinkFD == event->deviceHandle.xLinkFD) { + // mvLog(MVLOG_FATAL,"Duplicate id detected. \n"); + // } + // prevEvent = *event; - prevEvent = *event; return handleIncomingEvent(event); } diff --git a/src/shared/XLinkPrivateFields.c b/src/shared/XLinkPrivateFields.c index 064b8a0d..312e9596 100644 --- a/src/shared/XLinkPrivateFields.c +++ b/src/shared/XLinkPrivateFields.c @@ -34,6 +34,40 @@ xLinkDesc_t* getLinkById(linkId_t id) return NULL; } +XLinkError_t getLinkUpDeviceHandleByStreamId(streamId_t const streamId, xLinkDeviceHandle_t* const out_handle) { + ASSERT_XLINK(out_handle != NULL); + + linkId_t id = EXTRACT_LINK_ID(streamId); + return getLinkUpDeviceHandleByLinkId(id, out_handle); +} + +XLinkError_t getLinkUpDeviceHandleByLinkId(linkId_t id, xLinkDeviceHandle_t* const out_handle) +{ + ASSERT_XLINK(out_handle); + XLINK_RET_ERR_IF(pthread_mutex_lock(&availableXLinksMutex) != 0, X_LINK_ERROR); + + // Error if no valid id found + XLinkError_t ret = X_LINK_ERROR; + for (int i = 0; i < MAX_LINKS; i++) { + if (availableXLinks[i].id == id) { + // Copy handle out before unlocking the mutex + *out_handle = availableXLinks[i].deviceHandle; + // Check if state is up + if(availableXLinks[i].peerState == XLINK_UP){ + ret = X_LINK_SUCCESS; + } else { + ret = X_LINK_COMMUNICATION_NOT_OPEN; + } + // Exit the loop + break; + } + } + + XLINK_RET_ERR_IF(pthread_mutex_unlock(&availableXLinksMutex) != 0, X_LINK_ERROR); + // Return success/error status + return ret; +} + xLinkDesc_t* getLink(void* fd) { @@ -51,6 +85,19 @@ xLinkDesc_t* getLink(void* fd) return NULL; } +xLinkDesc_t* getLinkUnsafe(void* fd) +{ + + int i; + for (i = 0; i < MAX_LINKS; i++) { + if (availableXLinks[i].deviceHandle.xLinkFD == fd) { + return &availableXLinks[i]; + } + } + + return NULL; +} + streamId_t getStreamIdByName(xLinkDesc_t* link, const char* name) { streamDesc_t* stream = getStreamByName(link, name); diff --git a/src/shared/XLinkSemaphore.c b/src/shared/XLinkSemaphore.c index 40d90271..fe8dd65e 100644 --- a/src/shared/XLinkSemaphore.c +++ b/src/shared/XLinkSemaphore.c @@ -117,12 +117,15 @@ int XLink_sem_timedwait(XLink_sem_t* sem, const struct timespec* abstime) int XLink_sem_trywait(XLink_sem_t* sem) { + errno = EINVAL; XLINK_RET_ERR_IF(sem == NULL, -1); XLINK_RET_IF_FAIL(XLink_sem_inc(sem)); int ret = sem_trywait(&sem->psem); + int tmpErrno = errno; XLINK_RET_IF_FAIL(XLink_sem_dec(sem)); + errno = tmpErrno; return ret; }