diff --git a/CMakeLists.txt b/CMakeLists.txt index 6257297..5635965 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ set(TARGET_LANGUAGES CXX C) project(cc3dsfs VERSION 1.0.0 LANGUAGES ${TARGET_LANGUAGES}) include(ExternalProject) -set(N3DSXL_LOOPY_SUPPORT 1) +set(N3DSXL_LOOPY_SUPPORT 0) set(NEW_DS_LOOPY_SUPPORT 1) set(IS_NITRO_SUPPORT 1) set(OLD_DS_3DS_LOOPY_SUPPORT 1) @@ -172,7 +172,7 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") set(FTD2XX_SUBFOLDER win) set(FTD2XX_HEADER_PATH ftd2xx.h) if(${WINDOWS_FTD2XX_USE_SHARED_LIB}) - set(FTD2XX_BUILD_COMMAND ${FTD3XX_BUILD_COMMAND}_dll) + set(FTD2XX_BUILD_COMMAND ${FTD2XX_BUILD_COMMAND}_dll) set(FTD2XX_WINDOWS_PATH_SPECIFIER "") if(WINDOWS_ARM64) set(FTD2XX_WINDOWS_PATH_SPECIFIER Release) @@ -266,6 +266,9 @@ if(NEW_DS_LOOPY_SUPPORT) endif() endif() +set(TOOLS_DATA_DIR ${CMAKE_BINARY_DIR}/tools_and_data) +file(MAKE_DIRECTORY ${TOOLS_DATA_DIR}) + set(FETCH_CONTENT_MAKE_AVAILABLE_LIBRARIES "") set(SOURCE_CPP_EXTRA_FILES "") set(EXTRA_DEPENDENCIES "") @@ -283,7 +286,7 @@ if(N3DSXL_LOOPY_SUPPORT) endif() if(NEW_DS_LOOPY_SUPPORT) list(APPEND FETCH_CONTENT_MAKE_AVAILABLE_LIBRARIES FTD2XX) - list(APPEND SOURCE_CPP_EXTRA_FILES ${SOURCE_CPP_DEVICE_FILES_BASE_PATH}/dscapture_ftd2.cpp) + list(APPEND SOURCE_CPP_EXTRA_FILES ${SOURCE_CPP_DEVICE_FILES_BASE_PATH}/dscapture_ftd2.cpp ${TOOLS_DATA_DIR}/ftd2_ds2_fw_1.cpp ${TOOLS_DATA_DIR}/ftd2_ds2_fw_2.cpp) list(APPEND EXTRA_DEPENDENCIES FTD2XX_BUILD_PROJECT) if(MSVC) list(APPEND EXTRA_CXX_FLAGS "/DUSE_FTD2") @@ -360,11 +363,14 @@ else() set(FTD3XX_BUILD_COMMAND_PARAMETERS ${ftd3xx_SOURCE_DIR} ${ftd3xx_BINARY_DIR}/${FTD3XX_SUBFOLDER} ${FTD3XX_LIB}) set(FTD2XX_BUILD_COMMAND_PARAMETERS ${ftd2xx_SOURCE_DIR} ${ftd2xx_BINARY_DIR}/${FTD2XX_SUBFOLDER} build/${FTD2XX_LIB}) endif() + if(N3DSXL_LOOPY_SUPPORT) ExternalProject_Add(FTD3XX_BUILD_PROJECT SOURCE_DIR ${ftd3xx_SOURCE_DIR} BINARY_DIR ${ftd3xx_BINARY_DIR} BUILD_COMMAND ${FTD3XX_BUILD_COMMAND}${SCRIPT_EXTENSION} ${FTD3XX_BUILD_COMMAND_PARAMETERS} + #COMMAND ${TOOLS_DATA_DIR}/CMakePrepareRenameSymbols${HOST_FINAL_EXTENSION} ${SETUP_SCRIPTS_DIR}/ftd_shared_symbols.txt ftd3_ ${TOOLS_DATA_DIR}/bad_ftd3_symbols_list.txt ${TOOLS_DATA_DIR}/ftd3xx_symbols_renames.h + #COMMAND ${CMAKE_OBJCOPY} ARGS --redefine-syms=${TOOLS_DATA_DIR}/bad_ftd3_symbols_list.txt ${ftd3xx_BINARY_DIR}/${FTD3XX_SUBFOLDER}/${FTD3XX_LIB} UPDATE_COMMAND "" CONFIGURE_COMMAND "" INSTALL_COMMAND "" @@ -375,6 +381,8 @@ if(NEW_DS_LOOPY_SUPPORT) SOURCE_DIR ${ftd2xx_SOURCE_DIR} BINARY_DIR ${ftd2xx_BINARY_DIR} BUILD_COMMAND ${FTD2XX_BUILD_COMMAND}${SCRIPT_EXTENSION} ${FTD2XX_BUILD_COMMAND_PARAMETERS} + #COMMAND ${TOOLS_DATA_DIR}/CMakePrepareRenameSymbols${HOST_FINAL_EXTENSION} ${SETUP_SCRIPTS_DIR}/ftd_shared_symbols.txt ftd2_ ${TOOLS_DATA_DIR}/bad_ftd2_symbols_list.txt ${TOOLS_DATA_DIR}/ftd2xx_symbols_renames.h + #COMMAND ${CMAKE_OBJCOPY} ARGS --redefine-syms=${TOOLS_DATA_DIR}/bad_ftd2_symbols_list.txt ${ftd2xx_BINARY_DIR}/${FTD2XX_SUBFOLDER}/${FTD2XX_LIB} UPDATE_COMMAND "" CONFIGURE_COMMAND "" INSTALL_COMMAND "" @@ -386,8 +394,6 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) # search headers and libraries in the target environment set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -set(TOOLS_DATA_DIR ${CMAKE_BINARY_DIR}/tools_and_data) -file(MAKE_DIRECTORY ${TOOLS_DATA_DIR}) execute_process(COMMAND ${CMAKE_COMMAND} -B ${TOOLS_DATA_DIR} ${CMAKE_SOURCE_DIR}/tools) execute_process(COMMAND ${CMAKE_COMMAND} --build ${TOOLS_DATA_DIR}) @@ -426,6 +432,20 @@ add_custom_command( DEPENDS ${CMAKE_SOURCE_DIR}/data/font.ttf ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION} ) +add_custom_command( + OUTPUT ${TOOLS_DATA_DIR}/ftd2_ds2_fw_1.cpp + COMMENT "Convert fw binary to C - FTD2 NDS 1" + COMMAND ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION} ${CMAKE_SOURCE_DIR}/bin/ftd2_ds2_fw_1.bin ${TOOLS_DATA_DIR} ftd2_ds2_fw_1 ftd2_ds2_fw_1 + DEPENDS ${CMAKE_SOURCE_DIR}/bin/ftd2_ds2_fw_1.bin ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION} +) + +add_custom_command( + OUTPUT ${TOOLS_DATA_DIR}/ftd2_ds2_fw_2.cpp + COMMENT "Convert fw binary to C - FTD2 NDS 2" + COMMAND ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION} ${CMAKE_SOURCE_DIR}/bin/ftd2_ds2_fw_2.bin ${TOOLS_DATA_DIR} ftd2_ds2_fw_2 ftd2_ds2_fw_2 + DEPENDS ${CMAKE_SOURCE_DIR}/bin/ftd2_ds2_fw_2.bin ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION} +) + set(SHADERS_LIST "") list(APPEND SHADERS_LIST ${CMAKE_SOURCE_DIR}/shaders/bit_crusher_fragment_shader.2_to_x_1_7.frag ${CMAKE_SOURCE_DIR}/shaders/bit_merger_crusher_fragment_shader.2_to_x_1_6.frag ${CMAKE_SOURCE_DIR}/shaders/bit_merger_crusher_fragment_shader_7.frag ${CMAKE_SOURCE_DIR}/shaders/bit_merger_fragment_shader.2_to_x_0_6.frag ${CMAKE_SOURCE_DIR}/shaders/bit_merger_fragment_shader_7.frag ${CMAKE_SOURCE_DIR}/shaders/frame_blending_bit_crusher_fragment_shader.2_to_x_1_7.frag ${CMAKE_SOURCE_DIR}/shaders/frame_blending_fragment_shader.frag ${CMAKE_SOURCE_DIR}/shaders/no_effect_fragment_shader.frag) diff --git a/bin/ftd2_ds2_fw_1.bin b/bin/ftd2_ds2_fw_1.bin new file mode 100644 index 0000000..f5052e3 Binary files /dev/null and b/bin/ftd2_ds2_fw_1.bin differ diff --git a/bin/ftd2_ds2_fw_2.bin b/bin/ftd2_ds2_fw_2.bin new file mode 100644 index 0000000..16b3711 Binary files /dev/null and b/bin/ftd2_ds2_fw_2.bin differ diff --git a/include/CaptureDeviceSpecific/dscapture_ftd2.hpp b/include/CaptureDeviceSpecific/dscapture_ftd2.hpp index db1bafb..7405c29 100644 --- a/include/CaptureDeviceSpecific/dscapture_ftd2.hpp +++ b/include/CaptureDeviceSpecific/dscapture_ftd2.hpp @@ -8,6 +8,8 @@ #include "display_structs.hpp" #include "devicecapture.hpp" +#define FTD2_OLDDS_SYNCH_VALUES 0x4321 + void list_devices_ftd2(std::vector &devices_list, std::vector &no_access_list); bool connect_ftd2(bool print_failed, CaptureData* capture_data, CaptureDevice* device); void ftd2_capture_main_loop(CaptureData* capture_data); diff --git a/include/CaptureDeviceSpecific/usb_generic.hpp b/include/CaptureDeviceSpecific/usb_generic.hpp index cfc47c3..a7901e5 100644 --- a/include/CaptureDeviceSpecific/usb_generic.hpp +++ b/include/CaptureDeviceSpecific/usb_generic.hpp @@ -1,12 +1,14 @@ #ifndef __USB_GENERIC_HPP #define __USB_GENERIC_HPP +#if defined(USE_IS_NITRO_USB) || defined(USE_DS_3DS_USB) #include +libusb_context* get_usb_ctx(); +#endif void usb_init(); void usb_close(); bool usb_is_initialized(); -libusb_context* get_usb_ctx(); int get_usb_total_filtered_devices(const uint16_t valid_vids[], size_t num_vids, const uint16_t valid_pids[], size_t num_pids); #endif diff --git a/include/capture_structs.hpp b/include/capture_structs.hpp index eb464f3..3455be3 100755 --- a/include/capture_structs.hpp +++ b/include/capture_structs.hpp @@ -94,6 +94,12 @@ struct ALIGNED(16) PACKED USBOldDSCaptureReceived { USBOldDSFrameInfo frameinfo; }; +struct ALIGNED(16) PACKED FTD2OldDSCaptureReceived { + USBOldDSVideoInputData video_in; + uint16_t audio_data[DS_SAMPLES_IN]; + uint8_t unused_buffer[EXTRA_DATA_BUFFER_USB_SIZE]; +}; + struct ALIGNED(16) PACKED ISNitroCaptureReceived { ISNitroEmulatorVideoInputData video_in; }; @@ -106,13 +112,15 @@ union CaptureReceived { USB3DSCaptureReceived usb_received_3ds; USB3DSCaptureReceived_3D usb_received_3ds_3d; USBOldDSCaptureReceived usb_received_old_ds; + FTD2OldDSCaptureReceived ftd2_received_old_ds; ISNitroCaptureReceived is_nitro_capture_received; }; struct CaptureDevice { - CaptureDevice(std::string serial_number, std::string name, CaptureConnectionType cc_type, const void* descriptor, bool is_3ds, bool has_3d, bool has_audio, int width, int height, int max_samples_in, int base_rotation, int top_screen_x, int top_screen_y, int bot_screen_x, int bot_screen_y, InputVideoDataType video_data_type) : serial_number(serial_number), name(name), cc_type(cc_type), descriptor(descriptor), is_3ds(is_3ds), has_3d(has_3d), has_audio(has_audio), width(width), height(height), max_samples_in(max_samples_in), base_rotation(base_rotation), top_screen_x(top_screen_x), top_screen_y(top_screen_y), bot_screen_x(bot_screen_x), bot_screen_y(bot_screen_y), path(""), video_data_type(video_data_type) {} - CaptureDevice(std::string serial_number, std::string name, std::string path, CaptureConnectionType cc_type, const void* descriptor, bool is_3ds, bool has_3d, bool has_audio, int width, int height, int max_samples_in, int base_rotation, int top_screen_x, int top_screen_y, int bot_screen_x, int bot_screen_y, InputVideoDataType video_data_type) : serial_number(serial_number), name(name), cc_type(cc_type), descriptor(descriptor), is_3ds(is_3ds), has_3d(has_3d), has_audio(has_audio), width(width), height(height), max_samples_in(max_samples_in), base_rotation(base_rotation), top_screen_x(top_screen_x), top_screen_y(top_screen_y), bot_screen_x(bot_screen_x), bot_screen_y(bot_screen_y), path(path), video_data_type(video_data_type) {} - CaptureDevice(): serial_number(""), name(""), cc_type(CAPTURE_CONN_USB), descriptor(NULL), is_3ds(false), has_3d(false), has_audio(false), width(0), height(0), max_samples_in(0), base_rotation(0), top_screen_x(0), top_screen_y(0), bot_screen_x(0), bot_screen_y(0), path(""), video_data_type(VIDEO_DATA_RGB) {} + CaptureDevice(std::string serial_number, std::string name, CaptureConnectionType cc_type, const void* descriptor, bool is_3ds, bool has_3d, bool has_audio, int width, int height, int max_samples_in, int base_rotation, int top_screen_x, int top_screen_y, int bot_screen_x, int bot_screen_y, InputVideoDataType video_data_type) : serial_number(serial_number), name(name), cc_type(cc_type), descriptor(descriptor), is_3ds(is_3ds), has_3d(has_3d), has_audio(has_audio), width(width), height(height), max_samples_in(max_samples_in), base_rotation(base_rotation), top_screen_x(top_screen_x), top_screen_y(top_screen_y), bot_screen_x(bot_screen_x), bot_screen_y(bot_screen_y), path(""), video_data_type(video_data_type), firmware_id(0), is_rgb_888(false) {} + CaptureDevice(std::string serial_number, std::string name, CaptureConnectionType cc_type, const void* descriptor, bool is_3ds, bool has_3d, bool has_audio, int width, int height, int max_samples_in, int base_rotation, int top_screen_x, int top_screen_y, int bot_screen_x, int bot_screen_y, InputVideoDataType video_data_type, int firmware_id, bool is_rgb_888) : serial_number(serial_number), name(name), cc_type(cc_type), descriptor(descriptor), is_3ds(is_3ds), has_3d(has_3d), has_audio(has_audio), width(width), height(height), max_samples_in(max_samples_in), base_rotation(base_rotation), top_screen_x(top_screen_x), top_screen_y(top_screen_y), bot_screen_x(bot_screen_x), bot_screen_y(bot_screen_y), path(""), video_data_type(video_data_type), firmware_id(firmware_id), is_rgb_888(is_rgb_888) {} + CaptureDevice(std::string serial_number, std::string name, std::string path, CaptureConnectionType cc_type, const void* descriptor, bool is_3ds, bool has_3d, bool has_audio, int width, int height, int max_samples_in, int base_rotation, int top_screen_x, int top_screen_y, int bot_screen_x, int bot_screen_y, InputVideoDataType video_data_type) : serial_number(serial_number), name(name), cc_type(cc_type), descriptor(descriptor), is_3ds(is_3ds), has_3d(has_3d), has_audio(has_audio), width(width), height(height), max_samples_in(max_samples_in), base_rotation(base_rotation), top_screen_x(top_screen_x), top_screen_y(top_screen_y), bot_screen_x(bot_screen_x), bot_screen_y(bot_screen_y), path(path), video_data_type(video_data_type), firmware_id(0), is_rgb_888(false) {} + CaptureDevice(): serial_number(""), name(""), cc_type(CAPTURE_CONN_USB), descriptor(NULL), is_3ds(false), has_3d(false), has_audio(false), width(0), height(0), max_samples_in(0), base_rotation(0), top_screen_x(0), top_screen_y(0), bot_screen_x(0), bot_screen_y(0), path(""), firmware_id(0), video_data_type(VIDEO_DATA_RGB), is_rgb_888(false) {} std::string serial_number; std::string name; @@ -131,6 +139,8 @@ struct CaptureDevice { int top_screen_y; int bot_screen_x; int bot_screen_y; + int firmware_id; + bool is_rgb_888; }; struct CaptureStatus { diff --git a/include/hw_defs.hpp b/include/hw_defs.hpp index ddf1224..86455ad 100755 --- a/include/hw_defs.hpp +++ b/include/hw_defs.hpp @@ -71,7 +71,7 @@ // In general, it should be less than * 2, but you never know. For now, go for safety at x16... #define O3DS_SAMPLES_IN (1096 * 16) #define N3DSXL_SAMPLES_IN (1096 * 16) -#define DS_SAMPLES_IN (1096 * 16) +#define DS_SAMPLES_IN (1096) #define MAX_SAMPLES_IN O3DS_SAMPLES_IN #endif diff --git a/setup_scripts/ftd_shared_symbols.txt b/setup_scripts/ftd_shared_symbols.txt new file mode 100644 index 0000000..2cc3caa --- /dev/null +++ b/setup_scripts/ftd_shared_symbols.txt @@ -0,0 +1,8 @@ +FT_ListDevices +FT_GetVIDPID +FT_Close +FT_CreateDeviceInfoList +FT_GetDeviceInfoList +FT_GetDeviceInfoDetail +FT_GetDriverVersion +FT_GetLibraryVersion diff --git a/setup_scripts/libusb_ftd2_shared_symbols.txt b/setup_scripts/libusb_ftd2_shared_symbols.txt new file mode 100644 index 0000000..89f7cd2 --- /dev/null +++ b/setup_scripts/libusb_ftd2_shared_symbols.txt @@ -0,0 +1,69 @@ +usbi_hotplug_notification +usbi_default_context +usbi_log +usbi_alloc_device +usbi_connect_device +usbi_disconnect_device +usbi_sanitize_device +usbi_get_device_by_session_id +usbi_signal_event +usbi_clear_event +active_contexts_lock +discovered_devs_append +libusb_get_version +libusb_error_name +libusb_exit +libusb_init +libusb_set_option +libusb_set_debug +libusb_set_auto_detach_kernel_driver +libusb_attach_kernel_driver +libusb_detach_kernel_driver +libusb_kernel_driver_active +libusb_dev_mem_free +libusb_dev_mem_alloc +libusb_free_streams +libusb_alloc_streams +libusb_reset_device +libusb_clear_halt +libusb_unref_device +libusb_ref_device +libusb_has_capability +libusb_get_device_list +libusb_free_device_list +libusb_get_bus_number +libusb_get_port_number +libusb_get_port_numbers +libusb_get_port_path +libusb_get_parent +libusb_get_device_address +libusb_get_device_speed +libusb_get_max_packet_size +libusb_get_max_iso_packet_size +libusb_open +libusb_open_device_with_vid_pid +libusb_close +libusb_get_device +libusb_get_configuration +libusb_set_configuration +libusb_claim_interface +libusb_release_interface +libusb_set_interface_alt_setting +libusb_hotplug_register_callback +libusb_hotplug_deregister_callback +libusb_get_device_descriptor +libusb_get_active_config_descriptor +libusb_get_config_descriptor +libusb_get_config_descriptor_by_value +libusb_free_config_descriptor +libusb_get_ss_endpoint_companion_descriptor +libusb_free_ss_endpoint_companion_descriptor +libusb_free_bos_descriptor +libusb_get_bos_descriptor +libusb_get_usb_2_0_extension_descriptor +libusb_free_usb_2_0_extension_descriptor +libusb_get_ss_usb_device_capability_descriptor +libusb_free_ss_usb_device_capability_descriptor +libusb_get_container_id_descriptor +libusb_free_container_id_descriptor +libusb_get_string_descriptor_ascii diff --git a/setup_scripts/libusb_ftd3_shared_symbols.txt b/setup_scripts/libusb_ftd3_shared_symbols.txt new file mode 100644 index 0000000..e69de29 diff --git a/source/CaptureDeviceSpecific/3dscapture_ftd3.cpp b/source/CaptureDeviceSpecific/3dscapture_ftd3.cpp index 27249ee..45584db 100644 --- a/source/CaptureDeviceSpecific/3dscapture_ftd3.cpp +++ b/source/CaptureDeviceSpecific/3dscapture_ftd3.cpp @@ -1,5 +1,6 @@ #include "3dscapture_ftd3.hpp" #include "devicecapture.hpp" +//#include "ftd3xx_symbols_renames.h" #ifdef _WIN32 #define FTD3XX_STATIC @@ -103,7 +104,7 @@ void list_devices_ftd3(std::vector &devices_list, std::vector @@ -9,23 +14,492 @@ #include #include +#define FT_FAILED(x) ((x) != FT_OK) + +#define FTD2XX_VID 0x0403 + +#define REAL_SERIAL_NUMBER_SIZE 16 +#define SERIAL_NUMBER_SIZE (REAL_SERIAL_NUMBER_SIZE+1) + +#define LE16(x) ((x) & 0xff), (((x) >> 8) & 0xff) + +#define FTD2XX_IN_SIZE 0x10000 +#define FTD2XX_OUT_SIZE 0x10000 + +#define CLKRATE 6 // 1 - 25MHz +#define CLKDIV ((30 / CLKRATE) - 1) +#define RESETDELAY ((1 * CLKRATE) / 8) //1uS in bytes (clks/8) +#define INITDELAY ((1200 * CLKRATE) / 8) //1200uS + +#define TX_SPI_SIZE (1 << 16) +#define TX_SPI_OFFSET 3 + +#define MAX_PACKET_SIZE_FTD2 510 +#define ENABLE_AUDIO true + +const uint16_t ftd2xx_valid_vids[] = {FTD2XX_VID}; +const uint16_t ftd2xx_valid_pids[] = {0x6014}; + +const uint8_t* ftd2_ds2_fws[] = { +ftd2_ds2_fw_1, +ftd2_ds2_fw_2, +}; + +const size_t ftd2_ds2_sizes[] = { +ftd2_ds2_fw_1_len, +ftd2_ds2_fw_2_len, +}; + void list_devices_ftd2(std::vector &devices_list, std::vector &no_access_list) { + FT_STATUS ftStatus; + DWORD numDevs = 0; + std::string valid_descriptions[] = {"NDS.1", "NDS.2"}; + int descriptions_firmware_ids[] = {1, 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)) && (Flags & FT_FLAGS_HISPEED) && (Type == FT_DEVICE_232H)) + { + 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), "DS.2", CAPTURE_CONN_FTD2, (void*)NULL, false, false, ENABLE_AUDIO, WIDTH_DS, HEIGHT_DS + HEIGHT_DS, 0, 0, 0, 0, 0, HEIGHT_DS, VIDEO_DATA_RGB16, descriptions_firmware_ids[j], false); + break; + } + } + } + } + } + if(num_inserted == 0) { + #if defined(USE_IS_NITRO_USB) || defined(USE_DS_3DS_USB) + if(get_usb_total_filtered_devices(ftd2xx_valid_vids, sizeof(ftd2xx_valid_vids) / sizeof(ftd2xx_valid_vids[0]), ftd2xx_valid_pids, sizeof(ftd2xx_valid_pids) / sizeof(ftd2xx_valid_pids[0])) != numDevs) + no_access_list.emplace_back("FTD2XX"); + #endif + } } uint64_t ftd2_get_video_in_size(CaptureData* capture_data) { - return 0; + return sizeof(USBOldDSVideoInputData); } static uint64_t get_capture_size(CaptureData* capture_data) { - return 0; + return (((sizeof(FTD2OldDSCaptureReceived) - EXTRA_DATA_BUFFER_USB_SIZE) + (MAX_PACKET_SIZE_FTD2 - 1)) / MAX_PACKET_SIZE_FTD2) * MAX_PACKET_SIZE_FTD2; // multiple of maxPacketSize +} + +static bool pass_if_FT_queue_empty(FT_HANDLE handle) { + DWORD bytesIn = 0; + FT_STATUS ftStatus; + ftStatus = FT_GetQueueStatus(handle, &bytesIn); + if(FT_FAILED(ftStatus) || (bytesIn != 0)) //should be empty + return false; + return true; +} + +static bool full_ftd2_write(FT_HANDLE handle, const uint8_t* data, size_t size) { + FT_STATUS ftStatus; + if(!pass_if_FT_queue_empty(handle)) // maybe MPSSE error? + return false; + + DWORD sent; + ftStatus = FT_Write(handle, (void*)data, size, &sent); + if(FT_FAILED(ftStatus) || (sent != size)) + return false; + return true; +} + +//verify CDONE==val +static bool check_cdone(FT_HANDLE handle, bool want_active) { + static const uint8_t cmd[] = { + 0x81, //read D + 0x83, //read C + }; + uint8_t buf[2]; + + if(!full_ftd2_write(handle, cmd, sizeof(cmd))) + return false; + + DWORD bytesIn; + FT_STATUS ftStatus = FT_Read(handle, buf, 2, &bytesIn); + if(FT_FAILED(ftStatus) || (bytesIn != 2) || (buf[0] == 0xFA)) + return false; + + if(want_active) + return (buf[0] & 0x40); + return !(buf[0] & 0x40); +} + +static FT_STATUS end_spi_tx(uint8_t *txBuf, FT_STATUS ftStatus) { + delete []txBuf; + return ftStatus; +} + +static FT_STATUS ftd2_spi_tx(FT_HANDLE handle, const uint8_t* buf, int size) { + uint8_t *txBuf = new uint8_t[TX_SPI_SIZE + TX_SPI_OFFSET]; + FT_STATUS ftStatus; + int len; + DWORD sent; + DWORD bytesIn; + DWORD wrote = 0; + + if(!pass_if_FT_queue_empty(handle)) + return end_spi_tx(txBuf, FT_OTHER_ERROR); + + while(size > 0) { + len = size; + if(len > TX_SPI_SIZE) + len = TX_SPI_SIZE; + memcpy(&txBuf[TX_SPI_OFFSET], &buf[wrote], len); + + txBuf[0] = 0x11; + txBuf[1] = (len - 1) & 0xFF; + txBuf[2] = ((len - 1) >> 8) & 0xFF; + + ftStatus = FT_Write(handle, (void*)txBuf, len + TX_SPI_OFFSET, &sent); + if(FT_FAILED(ftStatus)) + return end_spi_tx(txBuf, ftStatus); + if(sent != (len + TX_SPI_OFFSET)) + return end_spi_tx(txBuf, FT_INSUFFICIENT_RESOURCES); + + if(!pass_if_FT_queue_empty(handle)) + return end_spi_tx(txBuf, FT_OTHER_ERROR); + + wrote += sent - TX_SPI_OFFSET; + size -= len; + } + return end_spi_tx(txBuf, FT_OK); +} + +static bool fpga_config(FT_HANDLE handle, const uint8_t* bitstream, int size) { + //D6=CDONE (in) + //D3=SS (out) + //D2=TDO (in) + //D1=TDI (out) + //D0=TCK (out) + //C7=reset (out) + + //Lattice programming: + // hold SS low + // pulse reset 200ns + // wait 1200us + // release SS + // send 8 clocks + // hold SS low + // send configuration MSB first, sampled on +clk + // release SS + // CDONE should go high within 100 clocks + // send >49 clocks after CDONE=1 + + static const uint8_t cmd0[] = { //configure for lattice SPI: + 0x82, 0x7f, 0x80, //set Cx pins {val,dir:1=out}: reset=0 + 0x80, 0xf0, 0x0b, //set Dx pins {val,dir:1=out}: SS=0, clk idle low, TDI out, TCK out + 0x8f, LE16(RESETDELAY), //reset delay + 0x82, 0xff, 0x00, //set Cx pins: reset=PU (does val=1 enable pullups? seems to...) + 0x8f, LE16(INITDELAY), //init delay + 0x80, 0xf8, 0x0b, //set Dx pins: SS=1 + 0x8f, LE16(1), //16 dummy clocks + 0x80, 0xf0, 0x0b, //set Dx pins: SS=0 + }; + + FT_STATUS ftStatus; + ftStatus = FT_SetTimeouts(handle, 300, 300); + if(FT_FAILED(ftStatus)) + return false; + if(!full_ftd2_write(handle, cmd0, sizeof(cmd0))) + return false; + + //verify CDONE=0 + if(!check_cdone(handle, false)) + return false; + + //send configuration + ftStatus = ftd2_spi_tx(handle, bitstream, size); + if(FT_FAILED(ftStatus)) + return false; + + //finish up + static const uint8_t cmd1[] = { + 0x80, 0xf8, 0x0b, //set Dx pins: SS=1 + 0x8f, LE16(20), //>150 dummy clocks + 0x80, 0x00, 0x00, //float Dx + 0x82, 0x00, 0x00, //float Cx + }; + if(!full_ftd2_write(handle, cmd1, sizeof(cmd1))) + return false; + + //verify CDONE=1 + if(!check_cdone(handle, true)) + return false; + + return true; +} + +static bool init_MPSSE(FT_HANDLE handle) { + static const uint8_t cmd[] = { + 0x85, //no loopback + 0x8d, //disable 3-phase clocking + 0x8a, //disable clk divide-by-5 + 0x97, //disable adaptive clocking + 0x86, LE16(CLKDIV), //set clock rate + }; + + FT_STATUS ftStatus; + ftStatus = FT_ResetDevice(handle); + if(FT_FAILED(ftStatus)) + return false; + ftStatus = FT_SetUSBParameters(handle, FTD2XX_IN_SIZE, FTD2XX_OUT_SIZE); //Multiple of 64 bytes up to 64k + if(FT_FAILED(ftStatus)) + return false; + ftStatus = FT_SetChars(handle, 0, 0, 0, 0); + if(FT_FAILED(ftStatus)) + return false; + ftStatus = FT_SetTimeouts(handle, 300, 300); //read,write timeout (ms) + if(FT_FAILED(ftStatus)) + return false; + ftStatus = FT_SetLatencyTimer(handle, 3); //time to wait before incomplete packet is sent (default=16ms). MPSSE read seems to fail on 2 sometimes, too fast? + if(FT_FAILED(ftStatus)) + return false; + ftStatus = FT_SetFlowControl(handle, FT_FLOW_RTS_CTS, 0, 0); //turn on flow control to synchronize IN requests + if(FT_FAILED(ftStatus)) + return false; + ftStatus = FT_SetBitMode(handle, 0x00, FT_BITMODE_RESET); //performs a general reset on MPSSE + if(FT_FAILED(ftStatus)) + return false; + ftStatus = FT_SetBitMode(handle, 0x00, FT_BITMODE_MPSSE); //enable MPSSE mode + if(FT_FAILED(ftStatus)) + return false; + + //MPSSE seems to choke on first write sometimes :/ Send, purge, resend. + DWORD sent; + ftStatus = FT_Write(handle, (void*)cmd, 1, &sent); //enable MPSSE mode + if(FT_FAILED(ftStatus)) + return false; + default_sleep(); + ftStatus = FT_Purge(handle, FT_PURGE_RX | FT_PURGE_TX); + if(FT_FAILED(ftStatus)) + return false; + return full_ftd2_write(handle, cmd, sizeof(cmd)); +} + +static void preemptive_close_connection(CaptureData* capture_data) { + FT_ResetDevice(capture_data->handle); + FT_Close(capture_data->handle); } bool connect_ftd2(bool print_failed, CaptureData* capture_data, CaptureDevice* device) { - return false; + 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_OpenEx(SerialNumber, FT_OPEN_BY_SERIAL_NUMBER, &capture_data->handle)) { + capture_error_print(print_failed, capture_data, "Create failed"); + return false; + } + + if(!init_MPSSE(capture_data->handle)) { + preemptive_close_connection(capture_data); + capture_error_print(print_failed, capture_data, "MPSSE init failed"); + return false; + } + + if(!fpga_config(capture_data->handle, ftd2_ds2_fws[device->firmware_id - 1], ftd2_ds2_sizes[device->firmware_id - 1])) { + preemptive_close_connection(capture_data); + capture_error_print(print_failed, capture_data, "FPGA config failed"); + return false; + } + + FT_STATUS ftStatus; + WORD val=0; + ftStatus = FT_ReadEE(capture_data->handle, 1, &val); + if(FT_FAILED(ftStatus) || (val != 0x0403)) { //=85A8: something went wrong (fpga is configured but FT chip detected wrong eeprom size) + preemptive_close_connection(capture_data); + capture_error_print(print_failed, capture_data, "EEPROM read error"); + return false; + } + + /* + WORD Firmware = 0; + WORD Hardware = 0; + ftStatus = FT_ReadEE(capture_data->handle, 0x10, &Firmware); + if(FT_FAILED(ftStatus)) { + preemptive_close_connection(capture_data); + capture_error_print(print_failed, capture_data, "Firmware ID read error"); + return false; + } + ftStatus = FT_ReadEE(capture_data->handle, 0x11, &Hardware); + if(FT_FAILED(ftStatus)) { + preemptive_close_connection(capture_data); + capture_error_print(print_failed, capture_data, "Hardware ID read error"); + return false; + } + */ + + ftStatus = FT_SetBitMode(capture_data->handle, 0x00, FT_BITMODE_SYNC_FIFO); //to FIFO mode. This takes over port B, pins shouldn't get modified though + if(FT_FAILED(ftStatus)) { + preemptive_close_connection(capture_data); + capture_error_print(print_failed, capture_data, "Bitmode setup error"); + return false; + } + + ftStatus = FT_SetTimeouts(capture_data->handle, 50, 50); + if(FT_FAILED(ftStatus)) { + preemptive_close_connection(capture_data); + capture_error_print(print_failed, capture_data, "Timeouts setup error"); + return false; + } + + static const uint8_t cmd[]={ 0x80, 0x01 }; //enable capture + if(!full_ftd2_write(capture_data->handle, cmd, sizeof(cmd))) { + preemptive_close_connection(capture_data); + capture_error_print(print_failed, capture_data, "Capture enable error"); + return false; + } + + return true; +} + +/* +//DS frame: +// video (top|bottom interleaved RGB16), 256*192*2*2 bytes +// audio (16bit stereo, approx. 32729 Hz), 0x8F4 bytes +// actual number of samples varies, audio is padded with 0x4321 +FrameResult DS2Device::getFrame(DSFrame *frame) { + enum { + FRAMESIZE = ndsWidth*ndsHeight*2*2, + S_MAX = 0x47A/2, //#audiosamples(dword) aligns frame to 510 bytes.. + READSIZE = FRAMESIZE + S_MAX*4, + MAX = READSIZE/2, //(usbFifoWords) + }; + + FT_STATUS status; + DWORD bytesIn; + + status=FT_Read(handle, frame->raw, READSIZE, &bytesIn); + if(status!=FT_OK) { + DEBUG_TRACE("err %d\n",status); //disconnected = FT_IO_ERROR + usb_close(); + return FRAME_ERROR; + } + if(bytesIn!=READSIZE) { //stream stopped (lid closed / DS is off) + DEBUG_TRACE("."); + return FRAME_SKIP; + } + + //check sync + uint16_t *src=(uint16_t*)frame->raw; + int samples; + if(src[0]==0x4321) { + samples=0; + while(samplesraw, samples*2, &bytesIn); + DEBUG_TRACE("resync(%d)",samples); + return FRAME_SKIP; + } else if(src[MAX-1]!=0x4321) { + samples=0; + while(samplesraw, samples*2, &bytesIn); + DEBUG_TRACE("resync(%d)",samples); + return FRAME_SKIP; + } else { + //DEBUG_TRACE("."); + } + + //count audio samples + samples=0; + uint32_t *a=(uint32_t*)(frame->raw+FRAMESIZE); + while(samples548) + DEBUG_TRACE("%d?",samples); + + frame->audioBuf=a; + frame->audioSamples=samples; + + return FRAME_OK; +} +*/ + +static bool synchronization_check(CaptureData* capture_data, uint16_t* data_buffer) { + //check sync + DWORD bytesIn; + int samples = 0; + int size_words = get_capture_size(capture_data) / 2; + if(data_buffer[0] == FTD2_OLDDS_SYNCH_VALUES) { + while((samples < size_words) && (data_buffer[samples] == FTD2_OLDDS_SYNCH_VALUES)) + samples++; + // Do a read to re-synchronize + FT_Read(capture_data->handle, data_buffer, samples * 2, &bytesIn); + return false; + } else if(data_buffer[size_words - 1] != FTD2_OLDDS_SYNCH_VALUES) { + // Find the first spot the padding is present + while((samples < size_words) && (data_buffer[samples] != FTD2_OLDDS_SYNCH_VALUES)) + samples++; + while((samples < size_words) && (data_buffer[samples] == FTD2_OLDDS_SYNCH_VALUES)) + samples++; + // Do a read to re-synchronize + FT_Read(capture_data->handle, data_buffer, samples * 2, &bytesIn); + return false; + } + return true; +} + +static inline void data_output_update(CaptureReceived* buffer, CaptureData* capture_data, int read_amount, std::chrono::time_point &base_time) { + const auto curr_time = std::chrono::high_resolution_clock::now(); + const std::chrono::duration diff = curr_time - base_time; + base_time = curr_time; + capture_data->data_buffers.WriteToBuffer(buffer, read_amount, 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(); } void ftd2_capture_main_loop(CaptureData* capture_data) { + int inner_curr_in = 0; + FT_STATUS ftStatus; + auto clock_start = std::chrono::high_resolution_clock::now(); + CaptureReceived* data_buffer = new CaptureReceived[2]; + DWORD bytesIn; + int read_size = get_capture_size(capture_data); + + while (capture_data->status.connected && capture_data->status.running) { + ftStatus = FT_Read(capture_data->handle, data_buffer, read_size, &bytesIn); + if(FT_FAILED(ftStatus)) { + capture_error_print(true, capture_data, "Disconnected: Read failed"); + return; + } + if(bytesIn < read_size) + continue; + if(!synchronization_check(capture_data, (uint16_t*)data_buffer)) + continue; + data_output_update(data_buffer, capture_data, bytesIn, clock_start); + } } void ftd2_capture_cleanup(CaptureData* capture_data) { + if(FT_Close(capture_data->handle)) { + capture_error_print(true, capture_data, "Disconnected: Close failed"); + } } diff --git a/source/conversions.cpp b/source/conversions.cpp index 50aadd7..9ee52ce 100755 --- a/source/conversions.cpp +++ b/source/conversions.cpp @@ -25,7 +25,6 @@ struct deinterleaved_ds_pixels_le { uint64_t fourth : 16; }; -#ifdef USE_FTD3 static inline void convertVideoToOutputChunk(RGB83DSVideoInputData *p_in, VideoOutputData *p_out, int iters, int start_in, int start_out) { memcpy(&p_out->screen_data[start_out], &p_in->screen_data[start_in], iters * 3); } @@ -62,14 +61,7 @@ static void ftd3_convertVideoToOutput(CaptureReceived *p_in, VideoOutputData *p_ convertVideoToOutputChunk_3D(&p_in->ftd3_received_3d.video_in, p_out, IN_VIDEO_WIDTH_3DS_3D, (((i * 3) + 1) * IN_VIDEO_WIDTH_3DS_3D) + IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D, TOP_SIZE_3DS + (i * IN_VIDEO_WIDTH_3DS_3D)); } } -#endif -#ifdef USE_FTD2 -static void ftd2_convertVideoToOutput(CaptureReceived *p_in, VideoOutputData *p_out) { -} -#endif - -#ifdef USE_DS_3DS_USB static inline void usb_oldDSconvertVideoToOutputHalfLineDirectOptLE(USBOldDSCaptureReceived *p_in, VideoOutputData *p_out, int input_halfline, int output_halfline) { //de-interleave pixels deinterleaved_ds_pixels_le* out_ptr_top = (deinterleaved_ds_pixels_le*)p_out->screen_data; @@ -162,6 +154,10 @@ static void usb_oldDSconvertVideoToOutput(USBOldDSCaptureReceived *p_in, VideoOu #endif } +static void ftd2_convertVideoToOutput(CaptureReceived *p_in, VideoOutputData *p_out, const bool is_big_endian) { + usb_oldDSconvertVideoToOutput(&p_in->usb_received_old_ds, p_out, is_big_endian); +} + static void usb_3DSconvertVideoToOutput(USB3DSCaptureReceived *p_in, VideoOutputData *p_out) { memcpy(p_out->screen_data, p_in->video_in.screen_data, IN_VIDEO_HEIGHT_3DS * IN_VIDEO_WIDTH_3DS * 3); } @@ -174,9 +170,7 @@ static void usb_convertVideoToOutput(CaptureReceived *p_in, VideoOutputData *p_o else usb_oldDSconvertVideoToOutput(&p_in->usb_received_old_ds, p_out, is_big_endian); } -#endif -#ifdef USE_IS_NITRO_USB static void usb_is_nitro_convertVideoToOutput(CaptureReceived *p_in, VideoOutputData *p_out, CaptureScreensType capture_type) { int num_pixels = usb_is_nitro_get_video_in_size(capture_type) / 3; int out_start_pos = 0; @@ -189,7 +183,6 @@ static void usb_is_nitro_convertVideoToOutput(CaptureReceived *p_in, VideoOutput memset(p_out->screen_data[out_clear_pos], 0, num_pixels * 3); memcpy(p_out->screen_data[out_start_pos], p_in->is_nitro_capture_received.video_in.screen_data, num_pixels * 3); } -#endif bool convertVideoToOutput(VideoOutputData *p_out, const bool is_big_endian, CaptureDataSingleBuffer* data_buffer, CaptureStatus* status) { CaptureReceived *p_in = &data_buffer->capture_buf; @@ -203,7 +196,7 @@ bool convertVideoToOutput(VideoOutputData *p_out, const bool is_big_endian, Capt #endif #ifdef USE_FTD2 if(chosen_device->cc_type == CAPTURE_CONN_FTD2) { - ftd2_convertVideoToOutput(p_in, p_out); + ftd2_convertVideoToOutput(p_in, p_out, is_big_endian); converted = true; } #endif @@ -237,6 +230,11 @@ bool convertAudioToOutput(std::int16_t *p_out, uint64_t n_samples, const bool is #endif #ifdef USE_FTD2 if(status->device.cc_type == CAPTURE_CONN_FTD2) { + base_ptr = (uint8_t*)p_in->ftd2_received_old_ds.audio_data; + int real_samples = 0; + while((real_samples < n_samples) && (((uint32_t*)base_ptr)[real_samples] != (FTD2_OLDDS_SYNCH_VALUES | (FTD2_OLDDS_SYNCH_VALUES << 16)))) + real_samples++; + n_samples = real_samples; } #endif #ifdef USE_DS_3DS_USB diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 4a9abf9..4ab3f44 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -26,3 +26,16 @@ add_custom_command( POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_BINARY_DIR} VERBATIM ) + +set(OUTPUT_NAME CMakePrepareRenameSymbols) +project(${OUTPUT_NAME} VERSION 1.0.0 LANGUAGES CXX) + +add_executable(${OUTPUT_NAME} prepare_rename_symbols_list.cpp) +target_compile_features(${OUTPUT_NAME} PRIVATE cxx_std_17) + +add_custom_command( + TARGET ${OUTPUT_NAME} + COMMENT "Copy Output" + POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_BINARY_DIR} + VERBATIM +) diff --git a/tools/prepare_rename_symbols_list.cpp b/tools/prepare_rename_symbols_list.cpp new file mode 100644 index 0000000..d7a3325 --- /dev/null +++ b/tools/prepare_rename_symbols_list.cpp @@ -0,0 +1,57 @@ +#include +#include +#include +#include + +#if (!defined(_MSC_VER)) || (_MSC_VER > 1916) +#include +#else +#include +#endif + +using namespace std; + +int main(int argc, char *argv[]) { + if(argc < 4) { + cout << "Usage: " << argv[0] << " text_file prefix new_file define_file" << endl; + return -1; + } + + ifstream input(argv[1], ios::in); + if(!input) { + cout << "Couldn't open input file!" << endl; + return -2; + } + vector file_lines; + string single_str = ""; + while (getline(input, single_str)) + file_lines.push_back(single_str); + + input.close(); + + string prefix(argv[2]); + + ofstream output(argv[3], ios::out); + if(!output) { + cout << "Couldn't open output file!" << endl; + return -2; + } + for(int i = 0; i < file_lines.size(); i++) + output << file_lines[i] << " " << prefix << file_lines[i] << endl; + + output.close(); + + if(argc > 4) { + ofstream output_define(argv[4], ios::out); + if(!output_define) { + cout << "Couldn't open output define file!" << endl; + return -2; + } + for(int i = 0; i < file_lines.size(); i++) + output_define << "#define " << file_lines[i] << " " << prefix << file_lines[i] << endl; + + output_define.close(); + } + + return 0; +} diff --git a/usb_rules/50-ftd2xx.rules b/usb_rules/50-ftd2xx.rules new file mode 100644 index 0000000..79572b6 --- /dev/null +++ b/usb_rules/50-ftd2xx.rules @@ -0,0 +1,4 @@ +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6014", PROGRAM="/bin/sh -c '\ + echo -n $id:1.0 > /sys/bus/usb/drivers/ftdi_sio/unbind;\ + echo -n $id:1.1 > /sys/bus/usb/drivers/ftdi_sio/unbind\ +'" diff --git a/usb_rules/51-ftd2xx.rules b/usb_rules/51-ftd2xx.rules new file mode 100644 index 0000000..90848e2 --- /dev/null +++ b/usb_rules/51-ftd2xx.rules @@ -0,0 +1 @@ +SUBSYSTEM=="usb", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6014", MODE="0666"