diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 65b690e..2330b09 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -54,3 +54,6 @@ if (UNIX AND !APPLE) add_example(xlink_client_local xlink_client_local.cpp) endif (UNIX AND !APPLE) +# EP example +add_example(xlink_usb_server xlink_usb_server.cpp) +add_example(xlink_usb_client xlink_usb_client.cpp) diff --git a/examples/xlink_usb_client.cpp b/examples/xlink_usb_client.cpp new file mode 100644 index 0000000..01b1d76 --- /dev/null +++ b/examples/xlink_usb_client.cpp @@ -0,0 +1,54 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "XLink/XLink.h" +#include "XLink/XLinkPublicDefines.h" +#include "XLink/XLinkLog.h" + +// Common constants +const uint8_t DUMMY_DATA[1024*128] = {}; + +int main(int argc, char** argv) { + XLinkGlobalHandler_t gHandler; + XLinkInitialize(&gHandler); + + mvLogDefaultLevelSet(MVLOG_DEBUG); + + deviceDesc_t deviceDesc; + strcpy(deviceDesc.name, "usbdev"); + deviceDesc.protocol = X_LINK_USB_EP; + + printf("Device name: %s\n", deviceDesc.name); + + XLinkHandler_t handler; + handler.devicePath = deviceDesc.name; + handler.protocol = deviceDesc.protocol; + auto connRet = XLinkConnect(&handler); + printf("Connection returned: %s\n", XLinkErrorToStr(connRet)); + if(connRet != X_LINK_SUCCESS) { + return -1; + } + + auto s = XLinkOpenStream(handler.linkId, "test_0", sizeof(DUMMY_DATA) * 2); + if(s == INVALID_STREAM_ID){ + printf("Open stream failed...\n"); + } else { + printf("Open stream OK - id: 0x%08X\n", s); + } + + auto w = XLinkWriteData(s, (uint8_t*) &s, sizeof(s)); + assert(w == X_LINK_SUCCESS); + + return 0; +} diff --git a/examples/xlink_usb_server.cpp b/examples/xlink_usb_server.cpp new file mode 100644 index 0000000..fe22396 --- /dev/null +++ b/examples/xlink_usb_server.cpp @@ -0,0 +1,62 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "XLink/XLink.h" +#include "XLink/XLinkPublicDefines.h" +#include "XLink/XLinkLog.h" + +// Common constants +constexpr static auto NUM_STREAMS = 16; +constexpr static auto NUM_PACKETS = 120; +const uint8_t DUMMY_DATA[1024*128] = {}; +XLinkGlobalHandler_t xlinkGlobalHandler = {}; + +// Server +// + +int main(int argc, const char** argv){ + + xlinkGlobalHandler.protocol = X_LINK_USB_EP; + + // Initialize and suppress XLink logs + mvLogDefaultLevelSet(MVLOG_DEBUG); + auto status = XLinkInitialize(&xlinkGlobalHandler); + if(X_LINK_SUCCESS != status) { + throw std::runtime_error("Couldn't initialize XLink"); + } + + XLinkHandler_t handler; + handler.devicePath = "/dev/usb-ffs/device"; + handler.protocol = X_LINK_USB_EP; + XLinkServerOnly(&handler); + + + // loop through streams + auto s = XLinkOpenStream(0, "test_0", sizeof(DUMMY_DATA) * 2); + assert(s != INVALID_STREAM_ID); + + // auto w = XLinkWriteData2(s, (uint8_t*) &s, sizeof(s/2), ((uint8_t*) &s) + sizeof(s/2), sizeof(s) - sizeof(s/2)); + // assert(w == X_LINK_SUCCESS); + + auto w = XLinkWriteData(s, (uint8_t*) &s, sizeof(s)); + assert(w == X_LINK_SUCCESS); + + + streamPacketDesc_t p; + w = XLinkReadMoveData(s, &p); + assert(w == X_LINK_SUCCESS); + XLinkDeallocateMoveData(p.data, p.length); + + return 0; +} diff --git a/include/XLink/XLink.h b/include/XLink/XLink.h index b55fe23..1774f38 100644 --- a/include/XLink/XLink.h +++ b/include/XLink/XLink.h @@ -306,6 +306,17 @@ XLinkError_t XLinkWriteData(streamId_t const streamId, const uint8_t* buffer, in XLinkError_t XLinkWriteData_(streamId_t streamId, const uint8_t* buffer, int size, XLinkTimespec* outTSend); +/** + * @brief Sends/Receives a message to Gate via USB + * @param[in] name - Device name/path + * @param[in] data - Data to be transmitted/collected + * @param[in] size - The data size + * @param[in] size - USB timeout + * @return Status code of the operation: X_LINK_SUCCESS (0) for success + */ +XLinkError_t XLinkGateWrite(const char *name, void *data, int size, int timeout); +XLinkError_t XLinkGateRead(const char *name, void *data, int size, int timeout); + /** * @brief Sends a package to initiate the writing of a file descriptor * @warning Actual size of the written data is ALIGN_UP(size, 64) diff --git a/include/XLink/XLinkPlatform.h b/include/XLink/XLinkPlatform.h index 77b67e3..c3974a9 100644 --- a/include/XLink/XLinkPlatform.h +++ b/include/XLink/XLinkPlatform.h @@ -37,6 +37,7 @@ typedef enum { X_LINK_PLATFORM_LOCAL_SHDMEM_DRIVER_NOT_LOADED = X_LINK_PLATFORM_DRIVER_NOT_LOADED+X_LINK_LOCAL_SHDMEM, X_LINK_PLATFORM_TCP_IP_OR_LOCAL_SHDMEM_DRIVER_NOT_LOADED = X_LINK_PLATFORM_DRIVER_NOT_LOADED+X_LINK_TCP_IP_OR_LOCAL_SHDMEM, X_LINK_PLATFORM_PCIE_DRIVER_NOT_LOADED = X_LINK_PLATFORM_DRIVER_NOT_LOADED+X_LINK_PCIE, + X_LINK_PLATFORM_USB_EP_DRIVER_NOT_LOADED = X_LINK_PLATFORM_DRIVER_NOT_LOADED+X_LINK_USB_EP, } xLinkPlatformErrorCode_t; // ------------------------------------ @@ -90,6 +91,8 @@ xLinkPlatformErrorCode_t XLinkPlatformCloseRemote(xLinkDeviceHandle_t* deviceHan int XLinkPlatformWrite(xLinkDeviceHandle_t *deviceHandle, void *data, int size); int XLinkPlatformWriteFd(xLinkDeviceHandle_t *deviceHandle, const long fd, void *data2, int size2); int XLinkPlatformRead(xLinkDeviceHandle_t *deviceHandle, void *data, int size, long *fd); +int XLinkPlatformGateWrite(const char *name, void *data, int size, int timeout); +int XLinkPlatformGateRead(const char *name, void *data, int size, int timeout); void* XLinkPlatformAllocateData(uint32_t size, uint32_t alignment); void XLinkPlatformDeallocateData(void *ptr, uint32_t size, uint32_t alignment); diff --git a/include/XLink/XLinkPublicDefines.h b/include/XLink/XLinkPublicDefines.h index 45af727..fd53d14 100644 --- a/include/XLink/XLinkPublicDefines.h +++ b/include/XLink/XLinkPublicDefines.h @@ -68,6 +68,7 @@ typedef enum{ X_LINK_TCP_IP, X_LINK_LOCAL_SHDMEM, X_LINK_TCP_IP_OR_LOCAL_SHDMEM, + X_LINK_USB_EP, X_LINK_NMB_OF_PROTOCOLS, X_LINK_ANY_PROTOCOL } XLinkProtocol_t; diff --git a/src/pc/PlatformData.c b/src/pc/PlatformData.c index c56cc89..9fb2d56 100644 --- a/src/pc/PlatformData.c +++ b/src/pc/PlatformData.c @@ -56,10 +56,12 @@ #include #include "usb_host.h" +#endif /*USE_USB_VSC*/ extern int usbFdWrite; extern int usbFdRead; -#endif /*USE_USB_VSC*/ +extern int usbGateFdWrite; +extern int usbGateFdRead; // ------------------------------------ // Wrappers declaration. Begin. @@ -87,7 +89,8 @@ int XLinkPlatformWrite(xLinkDeviceHandle_t *deviceHandle, void *data, int size) switch (deviceHandle->protocol) { case X_LINK_USB_VSC: case X_LINK_USB_CDC: - return usbPlatformWrite(deviceHandle->xLinkFD, data, size); + case X_LINK_USB_EP: + return usbPlatformWrite(deviceHandle->protocol, deviceHandle->xLinkFD, data, size); case X_LINK_PCIE: return pciePlatformWrite(deviceHandle->xLinkFD, data, size); @@ -134,7 +137,8 @@ int XLinkPlatformRead(xLinkDeviceHandle_t *deviceHandle, void *data, int size, l switch (deviceHandle->protocol) { case X_LINK_USB_VSC: case X_LINK_USB_CDC: - return usbPlatformRead(deviceHandle->xLinkFD, data, size); + case X_LINK_USB_EP: + return usbPlatformRead(deviceHandle->protocol, deviceHandle->xLinkFD, data, size); case X_LINK_PCIE: return pciePlatformRead(deviceHandle->xLinkFD, data, size); @@ -153,6 +157,26 @@ int XLinkPlatformRead(xLinkDeviceHandle_t *deviceHandle, void *data, int size, l } } +int XLinkPlatformGateWrite(const char *name, void *data, int size, int timeout) +{ + if(!XLinkIsProtocolInitialized(X_LINK_USB_EP)) { + return X_LINK_PLATFORM_DRIVER_NOT_LOADED+X_LINK_USB_EP; + } + + return usbPlatformGateWrite(name, data, size, timeout); +} + +int XLinkPlatformGateRead(const char *name, void *data, int size, int timeout) +{ + if(!XLinkIsProtocolInitialized(X_LINK_USB_EP)) { + return X_LINK_PLATFORM_DRIVER_NOT_LOADED+X_LINK_USB_EP; + } + + return usbPlatformGateRead(name, data, size, timeout); +} + + + void* XLinkPlatformAllocateData(uint32_t size, uint32_t alignment) { void* ret = NULL; diff --git a/src/pc/PlatformDeviceControl.c b/src/pc/PlatformDeviceControl.c index 6bd45fd..cce0bd6 100644 --- a/src/pc/PlatformDeviceControl.c +++ b/src/pc/PlatformDeviceControl.c @@ -24,10 +24,12 @@ #include #include #include +#endif /*USE_USB_VSC*/ int usbFdWrite = -1; int usbFdRead = -1; -#endif /*USE_USB_VSC*/ +int usbGateFdWrite = -1; +int usbGateFdRead = -1; #include "XLinkPublicDefines.h" @@ -90,6 +92,7 @@ xLinkPlatformErrorCode_t XLinkPlatformInit(XLinkGlobalHandler_t* globalHandler) // check for failed initialization; LIBUSB_SUCCESS = 0 if (usbInitialize(globalHandler->options) != 0) { xlinkSetProtocolInitialized(X_LINK_USB_VSC, 0); + xlinkSetProtocolInitialized(X_LINK_USB_EP, 0); } // Initialize tcpip protocol if necessary @@ -103,7 +106,7 @@ xLinkPlatformErrorCode_t XLinkPlatformInit(XLinkGlobalHandler_t* globalHandler) xlinkSetProtocolInitialized(X_LINK_LOCAL_SHDMEM, 0); } #endif - + xlinkSetProtocolInitialized(X_LINK_TCP_IP_OR_LOCAL_SHDMEM, 1); return X_LINK_PLATFORM_SUCCESS; @@ -185,7 +188,8 @@ xLinkPlatformErrorCode_t XLinkPlatformConnect(const char* devPathRead, const cha switch (*protocol) { case X_LINK_USB_VSC: case X_LINK_USB_CDC: - return usbPlatformConnect(devPathRead, devPathWrite, fd); + case X_LINK_USB_EP: + return usbPlatformConnect(*protocol, devPathRead, devPathWrite, fd); case X_LINK_PCIE: return pciePlatformConnect(devPathRead, devPathWrite, fd); @@ -209,6 +213,11 @@ xLinkPlatformErrorCode_t XLinkPlatformConnect(const char* devPathRead, const cha xLinkPlatformErrorCode_t XLinkPlatformServer(const char* devPathRead, const char* devPathWrite, XLinkProtocol_t *protocol, void** fd) { switch (*protocol) { + case X_LINK_USB_VSC: + case X_LINK_USB_CDC: + case X_LINK_USB_EP: + return usbPlatformServer(devPathRead, devPathWrite, fd); + case X_LINK_TCP_IP: return tcpipPlatformServer(devPathRead, devPathWrite, fd, NULL); @@ -260,7 +269,8 @@ xLinkPlatformErrorCode_t XLinkPlatformCloseRemote(xLinkDeviceHandle_t* deviceHan switch (deviceHandle->protocol) { case X_LINK_USB_VSC: case X_LINK_USB_CDC: - return usbPlatformClose(deviceHandle->xLinkFD); + case X_LINK_USB_EP: + return usbPlatformClose(deviceHandle->protocol, deviceHandle->xLinkFD); case X_LINK_PCIE: return pciePlatformClose(deviceHandle->xLinkFD); diff --git a/src/pc/PlatformDeviceSearch.c b/src/pc/PlatformDeviceSearch.c index 40c3eea..f029ef9 100644 --- a/src/pc/PlatformDeviceSearch.c +++ b/src/pc/PlatformDeviceSearch.c @@ -64,6 +64,7 @@ xLinkPlatformErrorCode_t XLinkPlatformFindDevices(const deviceDesc_t in_deviceRe switch (in_deviceRequirements.protocol){ case X_LINK_USB_CDC: case X_LINK_USB_VSC: + case X_LINK_USB_EP: if(!XLinkIsProtocolInitialized(in_deviceRequirements.protocol)) { return X_LINK_PLATFORM_DRIVER_NOT_LOADED+in_deviceRequirements.protocol; } diff --git a/src/pc/protocols/usb_host.cpp b/src/pc/protocols/usb_host.cpp index 34d6a50..e25f2ef 100644 --- a/src/pc/protocols/usb_host.cpp +++ b/src/pc/protocols/usb_host.cpp @@ -24,6 +24,22 @@ #include "usb_host.h" #include "../PlatformDeviceFd.h" +// std +#include +#include +#include +#include +#include +#include +#include + +// Used server side only +#if defined(__unix__) +#include +#include +#include +#endif + constexpr static int MAXIMUM_PORT_NUMBERS = 7; using VidPid = std::pair; static const int MX_ID_TIMEOUT_MS = 100; @@ -31,18 +47,29 @@ static const int MX_ID_NOPS_TIMEOUT_MS = 500; static constexpr auto DEFAULT_OPEN_TIMEOUT = std::chrono::seconds(5); static constexpr auto DEFAULT_WRITE_TIMEOUT = 2000; +static constexpr auto DEFAULT_READ_TIMEOUT = 2000; static constexpr std::chrono::milliseconds DEFAULT_CONNECT_TIMEOUT{20000}; static constexpr std::chrono::milliseconds DEFAULT_SEND_FILE_TIMEOUT{10000}; static constexpr auto USB1_CHUNKSZ = 64; -static constexpr int USB_ENDPOINT_IN = 0x81; -static constexpr int USB_ENDPOINT_OUT = 0x01; +static constexpr int USB_VSC_INTERFACE = 0; +static constexpr int USB_VSC_ENDPOINT_IN = 0x81; +static constexpr int USB_VSC_ENDPOINT_OUT = 0x01; + +// TBD could be taken from the USB descriptor, based on strings +static constexpr int USB_EP_INTERFACE_GATE = 2; +static constexpr int USB_EP_INTERFACE_DEVICE = 3; +static constexpr int USB_EP_ENDPOINT_GATE_IN = 0x83; +static constexpr int USB_EP_ENDPOINT_GATE_OUT = 0x03; +static constexpr int USB_EP_ENDPOINT_DEVICE_IN = 0x84; +static constexpr int USB_EP_ENDPOINT_DEVICE_OUT = 0x04; static constexpr int XLINK_USB_DATA_TIMEOUT = 0; static unsigned int bulk_chunklen = DEFAULT_CHUNKSZ; static int write_timeout = DEFAULT_WRITE_TIMEOUT; static int initialized; +static std::atomic isServer { false }; struct UsbSetupPacket { uint8_t requestType; @@ -94,10 +121,23 @@ static std::unordered_map vidPidToDeviceS {{0x03E7, 0xf63b}, X_LINK_BOOTED}, {{0x03E7, 0xf63c}, X_LINK_BOOTLOADER}, {{0x03E7, 0xf63d}, X_LINK_FLASH_BOOTED}, + {{0x05C6, 0x901d}, X_LINK_GATE}, +}; + +struct USBGateRequest { + uint32_t RequestNum; + uint32_t RequestSize; +}; + +struct GateResponse { + uint32_t state; + uint32_t protocol; + uint32_t platform; }; static std::string getLibusbDevicePath(libusb_device *dev); static libusb_error getLibusbDeviceMxId(XLinkDeviceState_t state, std::string devicePath, const libusb_device_descriptor* pDesc, libusb_device *dev, std::string& outMxId); +static libusb_error getLibusbDeviceGateResponse(const libusb_device_descriptor* pDesc, libusb_device *dev, GateResponse& outGateResponse, std::string& outSerial); static const char* xlink_libusb_strerror(int x); #ifdef _WIN32 std::string getWinUsbMxId(VidPid vidpid, libusb_device* dev); @@ -110,13 +150,6 @@ xLinkPlatformErrorCode_t getUSBDevices(const deviceDesc_t in_deviceRequirements, // Also protects usb_mx_id_cache std::lock_guard l(mutex); - // No RVC3/4 devices on USB now, return 0 - if(in_deviceRequirements.platform == X_LINK_RVC3 || in_deviceRequirements.platform == X_LINK_RVC4){ - *out_amountOfFoundDevices = 0; - return X_LINK_PLATFORM_SUCCESS; - } - - // Get list of usb devices static libusb_device **devs = NULL; auto numDevices = libusb_get_device_list(context, &devs); @@ -173,39 +206,64 @@ xLinkPlatformErrorCode_t getUSBDevices(const deviceDesc_t in_deviceRequirements, } } - // Get device mxid + XLinkPlatform_t platform = X_LINK_MYRIAD_X; + XLinkProtocol_t protocol = X_LINK_USB_VSC; std::string mxId; - libusb_error rc = getLibusbDeviceMxId(state, devicePath, &desc, devs[i], mxId); - mvLog(MVLOG_DEBUG, "getLibusbDeviceMxId returned: %s", xlink_libusb_strerror(rc)); - switch (rc) - { - case LIBUSB_SUCCESS: - status = X_LINK_SUCCESS; - break; - case LIBUSB_ERROR_ACCESS: - status = X_LINK_INSUFFICIENT_PERMISSIONS; - break; - case LIBUSB_ERROR_BUSY: - status = X_LINK_DEVICE_ALREADY_IN_USE; - break; - default: - status = X_LINK_ERROR; - break; + + // Check for RVC3 and RVC4 first + if(state == X_LINK_GATE || in_deviceRequirements.platform == X_LINK_RVC3 || in_deviceRequirements.platform == X_LINK_RVC4){ + + GateResponse gateResponse; + getLibusbDeviceGateResponse(&desc, devs[i], gateResponse, mxId); + + if (gateResponse.platform == 4){ + platform = X_LINK_RVC4; + } else { + platform = X_LINK_RVC3; + } + + protocol = (XLinkProtocol_t)gateResponse.protocol; + state = (XLinkDeviceState_t)gateResponse.state; + + } else { + // Get device mxid + libusb_error rc = getLibusbDeviceMxId(state, devicePath, &desc, devs[i], mxId); + mvLog(MVLOG_DEBUG, "getLibusbDeviceMxId returned: %s", xlink_libusb_strerror(rc)); + switch (rc) + { + case LIBUSB_SUCCESS: + status = X_LINK_SUCCESS; + break; + case LIBUSB_ERROR_ACCESS: + status = X_LINK_INSUFFICIENT_PERMISSIONS; + break; + case LIBUSB_ERROR_BUSY: + status = X_LINK_DEVICE_ALREADY_IN_USE; + break; + default: + status = X_LINK_ERROR; + break; + } + } - // compare with MxId + // Comparisons / filters + // compare deviceId std::string requiredMxId(in_deviceRequirements.mxid); if(requiredMxId.length() > 0 && requiredMxId != mxId){ // Current device doesn't match the "filter" continue; } - - // TODO(themarpe) - check platform + // compare platform + if(in_deviceRequirements.platform != X_LINK_ANY_PLATFORM && in_deviceRequirements.platform != platform){ + // Current device doesn't match the "filter" + continue; + } // Everything passed, fillout details of found device out_foundDevices[numDevicesFound].status = status; - out_foundDevices[numDevicesFound].platform = X_LINK_MYRIAD_X; - out_foundDevices[numDevicesFound].protocol = X_LINK_USB_VSC; + out_foundDevices[numDevicesFound].platform = platform; + out_foundDevices[numDevicesFound].protocol = protocol; out_foundDevices[numDevicesFound].state = state; memset(out_foundDevices[numDevicesFound].name, 0, sizeof(out_foundDevices[numDevicesFound].name)); strncpy(out_foundDevices[numDevicesFound].name, devicePath.c_str(), sizeof(out_foundDevices[numDevicesFound].name)); @@ -227,9 +285,6 @@ xLinkPlatformErrorCode_t getUSBDevices(const deviceDesc_t in_deviceRequirements, } extern "C" xLinkPlatformErrorCode_t refLibusbDeviceByName(const char* name, libusb_device** pdev) { - - std::lock_guard l(mutex); - // Get list of usb devices static libusb_device **devs = NULL; auto numDevices = libusb_get_device_list(context, &devs); @@ -531,12 +586,78 @@ libusb_error getLibusbDeviceMxId(XLinkDeviceState_t state, std::string devicePat } +static libusb_error getLibusbDeviceGateResponse(const libusb_device_descriptor* pDesc, libusb_device *dev, GateResponse& outGateResponse, std::string& outSerial) { + GateResponse gateResponse = {0}; + std::string serial = ""; + + // get serial from usb descriptor + libusb_device_handle *handle = nullptr; + int libusb_rc = LIBUSB_SUCCESS; + libusb_rc = libusb_open(dev, &handle); + if (libusb_rc != 0){ + return (libusb_error) libusb_rc; + } + + libusb_rc = libusb_claim_interface(handle, USB_EP_INTERFACE_GATE); + if (libusb_rc != 0){ + libusb_close(handle); + return (libusb_error) libusb_rc; + } + + USBGateRequest usbGateRequest = { + .RequestNum = 12, + .RequestSize = 0, + }; + + int transferred = 0; + + libusb_rc = libusb_bulk_transfer(handle, USB_EP_ENDPOINT_GATE_OUT, (unsigned char*)&usbGateRequest, sizeof(usbGateRequest), &transferred, DEFAULT_WRITE_TIMEOUT); + if (libusb_rc != 0) { + libusb_close(handle); + return (libusb_error) libusb_rc; + } + + USBGateRequest usbGateResponse = { 0 }; + libusb_rc = libusb_bulk_transfer(handle, USB_EP_ENDPOINT_GATE_IN, (unsigned char*)&usbGateResponse, sizeof(usbGateResponse), &transferred, DEFAULT_WRITE_TIMEOUT); + if (libusb_rc != 0) { + libusb_close(handle); + return (libusb_error) libusb_rc; + } + + std::vector respBuffer; + respBuffer.resize(usbGateResponse.RequestSize); + libusb_rc = libusb_bulk_transfer(handle, USB_EP_ENDPOINT_GATE_IN, (unsigned char*)&respBuffer[0], usbGateResponse.RequestSize, &transferred, DEFAULT_WRITE_TIMEOUT); + if (libusb_rc != 0) { + libusb_close(handle); + return (libusb_error) libusb_rc; + } + + + size_t serialStrLen = usbGateResponse.RequestSize - sizeof(GateResponse); + serial.resize(serialStrLen + 1); + for (int i = 0; i < serialStrLen; ++i) { + serial[i] = respBuffer[i]; + } + serial[serialStrLen] = '\0'; + outSerial = serial; + + memcpy(&gateResponse, &respBuffer[serialStrLen], sizeof(gateResponse)); + outGateResponse = gateResponse; + + // Close opened device + if(handle != nullptr){ + libusb_close(handle); + } + + return libusb_error::LIBUSB_SUCCESS; +} + const char* xlink_libusb_strerror(int x) { return libusb_strerror((libusb_error) x); } -static libusb_error usb_open_device(libusb_device *dev, uint8_t* endpoint, libusb_device_handle*& handle) +static libusb_error usb_open_device(XLinkProtocol_t protocol, libusb_device *dev, uint8_t* endpoint, libusb_device_handle*& handle) { struct libusb_config_descriptor *cdesc; const struct libusb_interface_descriptor *ifdesc; @@ -591,12 +712,21 @@ static libusb_error usb_open_device(libusb_device *dev, uint8_t* endpoint, libus // Set to auto detach & reattach kernel driver, and ignore result (success or not supported) libusb_set_auto_detach_kernel_driver(h, 1); - if((res = libusb_claim_interface(h, 0)) < 0) - { - mvLog(MVLOG_DEBUG, "claiming interface 0 failed: %s\n", xlink_libusb_strerror(res)); - libusb_close(h); - return (libusb_error) res; + + if(protocol == X_LINK_USB_EP){ + if((res = libusb_claim_interface(h, USB_EP_INTERFACE_DEVICE)) < 0){ + mvLog(MVLOG_DEBUG, "claiming interface %d failed: %s\n", USB_EP_INTERFACE_DEVICE, xlink_libusb_strerror(res)); + libusb_close(h); + return (libusb_error) res; + } + } else { + if((res = libusb_claim_interface(h, USB_VSC_INTERFACE)) < 0){ + mvLog(MVLOG_DEBUG, "claiming interface %d failed: %s\n", USB_VSC_INTERFACE, xlink_libusb_strerror(res)); + libusb_close(h); + return (libusb_error) res; + } } + if((res = libusb_get_config_descriptor(dev, 0, &cdesc)) < 0) { mvLog(MVLOG_DEBUG, "Unable to get USB config descriptor: %s\n", xlink_libusb_strerror(res)); @@ -712,7 +842,7 @@ int usb_boot(const char *addr, const void *mvcmd, unsigned size) auto t2 = steady_clock::now(); do { - if((res = usb_open_device(dev, &endpoint, h)) == LIBUSB_SUCCESS){ + if((res = usb_open_device(X_LINK_USB_VSC, dev, &endpoint, h)) == LIBUSB_SUCCESS){ break; } std::this_thread::sleep_for(milliseconds(100)); @@ -744,7 +874,7 @@ int usb_boot(const char *addr, const void *mvcmd, unsigned size) -xLinkPlatformErrorCode_t usbLinkOpen(const char *path, libusb_device_handle*& h) +xLinkPlatformErrorCode_t usbLinkOpen(XLinkProtocol_t protocol, const char *path, libusb_device_handle*& h) { using namespace std::chrono; if (path == NULL) { @@ -769,7 +899,7 @@ xLinkPlatformErrorCode_t usbLinkOpen(const char *path, libusb_device_handle*& h) } uint8_t ep = 0; - libusb_error libusb_rc = usb_open_device(dev, &ep, h); + libusb_error libusb_rc = usb_open_device(protocol, dev, &ep, h); libusb_unref_device(dev); if(libusb_rc == LIBUSB_SUCCESS) { return X_LINK_PLATFORM_SUCCESS; @@ -827,16 +957,46 @@ xLinkPlatformErrorCode_t usbLinkBootBootloader(const char *path) { return X_LINK_PLATFORM_SUCCESS; } -void usbLinkClose(libusb_device_handle *f) +void usbLinkClose(XLinkProtocol_t protocol, libusb_device_handle *f) { - libusb_release_interface(f, 0); + + if (protocol == X_LINK_USB_EP){ + libusb_release_interface(f, USB_EP_INTERFACE_DEVICE); + } else { + libusb_release_interface(f, USB_VSC_INTERFACE); + } + libusb_close(f); } +extern int usbFdWrite; +extern int usbFdRead; +int usbPlatformServer(const char *devPathRead, const char *devPathWrite, void **fd) +{ +#if defined(__unix__) + // FIXME: get this info from the caller, don't hardcode here + int outfd = open("/dev/usb-ffs/device/ep1", O_WRONLY); + int infd = open("/dev/usb-ffs/device/ep2", O_RDONLY); + + if(outfd < 0 || infd < 0) { + return -1; + } + + usbFdRead = infd; + usbFdWrite = outfd; + + isServer = true; + + *fd = createPlatformDeviceFdKey((void*) (uintptr_t) usbFdRead); +#endif + return 0; +} -int usbPlatformConnect(const char *devPathRead, const char *devPathWrite, void **fd) + +int usbPlatformConnect(XLinkProtocol_t protocol, const char *devPathRead, const char *devPathWrite, void **fd) { + std::lock_guard l(mutex); #if (!defined(USE_USB_VSC)) #ifdef USE_LINK_JTAG struct sockaddr_in serv_addr; @@ -927,7 +1087,7 @@ int usbPlatformConnect(const char *devPathRead, const char *devPathWrite, void * #else libusb_device_handle* usbHandle = nullptr; - xLinkPlatformErrorCode_t ret = usbLinkOpen(devPathWrite, usbHandle); + xLinkPlatformErrorCode_t ret = usbLinkOpen(protocol, devPathWrite, usbHandle); if (ret != X_LINK_PLATFORM_SUCCESS) { @@ -939,14 +1099,16 @@ int usbPlatformConnect(const char *devPathRead, const char *devPathWrite, void * // (as file descriptors are reused and can cause a clash with lookups between scheduler and link) *fd = createPlatformDeviceFdKey(usbHandle); + isServer = false; #endif /*USE_USB_VSC*/ return 0; } -int usbPlatformClose(void *fdKey) +int usbPlatformClose(XLinkProtocol_t protocol, void *fdKey) { + std::lock_guard l(mutex); #ifndef USE_USB_VSC #ifdef USE_LINK_JTAG @@ -968,7 +1130,7 @@ int usbPlatformClose(void *fdKey) mvLog(MVLOG_FATAL, "Cannot find USB Handle by key: %" PRIxPTR, (uintptr_t) fdKey); return -1; } - usbLinkClose((libusb_device_handle *) tmpUsbHandle); + usbLinkClose(protocol, (libusb_device_handle *) tmpUsbHandle); if(destroyPlatformDeviceFdKey(fdKey)){ mvLog(MVLOG_FATAL, "Cannot destroy USB Handle key: %" PRIxPTR, (uintptr_t) fdKey); @@ -994,7 +1156,7 @@ int usbPlatformBootFirmware(const deviceDesc_t* deviceDesc, const char* firmware -int usb_read(libusb_device_handle *f, void *data, size_t size) +int usb_read(libusb_device_handle *f, void *data, size_t size, uint8_t ep) { const int chunk_size = DEFAULT_CHUNKSZ; while(size > 0) @@ -1002,7 +1164,7 @@ int usb_read(libusb_device_handle *f, void *data, size_t size) int bt, ss = (int)size; if(ss > chunk_size) ss = chunk_size; - int rc = libusb_bulk_transfer(f, USB_ENDPOINT_IN,(unsigned char *)data, ss, &bt, XLINK_USB_DATA_TIMEOUT); + int rc = libusb_bulk_transfer(f, ep, (unsigned char *)data, ss, &bt, XLINK_USB_DATA_TIMEOUT); if(rc) return rc; data = ((char *)data) + bt; @@ -1011,7 +1173,7 @@ int usb_read(libusb_device_handle *f, void *data, size_t size) return 0; } -int usb_write(libusb_device_handle *f, const void *data, size_t size) +int usb_write(libusb_device_handle *f, const void *data, size_t size, uint8_t ep) { const int chunk_size = DEFAULT_CHUNKSZ; while(size > 0) @@ -1019,7 +1181,7 @@ int usb_write(libusb_device_handle *f, const void *data, size_t size) int bt, ss = (int)size; if(ss > chunk_size) ss = chunk_size; - int rc = libusb_bulk_transfer(f, USB_ENDPOINT_OUT, (unsigned char *)data, ss, &bt, XLINK_USB_DATA_TIMEOUT); + int rc = libusb_bulk_transfer(f, ep, (unsigned char *)data, ss, &bt, XLINK_USB_DATA_TIMEOUT); if(rc) return rc; data = (char *)data + bt; @@ -1028,7 +1190,7 @@ int usb_write(libusb_device_handle *f, const void *data, size_t size) return 0; } -int usbPlatformRead(void* fdKey, void* data, int size) +int usbPlatformRead(XLinkProtocol_t protocol, void* fdKey, void* data, int size) { int rc = 0; #ifndef USE_USB_VSC @@ -1069,19 +1231,27 @@ int usbPlatformRead(void* fdKey, void* data, int size) #endif /*USE_LINK_JTAG*/ #else - 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; + if(isServer){ + rc = read(usbFdRead, data, size); + } else { + 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); + if(protocol == X_LINK_USB_EP) { + rc = usb_read(usbHandle, data, size, USB_EP_ENDPOINT_DEVICE_IN); + } else { + rc = usb_read(usbHandle, data, size, USB_VSC_ENDPOINT_IN); + } + } #endif /*USE_USB_VSC*/ return rc; } -int usbPlatformWrite(void *fdKey, void *data, int size) +int usbPlatformWrite(XLinkProtocol_t protocol, void *fdKey, void *data, int size) { int rc = 0; #ifndef USE_USB_VSC @@ -1125,18 +1295,126 @@ int usbPlatformWrite(void *fdKey, void *data, int size) #endif /*USE_LINK_JTAG*/ #else - 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; + if(isServer){ + rc = write(usbFdWrite, data, size); + } else { + 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); + if(protocol == X_LINK_USB_EP){ + rc = usb_write(usbHandle, data, size, USB_EP_ENDPOINT_DEVICE_OUT); + } else { + rc = usb_write(usbHandle, data, size, USB_VSC_ENDPOINT_OUT); + } + } #endif /*USE_USB_VSC*/ return rc; } +int usbPlatformGateRead(const char *name, void *data, int size, int timeout) +{ + std::lock_guard l(mutex); + + if (context == nullptr) return -1; + + int rc = 0; + + /* Get our device */ + libusb_device *gate_dev; + refLibusbDeviceByName(name, &gate_dev); + if (gate_dev == NULL) { + rc = LIBUSB_ERROR_NO_DEVICE; + return rc; + } + + libusb_device_handle *gate_dev_handle; + libusb_open(gate_dev, &gate_dev_handle); + if (gate_dev_handle == NULL) { + rc = LIBUSB_ERROR_NO_DEVICE; + return rc; + } + + /* Not strictly necessary, but it is better to use it, + * as we're using kernel modules together with our interfaces + */ + rc = libusb_set_auto_detach_kernel_driver(gate_dev_handle, 1); + if (rc != LIBUSB_SUCCESS) { + libusb_close(gate_dev_handle); + + return rc; + } + + libusb_device* dev = libusb_get_device(gate_dev_handle); + + /* Now we claim our ffs interfaces */ + rc = libusb_claim_interface(gate_dev_handle, USB_EP_INTERFACE_GATE); + if (rc != LIBUSB_SUCCESS) { + libusb_close(gate_dev_handle); + + return rc; + } + + rc = libusb_bulk_transfer(gate_dev_handle, USB_EP_ENDPOINT_GATE_IN, (unsigned char*)data, size, &rc, timeout); + + libusb_close(gate_dev_handle); + + return rc; +} + +int usbPlatformGateWrite(const char *name, void *data, int size, int timeout) +{ + std::lock_guard l(mutex); + + if (context == nullptr) return -1; + + int rc = 0; + + /* Get our device */ + libusb_device *gate_dev; + refLibusbDeviceByName(name, &gate_dev); + if (gate_dev == NULL) { + rc = LIBUSB_ERROR_NO_DEVICE; + return rc; + } + + libusb_device_handle *gate_dev_handle; + libusb_open(gate_dev, &gate_dev_handle); + if (gate_dev_handle == NULL) { + rc = LIBUSB_ERROR_NO_DEVICE; + return rc; + } + + /* Not strictly necessary, but it is better to use it, + * as we're using kernel modules together with our interfaces + */ + rc = libusb_set_auto_detach_kernel_driver(gate_dev_handle, 1); + if (rc != LIBUSB_SUCCESS) { + libusb_close(gate_dev_handle); + + return rc; + } + + libusb_device* dev = libusb_get_device(gate_dev_handle); + + /* Now we claim our ffs interfaces */ + rc = libusb_claim_interface(gate_dev_handle, USB_EP_INTERFACE_GATE); + if (rc != LIBUSB_SUCCESS) { + libusb_close(gate_dev_handle); + + return rc; + } + + rc = libusb_bulk_transfer(gate_dev_handle, USB_EP_ENDPOINT_GATE_OUT, (unsigned char*)data, size, &rc, timeout); + + libusb_close(gate_dev_handle); + + return rc; +} + #ifdef _WIN32 #include #include diff --git a/src/pc/protocols/usb_host.h b/src/pc/protocols/usb_host.h index 1103fa4..574ddfa 100644 --- a/src/pc/protocols/usb_host.h +++ b/src/pc/protocols/usb_host.h @@ -47,12 +47,16 @@ int usb_boot(const char *addr, const void *mvcmd, unsigned size); int get_pid_by_name(const char* name); xLinkPlatformErrorCode_t usbLinkBootBootloader(const char* path); -int usbPlatformConnect(const char *devPathRead, const char *devPathWrite, void **fd); -int usbPlatformClose(void *fd); +int usbPlatformConnect(XLinkProtocol_t protocol, const char *devPathRead, const char *devPathWrite, void **fd); +int usbPlatformServer(const char *devPathRead, const char *devPathWrite, void **fd); +int usbPlatformClose(XLinkProtocol_t protocol, void *fd); int usbPlatformBootFirmware(const deviceDesc_t* deviceDesc, const char* firmware, size_t length); -int usbPlatformRead(void *fd, void *data, int size); -int usbPlatformWrite(void *fd, void *data, int size); +int usbPlatformRead(XLinkProtocol_t protocol, void *fd, void *data, int size); +int usbPlatformWrite(XLinkProtocol_t protocol, void *fd, void *data, int size); + +int usbPlatformGateRead(const char *name, void *data, int size, int timeout); +int usbPlatformGateWrite(const char *name, void *data, int size, int timeout); #else @@ -60,12 +64,16 @@ int usbPlatformWrite(void *fd, void *data, int size); static inline int usbInitialize(void* options) { return -1; } static inline xLinkPlatformErrorCode_t usbLinkBootBootloader(const char* path) { return X_LINK_PLATFORM_USB_DRIVER_NOT_LOADED; } -static inline int usbPlatformConnect(const char *devPathRead, const char *devPathWrite, void **fd) { return -1; } -static inline int usbPlatformClose(void *fd) { return -1; } +static inline int usbPlatformConnect(XLinkProtocol_t protocol, const char *devPathRead, const char *devPathWrite, void **fd) { return -1; } +static inline int usbPlatformServer(const char *devPathRead, const char *devPathWrite, void **fd) { return -1; } +static inline int usbPlatformClose(XLinkProtocol_t protocol, void *fd) { return -1; } static inline int usbPlatformBootFirmware(const deviceDesc_t* deviceDesc, const char* firmware, size_t length) { return -1; } -static inline int usbPlatformRead(void *fd, void *data, int size) { return -1; } -static inline int usbPlatformWrite(void *fd, void *data, int size) { return -1; } +static inline int usbPlatformRead(XLinkProtocol_t protocol, void *fd, void *data, int size) { return -1; } +static inline int usbPlatformWrite(XLinkProtocol_t protocol, void *fd, void *data, int size) { return -1; } + +static inline int usbPlatformGateRead(const char *name, void *data, int size, int timeout) { return -1; } +static inline int usbPlatformGateWrite(const char *name, void *data, int size, int timeout) { return -1; } static inline xLinkPlatformErrorCode_t getUSBDevices(const deviceDesc_t in_deviceRequirements, deviceDesc_t* out_foundDevices, int sizeFoundDevices, diff --git a/src/shared/XLinkData.c b/src/shared/XLinkData.c index bf3a885..2cc9365 100644 --- a/src/shared/XLinkData.c +++ b/src/shared/XLinkData.c @@ -117,6 +117,26 @@ XLinkError_t XLinkCloseStream(streamId_t const streamId) return X_LINK_SUCCESS; } +XLinkError_t XLinkGateWrite(const char *name, void *data, int size, int timeout) +{ + int rc = XLinkPlatformGateWrite(name, data, size, timeout); + if(rc < 0) { + return X_LINK_ERROR; + } else { + return X_LINK_SUCCESS; + } +} + +XLinkError_t XLinkGateRead(const char *name, void *data, int size, int timeout) +{ + int rc = XLinkPlatformGateRead(name, data, size, timeout); + if(rc < 0) { + return X_LINK_ERROR; + } else { + return X_LINK_SUCCESS; + } +} + XLinkError_t XLinkWriteData_(streamId_t streamId, const uint8_t* buffer, int size, XLinkTimespec* outTSend) { diff --git a/src/shared/XLinkDevice.c b/src/shared/XLinkDevice.c index cbcd073..dcf5c64 100644 --- a/src/shared/XLinkDevice.c +++ b/src/shared/XLinkDevice.c @@ -644,6 +644,7 @@ XLinkError_t parsePlatformError(xLinkPlatformErrorCode_t rc) { case X_LINK_PLATFORM_DEVICE_BUSY: return X_LINK_DEVICE_ALREADY_IN_USE; case X_LINK_PLATFORM_USB_DRIVER_NOT_LOADED: + case X_LINK_PLATFORM_USB_EP_DRIVER_NOT_LOADED: return X_LINK_INIT_USB_ERROR; case X_LINK_PLATFORM_TCP_IP_DRIVER_NOT_LOADED: return X_LINK_INIT_TCP_IP_ERROR; @@ -699,8 +700,9 @@ const char* XLinkProtocolToStr(XLinkProtocol_t val) { case X_LINK_PCIE: return "X_LINK_PCIE"; case X_LINK_IPC: return "X_LINK_IPC"; case X_LINK_TCP_IP: return "X_LINK_TCP_IP"; - case X_LINK_LOCAL_SHDMEM: return "X_LINK_LOCAL_SHDMEM"; + case X_LINK_LOCAL_SHDMEM: return "X_LINK_LOCAL_SHDMEM"; case X_LINK_TCP_IP_OR_LOCAL_SHDMEM: return "X_LINK_TCP_IP_OR_LOCAL_SHDMEM"; + case X_LINK_USB_EP: return "X_LINK_USB_EP"; case X_LINK_NMB_OF_PROTOCOLS: return "X_LINK_NMB_OF_PROTOCOLS"; case X_LINK_ANY_PROTOCOL: return "X_LINK_ANY_PROTOCOL"; default: