mirror of
https://github.com/Lorenzooone/cc3dsfs.git
synced 2025-06-18 08:35:33 -04:00
Remove ftd3xx library dependency for Linux and MacOS
This commit is contained in:
parent
86b5725af9
commit
fa5a708e22
@ -14,10 +14,15 @@ set(CYPRESS_NISETRO_SUPPORT 1)
|
||||
|
||||
set(USE_FTD2XX_FOR_NEW_DS_LOOPY ${NEW_DS_LOOPY_SUPPORT})
|
||||
set(USE_LIBFTDI_FOR_NEW_DS_LOOPY ${NEW_DS_LOOPY_SUPPORT})
|
||||
set(USE_LIBUSB_SUPPORT ${IS_DEVICES_SUPPORT} OR ${OLD_DS_3DS_LOOPY_SUPPORT} OR ${USE_LIBFTDI_FOR_NEW_DS_LOOPY} OR ${CYPRESS_NISETRO_SUPPORT})
|
||||
set(USE_FTD3XX_FOR_N3DSXL_LOOPY ${N3DSXL_LOOPY_SUPPORT})
|
||||
set(USE_LIBUSB_FOR_N3DSXL_LOOPY ${N3DSXL_LOOPY_SUPPORT})
|
||||
set(USE_LIBUSB_SUPPORT ${IS_DEVICES_SUPPORT} OR ${OLD_DS_3DS_LOOPY_SUPPORT} OR ${USE_LIBFTDI_FOR_NEW_DS_LOOPY} OR ${CYPRESS_NISETRO_SUPPORT} OR ${USE_LIBUSB_FOR_N3DSXL_LOOPY})
|
||||
if(NOT (${CMAKE_SYSTEM_NAME} STREQUAL "Windows"))
|
||||
#Performance outside of Windows is very bad for the official drivers...
|
||||
set(USE_FTD2XX_FOR_NEW_DS_LOOPY 0)
|
||||
#Availability issues and various bugs, forcing the use of an older release...
|
||||
#Just avoid using it, when possible...
|
||||
set(USE_FTD3XX_FOR_N3DSXL_LOOPY 0)
|
||||
endif()
|
||||
set(FTDI_EEPROM OFF)
|
||||
set(WINDOWS_ARM64 0)
|
||||
@ -260,7 +265,7 @@ else()
|
||||
endif()
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
|
||||
if(N3DSXL_LOOPY_SUPPORT)
|
||||
if(USE_FTD3XX_FOR_N3DSXL_LOOPY)
|
||||
FetchContent_Declare(FTD3XX
|
||||
URL ${FTD3XX_BASE_URL}${FTD3XX_URL_TIME}/${FTD3XX_ARCHIVE}
|
||||
DOWNLOAD_NO_EXTRACT TRUE
|
||||
@ -273,7 +278,7 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
|
||||
)
|
||||
endif()
|
||||
else()
|
||||
if(N3DSXL_LOOPY_SUPPORT)
|
||||
if(USE_FTD3XX_FOR_N3DSXL_LOOPY)
|
||||
FetchContent_Declare(FTD3XX
|
||||
URL ${FTD3XX_BASE_URL}${FTD3XX_URL_TIME}/${FTD3XX_ARCHIVE}
|
||||
)
|
||||
@ -295,17 +300,34 @@ set(EXTRA_DEPENDENCIES "")
|
||||
set(SOURCE_CPP_DEVICE_FILES_BASE_PATH "source/CaptureDeviceSpecific")
|
||||
set(SOURCE_CPP_IS_DEVICES_FILES_BASE_PATH "${SOURCE_CPP_DEVICE_FILES_BASE_PATH}/ISDevices")
|
||||
set(SOURCE_CPP_FTD2_FILES_BASE_PATH "${SOURCE_CPP_DEVICE_FILES_BASE_PATH}/DSCapture_FTD2")
|
||||
set(SOURCE_CPP_FTD3_FILES_BASE_PATH "${SOURCE_CPP_DEVICE_FILES_BASE_PATH}/3DSCapture_FTD3")
|
||||
set(SOURCE_CPP_CYPRESS_NISETRO_DEVICES_FILES_BASE_PATH "${SOURCE_CPP_DEVICE_FILES_BASE_PATH}/Nisetro")
|
||||
if(N3DSXL_LOOPY_SUPPORT)
|
||||
list(APPEND FETCH_CONTENT_MAKE_AVAILABLE_LIBRARIES FTD3XX)
|
||||
list(APPEND SOURCE_CPP_EXTRA_FILES ${SOURCE_CPP_DEVICE_FILES_BASE_PATH}/3dscapture_ftd3.cpp)
|
||||
list(APPEND EXTRA_DEPENDENCIES FTD3XX_BUILD_PROJECT)
|
||||
list(APPEND SOURCE_CPP_EXTRA_FILES ${SOURCE_CPP_FTD3_FILES_BASE_PATH}/3dscapture_ftd3_shared.cpp ${SOURCE_CPP_FTD3_FILES_BASE_PATH}/3dscapture_ftd3_compatibility.cpp)
|
||||
if(MSVC)
|
||||
list(APPEND EXTRA_CXX_FLAGS "/DUSE_FTD3")
|
||||
else()
|
||||
list(APPEND EXTRA_CXX_FLAGS "-DUSE_FTD3")
|
||||
endif()
|
||||
endif()
|
||||
if(USE_FTD3XX_FOR_N3DSXL_LOOPY)
|
||||
list(APPEND SOURCE_CPP_EXTRA_FILES ${SOURCE_CPP_FTD3_FILES_BASE_PATH}/3dscapture_ftd3_driver_comms.cpp ${SOURCE_CPP_FTD3_FILES_BASE_PATH}/3dscapture_ftd3_driver_acquisition.cpp)
|
||||
list(APPEND FETCH_CONTENT_MAKE_AVAILABLE_LIBRARIES FTD3XX)
|
||||
list(APPEND EXTRA_DEPENDENCIES FTD3XX_BUILD_PROJECT)
|
||||
if(MSVC)
|
||||
list(APPEND EXTRA_CXX_FLAGS "/DUSE_FTD3XX")
|
||||
else()
|
||||
list(APPEND EXTRA_CXX_FLAGS "-DUSE_FTD3XX")
|
||||
endif()
|
||||
endif()
|
||||
if(USE_LIBUSB_FOR_N3DSXL_LOOPY)
|
||||
list(APPEND SOURCE_CPP_EXTRA_FILES ${SOURCE_CPP_FTD3_FILES_BASE_PATH}/3dscapture_ftd3_libusb_comms.cpp ${SOURCE_CPP_FTD3_FILES_BASE_PATH}/3dscapture_ftd3_libusb_acquisition.cpp)
|
||||
if(MSVC)
|
||||
list(APPEND EXTRA_CXX_FLAGS "/DUSE_FTD3_LIBUSB")
|
||||
else()
|
||||
list(APPEND EXTRA_CXX_FLAGS "-DUSE_FTD3_LIBUSB")
|
||||
endif()
|
||||
endif()
|
||||
if(USE_LIBUSB_SUPPORT)
|
||||
list(APPEND FETCH_CONTENT_MAKE_AVAILABLE_LIBRARIES LibUSB)
|
||||
list(APPEND SOURCE_CPP_EXTRA_FILES ${SOURCE_CPP_DEVICE_FILES_BASE_PATH}/usb_generic.cpp)
|
||||
@ -373,7 +395,7 @@ set(LIBUSB_INCLUDE_DIR ${libusb_SOURCE_DIR}/libusb/libusb)
|
||||
FetchContent_MakeAvailable(${FETCH_CONTENT_MAKE_AVAILABLE_LIBRARIES_SEPARATE})
|
||||
|
||||
set(EXTRA_INCLUDE_DIRECTORIES "")
|
||||
if(N3DSXL_LOOPY_SUPPORT)
|
||||
if(USE_FTD3XX_FOR_N3DSXL_LOOPY)
|
||||
list(APPEND EXTRA_INCLUDE_DIRECTORIES ${ftd3xx_BINARY_DIR}/${FTD3XX_SUBFOLDER})
|
||||
endif()
|
||||
if(USE_FTD2XX_FOR_NEW_DS_LOOPY)
|
||||
@ -382,6 +404,9 @@ endif()
|
||||
if(USE_LIBUSB_SUPPORT)
|
||||
list(APPEND EXTRA_INCLUDE_DIRECTORIES ${libusb_SOURCE_DIR}/libusb/libusb)
|
||||
endif()
|
||||
if(USE_LIBFTDI_FOR_NEW_DS_LOOPY)
|
||||
list(APPEND EXTRA_INCLUDE_DIRECTORIES ${libftdi1_SOURCE_DIR}/src)
|
||||
endif()
|
||||
|
||||
if(IS_DIRECTORY "${sfml_SOURCE_DIR}")
|
||||
set_property(DIRECTORY ${sfml_SOURCE_DIR} PROPERTY EXCLUDE_FROM_ALL YES)
|
||||
@ -399,7 +424,7 @@ if(USE_LIBFTDI_FOR_NEW_DS_LOOPY)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(N3DSXL_LOOPY_SUPPORT)
|
||||
if(USE_FTD3XX_FOR_N3DSXL_LOOPY)
|
||||
file(MAKE_DIRECTORY ${ftd3xx_BINARY_DIR}/win)
|
||||
file(MAKE_DIRECTORY ${ftd3xx_BINARY_DIR}/macos)
|
||||
file(MAKE_DIRECTORY ${ftd3xx_BINARY_DIR}/linux)
|
||||
@ -428,7 +453,7 @@ else()
|
||||
set(FTD2XX_BUILD_COMMAND_PARAMETERS ${ftd2xx_SOURCE_DIR} ${ftd2xx_BINARY_DIR}/${FTD2XX_SUBFOLDER} build/${FTD2XX_LIB})
|
||||
endif()
|
||||
|
||||
if(N3DSXL_LOOPY_SUPPORT)
|
||||
if(USE_FTD3XX_FOR_N3DSXL_LOOPY)
|
||||
ExternalProject_Add(FTD3XX_BUILD_PROJECT
|
||||
SOURCE_DIR ${ftd3xx_SOURCE_DIR}
|
||||
BINARY_DIR ${ftd3xx_BINARY_DIR}
|
||||
@ -500,7 +525,7 @@ target_link_libraries(${OUTPUT_NAME} PRIVATE SFML::Graphics SFML::Audio SFML::Wi
|
||||
if(USE_LIBUSB_SUPPORT)
|
||||
target_link_libraries(${OUTPUT_NAME} PRIVATE usb-1.0)
|
||||
endif()
|
||||
if(N3DSXL_LOOPY_SUPPORT)
|
||||
if(USE_FTD3XX_FOR_N3DSXL_LOOPY)
|
||||
target_link_libraries(${OUTPUT_NAME} PRIVATE ${ftd3xx_BINARY_DIR}/${FTD3XX_SUBFOLDER}/${FTD3XX_LIB})
|
||||
endif()
|
||||
if(USE_LIBFTDI_FOR_NEW_DS_LOOPY)
|
||||
@ -509,7 +534,7 @@ endif()
|
||||
if(USE_FTD2XX_FOR_NEW_DS_LOOPY)
|
||||
target_link_libraries(${OUTPUT_NAME} PRIVATE ${ftd2xx_BINARY_DIR}/${FTD2XX_SUBFOLDER}/${FTD2XX_LIB})
|
||||
endif()
|
||||
target_include_directories(${OUTPUT_NAME} PRIVATE ${EXTRA_INCLUDE_DIRECTORIES} ${TOOLS_DATA_DIR} ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/include/Menus ${CMAKE_SOURCE_DIR}/include/CaptureDeviceSpecific ${CMAKE_SOURCE_DIR}/include/CaptureDeviceSpecific/ISDevices ${CMAKE_SOURCE_DIR}/include/CaptureDeviceSpecific/Nisetro ${CMAKE_SOURCE_DIR}/include/CaptureDeviceSpecific/DSCapture_FTD2 ${libftdi1_SOURCE_DIR}/src)
|
||||
target_include_directories(${OUTPUT_NAME} PRIVATE ${EXTRA_INCLUDE_DIRECTORIES} ${TOOLS_DATA_DIR} ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/include/Menus ${CMAKE_SOURCE_DIR}/include/CaptureDeviceSpecific ${CMAKE_SOURCE_DIR}/include/CaptureDeviceSpecific/ISDevices ${CMAKE_SOURCE_DIR}/include/CaptureDeviceSpecific/Nisetro ${CMAKE_SOURCE_DIR}/include/CaptureDeviceSpecific/3DSCapture_FTD3 ${CMAKE_SOURCE_DIR}/include/CaptureDeviceSpecific/DSCapture_FTD2)
|
||||
target_compile_features(${OUTPUT_NAME} PRIVATE cxx_std_20)
|
||||
target_compile_options(${OUTPUT_NAME} PRIVATE ${EXTRA_CXX_FLAGS})
|
||||
|
||||
@ -566,7 +591,7 @@ add_custom_command(
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
if(N3DSXL_LOOPY_SUPPORT AND WINDOWS_FTD3XX_USE_SHARED_LIB)
|
||||
if(USE_FTD3XX_FOR_N3DSXL_LOOPY AND WINDOWS_FTD3XX_USE_SHARED_LIB)
|
||||
add_custom_command(
|
||||
TARGET ${OUTPUT_NAME}
|
||||
COMMENT "Copy FTD3XX DLL"
|
||||
@ -597,9 +622,13 @@ else()
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/${OUTPUT_NAME}${FINAL_EXTENSION} DESTINATION .)
|
||||
endif()
|
||||
install(FILES LICENSE README.md DESTINATION .)
|
||||
install(DIRECTORY "other licenses" DESTINATION .)
|
||||
install(DIRECTORY "other licenses" DESTINATION .
|
||||
PATTERN "other licenses/ftd3xx.txt" EXCLUDE)
|
||||
if(USE_FTD3XX_FOR_N3DSXL_LOOPY)
|
||||
install(FILES "other licenses/ftd3xx.txt" DESTINATION "./other licenses")
|
||||
endif()
|
||||
if(WIN32)
|
||||
if(N3DSXL_LOOPY_SUPPORT AND WINDOWS_FTD3XX_USE_SHARED_LIB)
|
||||
if(USE_FTD3XX_FOR_N3DSXL_LOOPY AND WINDOWS_FTD3XX_USE_SHARED_LIB)
|
||||
install(FILES ${FTD3XX_DLL} DESTINATION .)
|
||||
endif()
|
||||
if(USE_FTD2XX_FOR_NEW_DS_LOOPY AND WINDOWS_FTD2XX_USE_SHARED_LIB)
|
||||
|
@ -27,7 +27,7 @@ cc3dsfs has three build dependencies: CMake, g++ and git.
|
||||
Make sure all are installed.
|
||||
On MacOS, [Homebrew](https://brew.sh/) can be used to install both CMake and git. An automatic popup should appear to install g++ at Compile time.
|
||||
|
||||
cc3dsfs has five library dependencies: [FTDI's D3XX driver](https://ftdichip.com/drivers/d3xx-drivers/), [FTDI's D2XX driver](https://ftdichip.com/drivers/d2xx-drivers/) (on Windows), [libusb](https://libusb.info/), [libftdi](https://www.intra2net.com/en/developer/libftdi/) and [SFML](https://www.sfml-dev.org/).
|
||||
cc3dsfs has five library dependencies: [FTDI's D3XX driver](https://ftdichip.com/drivers/d3xx-drivers/) (on Windows), [FTDI's D2XX driver](https://ftdichip.com/drivers/d2xx-drivers/) (on Windows), [libusb](https://libusb.info/), [libftdi](https://www.intra2net.com/en/developer/libftdi/) and [SFML](https://www.sfml-dev.org/).
|
||||
All of them should get downloaded automatically via CMake during the building process.
|
||||
|
||||
Linux users who wish to compile this, will also need to install the SFML dependencies. Different distributions will require slightly different processes.
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -13,5 +13,5 @@ to save on space.
|
||||
Feel free to contact me if you would like the files to be removed,
|
||||
if an agreement about their availability can be reached.
|
||||
|
||||
Changing FTDI\_BASE\_URL to https://ftdichip.com/wp-content/uploads will
|
||||
Changing FTDI\_BASE\_URL to https://ftdichip.com/wp-content/uploads/ will
|
||||
switch to automatic download during builds.
|
||||
|
@ -0,0 +1,26 @@
|
||||
#ifndef __3DSCAPTURE_FTD3_COMPATIBILITY_HPP
|
||||
#define __3DSCAPTURE_FTD3_COMPATIBILITY_HPP
|
||||
|
||||
#include "capture_structs.hpp"
|
||||
#include "devicecapture.hpp"
|
||||
|
||||
#define FTD3_CONCURRENT_BUFFERS 4
|
||||
|
||||
struct ftd3_device_device_handlers {
|
||||
void* usb_handle = NULL;
|
||||
void* driver_handle = NULL;
|
||||
};
|
||||
|
||||
void ftd3_list_devices_compat(std::vector<CaptureDevice> &devices_list, std::vector<no_access_recap_data> &no_access_list, const std::vector<std::string> &valid_descriptions);
|
||||
ftd3_device_device_handlers* ftd3_reconnect_compat(std::string wanted_serial_number, const std::vector<std::string> &valid_descriptions);
|
||||
void ftd3_close_compat(ftd3_device_device_handlers* handlers);
|
||||
bool ftd3_is_error_compat(ftd3_device_device_handlers* handlers, int error_num);
|
||||
int ftd3_abort_pipe_compat(ftd3_device_device_handlers* handlers, int pipe);
|
||||
int ftd3_set_stream_pipe_compat(ftd3_device_device_handlers* handlers, int pipe, size_t length);
|
||||
int ftd3_write_pipe_compat(ftd3_device_device_handlers* handlers, int pipe, const uint8_t* data, size_t size, int* num_transferred);
|
||||
int ftd3_read_pipe_compat(ftd3_device_device_handlers* handlers, int pipe, uint8_t* data, size_t size, int* num_transferred);
|
||||
bool ftd3_get_is_bad_compat(ftd3_device_device_handlers* handlers);
|
||||
bool ftd3_get_skip_initial_pipe_abort_compat(ftd3_device_device_handlers* handlers);
|
||||
void ftd3_main_loop_compat(CaptureData* capture_data, int pipe);
|
||||
|
||||
#endif
|
@ -0,0 +1,8 @@
|
||||
#ifndef __3DSCAPTURE_FTD3_DRIVER_ACQUISITION_HPP
|
||||
#define __3DSCAPTURE_FTD3_DRIVER_ACQUISITION_HPP
|
||||
|
||||
#include "capture_structs.hpp"
|
||||
|
||||
void ftd3_driver_capture_main_loop(CaptureData* capture_data, int pipe);
|
||||
|
||||
#endif
|
@ -0,0 +1,16 @@
|
||||
#ifndef __3DSCAPTURE_FTD3_DRIVER_COMMS_HPP
|
||||
#define __3DSCAPTURE_FTD3_DRIVER_COMMS_HPP
|
||||
|
||||
#include <vector>
|
||||
#include "utils.hpp"
|
||||
#include "capture_structs.hpp"
|
||||
#include "devicecapture.hpp"
|
||||
#include "3dscapture_ftd3_compatibility.hpp"
|
||||
|
||||
bool ftd3_driver_get_is_bad();
|
||||
bool ftd3_driver_get_skip_initial_pipe_abort();
|
||||
ftd3_device_device_handlers* ftd3_driver_serial_reconnection(std::string wanted_serial_number);
|
||||
void ftd3_driver_list_devices(std::vector<CaptureDevice> &devices_list, int *curr_serial_extra_id_ftd3, const std::vector<std::string> &valid_descriptions);
|
||||
void ftd3_driver_end_connection(ftd3_device_device_handlers* handlers);
|
||||
|
||||
#endif
|
@ -0,0 +1,8 @@
|
||||
#ifndef __3DSCAPTURE_FTD3_LIBUSB_ACQUISITION_HPP
|
||||
#define __3DSCAPTURE_FTD3_LIBUSB_ACQUISITION_HPP
|
||||
|
||||
#include "capture_structs.hpp"
|
||||
|
||||
void ftd3_libusb_capture_main_loop(CaptureData* capture_data, int pipe);
|
||||
|
||||
#endif
|
@ -0,0 +1,35 @@
|
||||
#ifndef __3DSCAPTURE_FTD3_LIBUSB_COMMS_HPP
|
||||
#define __3DSCAPTURE_FTD3_LIBUSB_COMMS_HPP
|
||||
|
||||
#include <vector>
|
||||
#include "capture_structs.hpp"
|
||||
#include "devicecapture.hpp"
|
||||
#include "3dscapture_ftd3_compatibility.hpp"
|
||||
|
||||
typedef void (*ftd3_async_callback_function)(void* user_data, int transfer_length, int transfer_status);
|
||||
|
||||
struct ftd3_async_callback_data {
|
||||
ftd3_async_callback_function function;
|
||||
void* actual_user_data;
|
||||
void* transfer_data;
|
||||
std::mutex transfer_data_access;
|
||||
int internal_index;
|
||||
};
|
||||
|
||||
int ftd3_libusb_ctrl_in(ftd3_device_device_handlers* handlers, uint32_t timeout, uint8_t* buf, int length, uint8_t request, uint16_t value, uint16_t index, int* transferred);
|
||||
int ftd3_libusb_ctrl_out(ftd3_device_device_handlers* handlers, uint32_t timeout, const uint8_t* buf, int length, uint8_t request, uint16_t value, uint16_t index, int* transferred);
|
||||
int ftd3_libusb_bulk_in(ftd3_device_device_handlers* handlers, int endpoint_in, uint32_t timeout, uint8_t* buf, int length, int* transferred);
|
||||
int ftd3_libusb_bulk_out(ftd3_device_device_handlers* handlers, int endpoint_out, uint32_t timeout, const uint8_t* buf, int length, int* transferred);
|
||||
int ftd3_libusb_async_in_start(ftd3_device_device_handlers* handlers, int endpoint_in, uint32_t timeout, uint8_t* buf, int length, ftd3_async_callback_data* cb_data);
|
||||
void ftd3_libusb_cancell_callback(ftd3_async_callback_data* cb_data);
|
||||
|
||||
void ftd3_libusb_list_devices(std::vector<CaptureDevice> &devices_list, bool* no_access_elems, bool* not_supported_elems, int *curr_serial_extra_id_ftd3, const std::vector<std::string> &valid_descriptions);
|
||||
ftd3_device_device_handlers* ftd3_libusb_serial_reconnection(std::string wanted_serial_number, int &curr_serial_extra_id, const std::vector<std::string> &valid_descriptions);
|
||||
|
||||
void ftd3_libusb_end_connection(ftd3_device_device_handlers* handlers, bool interface_claimed);
|
||||
int ftd3_libusb_abort_pipe(ftd3_device_device_handlers* handlers, int pipe);
|
||||
int ftd3_libusb_write_pipe(ftd3_device_device_handlers* handlers, int pipe, const uint8_t* data, size_t length, int* num_transferred);
|
||||
int ftd3_libusb_read_pipe(ftd3_device_device_handlers* handlers, int pipe, uint8_t* data, size_t length, int* num_transferred);
|
||||
int ftd3_libusb_set_stream_pipe(ftd3_device_device_handlers* handlers, int pipe, size_t length);
|
||||
|
||||
#endif
|
@ -1,5 +1,5 @@
|
||||
#ifndef __3DSCAPTURE_FTD3_HPP
|
||||
#define __3DSCAPTURE_FTD3_HPP
|
||||
#ifndef __3DSCAPTURE_FTD3_SHARED_HPP
|
||||
#define __3DSCAPTURE_FTD3_SHARED_HPP
|
||||
|
||||
#include <vector>
|
||||
#include "utils.hpp"
|
@ -0,0 +1,13 @@
|
||||
#ifndef __3DSCAPTURE_FTD3_SHARED_GENERAL_HPP
|
||||
#define __3DSCAPTURE_FTD3_SHARED_GENERAL_HPP
|
||||
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
#include "capture_structs.hpp"
|
||||
|
||||
uint64_t ftd3_get_capture_size(CaptureData* capture_data);
|
||||
std::string ftd3_get_serial(std::string serial_string, int &curr_serial_extra_id);
|
||||
void ftd3_insert_device(std::vector<CaptureDevice> &devices_list, std::string serial_string, int &curr_serial_extra_id, bool is_driver);
|
||||
void data_output_update(CaptureReceived* received_buffer, size_t read_data, CaptureData* capture_data, std::chrono::time_point<std::chrono::high_resolution_clock> &base_time);
|
||||
|
||||
#endif
|
@ -0,0 +1,164 @@
|
||||
#include "3dscapture_ftd3_compatibility.hpp"
|
||||
#include "3dscapture_ftd3_libusb_comms.hpp"
|
||||
#include "3dscapture_ftd3_driver_comms.hpp"
|
||||
#include "3dscapture_ftd3_driver_acquisition.hpp"
|
||||
#include "3dscapture_ftd3_libusb_acquisition.hpp"
|
||||
#include "devicecapture.hpp"
|
||||
|
||||
#ifdef USE_FTD3XX
|
||||
//#include "ftd3xx_symbols_renames.h"
|
||||
#ifdef _WIN32
|
||||
#define FTD3XX_STATIC
|
||||
#endif
|
||||
#include <ftd3xx.h>
|
||||
#endif
|
||||
|
||||
void ftd3_list_devices_compat(std::vector<CaptureDevice> &devices_list, std::vector<no_access_recap_data> &no_access_list, const std::vector<std::string> &valid_descriptions) {
|
||||
bool no_access_elems = false;
|
||||
bool not_supported_elems = false;
|
||||
int curr_serial_extra_id_ftd3 = 0;
|
||||
bool check_driver_too = true;
|
||||
#ifdef USE_FTD3_LIBUSB
|
||||
check_driver_too = false;
|
||||
ftd3_libusb_list_devices(devices_list, &no_access_elems, ¬_supported_elems, &curr_serial_extra_id_ftd3, valid_descriptions);
|
||||
#endif
|
||||
#ifdef USE_FTD3XX
|
||||
if(check_driver_too || not_supported_elems)
|
||||
ftd3_driver_list_devices(devices_list, &curr_serial_extra_id_ftd3, valid_descriptions);
|
||||
#endif
|
||||
if(no_access_elems)
|
||||
no_access_list.emplace_back("FTD3");
|
||||
}
|
||||
|
||||
ftd3_device_device_handlers* ftd3_reconnect_compat(std::string wanted_serial_number, const std::vector<std::string> &valid_descriptions) {
|
||||
int curr_serial_extra_id_ftd3 = 0;
|
||||
ftd3_device_device_handlers* final_handlers = NULL;
|
||||
#ifdef USE_FTD3_LIBUSB
|
||||
final_handlers = ftd3_libusb_serial_reconnection(wanted_serial_number, curr_serial_extra_id_ftd3, valid_descriptions);
|
||||
if(final_handlers != NULL)
|
||||
return final_handlers;
|
||||
#endif
|
||||
#ifdef USE_FTD3XX
|
||||
final_handlers = ftd3_driver_serial_reconnection(wanted_serial_number);
|
||||
if(final_handlers != NULL)
|
||||
return final_handlers;
|
||||
#endif
|
||||
return final_handlers;
|
||||
}
|
||||
|
||||
bool ftd3_is_error_compat(ftd3_device_device_handlers* handlers, int error_num) {
|
||||
#ifdef USE_FTD3_LIBUSB
|
||||
if(handlers->usb_handle)
|
||||
return error_num < 0;
|
||||
#endif
|
||||
#ifdef USE_FTD3XX
|
||||
if(handlers->driver_handle)
|
||||
return FT_FAILED(error_num);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void ftd3_close_compat(ftd3_device_device_handlers* handlers) {
|
||||
#ifdef USE_FTD3_LIBUSB
|
||||
ftd3_libusb_end_connection(handlers, true);
|
||||
#endif
|
||||
#ifdef USE_FTD3XX
|
||||
ftd3_driver_end_connection(handlers);
|
||||
#endif
|
||||
}
|
||||
|
||||
int ftd3_abort_pipe_compat(ftd3_device_device_handlers* handlers, int pipe) {
|
||||
#ifdef USE_FTD3_LIBUSB
|
||||
if(handlers->usb_handle)
|
||||
return ftd3_libusb_abort_pipe(handlers, pipe);
|
||||
#endif
|
||||
#ifdef USE_FTD3XX
|
||||
if(handlers->driver_handle)
|
||||
return FT_AbortPipe(handlers->driver_handle, pipe);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ftd3_set_stream_pipe_compat(ftd3_device_device_handlers* handlers, int pipe, size_t length) {
|
||||
#ifdef USE_FTD3_LIBUSB
|
||||
if(handlers->usb_handle)
|
||||
return ftd3_libusb_set_stream_pipe(handlers, pipe, length);
|
||||
#endif
|
||||
#ifdef USE_FTD3XX
|
||||
if(handlers->driver_handle)
|
||||
return FT_SetStreamPipe(handlers->driver_handle, false, false, pipe, length);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ftd3_write_pipe_compat(ftd3_device_device_handlers* handlers, int pipe, const uint8_t* data, size_t size, int* num_transferred) {
|
||||
#ifdef USE_FTD3_LIBUSB
|
||||
if(handlers->usb_handle)
|
||||
return ftd3_libusb_write_pipe(handlers, pipe, data, size, num_transferred);
|
||||
#endif
|
||||
#ifdef USE_FTD3XX
|
||||
if(handlers->driver_handle) {
|
||||
ULONG transferred_ftd3xx = 0;
|
||||
int result = FT_WritePipe(handlers->driver_handle, pipe, (uint8_t*)data, size, &transferred_ftd3xx, 0);
|
||||
if(FT_FAILED(result))
|
||||
return result;
|
||||
*num_transferred = (int)transferred_ftd3xx;
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ftd3_read_pipe_compat(ftd3_device_device_handlers* handlers, int pipe, uint8_t* data, size_t size, int* num_transferred) {
|
||||
#ifdef USE_FTD3_LIBUSB
|
||||
if(handlers->usb_handle)
|
||||
return ftd3_libusb_read_pipe(handlers, pipe, data, size, num_transferred);
|
||||
#endif
|
||||
#ifdef USE_FTD3XX
|
||||
if(handlers->driver_handle) {
|
||||
ULONG transferred_ftd3xx = 0;
|
||||
int result = FT_ReadPipe(handlers->driver_handle, pipe, data, size, &transferred_ftd3xx, 0);
|
||||
if(FT_FAILED(result))
|
||||
return result;
|
||||
*num_transferred = (int)transferred_ftd3xx;
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ftd3_get_is_bad_compat(ftd3_device_device_handlers* handlers) {
|
||||
#ifdef USE_FTD3_LIBUSB
|
||||
if(handlers->usb_handle)
|
||||
return false;
|
||||
#endif
|
||||
#ifdef USE_FTD3XX
|
||||
if(handlers->driver_handle)
|
||||
return ftd3_driver_get_is_bad();
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ftd3_get_skip_initial_pipe_abort_compat(ftd3_device_device_handlers* handlers) {
|
||||
#ifdef USE_FTD3_LIBUSB
|
||||
if(handlers->usb_handle)
|
||||
return false;
|
||||
#endif
|
||||
#ifdef USE_FTD3XX
|
||||
if(handlers->driver_handle)
|
||||
return ftd3_driver_get_skip_initial_pipe_abort();
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
void ftd3_main_loop_compat(CaptureData* capture_data, int pipe) {
|
||||
ftd3_device_device_handlers* handlers = (ftd3_device_device_handlers*)capture_data->handle;
|
||||
#ifdef USE_FTD3_LIBUSB
|
||||
if(handlers->usb_handle)
|
||||
ftd3_libusb_capture_main_loop(capture_data, pipe);
|
||||
#endif
|
||||
#ifdef USE_FTD3XX
|
||||
if(handlers->driver_handle)
|
||||
ftd3_driver_capture_main_loop(capture_data, pipe);
|
||||
#endif
|
||||
}
|
@ -0,0 +1,125 @@
|
||||
#include "3dscapture_ftd3_driver_acquisition.hpp"
|
||||
#include "3dscapture_ftd3_driver_comms.hpp"
|
||||
#include "3dscapture_ftd3_compatibility.hpp"
|
||||
#include "3dscapture_ftd3_shared_general.hpp"
|
||||
#include "devicecapture.hpp"
|
||||
#include "devicecapture.hpp"
|
||||
//#include "ftd3xx_symbols_renames.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define FTD3XX_STATIC
|
||||
#define FT_ASYNC_CALL FT_ReadPipeEx
|
||||
#else
|
||||
#define FT_ASYNC_CALL FT_ReadPipeAsync
|
||||
#endif
|
||||
#include <ftd3xx.h>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
struct FTD3XXReceivedDataBuffer {
|
||||
CaptureReceived capture_buf;
|
||||
OVERLAPPED overlap;
|
||||
ULONG read_buffer;
|
||||
};
|
||||
|
||||
static void fast_capture_call(FTD3XXReceivedDataBuffer* received_buffer, CaptureData* capture_data, int fifo_channel) {
|
||||
int inner_curr_in = 0;
|
||||
FT_STATUS ftStatus;
|
||||
void* handle = ((ftd3_device_device_handlers*)capture_data->handle)->driver_handle;
|
||||
for (inner_curr_in = 0; inner_curr_in < FTD3_CONCURRENT_BUFFERS; ++inner_curr_in) {
|
||||
ftStatus = FT_InitializeOverlapped(handle, &received_buffer[inner_curr_in].overlap);
|
||||
if(ftStatus) {
|
||||
capture_error_print(true, capture_data, "Disconnected: Initialize failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (inner_curr_in = 0; inner_curr_in < FTD3_CONCURRENT_BUFFERS - 1; ++inner_curr_in) {
|
||||
ftStatus = FT_ASYNC_CALL(handle, fifo_channel, (UCHAR*)&received_buffer[inner_curr_in].capture_buf, ftd3_get_capture_size(capture_data), &received_buffer[inner_curr_in].read_buffer, &received_buffer[inner_curr_in].overlap);
|
||||
if(ftStatus != FT_IO_PENDING) {
|
||||
capture_error_print(true, capture_data, "Disconnected: Read failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
inner_curr_in = FTD3_CONCURRENT_BUFFERS - 1;
|
||||
|
||||
auto clock_start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
while (capture_data->status.connected && capture_data->status.running) {
|
||||
|
||||
ftStatus = FT_ASYNC_CALL(handle, fifo_channel, (UCHAR*)&received_buffer[inner_curr_in].capture_buf, ftd3_get_capture_size(capture_data), &received_buffer[inner_curr_in].read_buffer, &received_buffer[inner_curr_in].overlap);
|
||||
if(ftStatus != FT_IO_PENDING) {
|
||||
capture_error_print(true, capture_data, "Disconnected: Read failed");
|
||||
return;
|
||||
}
|
||||
|
||||
inner_curr_in = (inner_curr_in + 1) % FTD3_CONCURRENT_BUFFERS;
|
||||
|
||||
ftStatus = FT_GetOverlappedResult(handle, &received_buffer[inner_curr_in].overlap, &received_buffer[inner_curr_in].read_buffer, true);
|
||||
if(FT_FAILED(ftStatus)) {
|
||||
capture_error_print(true, capture_data, "Disconnected: USB error");
|
||||
return;
|
||||
}
|
||||
|
||||
data_output_update(&received_buffer[inner_curr_in].capture_buf, received_buffer[inner_curr_in].read_buffer, capture_data, clock_start);
|
||||
}
|
||||
}
|
||||
|
||||
static bool safe_capture_call(FTD3XXReceivedDataBuffer* received_buffer, CaptureData* capture_data, int fifo_channel) {
|
||||
auto clock_start = std::chrono::high_resolution_clock::now();
|
||||
void* handle = ((ftd3_device_device_handlers*)capture_data->handle)->driver_handle;
|
||||
|
||||
while(capture_data->status.connected && capture_data->status.running) {
|
||||
|
||||
#ifdef _WIN32
|
||||
FT_STATUS ftStatus = FT_ReadPipeEx(handle, fifo_channel, (UCHAR*)&received_buffer->capture_buf, ftd3_get_capture_size(capture_data), &received_buffer->read_buffer, NULL);
|
||||
#else
|
||||
FT_STATUS ftStatus = FT_ReadPipeEx(handle, fifo_channel, (UCHAR*)&received_buffer->capture_buf, ftd3_get_capture_size(capture_data), &received_buffer->read_buffer, 1000);
|
||||
#endif
|
||||
if(FT_FAILED(ftStatus)) {
|
||||
capture_error_print(true, capture_data, "Disconnected: Read failed");
|
||||
return true;
|
||||
}
|
||||
|
||||
data_output_update(&received_buffer->capture_buf, received_buffer->read_buffer, capture_data, clock_start);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static FTD3XXReceivedDataBuffer* init_received_buffer() {
|
||||
if(ftd3_driver_get_is_bad())
|
||||
return new FTD3XXReceivedDataBuffer;
|
||||
|
||||
return new FTD3XXReceivedDataBuffer[FTD3_CONCURRENT_BUFFERS];
|
||||
}
|
||||
|
||||
static void close_received_buffer(FTD3XXReceivedDataBuffer* received_buffer, CaptureData* capture_data) {
|
||||
if(ftd3_driver_get_is_bad()) {
|
||||
delete received_buffer;
|
||||
return;
|
||||
}
|
||||
|
||||
void* handle = ((ftd3_device_device_handlers*)capture_data->handle)->driver_handle;
|
||||
for(int inner_curr_in = 0; inner_curr_in < FTD3_CONCURRENT_BUFFERS; ++inner_curr_in) {
|
||||
FT_STATUS ftStatus = FT_GetOverlappedResult(handle, &received_buffer[inner_curr_in].overlap, &received_buffer[inner_curr_in].read_buffer, true);
|
||||
if(FT_ReleaseOverlapped(handle, &received_buffer[inner_curr_in].overlap)) {
|
||||
capture_error_print(true, capture_data, "Disconnected: Release failed");
|
||||
}
|
||||
}
|
||||
delete []received_buffer;
|
||||
}
|
||||
|
||||
void ftd3_driver_capture_main_loop(CaptureData* capture_data, int pipe) {
|
||||
FTD3XXReceivedDataBuffer* received_buffer = init_received_buffer();
|
||||
int fifo_channel = pipe;
|
||||
#ifndef _WIN32
|
||||
fifo_channel = 0;
|
||||
#endif
|
||||
if(!ftd3_driver_get_is_bad())
|
||||
fast_capture_call(received_buffer, capture_data, fifo_channel);
|
||||
else
|
||||
safe_capture_call(received_buffer, capture_data, fifo_channel);
|
||||
close_received_buffer(received_buffer, capture_data);
|
||||
}
|
@ -0,0 +1,125 @@
|
||||
#include "3dscapture_ftd3_driver_comms.hpp"
|
||||
#include "3dscapture_ftd3_shared_general.hpp"
|
||||
#include "devicecapture.hpp"
|
||||
//#include "ftd3xx_symbols_renames.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define FTD3XX_STATIC
|
||||
#endif
|
||||
#include <ftd3xx.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
#define REAL_SERIAL_NUMBER_SIZE 16
|
||||
#define SERIAL_NUMBER_SIZE (REAL_SERIAL_NUMBER_SIZE+1)
|
||||
|
||||
static bool _ftd3_driver_get_is_bad();
|
||||
static bool _ftd3_driver_get_skip_initial_pipe_abort();
|
||||
|
||||
const bool is_bad_ftd3xx = _ftd3_driver_get_is_bad();
|
||||
const bool skip_initial_pipe_abort = _ftd3_driver_get_skip_initial_pipe_abort();
|
||||
|
||||
static bool _ftd3_driver_get_is_bad() {
|
||||
#ifdef _WIN32
|
||||
#ifdef _M_ARM64
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
#endif
|
||||
// For some reason, the version scheme seems broken...
|
||||
// For now, just return false... :/
|
||||
return false;
|
||||
|
||||
bool is_bad_ftd3xx = false;
|
||||
DWORD ftd3xx_lib_version;
|
||||
|
||||
if(FT_FAILED(FT_GetLibraryVersion(&ftd3xx_lib_version))) {
|
||||
ftd3xx_lib_version = 0;
|
||||
}
|
||||
if(ftd3xx_lib_version >= 0x0100001A) {
|
||||
is_bad_ftd3xx = true;
|
||||
}
|
||||
return is_bad_ftd3xx;
|
||||
}
|
||||
|
||||
static bool _ftd3_driver_get_skip_initial_pipe_abort() {
|
||||
#ifdef _WIN32
|
||||
return false;
|
||||
#endif
|
||||
|
||||
bool skip_initial_pipe_abort = false;
|
||||
DWORD ftd3xx_lib_version;
|
||||
|
||||
if(FT_FAILED(FT_GetLibraryVersion(&ftd3xx_lib_version))) {
|
||||
ftd3xx_lib_version = 0;
|
||||
}
|
||||
if(ftd3xx_lib_version >= 0x0100001A) {
|
||||
skip_initial_pipe_abort = true;
|
||||
}
|
||||
return skip_initial_pipe_abort;
|
||||
}
|
||||
|
||||
bool ftd3_driver_get_is_bad() {
|
||||
return is_bad_ftd3xx;
|
||||
}
|
||||
|
||||
bool ftd3_driver_get_skip_initial_pipe_abort() {
|
||||
return skip_initial_pipe_abort;
|
||||
}
|
||||
|
||||
void ftd3_driver_list_devices(std::vector<CaptureDevice> &devices_list, int *curr_serial_extra_id_ftd3, const std::vector<std::string> &valid_descriptions) {
|
||||
FT_STATUS ftStatus;
|
||||
DWORD numDevs = 0;
|
||||
ftStatus = FT_CreateDeviceInfoList(&numDevs);
|
||||
size_t num_inserted = 0;
|
||||
if(FT_FAILED(ftStatus) || (numDevs == 0))
|
||||
return;
|
||||
|
||||
FT_HANDLE ftHandle = NULL;
|
||||
DWORD Flags = 0;
|
||||
DWORD Type = 0;
|
||||
DWORD ID = 0;
|
||||
char SerialNumber[SERIAL_NUMBER_SIZE] = { 0 };
|
||||
char Description[65] = { 0 };
|
||||
for (DWORD i = 0; i < numDevs; i++)
|
||||
{
|
||||
ftStatus = FT_GetDeviceInfoDetail(i, &Flags, &Type, &ID, NULL,
|
||||
SerialNumber, Description, &ftHandle);
|
||||
if(FT_FAILED(ftStatus))
|
||||
continue;
|
||||
for(int j = 0; j < valid_descriptions.size(); j++) {
|
||||
if(Description == valid_descriptions[j]) {
|
||||
ftStatus = FT_Create(SerialNumber, FT_OPEN_BY_SERIAL_NUMBER, &ftHandle);
|
||||
if(FT_FAILED(ftStatus))
|
||||
break;
|
||||
ftd3_insert_device(devices_list, std::string(SerialNumber), *curr_serial_extra_id_ftd3, true);
|
||||
FT_Close(ftHandle);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ftd3_device_device_handlers* ftd3_driver_serial_reconnection(std::string wanted_serial_number) {
|
||||
ftd3_device_device_handlers* final_handlers = NULL;
|
||||
ftd3_device_device_handlers inside_handlers;
|
||||
char SerialNumber[SERIAL_NUMBER_SIZE] = { 0 };
|
||||
strncpy(SerialNumber, wanted_serial_number.c_str(), REAL_SERIAL_NUMBER_SIZE);
|
||||
SerialNumber[REAL_SERIAL_NUMBER_SIZE] = 0;
|
||||
if(!FT_FAILED(FT_Create(SerialNumber, FT_OPEN_BY_SERIAL_NUMBER, &inside_handlers.driver_handle))) {
|
||||
final_handlers = new ftd3_device_device_handlers;
|
||||
final_handlers->usb_handle = NULL;
|
||||
final_handlers->driver_handle = inside_handlers.driver_handle;
|
||||
}
|
||||
return final_handlers;
|
||||
}
|
||||
|
||||
void ftd3_driver_end_connection(ftd3_device_device_handlers* handlers) {
|
||||
if(handlers->driver_handle == NULL)
|
||||
return;
|
||||
FT_Close(handlers->driver_handle);
|
||||
handlers->driver_handle = NULL;
|
||||
}
|
@ -0,0 +1,233 @@
|
||||
#include "3dscapture_ftd3_libusb_acquisition.hpp"
|
||||
#include "3dscapture_ftd3_libusb_comms.hpp"
|
||||
#include "3dscapture_ftd3_compatibility.hpp"
|
||||
#include "3dscapture_ftd3_shared_general.hpp"
|
||||
#include "devicecapture.hpp"
|
||||
|
||||
#include <thread>
|
||||
#include <libusb.h>
|
||||
#include "usb_generic.hpp"
|
||||
|
||||
#define MAX_TIME_WAIT 0.5
|
||||
|
||||
// This was created to remove the dependency from the FTD3XX library
|
||||
// under Linux and MacOS (as well as WinUSB).
|
||||
// There were issues with said library which forced the use of an
|
||||
// older release (double free when a device is disconnected, for example).
|
||||
// There were problems with automatic downloads being blocked as well.
|
||||
// This is something which could not go on indefinitively.
|
||||
|
||||
// Optimize data capturing for libusb with async transfers and callbacks,
|
||||
// instead of waiting for the usb transfer to be done...
|
||||
|
||||
struct FTD3LibusbCaptureReceivedData {
|
||||
bool in_use;
|
||||
uint32_t index;
|
||||
CaptureData* capture_data;
|
||||
CaptureReceived buffer;
|
||||
uint32_t* last_index;
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> *clock_start;
|
||||
SharedConsumerMutex *is_buffer_free_shared_mutex;
|
||||
int* status;
|
||||
ftd3_async_callback_data cb_data;
|
||||
};
|
||||
|
||||
static void ftd3_libusb_read_frame_cb(void* user_data, int transfer_length, int transfer_status);
|
||||
|
||||
static void ftd3_device_usb_thread_function(bool* usb_thread_run) {
|
||||
if(!usb_is_initialized())
|
||||
return;
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 300000;
|
||||
while(*usb_thread_run)
|
||||
libusb_handle_events_timeout_completed(get_usb_ctx(), &tv, NULL);
|
||||
}
|
||||
|
||||
static void ftd3_libusb_start_thread(std::thread* thread_ptr, bool* usb_thread_run) {
|
||||
if(!usb_is_initialized())
|
||||
return;
|
||||
*usb_thread_run = true;
|
||||
*thread_ptr = std::thread(ftd3_device_usb_thread_function, usb_thread_run);
|
||||
}
|
||||
|
||||
static void ftd3_libusb_close_thread(std::thread* thread_ptr, bool* usb_thread_run) {
|
||||
if(!usb_is_initialized())
|
||||
return;
|
||||
*usb_thread_run = false;
|
||||
thread_ptr->join();
|
||||
}
|
||||
|
||||
static int get_ftd3_libusb_status(FTD3LibusbCaptureReceivedData* ftd3_libusb_capture_recv_data) {
|
||||
return *ftd3_libusb_capture_recv_data[0].status;
|
||||
}
|
||||
|
||||
static void error_ftd3_libusb_status(FTD3LibusbCaptureReceivedData* ftd3_libusb_capture_recv_data, int error_val) {
|
||||
if((error_val == 0) || (get_ftd3_libusb_status(ftd3_libusb_capture_recv_data) == 0))
|
||||
*ftd3_libusb_capture_recv_data[0].status = error_val;
|
||||
}
|
||||
|
||||
static void reset_ftd3_libusb_status(FTD3LibusbCaptureReceivedData* ftd3_libusb_capture_recv_data) {
|
||||
error_ftd3_libusb_status(ftd3_libusb_capture_recv_data, 0);
|
||||
}
|
||||
|
||||
static void ftd3_libusb_read_frame_request(CaptureData* capture_data, FTD3LibusbCaptureReceivedData* ftd3_libusb_capture_recv_data, uint32_t index, int pipe) {
|
||||
if(ftd3_libusb_capture_recv_data == NULL)
|
||||
return;
|
||||
if((*ftd3_libusb_capture_recv_data->status) < 0)
|
||||
return;
|
||||
ftd3_libusb_capture_recv_data->index = index;
|
||||
ftd3_libusb_capture_recv_data->cb_data.function = ftd3_libusb_read_frame_cb;
|
||||
ftd3_libusb_async_in_start((ftd3_device_device_handlers*)capture_data->handle, pipe, MAX_TIME_WAIT * 1000, (uint8_t*)&ftd3_libusb_capture_recv_data->buffer, ftd3_get_capture_size(capture_data), &ftd3_libusb_capture_recv_data->cb_data);
|
||||
}
|
||||
|
||||
static void end_ftd3_libusb_read_frame_cb(FTD3LibusbCaptureReceivedData* ftd3_libusb_capture_recv_data) {
|
||||
ftd3_libusb_capture_recv_data->in_use = false;
|
||||
ftd3_libusb_capture_recv_data->is_buffer_free_shared_mutex->specific_unlock(ftd3_libusb_capture_recv_data->cb_data.internal_index);
|
||||
}
|
||||
|
||||
static void ftd3_libusb_read_frame_cb(void* user_data, int transfer_length, int transfer_status) {
|
||||
FTD3LibusbCaptureReceivedData* ftd3_libusb_capture_recv_data = (FTD3LibusbCaptureReceivedData*)user_data;
|
||||
if((*ftd3_libusb_capture_recv_data->status) < 0)
|
||||
return end_ftd3_libusb_read_frame_cb(ftd3_libusb_capture_recv_data);
|
||||
if(transfer_status != LIBUSB_TRANSFER_COMPLETED) {
|
||||
*ftd3_libusb_capture_recv_data->status = LIBUSB_ERROR_OTHER;
|
||||
return end_ftd3_libusb_read_frame_cb(ftd3_libusb_capture_recv_data);
|
||||
}
|
||||
|
||||
if(((int32_t)(ftd3_libusb_capture_recv_data->index - (*ftd3_libusb_capture_recv_data->last_index))) <= 0) {
|
||||
//*ftd3_libusb_capture_recv_data->status = LIBUSB_ERROR_INTERRUPTED;
|
||||
return end_ftd3_libusb_read_frame_cb(ftd3_libusb_capture_recv_data);
|
||||
}
|
||||
*ftd3_libusb_capture_recv_data->last_index = ftd3_libusb_capture_recv_data->index;
|
||||
|
||||
data_output_update(&ftd3_libusb_capture_recv_data->buffer, transfer_length, ftd3_libusb_capture_recv_data->capture_data, *ftd3_libusb_capture_recv_data->clock_start);
|
||||
end_ftd3_libusb_read_frame_cb(ftd3_libusb_capture_recv_data);
|
||||
}
|
||||
|
||||
static int ftd3_libusb_get_num_free_buffers(FTD3LibusbCaptureReceivedData* ftd3_libusb_capture_recv_data) {
|
||||
int num_free = 0;
|
||||
for(int i = 0; i < FTD3_CONCURRENT_BUFFERS; i++)
|
||||
if(!ftd3_libusb_capture_recv_data[i].in_use)
|
||||
num_free += 1;
|
||||
return num_free;
|
||||
}
|
||||
|
||||
static void close_all_reads_error(FTD3LibusbCaptureReceivedData* ftd3_libusb_capture_recv_data, bool &async_read_closed) {
|
||||
if(get_ftd3_libusb_status(ftd3_libusb_capture_recv_data) >= 0)
|
||||
return;
|
||||
if(!async_read_closed) {
|
||||
for (int i = 0; i < FTD3_CONCURRENT_BUFFERS; i++)
|
||||
ftd3_libusb_cancell_callback(&ftd3_libusb_capture_recv_data[i].cb_data);
|
||||
async_read_closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool has_too_much_time_passed(const std::chrono::time_point<std::chrono::high_resolution_clock> &start_time) {
|
||||
const auto curr_time = std::chrono::high_resolution_clock::now();
|
||||
const std::chrono::duration<double> diff = curr_time - start_time;
|
||||
return diff.count() > MAX_TIME_WAIT;
|
||||
}
|
||||
|
||||
static void error_too_much_time_passed(FTD3LibusbCaptureReceivedData* ftd3_libusb_capture_recv_data, bool &async_read_closed, const std::chrono::time_point<std::chrono::high_resolution_clock> &start_time) {
|
||||
if(has_too_much_time_passed(start_time)) {
|
||||
error_ftd3_libusb_status(ftd3_libusb_capture_recv_data, -1);
|
||||
close_all_reads_error(ftd3_libusb_capture_recv_data, async_read_closed);
|
||||
}
|
||||
}
|
||||
|
||||
static void wait_all_ftd3_libusb_buffers_free(FTD3LibusbCaptureReceivedData* ftd3_libusb_capture_recv_data) {
|
||||
if(ftd3_libusb_capture_recv_data == NULL)
|
||||
return;
|
||||
bool async_read_closed = false;
|
||||
close_all_reads_error(ftd3_libusb_capture_recv_data, async_read_closed);
|
||||
const auto start_time = std::chrono::high_resolution_clock::now();
|
||||
for(int i = 0; i < FTD3_CONCURRENT_BUFFERS; i++)
|
||||
while(ftd3_libusb_capture_recv_data[i].in_use) {
|
||||
error_too_much_time_passed(ftd3_libusb_capture_recv_data, async_read_closed, start_time);
|
||||
ftd3_libusb_capture_recv_data[i].is_buffer_free_shared_mutex->specific_timed_lock(i);
|
||||
}
|
||||
}
|
||||
|
||||
static void wait_one_ftd3_libusb_buffer_free(FTD3LibusbCaptureReceivedData* ftd3_libusb_capture_recv_data) {
|
||||
bool done = false;
|
||||
const auto start_time = std::chrono::high_resolution_clock::now();
|
||||
while(!done) {
|
||||
for(int i = 0; i < FTD3_CONCURRENT_BUFFERS; i++) {
|
||||
if(!ftd3_libusb_capture_recv_data[i].in_use)
|
||||
done = true;
|
||||
}
|
||||
if(!done) {
|
||||
if(has_too_much_time_passed(start_time))
|
||||
return;
|
||||
if(get_ftd3_libusb_status(ftd3_libusb_capture_recv_data) < 0)
|
||||
return;
|
||||
int dummy = 0;
|
||||
ftd3_libusb_capture_recv_data[0].is_buffer_free_shared_mutex->general_timed_lock(&dummy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool ftd3_libusb_are_buffers_all_free(FTD3LibusbCaptureReceivedData* ftd3_libusb_capture_recv_data) {
|
||||
return ftd3_libusb_get_num_free_buffers(ftd3_libusb_capture_recv_data) == FTD3_CONCURRENT_BUFFERS;
|
||||
}
|
||||
|
||||
static FTD3LibusbCaptureReceivedData* ftd3_libusb_get_free_buffer(FTD3LibusbCaptureReceivedData* ftd3_libusb_capture_recv_data) {
|
||||
wait_one_ftd3_libusb_buffer_free(ftd3_libusb_capture_recv_data);
|
||||
if(get_ftd3_libusb_status(ftd3_libusb_capture_recv_data) < 0)
|
||||
return NULL;
|
||||
for(int i = 0; i < FTD3_CONCURRENT_BUFFERS; i++)
|
||||
if(!ftd3_libusb_capture_recv_data[i].in_use) {
|
||||
ftd3_libusb_capture_recv_data[i].is_buffer_free_shared_mutex->specific_try_lock(i);
|
||||
ftd3_libusb_capture_recv_data[i].in_use = true;
|
||||
return &ftd3_libusb_capture_recv_data[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ftd3_libusb_capture_main_loop_processing(FTD3LibusbCaptureReceivedData* ftd3_libusb_capture_recv_data, int pipe) {
|
||||
int index = 0;
|
||||
CaptureData* capture_data = ftd3_libusb_capture_recv_data[0].capture_data;
|
||||
|
||||
for(int i = 0; i < FTD3_CONCURRENT_BUFFERS; i++)
|
||||
ftd3_libusb_read_frame_request(capture_data, ftd3_libusb_get_free_buffer(ftd3_libusb_capture_recv_data), index++, pipe);
|
||||
|
||||
while(capture_data->status.connected && capture_data->status.running) {
|
||||
if(get_ftd3_libusb_status(ftd3_libusb_capture_recv_data) < 0) {
|
||||
capture_error_print(true, capture_data, "Disconnected: Read failed");
|
||||
return;
|
||||
}
|
||||
FTD3LibusbCaptureReceivedData* free_buffer = ftd3_libusb_get_free_buffer(ftd3_libusb_capture_recv_data);
|
||||
ftd3_libusb_read_frame_request(capture_data, free_buffer, index++, pipe);
|
||||
}
|
||||
}
|
||||
|
||||
void ftd3_libusb_capture_main_loop(CaptureData* capture_data, int pipe) {
|
||||
if(!usb_is_initialized())
|
||||
return;
|
||||
bool is_done_thread;
|
||||
std::thread async_processing_thread;
|
||||
|
||||
uint32_t last_index = -1;
|
||||
int status = 0;
|
||||
SharedConsumerMutex is_buffer_free_shared_mutex(FTD3_CONCURRENT_BUFFERS);
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> clock_start = std::chrono::high_resolution_clock::now();
|
||||
FTD3LibusbCaptureReceivedData* ftd3_libusb_capture_recv_data = new FTD3LibusbCaptureReceivedData[FTD3_CONCURRENT_BUFFERS];
|
||||
for(int i = 0; i < FTD3_CONCURRENT_BUFFERS; i++) {
|
||||
ftd3_libusb_capture_recv_data[i].in_use = false;
|
||||
ftd3_libusb_capture_recv_data[i].index = i;
|
||||
ftd3_libusb_capture_recv_data[i].capture_data = capture_data;
|
||||
ftd3_libusb_capture_recv_data[i].last_index = &last_index;
|
||||
ftd3_libusb_capture_recv_data[i].clock_start = &clock_start;
|
||||
ftd3_libusb_capture_recv_data[i].is_buffer_free_shared_mutex = &is_buffer_free_shared_mutex;
|
||||
ftd3_libusb_capture_recv_data[i].status = &status;
|
||||
ftd3_libusb_capture_recv_data[i].cb_data.actual_user_data = &ftd3_libusb_capture_recv_data[i];
|
||||
ftd3_libusb_capture_recv_data[i].cb_data.transfer_data = NULL;
|
||||
ftd3_libusb_capture_recv_data[i].cb_data.internal_index = i;
|
||||
}
|
||||
ftd3_libusb_start_thread(&async_processing_thread, &is_done_thread);
|
||||
ftd3_libusb_capture_main_loop_processing(ftd3_libusb_capture_recv_data, pipe);
|
||||
wait_all_ftd3_libusb_buffers_free(ftd3_libusb_capture_recv_data);
|
||||
ftd3_libusb_close_thread(&async_processing_thread, &is_done_thread);
|
||||
delete []ftd3_libusb_capture_recv_data;
|
||||
}
|
@ -0,0 +1,339 @@
|
||||
#include "3dscapture_ftd3_libusb_comms.hpp"
|
||||
#include "3dscapture_ftd3_shared_general.hpp"
|
||||
#include "devicecapture.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <libusb.h>
|
||||
#include "usb_generic.hpp"
|
||||
|
||||
// This was created to remove the dependency from the FTD3XX library
|
||||
// under Linux and MacOS (as well as WinUSB).
|
||||
// There were issues with said library which forced the use of an
|
||||
// older release (double free when a device is disconnected, for example).
|
||||
// There were problems with automatic downloads being blocked as well.
|
||||
// This is something which could not go on indefinitively.
|
||||
|
||||
// The functions present in this file represent the needs of this
|
||||
// particular program at this moment in time.
|
||||
// It may not include all the functions needed to replace the FTD3XX
|
||||
// library for you... If that's the case, Wireshark is your friend.
|
||||
|
||||
#define FTD3_COMMAND_CREATE_PIPE_ID 0x82
|
||||
#define FTD3_COMMAND_BULK_PIPE_ID 0x01
|
||||
|
||||
#define FTD3_COMMAND_TIMEOUT 500
|
||||
|
||||
#define FTD3_COMMAND_INTERFACE 0
|
||||
#define FTD3_BULK_INTERFACE 1
|
||||
|
||||
#define FTD3_COMMAND_ABORT_ID 0
|
||||
#define FTD3_COMMAND_RW_OPERATION_PREPARE_ID 1
|
||||
#define FTD3_COMMAND_SET_STREAM_PIPE_ID 2
|
||||
#define FTD3_COMMAND_CREATE_ID 3
|
||||
#define FTD3_COMMAND_DESTROY_ID 3
|
||||
|
||||
#define FTDI_VID 0x0403
|
||||
|
||||
const uint16_t ftd3_valid_vids[] = {FTDI_VID};
|
||||
const size_t ftd3_num_vids = sizeof(ftd3_valid_vids) / sizeof(ftd3_valid_vids[0]);
|
||||
const uint16_t ftd3_valid_pids[] = {0x601e, 0x601f, 0x602a, 0x602b, 0x602c, 0x602d, 0x602f};
|
||||
const size_t ftd3_num_pids = sizeof(ftd3_valid_pids) / sizeof(ftd3_valid_pids[0]);
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct ftd3_command_preamble_data {
|
||||
uint32_t unk;
|
||||
uint8_t pipe;
|
||||
uint8_t command;
|
||||
uint16_t unk2;
|
||||
} PACKED;
|
||||
|
||||
struct ftd3_command_with_ptr_data {
|
||||
ftd3_command_preamble_data preamble_data;
|
||||
uint64_t random_ptr;
|
||||
uint32_t unk;
|
||||
} PACKED;
|
||||
|
||||
struct ftd3_command_with_len_data {
|
||||
ftd3_command_preamble_data preamble_data;
|
||||
uint32_t len;
|
||||
uint64_t unk;
|
||||
} PACKED;
|
||||
#pragma pack(pop)
|
||||
|
||||
// Read from ctrl_in
|
||||
int ftd3_libusb_ctrl_in(ftd3_device_device_handlers* handlers, uint32_t timeout, uint8_t* buf, int length, uint8_t request, uint16_t value, uint16_t index, int* transferred) {
|
||||
int ret = libusb_control_transfer((libusb_device_handle*)handlers->usb_handle, 0xC0, request, value, index, buf, length, timeout);
|
||||
if(ret >= 0)
|
||||
*transferred = ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Write to ctrl_out
|
||||
int ftd3_libusb_ctrl_out(ftd3_device_device_handlers* handlers, uint32_t timeout, const uint8_t* buf, int length, uint8_t request, uint16_t value, uint16_t index, int* transferred) {
|
||||
int ret = libusb_control_transfer((libusb_device_handle*)handlers->usb_handle, 0x40, request, value, index, (uint8_t*)buf, length, timeout);
|
||||
if(ret >= 0)
|
||||
*transferred = ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Read from bulk
|
||||
int ftd3_libusb_bulk_in(ftd3_device_device_handlers* handlers, int endpoint_in, uint32_t timeout, uint8_t* buf, int length, int* transferred) {
|
||||
return libusb_bulk_transfer((libusb_device_handle*)handlers->usb_handle, endpoint_in, buf, length, transferred, timeout);
|
||||
}
|
||||
|
||||
// Write to bulk
|
||||
int ftd3_libusb_bulk_out(ftd3_device_device_handlers* handlers, int endpoint_out, uint32_t timeout, const uint8_t* buf, int length, int* transferred) {
|
||||
return libusb_bulk_transfer((libusb_device_handle*)handlers->usb_handle, endpoint_out, (uint8_t*)buf, length, transferred, timeout);
|
||||
}
|
||||
|
||||
void ftd3_libusb_cancell_callback(ftd3_async_callback_data* cb_data) {
|
||||
cb_data->transfer_data_access.lock();
|
||||
if(cb_data->transfer_data)
|
||||
libusb_cancel_transfer((libusb_transfer*)cb_data->transfer_data);
|
||||
cb_data->transfer_data_access.unlock();
|
||||
}
|
||||
|
||||
void STDCALL ftd3_libusb_async_callback(libusb_transfer* transfer) {
|
||||
ftd3_async_callback_data* cb_data = (ftd3_async_callback_data*)transfer->user_data;
|
||||
cb_data->transfer_data_access.lock();
|
||||
cb_data->transfer_data = NULL;
|
||||
cb_data->transfer_data_access.unlock();
|
||||
cb_data->function(cb_data->actual_user_data, transfer->actual_length, transfer->status);
|
||||
}
|
||||
|
||||
// Read from bulk
|
||||
int ftd3_libusb_async_in_start(ftd3_device_device_handlers* handlers, int endpoint_in, uint32_t timeout, uint8_t* buf, int length, ftd3_async_callback_data* cb_data) {
|
||||
libusb_transfer *transfer_in = libusb_alloc_transfer(0);
|
||||
if(!transfer_in)
|
||||
return LIBUSB_ERROR_OTHER;
|
||||
cb_data->transfer_data_access.lock();
|
||||
cb_data->transfer_data = transfer_in;
|
||||
libusb_fill_bulk_transfer(transfer_in, (libusb_device_handle*)handlers->usb_handle, endpoint_in, buf, length, ftd3_libusb_async_callback, cb_data, timeout);
|
||||
transfer_in->flags |= LIBUSB_TRANSFER_FREE_TRANSFER;
|
||||
int retval = libusb_submit_transfer(transfer_in);
|
||||
cb_data->transfer_data_access.unlock();
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int ftd3_libusb_send_command(libusb_device_handle* handle, uint8_t* data, size_t length) {
|
||||
int num_transferred = 0;
|
||||
int result = libusb_bulk_transfer(handle, FTD3_COMMAND_BULK_PIPE_ID, data, length, &num_transferred, FTD3_COMMAND_TIMEOUT);
|
||||
if(result < 0)
|
||||
return result;
|
||||
if(num_transferred != length)
|
||||
return -1;
|
||||
return result;
|
||||
}
|
||||
|
||||
static int ftd3_libusb_send_ptr_data_command(libusb_device_handle* handle, uint8_t pipe, uint8_t command) {
|
||||
ftd3_command_with_ptr_data command_with_ptr_data;
|
||||
memset((uint8_t*)&command_with_ptr_data, 0, sizeof(ftd3_command_with_ptr_data));
|
||||
command_with_ptr_data.preamble_data.pipe = pipe;
|
||||
command_with_ptr_data.preamble_data.command = command;
|
||||
return ftd3_libusb_send_command(handle, (uint8_t*)&command_with_ptr_data, sizeof(ftd3_command_with_ptr_data));
|
||||
}
|
||||
|
||||
static int ftd3_libusb_send_len_data_command(libusb_device_handle* handle, uint8_t pipe, uint8_t command, uint32_t length) {
|
||||
ftd3_command_with_len_data command_with_len_data;
|
||||
memset((uint8_t*)&command_with_len_data, 0, sizeof(ftd3_command_with_len_data));
|
||||
command_with_len_data.preamble_data.pipe = pipe;
|
||||
command_with_len_data.preamble_data.command = command;
|
||||
command_with_len_data.len = to_le(length);
|
||||
return ftd3_libusb_send_command(handle, (uint8_t*)&command_with_len_data, sizeof(ftd3_command_with_len_data));
|
||||
}
|
||||
|
||||
static int ftd3_libusb_send_create_command(libusb_device_handle* handle) {
|
||||
return ftd3_libusb_send_ptr_data_command(handle, FTD3_COMMAND_CREATE_PIPE_ID, FTD3_COMMAND_CREATE_ID);
|
||||
}
|
||||
|
||||
int ftd3_libusb_abort_pipe(ftd3_device_device_handlers* handlers, int pipe) {
|
||||
int result = ftd3_libusb_send_ptr_data_command((libusb_device_handle*)handlers->usb_handle, pipe, FTD3_COMMAND_ABORT_ID);
|
||||
if(result < 0)
|
||||
return result;
|
||||
result = ftd3_libusb_send_ptr_data_command((libusb_device_handle*)handlers->usb_handle, pipe, FTD3_COMMAND_ABORT_ID);
|
||||
if(result < 0)
|
||||
return result;
|
||||
return ftd3_libusb_send_ptr_data_command((libusb_device_handle*)handlers->usb_handle, pipe, FTD3_COMMAND_DESTROY_ID);
|
||||
}
|
||||
|
||||
int ftd3_libusb_write_pipe(ftd3_device_device_handlers* handlers, int pipe, const uint8_t* data, size_t length, int* num_transferred) {
|
||||
int result = ftd3_libusb_send_len_data_command((libusb_device_handle*)handlers->usb_handle, pipe, FTD3_COMMAND_RW_OPERATION_PREPARE_ID, length);
|
||||
if(result < 0)
|
||||
return result;
|
||||
return ftd3_libusb_bulk_out(handlers, pipe, FTD3_COMMAND_TIMEOUT, data, length, num_transferred);
|
||||
}
|
||||
|
||||
int ftd3_libusb_read_pipe(ftd3_device_device_handlers* handlers, int pipe, uint8_t* data, size_t length, int* num_transferred) {
|
||||
int result = ftd3_libusb_send_len_data_command((libusb_device_handle*)handlers->usb_handle, pipe, FTD3_COMMAND_RW_OPERATION_PREPARE_ID, length);
|
||||
if(result < 0)
|
||||
return result;
|
||||
return ftd3_libusb_bulk_in(handlers, pipe, FTD3_COMMAND_TIMEOUT, data, length, num_transferred);
|
||||
}
|
||||
|
||||
int ftd3_libusb_set_stream_pipe(ftd3_device_device_handlers* handlers, int pipe, size_t length) {
|
||||
return ftd3_libusb_send_len_data_command((libusb_device_handle*)handlers->usb_handle, pipe, FTD3_COMMAND_SET_STREAM_PIPE_ID, length);
|
||||
}
|
||||
|
||||
static bool ftd3_libusb_setup_connection(libusb_device_handle* handle, bool* claimed_cmd, bool* claimed_bulk) {
|
||||
*claimed_cmd = false;
|
||||
*claimed_bulk = false;
|
||||
int result = libusb_claim_interface(handle, FTD3_COMMAND_INTERFACE);
|
||||
if(result != LIBUSB_SUCCESS)
|
||||
return false;
|
||||
*claimed_cmd = true;
|
||||
result = libusb_claim_interface(handle, FTD3_BULK_INTERFACE);
|
||||
if(result != LIBUSB_SUCCESS)
|
||||
return false;
|
||||
*claimed_bulk = true;
|
||||
result = ftd3_libusb_send_create_command(handle);
|
||||
if(result < 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void read_strings(libusb_device_handle *handle, libusb_device_descriptor *usb_descriptor, char* manufacturer, char* product, char* serial) {
|
||||
manufacturer[0] = 0;
|
||||
product[0] = 0;
|
||||
serial[0] = 0;
|
||||
libusb_get_string_descriptor_ascii(handle, usb_descriptor->iManufacturer, (uint8_t*)manufacturer, 0x100);
|
||||
libusb_get_string_descriptor_ascii(handle, usb_descriptor->iProduct, (uint8_t*)product, 0x100);
|
||||
libusb_get_string_descriptor_ascii(handle, usb_descriptor->iSerialNumber, (uint8_t*)serial, 0x100);
|
||||
manufacturer[0xFF] = 0;
|
||||
product[0xFF] = 0;
|
||||
serial[0xFF] = 0;
|
||||
}
|
||||
|
||||
static int ftd3_libusb_insert_device(std::vector<CaptureDevice> &devices_list, libusb_device *usb_device, libusb_device_descriptor *usb_descriptor, int &curr_serial_extra_id, const std::vector<std::string> &valid_descriptions) {
|
||||
libusb_device_handle *handle = NULL;
|
||||
int result = libusb_open(usb_device, &handle);
|
||||
if((result < 0) || (handle == NULL))
|
||||
return result;
|
||||
char manufacturer[0x100];
|
||||
char product[0x100];
|
||||
char serial[0x100];
|
||||
read_strings(handle, usb_descriptor, manufacturer, product, serial);
|
||||
bool found = false;
|
||||
for(int i = 0; i < valid_descriptions.size(); i++)
|
||||
if(product == valid_descriptions[i]) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if(!found) {
|
||||
libusb_close(handle);
|
||||
return result;
|
||||
}
|
||||
bool claimed_cmd = false;
|
||||
bool claimed_bulk = false;
|
||||
bool result_setup = ftd3_libusb_setup_connection(handle, &claimed_cmd, &claimed_bulk);
|
||||
if(result_setup)
|
||||
ftd3_insert_device(devices_list, (std::string)(serial), curr_serial_extra_id, false);
|
||||
if(claimed_cmd)
|
||||
libusb_release_interface(handle, FTD3_COMMAND_INTERFACE);
|
||||
if(claimed_bulk)
|
||||
libusb_release_interface(handle, FTD3_BULK_INTERFACE);
|
||||
libusb_close(handle);
|
||||
return result;
|
||||
}
|
||||
|
||||
static ftd3_device_device_handlers* ftd3_libusb_serial_find_in_list(libusb_device **usb_devices, int num_devices, std::string wanted_serial_number, int &curr_serial_extra_id, const std::vector<std::string> &valid_descriptions) {
|
||||
for(int i = 0; i < num_devices; i++) {
|
||||
libusb_device_descriptor usb_descriptor{};
|
||||
int result = libusb_get_device_descriptor(usb_devices[i], &usb_descriptor);
|
||||
if(result < 0)
|
||||
continue;
|
||||
for(int j = 0; j < ftd3_num_vids; j++) {
|
||||
if(usb_descriptor.idVendor != ftd3_valid_vids[j])
|
||||
continue;
|
||||
for(int k = 0; k < ftd3_num_pids; k++) {
|
||||
if(usb_descriptor.idProduct != ftd3_valid_pids[k])
|
||||
continue;
|
||||
ftd3_device_device_handlers handlers;
|
||||
result = libusb_open(usb_devices[i], (libusb_device_handle**)&handlers.usb_handle);
|
||||
if((result < 0) || (handlers.usb_handle == NULL))
|
||||
continue;
|
||||
char manufacturer[0x100];
|
||||
char product[0x100];
|
||||
char serial[0x100];
|
||||
read_strings((libusb_device_handle*)handlers.usb_handle, &usb_descriptor, manufacturer, product, serial);
|
||||
for(int l = 0; l < valid_descriptions.size(); l++) {
|
||||
if(product != valid_descriptions[l])
|
||||
continue;
|
||||
std::string device_serial_number = ftd3_get_serial((std::string)(serial), curr_serial_extra_id);
|
||||
bool claimed_cmd = false;
|
||||
bool claimed_bulk = false;
|
||||
if((wanted_serial_number == device_serial_number) && (ftd3_libusb_setup_connection((libusb_device_handle*)handlers.usb_handle, &claimed_cmd, &claimed_bulk))) {
|
||||
ftd3_device_device_handlers* final_handlers = new ftd3_device_device_handlers;
|
||||
final_handlers->usb_handle = handlers.usb_handle;
|
||||
final_handlers->driver_handle = NULL;
|
||||
return final_handlers;
|
||||
}
|
||||
if(claimed_cmd)
|
||||
libusb_release_interface((libusb_device_handle*)handlers.usb_handle, FTD3_COMMAND_INTERFACE);
|
||||
if(claimed_bulk)
|
||||
libusb_release_interface((libusb_device_handle*)handlers.usb_handle, FTD3_BULK_INTERFACE);
|
||||
}
|
||||
libusb_close((libusb_device_handle*)handlers.usb_handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ftd3_device_device_handlers* ftd3_libusb_serial_reconnection(std::string wanted_serial_number, int &curr_serial_extra_id, const std::vector<std::string> &valid_descriptions) {
|
||||
if(!usb_is_initialized())
|
||||
return NULL;
|
||||
libusb_device **usb_devices;
|
||||
int num_devices = libusb_get_device_list(get_usb_ctx(), &usb_devices);
|
||||
|
||||
ftd3_device_device_handlers* final_handlers = ftd3_libusb_serial_find_in_list(usb_devices, num_devices, wanted_serial_number, curr_serial_extra_id, valid_descriptions);
|
||||
|
||||
if(num_devices >= 0)
|
||||
libusb_free_device_list(usb_devices, 1);
|
||||
|
||||
return final_handlers;
|
||||
}
|
||||
|
||||
void ftd3_libusb_end_connection(ftd3_device_device_handlers* handlers, bool interface_claimed) {
|
||||
if(handlers->usb_handle == NULL)
|
||||
return;
|
||||
if(interface_claimed) {
|
||||
libusb_release_interface((libusb_device_handle*)handlers->usb_handle, FTD3_COMMAND_INTERFACE);
|
||||
libusb_release_interface((libusb_device_handle*)handlers->usb_handle, FTD3_BULK_INTERFACE);
|
||||
}
|
||||
libusb_close((libusb_device_handle*)handlers->usb_handle);
|
||||
handlers->usb_handle = NULL;
|
||||
}
|
||||
|
||||
void ftd3_libusb_list_devices(std::vector<CaptureDevice> &devices_list, bool* no_access_elems, bool* not_supported_elems, int *curr_serial_extra_id_ftd3, const std::vector<std::string> &valid_descriptions) {
|
||||
if(!usb_is_initialized())
|
||||
return;
|
||||
libusb_device **usb_devices;
|
||||
int num_devices = libusb_get_device_list(get_usb_ctx(), &usb_devices);
|
||||
libusb_device_descriptor usb_descriptor{};
|
||||
|
||||
for(int i = 0; i < num_devices; i++) {
|
||||
int result = libusb_get_device_descriptor(usb_devices[i], &usb_descriptor);
|
||||
if(result < 0)
|
||||
continue;
|
||||
for(int j = 0; j < ftd3_num_vids; j++) {
|
||||
if(usb_descriptor.idVendor != ftd3_valid_vids[j])
|
||||
continue;
|
||||
for(int k = 0; k < ftd3_num_pids; k++) {
|
||||
if(usb_descriptor.idProduct != ftd3_valid_pids[k])
|
||||
continue;
|
||||
result = ftd3_libusb_insert_device(devices_list, usb_devices[i], &usb_descriptor, *curr_serial_extra_id_ftd3, valid_descriptions);
|
||||
// Apparently this is how it fails if FTD3XX is the driver on Windows...
|
||||
if(result == LIBUSB_ERROR_NOT_FOUND)
|
||||
*not_supported_elems = true;
|
||||
if(result == LIBUSB_ERROR_ACCESS)
|
||||
*no_access_elems = true;
|
||||
if(result == LIBUSB_ERROR_NOT_SUPPORTED)
|
||||
*not_supported_elems = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(num_devices >= 0)
|
||||
libusb_free_device_list(usb_devices, 1);
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
#include "3dscapture_ftd3_shared.hpp"
|
||||
#include "3dscapture_ftd3_shared_general.hpp"
|
||||
#include "3dscapture_ftd3_compatibility.hpp"
|
||||
#include "devicecapture.hpp"
|
||||
//#include "ftd3xx_symbols_renames.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <chrono>
|
||||
|
||||
#define BULK_OUT 0x02
|
||||
#define BULK_IN 0x82
|
||||
|
||||
const std::vector<std::string> valid_3dscapture_descriptions = {"N3DSXL", "N3DSXL.2"};
|
||||
|
||||
std::string ftd3_get_serial(std::string serial_string, int &curr_serial_extra_id) {
|
||||
if(serial_string != "")
|
||||
return serial_string;
|
||||
return std::to_string(curr_serial_extra_id++);
|
||||
}
|
||||
|
||||
void ftd3_insert_device(std::vector<CaptureDevice> &devices_list, std::string serial_string, int &curr_serial_extra_id, bool is_driver) {
|
||||
std::string short_name = "N3DSXL";
|
||||
std::string long_name = short_name;
|
||||
if(is_driver)
|
||||
long_name += ".d";
|
||||
else
|
||||
long_name += ".l";
|
||||
devices_list.emplace_back(ftd3_get_serial(serial_string, curr_serial_extra_id), short_name, long_name, CAPTURE_CONN_FTD3, (void*)NULL, true, true, true, HEIGHT_3DS, TOP_WIDTH_3DS + BOT_WIDTH_3DS, N3DSXL_SAMPLES_IN, 90, 0, 0, TOP_WIDTH_3DS, 0, VIDEO_DATA_RGB);
|
||||
}
|
||||
|
||||
void list_devices_ftd3(std::vector<CaptureDevice> &devices_list, std::vector<no_access_recap_data> &no_access_list) {
|
||||
ftd3_list_devices_compat(devices_list, no_access_list, valid_3dscapture_descriptions);
|
||||
}
|
||||
|
||||
void data_output_update(CaptureReceived* received_buffer, size_t read_data, CaptureData* capture_data, std::chrono::time_point<std::chrono::high_resolution_clock> &base_time) {
|
||||
const auto curr_time = std::chrono::high_resolution_clock::now();
|
||||
const std::chrono::duration<double> diff = curr_time - base_time;
|
||||
base_time = curr_time;
|
||||
capture_data->data_buffers.WriteToBuffer(received_buffer, read_data, diff.count(), &capture_data->status.device);
|
||||
|
||||
if(capture_data->status.cooldown_curr_in)
|
||||
capture_data->status.cooldown_curr_in = capture_data->status.cooldown_curr_in - 1;
|
||||
// Signal that there is data available
|
||||
capture_data->status.video_wait.unlock();
|
||||
capture_data->status.audio_wait.unlock();
|
||||
}
|
||||
|
||||
uint64_t ftd3_get_video_in_size(CaptureData* capture_data) {
|
||||
if(!capture_data->status.enabled_3d)
|
||||
return sizeof(RGB83DSVideoInputData);
|
||||
return sizeof(RGB83DSVideoInputData_3D);
|
||||
}
|
||||
|
||||
uint64_t ftd3_get_capture_size(CaptureData* capture_data) {
|
||||
if(!capture_data->status.enabled_3d)
|
||||
return sizeof(FTD3_3DSCaptureReceived) & (~(EXTRA_DATA_BUFFER_FTD3XX_SIZE - 1));
|
||||
return sizeof(FTD3_3DSCaptureReceived_3D) & (~(EXTRA_DATA_BUFFER_FTD3XX_SIZE - 1));
|
||||
}
|
||||
|
||||
static void preemptive_close_connection(CaptureData* capture_data) {
|
||||
ftd3_device_device_handlers* handlers = (ftd3_device_device_handlers*)capture_data->handle;
|
||||
ftd3_abort_pipe_compat(handlers, BULK_IN);
|
||||
ftd3_close_compat(handlers);
|
||||
delete handlers;
|
||||
capture_data->handle = NULL;
|
||||
}
|
||||
|
||||
bool connect_ftd3(bool print_failed, CaptureData* capture_data, CaptureDevice* device) {
|
||||
capture_data->handle = ftd3_reconnect_compat(device->serial_number, valid_3dscapture_descriptions);
|
||||
if(capture_data->handle == NULL) {
|
||||
capture_error_print(print_failed, capture_data, "Create failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
ftd3_device_device_handlers* handlers = (ftd3_device_device_handlers*)capture_data->handle;
|
||||
uint8_t buf[4] = {0x40, 0x80, 0x00, 0x00};
|
||||
int transferred = 0;
|
||||
|
||||
if(ftd3_is_error_compat(handlers, ftd3_write_pipe_compat(handlers, BULK_OUT, buf, 4, &transferred))) {
|
||||
capture_error_print(print_failed, capture_data, "Write failed");
|
||||
preemptive_close_connection(capture_data);
|
||||
return false;
|
||||
}
|
||||
|
||||
buf[1] = 0x00;
|
||||
|
||||
if(ftd3_is_error_compat(handlers, ftd3_write_pipe_compat(handlers, BULK_OUT, buf, 4, &transferred))) {
|
||||
capture_error_print(print_failed, capture_data, "Write failed");
|
||||
preemptive_close_connection(capture_data);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(ftd3_is_error_compat(handlers, ftd3_set_stream_pipe_compat(handlers, BULK_IN, ftd3_get_capture_size(capture_data)))) {
|
||||
capture_error_print(print_failed, capture_data, "Stream failed");
|
||||
preemptive_close_connection(capture_data);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!ftd3_get_skip_initial_pipe_abort_compat(handlers)) {
|
||||
if(ftd3_is_error_compat(handlers, ftd3_abort_pipe_compat(handlers, BULK_IN))) {
|
||||
capture_error_print(print_failed, capture_data, "Abort failed");
|
||||
preemptive_close_connection(capture_data);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(ftd3_is_error_compat(handlers, ftd3_set_stream_pipe_compat(handlers, BULK_IN, ftd3_get_capture_size(capture_data)))) {
|
||||
capture_error_print(print_failed, capture_data, "Stream failed");
|
||||
preemptive_close_connection(capture_data);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ftd3_capture_main_loop(CaptureData* capture_data) {
|
||||
ftd3_main_loop_compat(capture_data, BULK_IN);
|
||||
}
|
||||
|
||||
void ftd3_capture_cleanup(CaptureData* capture_data) {
|
||||
ftd3_device_device_handlers* handlers = (ftd3_device_device_handlers*)capture_data->handle;
|
||||
|
||||
ftd3_is_error_compat(handlers, ftd3_abort_pipe_compat(handlers, BULK_IN));
|
||||
|
||||
ftd3_close_compat(handlers);
|
||||
|
||||
delete handlers;
|
||||
capture_data->handle = NULL;
|
||||
}
|
@ -1,319 +0,0 @@
|
||||
#include "3dscapture_ftd3.hpp"
|
||||
#include "devicecapture.hpp"
|
||||
//#include "ftd3xx_symbols_renames.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define FTD3XX_STATIC
|
||||
#define FT_ASYNC_CALL FT_ReadPipeEx
|
||||
#else
|
||||
#define FT_ASYNC_CALL FT_ReadPipeAsync
|
||||
#endif
|
||||
#include <ftd3xx.h>
|
||||
#ifdef USE_LIBUSB
|
||||
#include "usb_generic.hpp"
|
||||
#endif
|
||||
|
||||
#include <cstring>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
|
||||
#define BULK_OUT 0x02
|
||||
#define BULK_IN 0x82
|
||||
|
||||
#ifdef _WIN32
|
||||
#define FIFO_CHANNEL 0x82
|
||||
#else
|
||||
#define FIFO_CHANNEL 0
|
||||
#endif
|
||||
|
||||
#define FTD3XX_VID 0x0403
|
||||
|
||||
#define REAL_SERIAL_NUMBER_SIZE 16
|
||||
#define SERIAL_NUMBER_SIZE (REAL_SERIAL_NUMBER_SIZE+1)
|
||||
|
||||
#define FTD3XX_CONCURRENT_BUFFERS 4
|
||||
|
||||
struct FTD3XXReceivedDataBuffer {
|
||||
CaptureReceived capture_buf;
|
||||
OVERLAPPED overlap;
|
||||
ULONG read_buffer;
|
||||
};
|
||||
|
||||
const uint16_t ftd3xx_valid_vids[] = {FTD3XX_VID};
|
||||
const uint16_t ftd3xx_valid_pids[] = {0x601e, 0x601f, 0x602a, 0x602b, 0x602c, 0x602d, 0x602f};
|
||||
|
||||
static bool get_is_bad_ftd3xx();
|
||||
static bool get_skip_initial_pipe_abort();
|
||||
|
||||
const bool is_bad_ftd3xx = get_is_bad_ftd3xx();
|
||||
const bool skip_initial_pipe_abort = get_skip_initial_pipe_abort();
|
||||
|
||||
static bool get_is_bad_ftd3xx() {
|
||||
#ifdef _WIN32
|
||||
#ifdef _M_ARM64
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
#endif
|
||||
// For some reason, the version scheme seems broken...
|
||||
// For now, just return false... :/
|
||||
return false;
|
||||
|
||||
bool is_bad_ftd3xx = false;
|
||||
DWORD ftd3xx_lib_version;
|
||||
|
||||
if(FT_FAILED(FT_GetLibraryVersion(&ftd3xx_lib_version))) {
|
||||
ftd3xx_lib_version = 0;
|
||||
}
|
||||
if(ftd3xx_lib_version >= 0x0100001A) {
|
||||
is_bad_ftd3xx = true;
|
||||
}
|
||||
return is_bad_ftd3xx;
|
||||
}
|
||||
|
||||
static bool get_skip_initial_pipe_abort() {
|
||||
#ifdef _WIN32
|
||||
return false;
|
||||
#endif
|
||||
|
||||
bool skip_initial_pipe_abort = false;
|
||||
DWORD ftd3xx_lib_version;
|
||||
|
||||
if(FT_FAILED(FT_GetLibraryVersion(&ftd3xx_lib_version))) {
|
||||
ftd3xx_lib_version = 0;
|
||||
}
|
||||
if(ftd3xx_lib_version >= 0x0100001A) {
|
||||
skip_initial_pipe_abort = true;
|
||||
}
|
||||
return skip_initial_pipe_abort;
|
||||
}
|
||||
|
||||
void list_devices_ftd3(std::vector<CaptureDevice> &devices_list, std::vector<no_access_recap_data> &no_access_list) {
|
||||
FT_STATUS ftStatus;
|
||||
DWORD numDevs = 0;
|
||||
std::string valid_descriptions[] = {"N3DSXL", "N3DSXL.2"};
|
||||
ftStatus = FT_CreateDeviceInfoList(&numDevs);
|
||||
size_t num_inserted = 0;
|
||||
if(!FT_FAILED(ftStatus) && numDevs > 0)
|
||||
{
|
||||
const int debug_multiplier = 1;
|
||||
FT_HANDLE ftHandle = NULL;
|
||||
DWORD Flags = 0;
|
||||
DWORD Type = 0;
|
||||
DWORD ID = 0;
|
||||
char SerialNumber[SERIAL_NUMBER_SIZE] = { 0 };
|
||||
char Description[65] = { 0 };
|
||||
for (DWORD i = 0; i < numDevs; i++)
|
||||
{
|
||||
ftStatus = FT_GetDeviceInfoDetail(i, &Flags, &Type, &ID, NULL,
|
||||
SerialNumber, Description, &ftHandle);
|
||||
if(!FT_FAILED(ftStatus))
|
||||
{
|
||||
ftStatus = FT_Create(SerialNumber, FT_OPEN_BY_SERIAL_NUMBER, &ftHandle);
|
||||
if(!FT_FAILED(ftStatus)) {
|
||||
for(int j = 0; j < sizeof(valid_descriptions) / sizeof(*valid_descriptions); j++) {
|
||||
if(Description == valid_descriptions[j]) {
|
||||
for(int u = 0; u < debug_multiplier; u++)
|
||||
devices_list.emplace_back(std::string(SerialNumber), "N3DSXL", CAPTURE_CONN_FTD3, (void*)NULL, true, true, true, HEIGHT_3DS, TOP_WIDTH_3DS + BOT_WIDTH_3DS, N3DSXL_SAMPLES_IN, 90, 0, 0, TOP_WIDTH_3DS, 0, VIDEO_DATA_RGB);
|
||||
break;
|
||||
}
|
||||
}
|
||||
FT_Close(ftHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(num_inserted == 0) {
|
||||
#ifdef USE_LIBUSB
|
||||
if(get_usb_total_filtered_devices(ftd3xx_valid_vids, sizeof(ftd3xx_valid_vids) / sizeof(ftd3xx_valid_vids[0]), ftd3xx_valid_pids, sizeof(ftd3xx_valid_pids) / sizeof(ftd3xx_valid_pids[0])) != numDevs)
|
||||
no_access_list.emplace_back("FTD3XX");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t ftd3_get_video_in_size(CaptureData* capture_data) {
|
||||
if(!capture_data->status.enabled_3d)
|
||||
return sizeof(RGB83DSVideoInputData);
|
||||
return sizeof(RGB83DSVideoInputData_3D);
|
||||
}
|
||||
|
||||
static uint64_t get_capture_size(CaptureData* capture_data) {
|
||||
if(!capture_data->status.enabled_3d)
|
||||
return sizeof(FTD3_3DSCaptureReceived) & (~(EXTRA_DATA_BUFFER_FTD3XX_SIZE - 1));
|
||||
return sizeof(FTD3_3DSCaptureReceived_3D) & (~(EXTRA_DATA_BUFFER_FTD3XX_SIZE - 1));
|
||||
}
|
||||
|
||||
static void preemptive_close_connection(CaptureData* capture_data) {
|
||||
FT_AbortPipe(capture_data->handle, BULK_IN);
|
||||
FT_Close(capture_data->handle);
|
||||
}
|
||||
|
||||
bool connect_ftd3(bool print_failed, CaptureData* capture_data, CaptureDevice* device) {
|
||||
|
||||
char SerialNumber[SERIAL_NUMBER_SIZE] = { 0 };
|
||||
strncpy(SerialNumber, device->serial_number.c_str(), REAL_SERIAL_NUMBER_SIZE);
|
||||
SerialNumber[REAL_SERIAL_NUMBER_SIZE] = 0;
|
||||
if(FT_Create(SerialNumber, FT_OPEN_BY_SERIAL_NUMBER, &capture_data->handle)) {
|
||||
capture_error_print(print_failed, capture_data, "Create failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
UCHAR buf[4] = {0x40, 0x80, 0x00, 0x00};
|
||||
ULONG written = 0;
|
||||
|
||||
if(FT_WritePipe(capture_data->handle, BULK_OUT, buf, 4, &written, 0)) {
|
||||
capture_error_print(print_failed, capture_data, "Write failed");
|
||||
preemptive_close_connection(capture_data);
|
||||
return false;
|
||||
}
|
||||
|
||||
buf[1] = 0x00;
|
||||
|
||||
if(FT_WritePipe(capture_data->handle, BULK_OUT, buf, 4, &written, 0)) {
|
||||
capture_error_print(print_failed, capture_data, "Write failed");
|
||||
preemptive_close_connection(capture_data);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(FT_SetStreamPipe(capture_data->handle, false, false, BULK_IN, get_capture_size(capture_data))) {
|
||||
capture_error_print(print_failed, capture_data, "Stream failed");
|
||||
preemptive_close_connection(capture_data);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!skip_initial_pipe_abort) {
|
||||
if(FT_AbortPipe(capture_data->handle, BULK_IN)) {
|
||||
capture_error_print(print_failed, capture_data, "Abort failed");
|
||||
preemptive_close_connection(capture_data);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(FT_SetStreamPipe(capture_data->handle, false, false, BULK_IN, get_capture_size(capture_data))) {
|
||||
capture_error_print(print_failed, capture_data, "Stream failed");
|
||||
preemptive_close_connection(capture_data);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void data_output_update(FTD3XXReceivedDataBuffer* received_buffer, CaptureData* capture_data, std::chrono::time_point<std::chrono::high_resolution_clock> &base_time) {
|
||||
const auto curr_time = std::chrono::high_resolution_clock::now();
|
||||
const std::chrono::duration<double> diff = curr_time - base_time;
|
||||
base_time = curr_time;
|
||||
capture_data->data_buffers.WriteToBuffer(&received_buffer->capture_buf, received_buffer->read_buffer, diff.count(), &capture_data->status.device);
|
||||
|
||||
if(capture_data->status.cooldown_curr_in)
|
||||
capture_data->status.cooldown_curr_in = capture_data->status.cooldown_curr_in - 1;
|
||||
// Signal that there is data available
|
||||
capture_data->status.video_wait.unlock();
|
||||
capture_data->status.audio_wait.unlock();
|
||||
}
|
||||
|
||||
static void fast_capture_call(FTD3XXReceivedDataBuffer* received_buffer, CaptureData* capture_data) {
|
||||
int inner_curr_in = 0;
|
||||
FT_STATUS ftStatus;
|
||||
for (inner_curr_in = 0; inner_curr_in < FTD3XX_CONCURRENT_BUFFERS; ++inner_curr_in) {
|
||||
ftStatus = FT_InitializeOverlapped(capture_data->handle, &received_buffer[inner_curr_in].overlap);
|
||||
if(ftStatus) {
|
||||
capture_error_print(true, capture_data, "Disconnected: Initialize failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (inner_curr_in = 0; inner_curr_in < FTD3XX_CONCURRENT_BUFFERS - 1; ++inner_curr_in) {
|
||||
ftStatus = FT_ASYNC_CALL(capture_data->handle, FIFO_CHANNEL, (UCHAR*)&received_buffer[inner_curr_in].capture_buf, get_capture_size(capture_data), &received_buffer[inner_curr_in].read_buffer, &received_buffer[inner_curr_in].overlap);
|
||||
if(ftStatus != FT_IO_PENDING) {
|
||||
capture_error_print(true, capture_data, "Disconnected: Read failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
inner_curr_in = FTD3XX_CONCURRENT_BUFFERS - 1;
|
||||
|
||||
auto clock_start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
while (capture_data->status.connected && capture_data->status.running) {
|
||||
|
||||
ftStatus = FT_ASYNC_CALL(capture_data->handle, FIFO_CHANNEL, (UCHAR*)&received_buffer[inner_curr_in].capture_buf, get_capture_size(capture_data), &received_buffer[inner_curr_in].read_buffer, &received_buffer[inner_curr_in].overlap);
|
||||
if(ftStatus != FT_IO_PENDING) {
|
||||
capture_error_print(true, capture_data, "Disconnected: Read failed");
|
||||
return;
|
||||
}
|
||||
|
||||
inner_curr_in = (inner_curr_in + 1) % FTD3XX_CONCURRENT_BUFFERS;
|
||||
|
||||
ftStatus = FT_GetOverlappedResult(capture_data->handle, &received_buffer[inner_curr_in].overlap, &received_buffer[inner_curr_in].read_buffer, true);
|
||||
if(FT_FAILED(ftStatus)) {
|
||||
capture_error_print(true, capture_data, "Disconnected: USB error");
|
||||
return;
|
||||
}
|
||||
|
||||
data_output_update(&received_buffer[inner_curr_in], capture_data, clock_start);
|
||||
}
|
||||
}
|
||||
|
||||
static bool safe_capture_call(FTD3XXReceivedDataBuffer* received_buffer, CaptureData* capture_data) {
|
||||
auto clock_start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
while(capture_data->status.connected && capture_data->status.running) {
|
||||
|
||||
#ifdef _WIN32
|
||||
FT_STATUS ftStatus = FT_ReadPipeEx(capture_data->handle, FIFO_CHANNEL, (UCHAR*)&received_buffer->capture_buf, get_capture_size(capture_data), &received_buffer->read_buffer, NULL);
|
||||
#else
|
||||
FT_STATUS ftStatus = FT_ReadPipeEx(capture_data->handle, FIFO_CHANNEL, (UCHAR*)&received_buffer->capture_buf, get_capture_size(capture_data), &received_buffer->read_buffer, 1000);
|
||||
#endif
|
||||
if(FT_FAILED(ftStatus)) {
|
||||
capture_error_print(true, capture_data, "Disconnected: Read failed");
|
||||
return true;
|
||||
}
|
||||
|
||||
data_output_update(received_buffer, capture_data, clock_start);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static FTD3XXReceivedDataBuffer* init_received_buffer() {
|
||||
if(is_bad_ftd3xx)
|
||||
return new FTD3XXReceivedDataBuffer;
|
||||
|
||||
return new FTD3XXReceivedDataBuffer[FTD3XX_CONCURRENT_BUFFERS];
|
||||
}
|
||||
|
||||
static void close_received_buffer(FTD3XXReceivedDataBuffer* received_buffer, CaptureData* capture_data) {
|
||||
if(is_bad_ftd3xx) {
|
||||
delete received_buffer;
|
||||
return;
|
||||
}
|
||||
|
||||
for(int inner_curr_in = 0; inner_curr_in < FTD3XX_CONCURRENT_BUFFERS; ++inner_curr_in) {
|
||||
FT_STATUS ftStatus = FT_GetOverlappedResult(capture_data->handle, &received_buffer[inner_curr_in].overlap, &received_buffer[inner_curr_in].read_buffer, true);
|
||||
if(FT_ReleaseOverlapped(capture_data->handle, &received_buffer[inner_curr_in].overlap)) {
|
||||
capture_error_print(true, capture_data, "Disconnected: Release failed");
|
||||
}
|
||||
}
|
||||
delete []received_buffer;
|
||||
}
|
||||
|
||||
void ftd3_capture_main_loop(CaptureData* capture_data) {
|
||||
FTD3XXReceivedDataBuffer* received_buffer = init_received_buffer();
|
||||
if(!is_bad_ftd3xx)
|
||||
fast_capture_call(received_buffer, capture_data);
|
||||
else
|
||||
safe_capture_call(received_buffer, capture_data);
|
||||
close_received_buffer(received_buffer, capture_data);
|
||||
}
|
||||
|
||||
void ftd3_capture_cleanup(CaptureData* capture_data) {
|
||||
if(FT_AbortPipe(capture_data->handle, BULK_IN)) {
|
||||
capture_error_print(true, capture_data, "Disconnected: Abort failed");
|
||||
}
|
||||
|
||||
if(FT_Close(capture_data->handle)) {
|
||||
capture_error_print(true, capture_data, "Disconnected: Close failed");
|
||||
}
|
||||
}
|
@ -297,24 +297,24 @@ int is_device_get_num_free_buffers(ISDeviceCaptureReceivedData* is_device_captur
|
||||
}
|
||||
|
||||
static void close_all_reads_error(CaptureData* capture_data, ISDeviceCaptureReceivedData* is_device_capture_recv_data, bool &async_read_closed, bool &reset_usb_device, bool do_reset) {
|
||||
if(get_is_device_status(is_device_capture_recv_data) < 0) {
|
||||
if(!async_read_closed) {
|
||||
for (int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++)
|
||||
CloseAsyncRead((is_device_device_handlers*)capture_data->handle, &is_device_capture_recv_data[i].cb_data);
|
||||
async_read_closed = true;
|
||||
}
|
||||
if(do_reset && (!reset_usb_device)) {
|
||||
int ret = ResetUSBDevice((is_device_device_handlers*)capture_data->handle);
|
||||
if((ret == LIBUSB_ERROR_NO_DEVICE) || (ret == LIBUSB_ERROR_NOT_FOUND)) {
|
||||
for(int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) {
|
||||
is_device_capture_recv_data[i].cb_data.transfer_data_access.lock();
|
||||
is_device_capture_recv_data[i].cb_data.transfer_data = NULL;
|
||||
is_device_capture_recv_data[i].cb_data.transfer_data_access.unlock();
|
||||
is_device_capture_recv_data[i].in_use = false;
|
||||
}
|
||||
if(get_is_device_status(is_device_capture_recv_data) >= 0)
|
||||
return;
|
||||
if(!async_read_closed) {
|
||||
for (int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++)
|
||||
CloseAsyncRead((is_device_device_handlers*)capture_data->handle, &is_device_capture_recv_data[i].cb_data);
|
||||
async_read_closed = true;
|
||||
}
|
||||
if(do_reset && (!reset_usb_device)) {
|
||||
int ret = ResetUSBDevice((is_device_device_handlers*)capture_data->handle);
|
||||
if((ret == LIBUSB_ERROR_NO_DEVICE) || (ret == LIBUSB_ERROR_NOT_FOUND)) {
|
||||
for(int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) {
|
||||
is_device_capture_recv_data[i].cb_data.transfer_data_access.lock();
|
||||
is_device_capture_recv_data[i].cb_data.transfer_data = NULL;
|
||||
is_device_capture_recv_data[i].cb_data.transfer_data_access.unlock();
|
||||
is_device_capture_recv_data[i].in_use = false;
|
||||
}
|
||||
reset_usb_device = true;
|
||||
}
|
||||
reset_usb_device = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -424,9 +424,6 @@ void is_device_acquisition_main_loop(CaptureData* capture_data) {
|
||||
|
||||
uint32_t last_index = -1;
|
||||
int status = 0;
|
||||
isd_async_callback_data* cb_queue[NUM_CAPTURE_RECEIVED_DATA_BUFFERS];
|
||||
int queue_elems = 0;
|
||||
bool one_transfer_active = false;
|
||||
SharedConsumerMutex is_buffer_free_shared_mutex(NUM_CAPTURE_RECEIVED_DATA_BUFFERS);
|
||||
SharedConsumerMutex is_transfer_done_shared_mutex(NUM_CAPTURE_RECEIVED_DATA_BUFFERS);
|
||||
SharedConsumerMutex is_transfer_data_ready_shared_mutex(NUM_CAPTURE_RECEIVED_DATA_BUFFERS);
|
||||
|
@ -22,7 +22,7 @@ static cyni_device_device_handlers* usb_find_by_serial_number(const cyni_device_
|
||||
int curr_serial_extra_id = 0;
|
||||
final_handlers = cypress_libusb_serial_reconnection(usb_device_desc, wanted_serial_number, curr_serial_extra_id, new_device);
|
||||
|
||||
if (final_handlers == NULL)
|
||||
if(final_handlers == NULL)
|
||||
final_handlers = cypress_driver_find_by_serial_number(usb_device_desc, wanted_serial_number, curr_serial_extra_id, new_device);
|
||||
return final_handlers;
|
||||
}
|
||||
|
@ -103,7 +103,8 @@ int cypress_libusb_async_in_start(cyni_device_device_handlers* handlers, const c
|
||||
return retval;
|
||||
}
|
||||
|
||||
static bool cypress_libusb_setup_connection(libusb_device_handle* handle, const cyni_device_usb_device* usb_device_desc) {
|
||||
static bool cypress_libusb_setup_connection(libusb_device_handle* handle, const cyni_device_usb_device* usb_device_desc, bool *claimed) {
|
||||
*claimed = false;
|
||||
int result = libusb_kernel_driver_active(handle, usb_device_desc->default_interface);
|
||||
if(result == 1)
|
||||
libusb_detach_kernel_driver(handle, usb_device_desc->default_interface);
|
||||
@ -116,6 +117,7 @@ static bool cypress_libusb_setup_connection(libusb_device_handle* handle, const
|
||||
result = libusb_claim_interface(handle, usb_device_desc->default_interface);
|
||||
if(result != LIBUSB_SUCCESS)
|
||||
return false;
|
||||
*claimed = true;
|
||||
if(usb_device_desc->alt_interface != 0) {
|
||||
result = libusb_set_interface_alt_setting(handle, usb_device_desc->default_interface, usb_device_desc->alt_interface);
|
||||
if(result != LIBUSB_SUCCESS)
|
||||
@ -143,10 +145,12 @@ static int cypress_libusb_insert_device(std::vector<CaptureDevice> &devices_list
|
||||
char manufacturer[0x100];
|
||||
char serial[0x100];
|
||||
read_strings(handle, usb_descriptor, manufacturer, serial);
|
||||
bool result_setup = cypress_libusb_setup_connection(handle, usb_device_desc);
|
||||
bool claimed = false;
|
||||
bool result_setup = cypress_libusb_setup_connection(handle, usb_device_desc, &claimed);
|
||||
if(result_setup)
|
||||
cypress_insert_device(devices_list, usb_device_desc, (std::string)(serial), usb_descriptor->bcdDevice, curr_serial_extra_id);
|
||||
libusb_release_interface(handle, usb_device_desc->default_interface);
|
||||
if(claimed)
|
||||
libusb_release_interface(handle, usb_device_desc->default_interface);
|
||||
libusb_close(handle);
|
||||
return result;
|
||||
}
|
||||
@ -167,19 +171,22 @@ cyni_device_device_handlers* cypress_libusb_serial_reconnection(const cyni_devic
|
||||
if((usb_descriptor.idVendor != usb_device_desc->vid) || (usb_descriptor.idProduct != usb_device_desc->pid))
|
||||
continue;
|
||||
result = libusb_open(usb_devices[i], &handlers.usb_handle);
|
||||
if(result || (handlers.usb_handle == NULL))
|
||||
if((result < 0) || (handlers.usb_handle == NULL))
|
||||
continue;
|
||||
char manufacturer[0x100];
|
||||
char serial[0x100];
|
||||
read_strings(handlers.usb_handle, &usb_descriptor, manufacturer, serial);
|
||||
std::string device_serial_number = get_serial(usb_device_desc, (std::string)(serial), usb_descriptor.bcdDevice, curr_serial_extra_id);
|
||||
if((wanted_serial_number == device_serial_number) && (cypress_libusb_setup_connection(handlers.usb_handle, usb_device_desc))) {
|
||||
bool claimed = false;
|
||||
if((wanted_serial_number == device_serial_number) && (cypress_libusb_setup_connection(handlers.usb_handle, usb_device_desc, &claimed))) {
|
||||
final_handlers = new cyni_device_device_handlers;
|
||||
final_handlers->usb_handle = handlers.usb_handle;
|
||||
if(new_device != NULL)
|
||||
*new_device = cypress_create_device(usb_device_desc, wanted_serial_number);
|
||||
break;
|
||||
}
|
||||
if(claimed)
|
||||
libusb_release_interface(handlers.usb_handle, usb_device_desc->default_interface);
|
||||
libusb_close(handlers.usb_handle);
|
||||
}
|
||||
|
||||
|
@ -142,7 +142,7 @@ static const LicenseMenuOptionInfo* pollable_options[] = {
|
||||
&sfml_license_2_option,
|
||||
&sfml_license_3_option,
|
||||
&sfml_license_4_option,
|
||||
#if defined(USE_FTD3) || defined(USE_FTD2_DRIVER)
|
||||
#if defined(USE_FTD3XX) || defined(USE_FTD2_DRIVER)
|
||||
&ftd3xx_license_0_option,
|
||||
&ftd3xx_license_1_option,
|
||||
&ftd3xx_license_2_option,
|
||||
@ -156,7 +156,7 @@ static const LicenseMenuOptionInfo* pollable_options[] = {
|
||||
&libftdi_license_3_option,
|
||||
&libftdi_license_4_option,
|
||||
#endif
|
||||
#if defined(USE_LIBUSB) || defined(USE_FTD3) || defined(USE_FTD2_DRIVER)
|
||||
#if defined(USE_LIBUSB) || defined(USE_FTD3XX) || defined(USE_FTD2_DRIVER)
|
||||
&libusb_license_0_option,
|
||||
&libusb_license_1_option,
|
||||
&libusb_license_2_option,
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "conversions.hpp"
|
||||
#include "devicecapture.hpp"
|
||||
#include "3dscapture_ftd3.hpp"
|
||||
#include "3dscapture_ftd3_shared.hpp"
|
||||
#include "dscapture_ftd2_shared.hpp"
|
||||
#include "usb_ds_3ds_capture.hpp"
|
||||
#include "usb_is_device_acquisition.hpp"
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include "devicecapture.hpp"
|
||||
#include "3dscapture_ftd3.hpp"
|
||||
#include "3dscapture_ftd3_shared.hpp"
|
||||
#include "dscapture_ftd2_shared.hpp"
|
||||
#include "usb_ds_3ds_capture.hpp"
|
||||
#include "usb_is_device_acquisition.hpp"
|
||||
|
Loading…
Reference in New Issue
Block a user