Remove ftd3xx library dependency for Linux and MacOS

This commit is contained in:
Lorenzooone 2025-03-06 18:02:36 +01:00
parent 86b5725af9
commit fa5a708e22
33 changed files with 1300 additions and 366 deletions

View File

@ -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)

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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, &not_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
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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");
}
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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,

View File

@ -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"

View File

@ -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"