From 8da1172b703c14d6a15e9a55631addcbe7f84c25 Mon Sep 17 00:00:00 2001 From: Lorenzooone Date: Fri, 29 Nov 2024 10:07:51 +0100 Subject: [PATCH] Attempt using libftdi --- CMakeLists.txt | 525 +++++++------ README.md | 7 +- .../dscapture_ftd2_compatibility.hpp | 28 + .../DSCapture_FTD2/dscapture_ftd2_driver.hpp | 17 + .../DSCapture_FTD2/dscapture_ftd2_general.hpp | 52 ++ .../DSCapture_FTD2/dscapture_ftd2_shared.hpp | 21 + .../DSCapture_FTD2/dscapture_libftdi2.hpp | 27 + .../ISNitro/usb_is_nitro_communications.hpp | 1 + .../CaptureDeviceSpecific/dscapture_ftd2.hpp | 19 - include/capture_structs.hpp | 30 +- include/conversions.hpp | 2 +- include/devicecapture.hpp | 2 +- other licenses/libftdi.txt | 26 + setup_scripts/ftd_shared_symbols_macos.txt | 8 + .../ftd_shared_symbols_special_windows.txt | 15 + .../ftd_shared_symbols_special_windows32.txt | 15 + setup_scripts/libusb_ftd2_shared_symbols.txt | 69 -- setup_scripts/libusb_ftd3_shared_symbols.txt | 0 ...it_crusher_fragment_shader.2_to_x_1_7.frag | 2 +- ...er_crusher_fragment_shader.2_to_x_1_6.frag | 2 +- .../bit_merger_crusher_fragment_shader_7.frag | 2 +- ...bit_merger_fragment_shader.2_to_x_0_6.frag | 2 +- shaders/bit_merger_fragment_shader_7.frag | 2 +- ...it_crusher_fragment_shader.2_to_x_1_7.frag | 2 +- shaders/frame_blending_fragment_shader.frag | 2 +- shaders/no_effect_fragment_shader.frag | 2 +- source/CaptureDataBuffers.cpp | 1 + .../CaptureDeviceSpecific/3dscapture_ftd3.cpp | 4 +- .../dscapture_ftd2_compatibility.cpp | 273 +++++++ .../DSCapture_FTD2/dscapture_ftd2_driver.cpp | 110 +++ .../DSCapture_FTD2/dscapture_ftd2_shared.cpp | 399 ++++++++++ .../DSCapture_FTD2/dscapture_libftdi2.cpp | 704 ++++++++++++++++++ .../ISNitro/usb_is_nitro_acquisition.cpp | 4 +- .../ISNitro/usb_is_nitro_communications.cpp | 64 +- .../CaptureDeviceSpecific/dscapture_ftd2.cpp | 505 ------------- .../usb_ds_3ds_capture.cpp | 7 + source/Menus/LicenseMenu.cpp | 28 +- source/Menus/StatusMenu.cpp | 2 +- source/WindowScreen.cpp | 54 +- source/cc3dsfs.cpp | 2 +- source/conversions.cpp | 11 +- source/devicecapture.cpp | 22 +- source/utils.cpp | 10 +- tools/CMakeLists.txt | 26 + tools/rename_lib_functions.cpp | 93 +++ tools/rename_symbols_list.cpp | 52 ++ 46 files changed, 2325 insertions(+), 926 deletions(-) create mode 100644 include/CaptureDeviceSpecific/DSCapture_FTD2/dscapture_ftd2_compatibility.hpp create mode 100644 include/CaptureDeviceSpecific/DSCapture_FTD2/dscapture_ftd2_driver.hpp create mode 100644 include/CaptureDeviceSpecific/DSCapture_FTD2/dscapture_ftd2_general.hpp create mode 100644 include/CaptureDeviceSpecific/DSCapture_FTD2/dscapture_ftd2_shared.hpp create mode 100644 include/CaptureDeviceSpecific/DSCapture_FTD2/dscapture_libftdi2.hpp delete mode 100644 include/CaptureDeviceSpecific/dscapture_ftd2.hpp create mode 100644 other licenses/libftdi.txt create mode 100644 setup_scripts/ftd_shared_symbols_macos.txt create mode 100644 setup_scripts/ftd_shared_symbols_special_windows.txt create mode 100644 setup_scripts/ftd_shared_symbols_special_windows32.txt delete mode 100644 setup_scripts/libusb_ftd2_shared_symbols.txt delete mode 100644 setup_scripts/libusb_ftd3_shared_symbols.txt create mode 100644 source/CaptureDeviceSpecific/DSCapture_FTD2/dscapture_ftd2_compatibility.cpp create mode 100644 source/CaptureDeviceSpecific/DSCapture_FTD2/dscapture_ftd2_driver.cpp create mode 100644 source/CaptureDeviceSpecific/DSCapture_FTD2/dscapture_ftd2_shared.cpp create mode 100644 source/CaptureDeviceSpecific/DSCapture_FTD2/dscapture_libftdi2.cpp delete mode 100644 source/CaptureDeviceSpecific/dscapture_ftd2.cpp create mode 100644 tools/rename_lib_functions.cpp create mode 100644 tools/rename_symbols_list.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 5635965..227f850 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,15 +1,24 @@ cmake_minimum_required(VERSION 3.16) set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64" CACHE STRING "Build archs for Mac OS X" FORCE) set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version") +set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) set(TARGET_LANGUAGES CXX C) project(cc3dsfs VERSION 1.0.0 LANGUAGES ${TARGET_LANGUAGES}) include(ExternalProject) -set(N3DSXL_LOOPY_SUPPORT 0) +set(N3DSXL_LOOPY_SUPPORT 1) set(NEW_DS_LOOPY_SUPPORT 1) set(IS_NITRO_SUPPORT 1) set(OLD_DS_3DS_LOOPY_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_NITRO_SUPPORT} OR ${OLD_DS_3DS_LOOPY_SUPPORT} OR ${USE_LIBFTDI_FOR_NEW_DS_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) +endif() +set(FTDI_EEPROM OFF) set(WINDOWS_ARM64 0) set(WINDOWS_x86_32 0) set(FETCHCONTENT_UPDATES_DISCONNECTED ON) @@ -19,14 +28,14 @@ set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") set(SFML_USE_STATIC_STD_LIBS TRUE) set(CMAKE_HOST_CXX_COMPILER ${CMAKE_CXX_COMPILER} CACHE STRING "Host Compiler") if(FORCE_WINDOWS_FTD3XX_SHARED_LIB) -set(WINDOWS_FTD3XX_USE_SHARED_LIB 1) + set(WINDOWS_FTD3XX_USE_SHARED_LIB 1) else() -set(WINDOWS_FTD3XX_USE_SHARED_LIB 0) + set(WINDOWS_FTD3XX_USE_SHARED_LIB 0) endif() if(FORCE_WINDOWS_FTD2XX_SHARED_LIB) -set(WINDOWS_FTD2XX_USE_SHARED_LIB 1) + set(WINDOWS_FTD2XX_USE_SHARED_LIB 1) else() -set(WINDOWS_FTD2XX_USE_SHARED_LIB 0) + set(WINDOWS_FTD2XX_USE_SHARED_LIB 0) endif() set(FETCHCONTENT_QUIET FALSE) set(EXTRA_CXX_FLAGS "") @@ -52,27 +61,34 @@ if (RASPBERRY_PI_COMPILATION) endif() if((${CMAKE_SYSTEM_NAME} STREQUAL "Windows") AND ((${CMAKE_GENERATOR_PLATFORM} MATCHES "ARM64") OR (("${CMAKE_GENERATOR_PLATFORM}" STREQUAL "") AND (${CMAKE_SYSTEM_PROCESSOR} MATCHES "ARM64")))) - set(WINDOWS_ARM64 1) + set(WINDOWS_ARM64 1) endif() if((${CMAKE_SYSTEM_NAME} STREQUAL "Windows") AND ((${CMAKE_GENERATOR_PLATFORM} MATCHES "Win32") OR (("${CMAKE_GENERATOR_PLATFORM}" STREQUAL "") AND ((${CMAKE_SYSTEM_PROCESSOR} MATCHES "Win32") OR (${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86") OR (${CMAKE_SYSTEM_PROCESSOR} MATCHES "X86"))))) - set(WINDOWS_x86_32 1) + set(WINDOWS_x86_32 1) endif() # Avoid warning about DOWNLOAD_EXTRACT_TIMESTAMP in CMake 3.24: if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0") - cmake_policy(SET CMP0135 NEW) + cmake_policy(SET CMP0135 NEW) endif() include(FetchContent) FetchContent_Declare(SFML - GIT_REPOSITORY https://github.com/SFML/SFML.git - GIT_TAG master) + GIT_REPOSITORY https://github.com/SFML/SFML.git + GIT_TAG master) -if(IS_NITRO_SUPPORT OR OLD_DS_3DS_LOOPY_SUPPORT) - FetchContent_Declare(libusb1 +if(USE_LIBUSB_SUPPORT) + FetchContent_Declare(LibUSB GIT_REPOSITORY https://github.com/libusb/libusb-cmake.git - GIT_TAG main) + GIT_TAG main + OVERRIDE_FIND_PACKAGE) +endif() + +if(USE_LIBFTDI_FOR_NEW_DS_LOOPY) + FetchContent_Declare(libftdi1 + GIT_REPOSITORY git://developer.intra2net.com/libftdi + ) endif() if(${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Windows") @@ -104,32 +120,32 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") set(FTD3XX_LIB FTD3XX.lib) set(FTD3XX_DLL FTD3XX.dll) if(WINDOWS_ARM64) - set(FTD3XX_LIB FTD3XXWU.lib) + set(FTD3XX_LIB FTD3XXWU.lib) set(FTD3XX_DLL FTD3XXWU.dll) - set(FTD3XX_URL_TIME 2024/06) - set(FTD3XX_BUILD_COMMAND ${SETUP_SCRIPTS_DIR}/windows_setup_ftd3xx_winusb) - set(FTD3XX_ARCHIVE FTD3XX_WinUSB_Package.zip) - set(FTD3XX_PATH_WINDOWS_ARCH ARM64) + set(FTD3XX_URL_TIME 2024/06) + set(FTD3XX_BUILD_COMMAND ${SETUP_SCRIPTS_DIR}/windows_setup_ftd3xx_winusb) + set(FTD3XX_ARCHIVE FTD3XX_WinUSB_Package.zip) + set(FTD3XX_PATH_WINDOWS_ARCH ARM64) elseif("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") - set(FTD3XX_PATH_WINDOWS_ARCH Win32) + set(FTD3XX_PATH_WINDOWS_ARCH Win32) else () - set(FTD3XX_PATH_WINDOWS_ARCH x64) + set(FTD3XX_PATH_WINDOWS_ARCH x64) endif() if(${WINDOWS_FTD3XX_USE_SHARED_LIB}) set(FTD3XX_BUILD_COMMAND ${FTD3XX_BUILD_COMMAND}_dll) - set(FTD3XX_WINDOWS_PATH_SPECIFIER DLL) - if(WINDOWS_ARM64) - set(FTD3XX_WINDOWS_PATH_SPECIFIER Dynamic) - endif() + set(FTD3XX_WINDOWS_PATH_SPECIFIER DLL) + if(WINDOWS_ARM64) + set(FTD3XX_WINDOWS_PATH_SPECIFIER Dynamic) + endif() else() - set(FTD3XX_WINDOWS_PATH_SPECIFIER Static_Lib) - if(WINDOWS_ARM64) - set(FTD3XX_WINDOWS_PATH_SPECIFIER Static) - endif() + set(FTD3XX_WINDOWS_PATH_SPECIFIER Static_Lib) + if(WINDOWS_ARM64) + set(FTD3XX_WINDOWS_PATH_SPECIFIER Static) + endif() endif() set(FTD3XX_PRE_WINDOWS_PATH ${FTD3XX_PATH_WINDOWS_ARCH}/${FTD3XX_WINDOWS_PATH_SPECIFIER}) if(WINDOWS_ARM64) - set(FTD3XX_PRE_WINDOWS_PATH ${FTD3XX_WINDOWS_PATH_SPECIFIER}/${FTD3XX_PATH_WINDOWS_ARCH}) + set(FTD3XX_PRE_WINDOWS_PATH ${FTD3XX_WINDOWS_PATH_SPECIFIER}/${FTD3XX_PATH_WINDOWS_ARCH}) endif() elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") set(FTD3XX_BUILD_COMMAND ${SETUP_SCRIPTS_DIR}/macos_setup_ftd3xx) @@ -145,17 +161,17 @@ else() set(FTD3XX_URL_TIME 2023/03) set(FTD3XX_VER 1.0.5) if((${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch") OR (${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm")) - if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8") - set(FTD3XX_VOL libftd3xx-linux-arm-v8-${FTD3XX_VER}) - elseif("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") - set(FTD3XX_VOL libftd3xx-linux-arm-v7_32-${FTD3XX_VER}) - endif() + if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8") + set(FTD3XX_VOL libftd3xx-linux-arm-v8-${FTD3XX_VER}) + elseif("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") + set(FTD3XX_VOL libftd3xx-linux-arm-v7_32-${FTD3XX_VER}) + endif() else() - if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8") - set(FTD3XX_VOL libftd3xx-linux-x86_64-${FTD3XX_VER}) - elseif("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") - set(FTD3XX_VOL libftd3xx-linux-x86_32-${FTD3XX_VER}) - endif() + if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8") + set(FTD3XX_VOL libftd3xx-linux-x86_64-${FTD3XX_VER}) + elseif("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") + set(FTD3XX_VOL libftd3xx-linux-x86_32-${FTD3XX_VER}) + endif() endif() set(FTD3XX_ARCHIVE ${FTD3XX_VOL}.tgz) set(FTD3XX_LIB libftd3xx-static.a) @@ -164,80 +180,80 @@ endif() set(FTD2XX_BASE_URL https://ftdichip.com/wp-content/uploads/) if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - set(FTD2XX_BUILD_COMMAND ${SETUP_SCRIPTS_DIR}/windows_setup_ftd2xx) - set(FTD2XX_URL_TIME 2023/09) - set(FTD2XX_VER 2.12.36.4-WHQL-Certified) - set(FTD2XX_VOL CDM-v${FTD2XX_VER}) - set(FTD2XX_ARCHIVE ${FTD2XX_VOL}.zip) - set(FTD2XX_SUBFOLDER win) - set(FTD2XX_HEADER_PATH ftd2xx.h) - if(${WINDOWS_FTD2XX_USE_SHARED_LIB}) - set(FTD2XX_BUILD_COMMAND ${FTD2XX_BUILD_COMMAND}_dll) - set(FTD2XX_WINDOWS_PATH_SPECIFIER "") - if(WINDOWS_ARM64) - set(FTD2XX_WINDOWS_PATH_SPECIFIER Release) - set(FTD2XX_LIB FTD2XX.lib) - set(FTD2XX_DLL FTD2XX.dll) - elseif("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") - set(FTD2XX_LIB ftd2xx.lib) - set(FTD2XX_DLL ftd2xx.dll) - else() - set(FTD2XX_LIB ftd2xx.lib) - set(FTD2XX_DLL ftd2xx64.lib) - endif() - else() - set(FTD2XX_WINDOWS_PATH_SPECIFIER Static) - set(FTD2XX_LIB ftd2xx.lib) - if(WINDOWS_ARM64) - set(FTD2XX_WINDOWS_PATH_SPECIFIER Release) - set(FTD2XX_LIB FTD2XXstatic.lib) - endif() - endif() - if(WINDOWS_ARM64) - set(FTD2XX_URL_TIME 2022/02) - set(FTD2XX_VER 2.12.36.4-for-ARM64-Signed-Distributable) - set(FTD2XX_VOL CDM-v${FTD2XX_VER}) - set(FTD2XX_ARCHIVE ${FTD2XX_VOL}.zip) - set(FTD2XX_PATH_WINDOWS_ARCH ARM64) - set(FTD2XX_HEADER_PATH x86/FTD2XX.H) - elseif("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") - set(FTD2XX_PATH_WINDOWS_ARCH i386) - else () - set(FTD2XX_PATH_WINDOWS_ARCH amd64) - endif() - set(FTD2XX_PRE_WINDOWS_PATH ${FTD2XX_WINDOWS_PATH_SPECIFIER}/${FTD2XX_PATH_WINDOWS_ARCH}) - if(WINDOWS_ARM64) - set(FTD2XX_PRE_WINDOWS_PATH ${FTD2XX_PATH_WINDOWS_ARCH}/${FTD2XX_WINDOWS_PATH_SPECIFIER}) - endif() + set(FTD2XX_BUILD_COMMAND ${SETUP_SCRIPTS_DIR}/windows_setup_ftd2xx) + set(FTD2XX_URL_TIME 2023/09) + set(FTD2XX_VER 2.12.36.4-WHQL-Certified) + set(FTD2XX_VOL CDM-v${FTD2XX_VER}) + set(FTD2XX_ARCHIVE ${FTD2XX_VOL}.zip) + set(FTD2XX_SUBFOLDER win) + set(FTD2XX_HEADER_PATH ftd2xx.h) + if(${WINDOWS_FTD2XX_USE_SHARED_LIB}) + set(FTD2XX_BUILD_COMMAND ${FTD2XX_BUILD_COMMAND}_dll) + set(FTD2XX_WINDOWS_PATH_SPECIFIER "") + if(WINDOWS_ARM64) + set(FTD2XX_WINDOWS_PATH_SPECIFIER Release) + set(FTD2XX_LIB FTD2XX.lib) + set(FTD2XX_DLL FTD2XX.dll) + elseif("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") + set(FTD2XX_LIB ftd2xx.lib) + set(FTD2XX_DLL ftd2xx.dll) + else() + set(FTD2XX_LIB ftd2xx.lib) + set(FTD2XX_DLL ftd2xx64.lib) + endif() + else() + set(FTD2XX_WINDOWS_PATH_SPECIFIER Static) + set(FTD2XX_LIB ftd2xx.lib) + if(WINDOWS_ARM64) + set(FTD2XX_WINDOWS_PATH_SPECIFIER Release) + set(FTD2XX_LIB FTD2XXstatic.lib) + endif() + endif() + if(WINDOWS_ARM64) + set(FTD2XX_URL_TIME 2022/02) + set(FTD2XX_VER 2.12.36.4-for-ARM64-Signed-Distributable) + set(FTD2XX_VOL CDM-v${FTD2XX_VER}) + set(FTD2XX_ARCHIVE ${FTD2XX_VOL}.zip) + set(FTD2XX_PATH_WINDOWS_ARCH ARM64) + set(FTD2XX_HEADER_PATH x86/FTD2XX.H) + elseif("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") + set(FTD2XX_PATH_WINDOWS_ARCH i386) + else () + set(FTD2XX_PATH_WINDOWS_ARCH amd64) + endif() + set(FTD2XX_PRE_WINDOWS_PATH ${FTD2XX_WINDOWS_PATH_SPECIFIER}/${FTD2XX_PATH_WINDOWS_ARCH}) + if(WINDOWS_ARM64) + set(FTD2XX_PRE_WINDOWS_PATH ${FTD2XX_PATH_WINDOWS_ARCH}/${FTD2XX_WINDOWS_PATH_SPECIFIER}) + endif() elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") - set(FTD2XX_BUILD_COMMAND ${SETUP_SCRIPTS_DIR}/macos_setup_ftd2xx) - set(FTD2XX_URL_TIME 2024/04) - set(FTD2XX_VER 1.4.30) - set(FTD2XX_VOL D2XX${FTD2XX_VER}) - set(FTD2XX_ARCHIVE ${FTD2XX_VOL}.dmg) - set(FTD2XX_LIB libftd2xx.a) - set(FTD2XX_MOUNTED_FOLDER /Volumes/dmg) - set(FTD2XX_SUBFOLDER macos) + set(FTD2XX_BUILD_COMMAND ${SETUP_SCRIPTS_DIR}/macos_setup_ftd2xx) + set(FTD2XX_URL_TIME 2024/04) + set(FTD2XX_VER 1.4.30) + set(FTD2XX_VOL D2XX${FTD2XX_VER}) + set(FTD2XX_ARCHIVE ${FTD2XX_VOL}.dmg) + set(FTD2XX_LIB libftd2xx.a) + set(FTD2XX_MOUNTED_FOLDER /Volumes/dmg) + set(FTD2XX_SUBFOLDER macos) else() - set(FTD2XX_BUILD_COMMAND ${SETUP_SCRIPTS_DIR}/linux_setup_ftd3xx) - set(FTD2XX_URL_TIME 2022/07) - set(FTD2XX_VER 1.4.27) - if((${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch") OR (${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm")) - if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8") - set(FTD2XX_VOL libftd2xx-arm-v8-${FTD2XX_VER}) - elseif("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") - set(FTD2XX_VOL libftd2xx-arm-v7-hf-${FTD2XX_VER}) - endif() - else() - if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8") - set(FTD2XX_VOL libftd2xx-x86_64-${FTD2XX_VER}) - elseif("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") - set(FTD2XX_VOL libftd2xx-x86_32-${FTD2XX_VER}) - endif() - endif() - set(FTD2XX_ARCHIVE ${FTD2XX_VOL}.tgz) - set(FTD2XX_LIB libftd2xx.a) - set(FTD2XX_SUBFOLDER linux) + set(FTD2XX_BUILD_COMMAND ${SETUP_SCRIPTS_DIR}/linux_setup_ftd3xx) + set(FTD2XX_URL_TIME 2022/07) + set(FTD2XX_VER 1.4.27) + if((${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch") OR (${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm")) + if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8") + set(FTD2XX_VOL libftd2xx-arm-v8-${FTD2XX_VER}) + elseif("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") + set(FTD2XX_VOL libftd2xx-arm-v7-hf-${FTD2XX_VER}) + endif() + else() + if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8") + set(FTD2XX_VOL libftd2xx-x86_64-${FTD2XX_VER}) + elseif("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") + set(FTD2XX_VOL libftd2xx-x86_32-${FTD2XX_VER}) + endif() + endif() + set(FTD2XX_ARCHIVE ${FTD2XX_VOL}.tgz) + set(FTD2XX_LIB libftd2xx.a) + set(FTD2XX_SUBFOLDER linux) endif() if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") @@ -247,7 +263,7 @@ if(N3DSXL_LOOPY_SUPPORT) DOWNLOAD_NO_EXTRACT TRUE ) endif() -if(NEW_DS_LOOPY_SUPPORT) +if(USE_FTD2XX_FOR_NEW_DS_LOOPY) FetchContent_Declare(FTD2XX URL ${FTD2XX_BASE_URL}${FTD2XX_URL_TIME}/${FTD2XX_ARCHIVE} DOWNLOAD_NO_EXTRACT TRUE @@ -259,7 +275,7 @@ if(N3DSXL_LOOPY_SUPPORT) URL ${FTD3XX_BASE_URL}${FTD3XX_URL_TIME}/${FTD3XX_ARCHIVE} ) endif() -if(NEW_DS_LOOPY_SUPPORT) +if(USE_FTD2XX_FOR_NEW_DS_LOOPY) FetchContent_Declare(FTD2XX URL ${FTD2XX_BASE_URL}${FTD2XX_URL_TIME}/${FTD2XX_ARCHIVE} ) @@ -270,10 +286,12 @@ set(TOOLS_DATA_DIR ${CMAKE_BINARY_DIR}/tools_and_data) file(MAKE_DIRECTORY ${TOOLS_DATA_DIR}) set(FETCH_CONTENT_MAKE_AVAILABLE_LIBRARIES "") +set(FETCH_CONTENT_MAKE_AVAILABLE_LIBRARIES_SEPARATE "") set(SOURCE_CPP_EXTRA_FILES "") set(EXTRA_DEPENDENCIES "") set(SOURCE_CPP_DEVICE_FILES_BASE_PATH "source/CaptureDeviceSpecific") set(SOURCE_CPP_IS_NITRO_FILES_BASE_PATH "${SOURCE_CPP_DEVICE_FILES_BASE_PATH}/ISNitro") +set(SOURCE_CPP_FTD2_FILES_BASE_PATH "${SOURCE_CPP_DEVICE_FILES_BASE_PATH}/DSCapture_FTD2") 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) @@ -284,54 +302,88 @@ if(N3DSXL_LOOPY_SUPPORT) list(APPEND EXTRA_CXX_FLAGS "-DUSE_FTD3") 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) + if(MSVC) + list(APPEND EXTRA_CXX_FLAGS "/DUSE_LIBUSB") + else() + list(APPEND EXTRA_CXX_FLAGS "-DUSE_LIBUSB") + endif() +endif() +if(IS_NITRO_SUPPORT) + list(APPEND SOURCE_CPP_EXTRA_FILES ${SOURCE_CPP_IS_NITRO_FILES_BASE_PATH}/usb_is_nitro_communications.cpp ${SOURCE_CPP_IS_NITRO_FILES_BASE_PATH}/usb_is_nitro_acquisition.cpp ${SOURCE_CPP_IS_NITRO_FILES_BASE_PATH}/usb_is_nitro_acquisition_capture.cpp ${SOURCE_CPP_IS_NITRO_FILES_BASE_PATH}/usb_is_nitro_acquisition_emulator.cpp ${SOURCE_CPP_IS_NITRO_FILES_BASE_PATH}/usb_is_nitro_is_driver.cpp ${SOURCE_CPP_IS_NITRO_FILES_BASE_PATH}/usb_is_nitro_libusb.cpp) + if(MSVC) + list(APPEND EXTRA_CXX_FLAGS "/DUSE_IS_NITRO_USB") + else() + list(APPEND EXTRA_CXX_FLAGS "-DUSE_IS_NITRO_USB") + endif() +endif() +if(OLD_DS_3DS_LOOPY_SUPPORT) + list(APPEND SOURCE_CPP_EXTRA_FILES ${SOURCE_CPP_DEVICE_FILES_BASE_PATH}/usb_ds_3ds_capture.cpp) + if(MSVC) + list(APPEND EXTRA_CXX_FLAGS "/DUSE_DS_3DS_USB") + else() + list(APPEND EXTRA_CXX_FLAGS "-DUSE_DS_3DS_USB") + endif() +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 ${TOOLS_DATA_DIR}/ftd2_ds2_fw_1.cpp ${TOOLS_DATA_DIR}/ftd2_ds2_fw_2.cpp) - list(APPEND EXTRA_DEPENDENCIES FTD2XX_BUILD_PROJECT) + list(APPEND SOURCE_CPP_EXTRA_FILES ${SOURCE_CPP_FTD2_FILES_BASE_PATH}/dscapture_ftd2_shared.cpp ${SOURCE_CPP_FTD2_FILES_BASE_PATH}/dscapture_ftd2_compatibility.cpp ${TOOLS_DATA_DIR}/ftd2_ds2_fw_1.cpp ${TOOLS_DATA_DIR}/ftd2_ds2_fw_2.cpp) if(MSVC) list(APPEND EXTRA_CXX_FLAGS "/DUSE_FTD2") else() list(APPEND EXTRA_CXX_FLAGS "-DUSE_FTD2") endif() endif() -if(IS_NITRO_SUPPORT OR OLD_DS_3DS_LOOPY_SUPPORT) - list(APPEND FETCH_CONTENT_MAKE_AVAILABLE_LIBRARIES libusb1) - list(APPEND SOURCE_CPP_EXTRA_FILES ${SOURCE_CPP_DEVICE_FILES_BASE_PATH}/usb_generic.cpp) - if(IS_NITRO_SUPPORT) - list(APPEND SOURCE_CPP_EXTRA_FILES ${SOURCE_CPP_IS_NITRO_FILES_BASE_PATH}/usb_is_nitro_communications.cpp ${SOURCE_CPP_IS_NITRO_FILES_BASE_PATH}/usb_is_nitro_acquisition.cpp ${SOURCE_CPP_IS_NITRO_FILES_BASE_PATH}/usb_is_nitro_acquisition_capture.cpp ${SOURCE_CPP_IS_NITRO_FILES_BASE_PATH}/usb_is_nitro_acquisition_emulator.cpp ${SOURCE_CPP_IS_NITRO_FILES_BASE_PATH}/usb_is_nitro_is_driver.cpp ${SOURCE_CPP_IS_NITRO_FILES_BASE_PATH}/usb_is_nitro_libusb.cpp) - if(MSVC) - list(APPEND EXTRA_CXX_FLAGS "/DUSE_IS_NITRO_USB") - else() - list(APPEND EXTRA_CXX_FLAGS "-DUSE_IS_NITRO_USB") - endif() +if(USE_LIBFTDI_FOR_NEW_DS_LOOPY) + list(APPEND FETCH_CONTENT_MAKE_AVAILABLE_LIBRARIES_SEPARATE libftdi1) + list(APPEND SOURCE_CPP_EXTRA_FILES ${SOURCE_CPP_FTD2_FILES_BASE_PATH}/dscapture_libftdi2.cpp) + if(MSVC) + list(APPEND EXTRA_CXX_FLAGS "/DUSE_FTD2_LIBFTDI") + else() + list(APPEND EXTRA_CXX_FLAGS "-DUSE_FTD2_LIBFTDI") endif() - if(OLD_DS_3DS_LOOPY_SUPPORT) - list(APPEND SOURCE_CPP_EXTRA_FILES ${SOURCE_CPP_DEVICE_FILES_BASE_PATH}/usb_ds_3ds_capture.cpp) - if(MSVC) - list(APPEND EXTRA_CXX_FLAGS "/DUSE_DS_3DS_USB") - else() - list(APPEND EXTRA_CXX_FLAGS "-DUSE_DS_3DS_USB") - endif() +endif() +if(USE_FTD2XX_FOR_NEW_DS_LOOPY) + list(APPEND FETCH_CONTENT_MAKE_AVAILABLE_LIBRARIES FTD2XX) + list(APPEND SOURCE_CPP_EXTRA_FILES ${SOURCE_CPP_FTD2_FILES_BASE_PATH}/dscapture_ftd2_driver.cpp) + list(APPEND EXTRA_DEPENDENCIES FTD2XX_BUILD_PROJECT) + if(MSVC) + list(APPEND EXTRA_CXX_FLAGS "/DUSE_FTD2_DRIVER") + else() + list(APPEND EXTRA_CXX_FLAGS "-DUSE_FTD2_DRIVER") endif() endif() FetchContent_MakeAvailable(SFML ${FETCH_CONTENT_MAKE_AVAILABLE_LIBRARIES}) +# Find libusb +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) list(APPEND EXTRA_INCLUDE_DIRECTORIES ${ftd3xx_BINARY_DIR}/${FTD3XX_SUBFOLDER}) endif() -if(NEW_DS_LOOPY_SUPPORT) +if(USE_FTD2XX_FOR_NEW_DS_LOOPY) list(APPEND EXTRA_INCLUDE_DIRECTORIES ${ftd2xx_BINARY_DIR}/${FTD2XX_SUBFOLDER}) endif() +if(USE_LIBUSB_SUPPORT) + list(APPEND EXTRA_INCLUDE_DIRECTORIES ${libusb_SOURCE_DIR}/libusb/libusb) +endif() if(IS_DIRECTORY "${sfml_SOURCE_DIR}") - set_property(DIRECTORY ${sfml_SOURCE_DIR} PROPERTY EXCLUDE_FROM_ALL YES) + set_property(DIRECTORY ${sfml_SOURCE_DIR} PROPERTY EXCLUDE_FROM_ALL YES) endif() -if(IS_NITRO_SUPPORT OR OLD_DS_3DS_LOOPY_SUPPORT) - if(IS_DIRECTORY "${libusb1_SOURCE_DIR}") - set_property(DIRECTORY ${libusb1_SOURCE_DIR} PROPERTY EXCLUDE_FROM_ALL YES) +if(USE_LIBUSB_SUPPORT) + if(IS_DIRECTORY "${libusb_SOURCE_DIR}") + set_property(DIRECTORY ${libusb_SOURCE_DIR} PROPERTY EXCLUDE_FROM_ALL YES) + endif() +endif() + +if(USE_LIBFTDI_FOR_NEW_DS_LOOPY) + if(IS_DIRECTORY "${libftdi1_SOURCE_DIR}") + set_property(DIRECTORY ${libftdi1_SOURCE_DIR} PROPERTY EXCLUDE_FROM_ALL YES) endif() endif() @@ -341,27 +393,27 @@ if(N3DSXL_LOOPY_SUPPORT) file(MAKE_DIRECTORY ${ftd3xx_BINARY_DIR}/linux) endif() -if(NEW_DS_LOOPY_SUPPORT) +if(USE_FTD2XX_FOR_NEW_DS_LOOPY) file(MAKE_DIRECTORY ${ftd2xx_BINARY_DIR}/win) file(MAKE_DIRECTORY ${ftd2xx_BINARY_DIR}/macos) file(MAKE_DIRECTORY ${ftd2xx_BINARY_DIR}/linux) endif() if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") -set(FTD3XX_BUILD_COMMAND_PARAMETERS ${ftd3xx_SOURCE_DIR}/${FTD3XX_ARCHIVE} ${FTD3XX_MOUNTED_FOLDER} ${ftd3xx_BINARY_DIR}/${FTD3XX_SUBFOLDER} ${FTD3XX_LIB}) -set(FTD2XX_BUILD_COMMAND_PARAMETERS ${ftd2xx_SOURCE_DIR}/${FTD2XX_ARCHIVE} ${FTD2XX_MOUNTED_FOLDER} ${ftd2xx_BINARY_DIR}/${FTD2XX_SUBFOLDER} ${FTD2XX_LIB}) + set(FTD3XX_BUILD_COMMAND_PARAMETERS ${ftd3xx_SOURCE_DIR}/${FTD3XX_ARCHIVE} ${FTD3XX_MOUNTED_FOLDER} ${ftd3xx_BINARY_DIR}/${FTD3XX_SUBFOLDER} ${FTD3XX_LIB}) + set(FTD2XX_BUILD_COMMAND_PARAMETERS ${ftd2xx_SOURCE_DIR}/${FTD2XX_ARCHIVE} ${FTD2XX_MOUNTED_FOLDER} ${ftd2xx_BINARY_DIR}/${FTD2XX_SUBFOLDER} ${FTD2XX_LIB}) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") -set(FTD3XX_BUILD_COMMAND_PARAMETERS ${ftd3xx_SOURCE_DIR} ${ftd3xx_BINARY_DIR}/${FTD3XX_SUBFOLDER} ${FTD3XX_PRE_WINDOWS_PATH}/${FTD3XX_LIB}) + set(FTD3XX_BUILD_COMMAND_PARAMETERS ${ftd3xx_SOURCE_DIR} ${ftd3xx_BINARY_DIR}/${FTD3XX_SUBFOLDER} ${FTD3XX_PRE_WINDOWS_PATH}/${FTD3XX_LIB}) if(WINDOWS_FTD3XX_USE_SHARED_LIB) set(FTD3XX_BUILD_COMMAND_PARAMETERS ${FTD3XX_BUILD_COMMAND_PARAMETERS} ${FTD3XX_PRE_WINDOWS_PATH}/${FTD3XX_DLL}) endif() -set(FTD2XX_BUILD_COMMAND_PARAMETERS ${ftd2xx_SOURCE_DIR} ${ftd2xx_BINARY_DIR}/${FTD2XX_SUBFOLDER} ${FTD2XX_PRE_WINDOWS_PATH}/${FTD2XX_LIB} ${FTD2XX_HEADER_PATH}) + set(FTD2XX_BUILD_COMMAND_PARAMETERS ${ftd2xx_SOURCE_DIR} ${ftd2xx_BINARY_DIR}/${FTD2XX_SUBFOLDER} ${FTD2XX_PRE_WINDOWS_PATH}/${FTD2XX_LIB} ${FTD2XX_HEADER_PATH}) if(WINDOWS_FTD2XX_USE_SHARED_LIB) set(FTD2XX_BUILD_COMMAND_PARAMETERS ${FTD2XX_BUILD_COMMAND_PARAMETERS} ${FTD2XX_PRE_WINDOWS_PATH}/${FTD2XX_DLL}) endif() 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}) + 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) @@ -369,20 +421,41 @@ if(N3DSXL_LOOPY_SUPPORT) 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 "" ) endif() -if(NEW_DS_LOOPY_SUPPORT) +set(BASE_REPLACEMENT_FTD2XX_SYMBOL F2) +set(BASE_REPLACEMENT_FTD2XX_SYMBOLS_LIST ${SETUP_SCRIPTS_DIR}/ftd_shared_symbols.txt) +set(REPLACEMENT_FTD2XX_SYMBOL ${BASE_REPLACEMENT_FTD2XX_SYMBOL}) +set(REPLACEMENT_FTD2XX_SYMBOLS_LIST ${BASE_REPLACEMENT_FTD2XX_SYMBOLS_LIST}) +if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") + set(REPLACEMENT_FTD2XX_SYMBOL _F2) + set(REPLACEMENT_FTD2XX_SYMBOLS_LIST ${SETUP_SCRIPTS_DIR}/ftd_shared_symbols_macos.txt) +endif() +if((${CMAKE_SYSTEM_NAME} STREQUAL "Windows") AND ("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4")) + set(REPLACEMENT_FTD2XX_SYMBOL _F2) + set(REPLACEMENT_FTD2XX_SYMBOLS_LIST ${SETUP_SCRIPTS_DIR}/ftd_shared_symbols_macos.txt) +endif() +set(REPLACEMENT_FTD2XX_SYMBOL_EXTRA ${REPLACEMENT_FTD2XX_SYMBOL}) +set(REPLACEMENT_FTD2XX_SYMBOLS_LIST_EXTRA ${REPLACEMENT_FTD2XX_SYMBOLS_LIST}) +if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + set(REPLACEMENT_FTD2XX_SYMBOL_EXTRA ?F2) + if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") + set(REPLACEMENT_FTD2XX_SYMBOLS_LIST_EXTRA ${SETUP_SCRIPTS_DIR}/ftd_shared_symbols_special_windows32.txt) + else() + set(REPLACEMENT_FTD2XX_SYMBOLS_LIST_EXTRA ${SETUP_SCRIPTS_DIR}/ftd_shared_symbols_special_windows.txt) + endif() +endif() +if(USE_FTD2XX_FOR_NEW_DS_LOOPY) ExternalProject_Add(FTD2XX_BUILD_PROJECT 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} + COMMAND ${TOOLS_DATA_DIR}/CMakeRenameLibFunctions${HOST_FINAL_EXTENSION} ${REPLACEMENT_FTD2XX_SYMBOLS_LIST} ${REPLACEMENT_FTD2XX_SYMBOL} ${ftd2xx_BINARY_DIR}/${FTD2XX_SUBFOLDER}/${FTD2XX_LIB} + COMMAND ${TOOLS_DATA_DIR}/CMakeRenameLibFunctions${HOST_FINAL_EXTENSION} ${REPLACEMENT_FTD2XX_SYMBOLS_LIST_EXTRA} ${REPLACEMENT_FTD2XX_SYMBOL_EXTRA} ${ftd2xx_BINARY_DIR}/${FTD2XX_SUBFOLDER}/${FTD2XX_LIB} + COMMAND ${TOOLS_DATA_DIR}/CMakeRenameSymbols${HOST_FINAL_EXTENSION} ${BASE_REPLACEMENT_FTD2XX_SYMBOLS_LIST} ${BASE_REPLACEMENT_FTD2XX_SYMBOL} ${TOOLS_DATA_DIR}/ftd2xx_symbols_renames.h UPDATE_COMMAND "" CONFIGURE_COMMAND "" INSTALL_COMMAND "" @@ -412,38 +485,41 @@ if(NOT ("${EXTRA_DEPENDENCIES}" STREQUAL "")) add_dependencies(${OUTPUT_NAME} ${EXTRA_DEPENDENCIES}) endif() target_link_libraries(${OUTPUT_NAME} PRIVATE SFML::Graphics SFML::Audio SFML::Window SFML::System ${EXTRA_LIBRARIES}) -if(IS_NITRO_SUPPORT OR OLD_DS_3DS_LOOPY_SUPPORT) +if(USE_LIBUSB_SUPPORT) target_link_libraries(${OUTPUT_NAME} PRIVATE usb-1.0) endif() if(N3DSXL_LOOPY_SUPPORT) target_link_libraries(${OUTPUT_NAME} PRIVATE ${ftd3xx_BINARY_DIR}/${FTD3XX_SUBFOLDER}/${FTD3XX_LIB}) endif() -if(NEW_DS_LOOPY_SUPPORT) +if(USE_LIBFTDI_FOR_NEW_DS_LOOPY) + target_link_libraries(${OUTPUT_NAME} PRIVATE ftdi1-static) +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/ISNitro) +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/ISNitro ${CMAKE_SOURCE_DIR}/include/CaptureDeviceSpecific/DSCapture_FTD2 ${libftdi1_SOURCE_DIR}/src) target_compile_features(${OUTPUT_NAME} PRIVATE cxx_std_20) target_compile_options(${OUTPUT_NAME} PRIVATE ${EXTRA_CXX_FLAGS}) add_custom_command( - OUTPUT ${TOOLS_DATA_DIR}/font_ttf.cpp - COMMENT "Convert font to binary" - COMMAND ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION} ${CMAKE_SOURCE_DIR}/data/font.ttf ${TOOLS_DATA_DIR} font_ttf font_ttf - DEPENDS ${CMAKE_SOURCE_DIR}/data/font.ttf ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION} + OUTPUT ${TOOLS_DATA_DIR}/font_ttf.cpp + COMMENT "Convert font to binary" + COMMAND ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION} ${CMAKE_SOURCE_DIR}/data/font.ttf ${TOOLS_DATA_DIR} font_ttf font_ttf + 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} + 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} + 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 "") @@ -451,35 +527,35 @@ list(APPEND SHADERS_LIST ${CMAKE_SOURCE_DIR}/shaders/bit_crusher_fragment_shader add_custom_command( OUTPUT ${TOOLS_DATA_DIR}/shaders_list.cpp - COMMENT "Prepare shaders list" - COMMAND ${TOOLS_DATA_DIR}/CMakeShader2C${HOST_FINAL_EXTENSION} ${CMAKE_SOURCE_DIR}/shaders ${CMAKE_SOURCE_DIR}/source/shaders_list_template.cpp ${TOOLS_DATA_DIR}/shaders_list.cpp - DEPENDS ${CMAKE_SOURCE_DIR}/source/shaders_list_template.cpp ${SHADERS_LIST} ${TOOLS_DATA_DIR}/CMakeShader2C${HOST_FINAL_EXTENSION} + COMMENT "Prepare shaders list" + COMMAND ${TOOLS_DATA_DIR}/CMakeShader2C${HOST_FINAL_EXTENSION} ${CMAKE_SOURCE_DIR}/shaders ${CMAKE_SOURCE_DIR}/source/shaders_list_template.cpp ${TOOLS_DATA_DIR}/shaders_list.cpp + DEPENDS ${CMAKE_SOURCE_DIR}/source/shaders_list_template.cpp ${SHADERS_LIST} ${TOOLS_DATA_DIR}/CMakeShader2C${HOST_FINAL_EXTENSION} ) if(WIN32) if(N3DSXL_LOOPY_SUPPORT AND WINDOWS_FTD3XX_USE_SHARED_LIB) - add_custom_command( - TARGET ${OUTPUT_NAME} - COMMENT "Copy FTD3XX DLL" - POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${ftd3xx_BINARY_DIR}/${FTD3XX_SUBFOLDER}/${FTD3XX_DLL} ${CMAKE_SOURCE_DIR} - VERBATIM - ) - endif() - if(NEW_DS_LOOPY_SUPPORT AND WINDOWS_FTD2XX_USE_SHARED_LIB) - add_custom_command( - TARGET ${OUTPUT_NAME} - COMMENT "Copy FTD2XX DLL" - POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${ftd2xx_BINARY_DIR}/${FTD2XX_SUBFOLDER}/${FTD2XX_DLL} ${CMAKE_SOURCE_DIR} - VERBATIM - ) - endif() + add_custom_command( + TARGET ${OUTPUT_NAME} + COMMENT "Copy FTD3XX DLL" + POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${ftd3xx_BINARY_DIR}/${FTD3XX_SUBFOLDER}/${FTD3XX_DLL} ${CMAKE_SOURCE_DIR} + VERBATIM + ) + endif() + if(USE_FTD2XX_FOR_NEW_DS_LOOPY AND WINDOWS_FTD2XX_USE_SHARED_LIB) + add_custom_command( + TARGET ${OUTPUT_NAME} + COMMENT "Copy FTD2XX DLL" + POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${ftd2xx_BINARY_DIR}/${FTD2XX_SUBFOLDER}/${FTD2XX_DLL} ${CMAKE_SOURCE_DIR} + VERBATIM + ) + endif() endif() add_custom_command( - TARGET ${OUTPUT_NAME} - COMMENT "Copy Output" - POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_SOURCE_DIR} - VERBATIM + TARGET ${OUTPUT_NAME} + COMMENT "Copy Output" + POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_SOURCE_DIR} + VERBATIM ) if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") @@ -491,37 +567,38 @@ install(FILES LICENSE README.md DESTINATION .) install(DIRECTORY "other licenses" DESTINATION .) if(WIN32) if(N3DSXL_LOOPY_SUPPORT AND WINDOWS_FTD3XX_USE_SHARED_LIB) - install(FILES ${FTD3XX_DLL} DESTINATION .) + install(FILES ${FTD3XX_DLL} DESTINATION .) endif() - if(NEW_DS_LOOPY_SUPPORT AND WINDOWS_FTD2XX_USE_SHARED_LIB) - install(FILES ${FTD2XX_DLL} DESTINATION .) + if(USE_FTD2XX_FOR_NEW_DS_LOOPY AND WINDOWS_FTD2XX_USE_SHARED_LIB) + install(FILES ${FTD2XX_DLL} DESTINATION .) endif() endif() if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") - set(FW_APP ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${OUTPUT_NAME}.app) - set(FW_DIRS ${sfml_SOURCE_DIR}/extlibs/libs-macos/Frameworks) - set_target_properties(${OUTPUT_NAME} PROPERTIES - MACOSX_BUNDLE TRUE - MACOSX_BUNDLE_BUNDLE_NAME ${OUTPUT_NAME} - MACOSX_BUNDLE_GUI_IDENTIFIER ${OUTPUT_NAME} - MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/data/MacOSXBundleInfo.plist.in) - set(CMAKE_MACOSX_RPATH TRUE) - - add_custom_command( - TARGET ${OUTPUT_NAME} - COMMENT "Prepare bundle" - POST_BUILD COMMAND ${SETUP_SCRIPTS_DIR}/macos_bundle_setup${SCRIPT_EXTENSION} ${FW_APP}/Contents/MacOS/${OUTPUT_NAME} ${FW_DIRS} ${FW_APP}/Contents/Frameworks - VERBATIM - ) + set(FW_APP ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${OUTPUT_NAME}.app) + set(FW_DIRS ${sfml_SOURCE_DIR}/extlibs/libs-macos/Frameworks) + set_target_properties(${OUTPUT_NAME} PROPERTIES + MACOSX_BUNDLE TRUE + MACOSX_BUNDLE_BUNDLE_NAME ${OUTPUT_NAME} + MACOSX_BUNDLE_GUI_IDENTIFIER ${OUTPUT_NAME} + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/data/MacOSXBundleInfo.plist.in) + set(CMAKE_MACOSX_RPATH TRUE) + add_custom_command( + TARGET ${OUTPUT_NAME} + COMMENT "Prepare bundle" + POST_BUILD COMMAND ${SETUP_SCRIPTS_DIR}/macos_bundle_setup${SCRIPT_EXTENSION} ${FW_APP}/Contents/MacOS/${OUTPUT_NAME} ${FW_DIRS} ${FW_APP}/Contents/Frameworks + VERBATIM + ) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") else() - install(FILES ${USB_RULES_DIR}/51-ftd3xx.rules DESTINATION .) - install(FILES ${USB_RULES_DIR}/95-usb3dscapture.rules DESTINATION .) - install(FILES ${USB_RULES_DIR}/95-usbdscapture.rules DESTINATION .) - install(FILES ${USB_RULES_DIR}/51-isnitro.rules DESTINATION .) - install(FILES ${SETUP_SCRIPTS_DIR}/install_usb_rules${SCRIPT_EXTENSION} DESTINATION .) + install(FILES ${USB_RULES_DIR}/51-ftd3xx.rules DESTINATION .) + install(FILES ${USB_RULES_DIR}/95-usb3dscapture.rules DESTINATION .) + install(FILES ${USB_RULES_DIR}/95-usbdscapture.rules DESTINATION .) + install(FILES ${USB_RULES_DIR}/51-isnitro.rules DESTINATION .) + install(FILES ${USB_RULES_DIR}/50-ftd2xx.rules DESTINATION .) + install(FILES ${USB_RULES_DIR}/51-ftd2xx.rules DESTINATION .) + install(FILES ${SETUP_SCRIPTS_DIR}/install_usb_rules${SCRIPT_EXTENSION} DESTINATION .) endif() @@ -533,25 +610,25 @@ set(CPACK_PACKAGE_INSTALL_DIRECTORY ${CPACK_PACKAGE_NAME}) set(CPACK_VERBATIM_VARIABLES TRUE) if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") - set(CPACK_PACKAGE_FILE_NAME ${CPACK_PACKAGE_NAME}_macos) + set(CPACK_PACKAGE_FILE_NAME ${CPACK_PACKAGE_NAME}_macos) elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") if(WINDOWS_ARM64) - set(CPACK_PACKAGE_FILE_NAME ${CPACK_PACKAGE_NAME}_windows_arm64) - elseif(WINDOWS_x86_32) - set(CPACK_PACKAGE_FILE_NAME ${CPACK_PACKAGE_NAME}_windows_x86_32) - else() - set(CPACK_PACKAGE_FILE_NAME ${CPACK_PACKAGE_NAME}_windows_x86_64) - endif() + set(CPACK_PACKAGE_FILE_NAME ${CPACK_PACKAGE_NAME}_windows_arm64) + elseif(WINDOWS_x86_32) + set(CPACK_PACKAGE_FILE_NAME ${CPACK_PACKAGE_NAME}_windows_x86_32) + else() + set(CPACK_PACKAGE_FILE_NAME ${CPACK_PACKAGE_NAME}_windows_x86_64) + endif() else() if(RASPBERRY_PI_COMPILATION) - if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8") - set(CPACK_PACKAGE_FILE_NAME ${CPACK_PACKAGE_NAME}_linux_pi64) - else() - set(CPACK_PACKAGE_FILE_NAME ${CPACK_PACKAGE_NAME}_linux_pi32) - endif() + if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8") + set(CPACK_PACKAGE_FILE_NAME ${CPACK_PACKAGE_NAME}_linux_pi64) + else() + set(CPACK_PACKAGE_FILE_NAME ${CPACK_PACKAGE_NAME}_linux_pi32) + endif() else() - set(CPACK_PACKAGE_FILE_NAME ${CPACK_PACKAGE_NAME}_linux_${CMAKE_SYSTEM_PROCESSOR}) - endif() + set(CPACK_PACKAGE_FILE_NAME ${CPACK_PACKAGE_NAME}_linux_${CMAKE_SYSTEM_PROCESSOR}) + endif() endif() include(CPack) diff --git a/README.md b/README.md index 77c3e0e..3503011 100755 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ IS Nitro Emulator (newer revisions) and IS Nitro Capture support is also present - Make your game run in fullscreen mode. If you own multiple displays, you can even use one per-window. - Many builtin crop options for the screens. - Many other settings, explained in [Controls](#Controls). +- Prebuilt executables available in the [Releases](https://github.com/Lorenzooone/cc3dsfs/releases/latest) page for ease of use. _Note: On 3DS, DS, GBA, GBC and GB games boot in scaled resolution mode by default. Holding START or SELECT while launching these games will boot in native resolution mode._ @@ -23,10 +24,10 @@ 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 four library dependencies: [FTDI's D3XX driver](https://ftdichip.com/drivers/d3xx-drivers/), [FTDI's D2XX driver](https://ftdichip.com/drivers/d2xx-drivers/), [libusb](https://libusb.info/) and [SFML](https://www.sfml-dev.org/). +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/). All of them should get downloaded automatically via CMake during the building process. -Linux users will also need to install the SFML dependencies. Different distributions will require slightly different processes. +Linux users who wish to compile this, will also need to install the SFML dependencies. Different distributions will require slightly different processes. Below, the command for Debian-based distributions, which also lists the required libraries. ``` @@ -135,7 +136,7 @@ On Linux and MacOS, the profiles can be found at the "${HOME}/.config/cc3dsfs" f On Windows, the profiles can be found in the ".config/cc3dsfs" folder inside the directory in which the program runs from. ## Notes -- On Linux, you may need to include the udev USB access rules. You can use the .rules files available in the repository's usb\_rules directory, or define your own. For ease of use, releases come bundled with a script to do it named install\_usb\_rules.sh. It may require elevated permissions to execute properly. +- On Linux, you may need to include the udev USB access rules. You can use the .rules files available in the repository's usb\_rules directory, or define your own. For ease of use, releases come bundled with a script to do it named install\_usb\_rules.sh. It may require elevated permissions to execute properly. You may get a permission error if the rules are not installed. - At startup, the audio may be unstable. It should fix itself, if you give it enough time. - If, at first, the connection to the 3DS/DS fails, reconnect the 3DS/DS and then try again. If that also doesn't work, try restarting the program. If that also doesn't work, try restarting the computer. - USB Hubs can be the cause of connection issues. If you're having problems, try checking whether the 3DS/DS connects fine or not without any other devices connected. diff --git a/include/CaptureDeviceSpecific/DSCapture_FTD2/dscapture_ftd2_compatibility.hpp b/include/CaptureDeviceSpecific/DSCapture_FTD2/dscapture_ftd2_compatibility.hpp new file mode 100644 index 0000000..5c989ba --- /dev/null +++ b/include/CaptureDeviceSpecific/DSCapture_FTD2/dscapture_ftd2_compatibility.hpp @@ -0,0 +1,28 @@ +#ifndef __DSCAPTURE_FTD2_COMPATIBILITY_HPP +#define __DSCAPTURE_FTD2_COMPATIBILITY_HPP + +#include "devicecapture.hpp" + +void list_devices_ftd2_compatibility(std::vector &devices_list, std::vector &no_access_list); +void ftd2_capture_main_loop(CaptureData* capture_data); +int ftd2_get_queue_status(void* handle, bool is_libftdi, size_t* bytes_in); +bool ftd2_is_error(int value, bool is_libftdi); +int ftd2_write(void* handle, bool is_libftdi, const uint8_t* data, size_t size, size_t *sent); +int ftd2_read(void* handle, bool is_libftdi, uint8_t* data, size_t size, size_t *bytesIn); +int ftd2_set_timeouts(void* handle, bool is_libftdi, int timeout_read, int timeout_write); +int ftd2_reset_device(void* handle, bool is_libftdi); +int ftd2_set_usb_parameters(void* handle, bool is_libftdi, size_t size_in, size_t size_out); +int ftd2_set_chars(void* handle, bool is_libftdi, unsigned char eventch, unsigned char event_enable, unsigned char errorch, unsigned char error_enable); +int ftd2_set_latency_timer(void* handle, bool is_libftdi, unsigned char latency); +int ftd2_set_flow_ctrl_rts_cts(void* handle, bool is_libftdi); +int ftd2_reset_bitmode(void* handle, bool is_libftdi); +int ftd2_set_mpsse_bitmode(void* handle, bool is_libftdi); +int ftd2_set_fifo_bitmode(void* handle, bool is_libftdi); +int ftd2_purge_all(void* handle, bool is_libftdi); +int ftd2_read_ee(void* handle, bool is_libftdi, int eeprom_addr, int *eeprom_val); +int ftd2_close(void* handle, bool is_libftdi); +int ftd2_open(CaptureDevice* device, void** handle, bool is_libftdi); +void ftd2_init(); +void ftd2_end(); + +#endif diff --git a/include/CaptureDeviceSpecific/DSCapture_FTD2/dscapture_ftd2_driver.hpp b/include/CaptureDeviceSpecific/DSCapture_FTD2/dscapture_ftd2_driver.hpp new file mode 100644 index 0000000..f01f8ea --- /dev/null +++ b/include/CaptureDeviceSpecific/DSCapture_FTD2/dscapture_ftd2_driver.hpp @@ -0,0 +1,17 @@ +#ifndef __DSCAPTURE_FTD2_DRIVER_HPP +#define __DSCAPTURE_FTD2_DRIVER_HPP + +#include +#include "utils.hpp" +#include "hw_defs.hpp" +#include "capture_structs.hpp" +#include "display_structs.hpp" +#include "devicecapture.hpp" + +#define FTD2_OLDDS_SYNCH_VALUES 0x4321 + +void list_devices_ftd2_driver(std::vector &devices_list, std::vector &no_access_list); +int ftd2_driver_open_serial(CaptureDevice* device, void** handle); +void ftd2_capture_main_loop_driver(CaptureData* capture_data); + +#endif diff --git a/include/CaptureDeviceSpecific/DSCapture_FTD2/dscapture_ftd2_general.hpp b/include/CaptureDeviceSpecific/DSCapture_FTD2/dscapture_ftd2_general.hpp new file mode 100644 index 0000000..421f65d --- /dev/null +++ b/include/CaptureDeviceSpecific/DSCapture_FTD2/dscapture_ftd2_general.hpp @@ -0,0 +1,52 @@ +#ifndef __DSCAPTURE_FTD2_GENERAL_HPP +#define __DSCAPTURE_FTD2_GENERAL_HPP + +#include "utils.hpp" +#include "capture_structs.hpp" +#include "display_structs.hpp" + +#include + +// Sometimes the CC returns a 2 length packet, if you're too fast +#define BASE_NUM_CAPTURE_RECEIVED_DATA_BUFFERS 4 +#define NUM_CAPTURE_RECEIVED_DATA_0_MULTIPLIER 2 +#define NUM_CAPTURE_RECEIVED_DATA_BUFFERS (BASE_NUM_CAPTURE_RECEIVED_DATA_BUFFERS * NUM_CAPTURE_RECEIVED_DATA_0_MULTIPLIER) + +typedef void (*fdt2_async_callback_function)(void* user_data, int transfer_length, int transfer_status); + +struct ftd2_async_callback_data { + FTD2OldDSCaptureReceivedRaw buffer_raw; + fdt2_async_callback_function function; + void* actual_user_data; + void* transfer_data; + void* handle; + std::mutex transfer_data_access; + SharedConsumerMutex* is_transfer_done_mutex; + size_t requested_length; + int internal_index; +}; + +struct FTD2CaptureReceivedData { + size_t actual_length; + volatile bool in_use; + volatile bool is_data_ready; + SharedConsumerMutex* is_buffer_free_shared_mutex; + int* status; + uint32_t index; + uint32_t* last_used_index; + size_t* curr_offset; + CaptureData* capture_data; + std::chrono::time_point* clock_start; + ftd2_async_callback_data cb_data; +}; + +int get_num_ftd2_device_types(); +const std::string get_ftd2_fw_desc(int index); +const int get_ftd2_fw_index(int index); +uint64_t get_max_samples(bool is_rgb888); +uint64_t get_capture_size(bool is_rgb888); +size_t remove_synch_from_final_length(uint32_t* out_buffer, size_t real_length); +bool enable_capture(void* handle, bool is_libftdi); +bool synchronization_check(uint16_t* data_buffer, size_t size, uint16_t* next_data_buffer, size_t* next_size, bool special_check = false); + +#endif diff --git a/include/CaptureDeviceSpecific/DSCapture_FTD2/dscapture_ftd2_shared.hpp b/include/CaptureDeviceSpecific/DSCapture_FTD2/dscapture_ftd2_shared.hpp new file mode 100644 index 0000000..62dc7fc --- /dev/null +++ b/include/CaptureDeviceSpecific/DSCapture_FTD2/dscapture_ftd2_shared.hpp @@ -0,0 +1,21 @@ +#ifndef __DSCAPTURE_FTD2_SHARED_HPP +#define __DSCAPTURE_FTD2_SHARED_HPP + +#include +#include "utils.hpp" +#include "hw_defs.hpp" +#include "capture_structs.hpp" +#include "display_structs.hpp" +#include "devicecapture.hpp" + +#define FTD2_OLDDS_SYNCH_VALUES 0x4321 + +void list_devices_ftd2_shared(std::vector &devices_list, std::vector &no_access_list); +bool connect_ftd2_shared(bool print_failed, CaptureData* capture_data, CaptureDevice* device); +void ftd2_capture_main_loop_shared(CaptureData* capture_data); +void ftd2_capture_cleanup_shared(CaptureData* capture_data); +uint64_t ftd2_get_video_in_size(CaptureData* capture_data); +void ftd2_init_shared(); +void ftd2_end_shared(); + +#endif diff --git a/include/CaptureDeviceSpecific/DSCapture_FTD2/dscapture_libftdi2.hpp b/include/CaptureDeviceSpecific/DSCapture_FTD2/dscapture_libftdi2.hpp new file mode 100644 index 0000000..896632d --- /dev/null +++ b/include/CaptureDeviceSpecific/DSCapture_FTD2/dscapture_libftdi2.hpp @@ -0,0 +1,27 @@ +#ifndef __DSCAPTURE_LIBFTDI2_HPP +#define __DSCAPTURE_LIBFTDI2_HPP + +#include "dscapture_ftd2_shared.hpp" +#include "capture_structs.hpp" + +void libftdi_init(); +void libftdi_end(); + +void list_devices_libftdi(std::vector &devices_list, std::vector &no_access_list); +void ftd2_capture_main_loop_libftdi(CaptureData* capture_data); +int libftdi_reset(void* handle); +int libftdi_set_latency_timer(void* handle, unsigned char latency); +int libftdi_setflowctrl(void* handle, int flowctrl, unsigned char xon, unsigned char xoff); +int libftdi_set_bitmode(void* handle, unsigned char bitmask, unsigned char mode); +int libftdi_purge(void* handle, bool do_read, bool do_write); +int libftdi_read_eeprom(void* handle, int eeprom_addr, int *eeprom_val); +int libftdi_set_chars(void* handle, unsigned char eventch, unsigned char event_enable, unsigned char errorch, unsigned char error_enable); +int libftdi_set_usb_chunksizes(void* handle, unsigned int chunksize_in, unsigned int chunksize_out); +void libftdi_set_timeouts(void* handle, int timeout_in_ms, int timeout_out_ms); +int libftdi_write(void* handle, const uint8_t* data, size_t size, size_t* bytesOut); +int libftdi_read(void* handle, uint8_t* data, size_t size, size_t* bytesIn); +int get_libftdi_read_queue_size(void* handle, size_t* bytesIn); +int libftdi_open_serial(CaptureDevice* device, void** handle); +int libftdi_close(void* handle); + +#endif diff --git a/include/CaptureDeviceSpecific/ISNitro/usb_is_nitro_communications.hpp b/include/CaptureDeviceSpecific/ISNitro/usb_is_nitro_communications.hpp index 747bb06..d5b4468 100644 --- a/include/CaptureDeviceSpecific/ISNitro/usb_is_nitro_communications.hpp +++ b/include/CaptureDeviceSpecific/ISNitro/usb_is_nitro_communications.hpp @@ -47,6 +47,7 @@ struct isn_async_callback_data { struct is_nitro_usb_device { std::string name; + std::string long_name; int vid; int pid; int default_config; diff --git a/include/CaptureDeviceSpecific/dscapture_ftd2.hpp b/include/CaptureDeviceSpecific/dscapture_ftd2.hpp deleted file mode 100644 index 7405c29..0000000 --- a/include/CaptureDeviceSpecific/dscapture_ftd2.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef __DSCAPTURE_FTD2_HPP -#define __DSCAPTURE_FTD2_HPP - -#include -#include "utils.hpp" -#include "hw_defs.hpp" -#include "capture_structs.hpp" -#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); -void ftd2_capture_cleanup(CaptureData* capture_data); -uint64_t ftd2_get_video_in_size(CaptureData* capture_data); - -#endif diff --git a/include/capture_structs.hpp b/include/capture_structs.hpp index 3455be3..2e18be5 100755 --- a/include/capture_structs.hpp +++ b/include/capture_structs.hpp @@ -13,9 +13,13 @@ #define FIX_PARTIAL_FIRST_FRAME_NUM 3 -#define EXTRA_DATA_BUFFER_USB_SIZE (1 << 9) +#define MAX_PACKET_SIZE_USB2 (1 << 9) +#define EXTRA_DATA_BUFFER_USB_SIZE MAX_PACKET_SIZE_USB2 #define EXTRA_DATA_BUFFER_FTD3XX_SIZE (1 << 10) +#define FTD2_INTRA_PACKET_HEADER_SIZE 2 +#define MAX_PACKET_SIZE_FTD2 (MAX_PACKET_SIZE_USB2 - FTD2_INTRA_PACKET_HEADER_SIZE) + enum CaptureConnectionType { CAPTURE_CONN_FTD3, CAPTURE_CONN_USB, CAPTURE_CONN_FTD2, CAPTURE_CONN_IS_NITRO }; enum InputVideoDataType { VIDEO_DATA_RGB, VIDEO_DATA_BGR, VIDEO_DATA_RGB16, VIDEO_DATA_BGR16 }; enum CaptureScreensType { CAPTURE_SCREENS_BOTH, CAPTURE_SCREENS_TOP, CAPTURE_SCREENS_BOTTOM, CAPTURE_SCREENS_ENUM_END }; @@ -100,6 +104,11 @@ struct ALIGNED(16) PACKED FTD2OldDSCaptureReceived { uint8_t unused_buffer[EXTRA_DATA_BUFFER_USB_SIZE]; }; +struct ALIGNED(16) PACKED FTD2OldDSCaptureReceivedRaw { + FTD2OldDSCaptureReceived data; + uint8_t extra_ftd2_buffer[((sizeof(FTD2OldDSCaptureReceived) + MAX_PACKET_SIZE_FTD2 - 1) / MAX_PACKET_SIZE_FTD2) * FTD2_INTRA_PACKET_HEADER_SIZE]; +}; + struct ALIGNED(16) PACKED ISNitroCaptureReceived { ISNitroEmulatorVideoInputData video_in; }; @@ -113,17 +122,21 @@ union CaptureReceived { USB3DSCaptureReceived_3D usb_received_3ds_3d; USBOldDSCaptureReceived usb_received_old_ds; FTD2OldDSCaptureReceived ftd2_received_old_ds; + FTD2OldDSCaptureReceivedRaw ftd2_received_old_ds_raw; 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), 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) {} + 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), long_name(name) {} + CaptureDevice(std::string serial_number, std::string name, std::string long_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), long_name(long_name) {} + CaptureDevice(std::string serial_number, std::string name, std::string long_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), long_name(name) {} + CaptureDevice(std::string serial_number, std::string name, std::string long_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, 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(path), video_data_type(video_data_type), firmware_id(firmware_id), is_rgb_888(is_rgb_888), long_name(long_name) {} + CaptureDevice(std::string serial_number, std::string name, std::string long_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), long_name(long_name) {} + 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), long_name("") {} std::string serial_number; std::string name; + std::string long_name; std::string path; CaptureConnectionType cc_type; InputVideoDataType video_data_type; @@ -166,6 +179,7 @@ struct CaptureDataSingleBuffer { uint64_t read; CaptureReceived capture_buf; double time_in_buf; + uint32_t inner_index; }; class CaptureDataBuffers { @@ -174,7 +188,10 @@ public: CaptureDataSingleBuffer* GetReaderBuffer(CaptureReaderType reader_type); void ReleaseReaderBuffer(CaptureReaderType reader_type); void WriteToBuffer(CaptureReceived* buffer, uint64_t read, double time_in_buf, CaptureDevice* device, CaptureScreensType capture_type = CAPTURE_SCREENS_BOTH); + CaptureDataSingleBuffer* GetWriterBuffer(); + void ReleaseWriterBuffer(); private: + uint32_t inner_index = 0; std::mutex access_mutex; int last_curr_in; int curr_writer_pos; @@ -182,9 +199,6 @@ private: int num_readers[NUM_CONCURRENT_DATA_BUFFERS]; bool has_read_data[NUM_CONCURRENT_DATA_BUFFERS][NUM_CONCURRENT_DATA_BUFFER_READERS]; CaptureDataSingleBuffer buffers[NUM_CONCURRENT_DATA_BUFFERS]; - - CaptureDataSingleBuffer* GetWriterBuffer(); - void ReleaseWriterBuffer(); }; struct CaptureData { diff --git a/include/conversions.hpp b/include/conversions.hpp index f3f622b..9555f77 100755 --- a/include/conversions.hpp +++ b/include/conversions.hpp @@ -5,5 +5,5 @@ #include "display_structs.hpp" bool convertVideoToOutput(VideoOutputData *p_out, const bool is_big_endian, CaptureDataSingleBuffer* data_buffer, CaptureStatus* status); -bool convertAudioToOutput(std::int16_t *p_out, uint64_t n_samples, const bool is_big_endian, CaptureDataSingleBuffer* data_buffer, CaptureStatus* status); +bool convertAudioToOutput(std::int16_t *p_out, uint64_t &n_samples, const bool is_big_endian, CaptureDataSingleBuffer* data_buffer, CaptureStatus* status); #endif diff --git a/include/devicecapture.hpp b/include/devicecapture.hpp index 4a3bb67..9f3577e 100755 --- a/include/devicecapture.hpp +++ b/include/devicecapture.hpp @@ -23,5 +23,5 @@ void capture_error_print(bool print_failed, CaptureData* capture_data, std::stri void capture_error_print(bool print_failed, CaptureData* capture_data, std::string graphical_string, std::string detailed_string); uint64_t get_audio_n_samples(CaptureData* capture_data, uint64_t read); uint64_t get_video_in_size(CaptureData* capture_data); -std::string get_name_of_device(CaptureStatus* capture_status); +std::string get_name_of_device(CaptureStatus* capture_status, bool use_long = false); #endif diff --git a/other licenses/libftdi.txt b/other licenses/libftdi.txt new file mode 100644 index 0000000..1c5430a --- /dev/null +++ b/other licenses/libftdi.txt @@ -0,0 +1,26 @@ +The C library "libftdi1" is distributed under the +GNU Library General Public License version 2. + +A copy of the GNU Library General Public License (LGPL) is included +in this distribution, in the file COPYING.LIB. + +---------------------------------------------------------------------- + +The C++ wrapper "ftdipp1" is distributed under the GNU General +Public License version 2 (with a special exception described below). + +A copy of the GNU General Public License (GPL) is included +in this distribution, in the file COPYING.GPL. + +As a special exception, if other files instantiate templates or use macros +or inline functions from this file, or you compile this file and link it +with other works to produce a work based on this file, this file +does not by itself cause the resulting work to be covered +by the GNU General Public License. + +However the source code for this file must still be made available +in accordance with section (3) of the GNU General Public License. + +This exception does not invalidate any other reasons why a work based +on this file might be covered by the GNU General Public License. + diff --git a/setup_scripts/ftd_shared_symbols_macos.txt b/setup_scripts/ftd_shared_symbols_macos.txt new file mode 100644 index 0000000..fd0edeb --- /dev/null +++ b/setup_scripts/ftd_shared_symbols_macos.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/ftd_shared_symbols_special_windows.txt b/setup_scripts/ftd_shared_symbols_special_windows.txt new file mode 100644 index 0000000..9aad04e --- /dev/null +++ b/setup_scripts/ftd_shared_symbols_special_windows.txt @@ -0,0 +1,15 @@ +?AddDevice@@YAPEAUft_private_vars@@XZ +?CreateDeviceInfoList@@YAKPEAK@Z +?FT_GetPacketSize@@YAKPEAXPEAG@Z +?FindDevice@@YAPEAUft_private_vars@@K@Z +?IsDeviceValid@@YAEPEAUft_private_vars@@@Z +?RemoveDevice@@YAKPEAUft_private_vars@@@Z +?ResetAttachedList@@YAKXZ +?dwNumberOfAttachedDevices@@3KA +?ghFtOpenLock@@3PEAXEA +?ghFtDevListLock@@3PEAXEA +?gCS@@3U_RTL_CRITICAL_SECTION@@A +?gInitialised@@3HA +?pgDeviceList@@3PEAUft_private_vars@@EA +?Set1Ioctls@@3PAKA +?Set2Ioctls@@3PAKA diff --git a/setup_scripts/ftd_shared_symbols_special_windows32.txt b/setup_scripts/ftd_shared_symbols_special_windows32.txt new file mode 100644 index 0000000..2bbb37b --- /dev/null +++ b/setup_scripts/ftd_shared_symbols_special_windows32.txt @@ -0,0 +1,15 @@ +?AddDevice@@YAPAUft_private_vars@@XZ +?CreateDeviceInfoList@@YAKPAK@Z +?FT_GetPacketSize@@YAKPAXPAG@Z +?FindDevice@@YAPAUft_private_vars@@K@Z +?IsDeviceValid@@YAEPAUft_private_vars@@@Z +?RemoveDevice@@YAKPAUft_private_vars@@@Z +?ghFtOpenLock@@3PAXA +?ghFtDevListLock@@3PAXA +?pgDeviceList@@3PAUft_private_vars@@A +?ResetAttachedList@@YAKXZ +?dwNumberOfAttachedDevices@@3KA +?gCS@@3U_RTL_CRITICAL_SECTION@@A +?gInitialised@@3HA +?Set1Ioctls@@3PAKA +?Set2Ioctls@@3PAKA diff --git a/setup_scripts/libusb_ftd2_shared_symbols.txt b/setup_scripts/libusb_ftd2_shared_symbols.txt deleted file mode 100644 index 89f7cd2..0000000 --- a/setup_scripts/libusb_ftd2_shared_symbols.txt +++ /dev/null @@ -1,69 +0,0 @@ -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 deleted file mode 100644 index e69de29..0000000 diff --git a/shaders/bit_crusher_fragment_shader.2_to_x_1_7.frag b/shaders/bit_crusher_fragment_shader.2_to_x_1_7.frag index 52adb15..b6cf75d 100644 --- a/shaders/bit_crusher_fragment_shader.2_to_x_1_7.frag +++ b/shaders/bit_crusher_fragment_shader.2_to_x_1_7.frag @@ -6,4 +6,4 @@ const float normalizer = inner_divisor * (255.0 / (256.0 - inner_divisor)) / 255 void main() { gl_FragColor = clamp(floor(texture2D(Texture0, gl_TexCoord[0].xy) * bit_crusher) * normalizer, 0.0, 1.0); -}; +} diff --git a/shaders/bit_merger_crusher_fragment_shader.2_to_x_1_6.frag b/shaders/bit_merger_crusher_fragment_shader.2_to_x_1_6.frag index 598e8d9..59f5178 100644 --- a/shaders/bit_merger_crusher_fragment_shader.2_to_x_1_6.frag +++ b/shaders/bit_merger_crusher_fragment_shader.2_to_x_1_6.frag @@ -16,4 +16,4 @@ void main() { vec4 actual_nth_bit_component = get_nth_bit_component(gl_FragColor); vec4 old_nth_bit_component = get_nth_bit_component(OldFragColor); gl_FragColor = clamp((((floor(gl_FragColor * bit_crusher_greater) * inner_divisor_greater) + ((actual_nth_bit_component + old_nth_bit_component) / 2.0)) / inner_divisor) * normalizer, 0.0, 1.0); -}; +} diff --git a/shaders/bit_merger_crusher_fragment_shader_7.frag b/shaders/bit_merger_crusher_fragment_shader_7.frag index e6a9a3c..fbb457c 100644 --- a/shaders/bit_merger_crusher_fragment_shader_7.frag +++ b/shaders/bit_merger_crusher_fragment_shader_7.frag @@ -14,4 +14,4 @@ void main() { vec4 actual_nth_bit_component = get_nth_bit_component(gl_FragColor); vec4 old_nth_bit_component = get_nth_bit_component(OldFragColor); gl_FragColor = clamp(((((actual_nth_bit_component + old_nth_bit_component) / 2.0)) / inner_divisor) * normalizer, 0.0, 1.0); -}; +} diff --git a/shaders/bit_merger_fragment_shader.2_to_x_0_6.frag b/shaders/bit_merger_fragment_shader.2_to_x_0_6.frag index f28fbb1..5f3c902 100644 --- a/shaders/bit_merger_fragment_shader.2_to_x_0_6.frag +++ b/shaders/bit_merger_fragment_shader.2_to_x_0_6.frag @@ -16,4 +16,4 @@ void main() { vec4 actual_nth_bit_component = get_nth_bit_component(gl_FragColor); vec4 old_nth_bit_component = get_nth_bit_component(OldFragColor); gl_FragColor = clamp((floor(gl_FragColor * 255.0) - actual_nth_bit_component + ((actual_nth_bit_component + old_nth_bit_component) / 2.0)) / 255.0, 0.0, 1.0); -}; +} diff --git a/shaders/bit_merger_fragment_shader_7.frag b/shaders/bit_merger_fragment_shader_7.frag index 7485524..f551ade 100644 --- a/shaders/bit_merger_fragment_shader_7.frag +++ b/shaders/bit_merger_fragment_shader_7.frag @@ -13,4 +13,4 @@ void main() { vec4 actual_nth_bit_component = get_nth_bit_component(gl_FragColor); vec4 old_nth_bit_component = get_nth_bit_component(OldFragColor); gl_FragColor = clamp((floor(gl_FragColor * 255.0) - actual_nth_bit_component + ((actual_nth_bit_component + old_nth_bit_component) / 2.0)) / 255.0, 0.0, 1.0); -}; +} diff --git a/shaders/frame_blending_bit_crusher_fragment_shader.2_to_x_1_7.frag b/shaders/frame_blending_bit_crusher_fragment_shader.2_to_x_1_7.frag index 5bec6b1..4f9b3fd 100644 --- a/shaders/frame_blending_bit_crusher_fragment_shader.2_to_x_1_7.frag +++ b/shaders/frame_blending_bit_crusher_fragment_shader.2_to_x_1_7.frag @@ -11,4 +11,4 @@ void main() { vec4 OldFragColor = texture2D(Texture0, gl_TexCoord[0].xy + old_frame_offset); OldFragColor = clamp(floor(OldFragColor * bit_crusher) * normalizer, 0.0, 1.0); gl_FragColor = (gl_FragColor + OldFragColor) / 2.0; -}; +} diff --git a/shaders/frame_blending_fragment_shader.frag b/shaders/frame_blending_fragment_shader.frag index 7c16461..9499713 100644 --- a/shaders/frame_blending_fragment_shader.frag +++ b/shaders/frame_blending_fragment_shader.frag @@ -5,4 +5,4 @@ void main() { gl_FragColor = texture2D(Texture0, gl_TexCoord[0].xy); vec4 OldFragColor = texture2D(Texture0, gl_TexCoord[0].xy + old_frame_offset); gl_FragColor = (gl_FragColor + OldFragColor) / 2.0; -}; +} diff --git a/shaders/no_effect_fragment_shader.frag b/shaders/no_effect_fragment_shader.frag index e9b320d..d62299e 100644 --- a/shaders/no_effect_fragment_shader.frag +++ b/shaders/no_effect_fragment_shader.frag @@ -2,4 +2,4 @@ uniform sampler2D Texture0; void main() { gl_FragColor = texture2D(Texture0, gl_TexCoord[0].xy); -}; +} diff --git a/source/CaptureDataBuffers.cpp b/source/CaptureDataBuffers.cpp index 42b8c09..6b244c7 100644 --- a/source/CaptureDataBuffers.cpp +++ b/source/CaptureDataBuffers.cpp @@ -71,6 +71,7 @@ void CaptureDataBuffers::ReleaseReaderBuffer(CaptureReaderType reader_type) { void CaptureDataBuffers::ReleaseWriterBuffer() { access_mutex.lock(); if(curr_writer_pos != -1) { + buffers[curr_writer_pos].inner_index = inner_index++; last_curr_in = curr_writer_pos; curr_writer_pos = -1; } diff --git a/source/CaptureDeviceSpecific/3dscapture_ftd3.cpp b/source/CaptureDeviceSpecific/3dscapture_ftd3.cpp index 45584db..d2b6b0d 100644 --- a/source/CaptureDeviceSpecific/3dscapture_ftd3.cpp +++ b/source/CaptureDeviceSpecific/3dscapture_ftd3.cpp @@ -9,7 +9,7 @@ #define FT_ASYNC_CALL FT_ReadPipeAsync #endif #include -#if defined(USE_IS_NITRO_USB) || defined(USE_DS_3DS_USB) +#ifdef USE_LIBUSB #include "usb_generic.hpp" #endif @@ -122,7 +122,7 @@ void list_devices_ftd3(std::vector &devices_list, std::vector +#endif +#ifdef USE_FTD2_DRIVER +#define FTD2XX_STATIC +#include "ftd2xx_symbols_renames.h" +#include +#endif + +#include +#include +#include +#include + +#define FT_FAILED(x) ((x) != FT_OK) + +void list_devices_ftd2_compatibility(std::vector &devices_list, std::vector &no_access_list) { + #ifdef USE_FTD2_DRIVER + list_devices_ftd2_driver(devices_list, no_access_list); + #endif + #ifdef USE_FTD2_LIBFTDI + list_devices_libftdi(devices_list, no_access_list); + #endif +} + +void ftd2_capture_main_loop(CaptureData* capture_data) { + bool is_libftdi = capture_data->status.device.descriptor != NULL; + #ifdef USE_FTD2_DRIVER + if(!is_libftdi) + return ftd2_capture_main_loop_driver(capture_data); + #endif + #ifdef USE_FTD2_LIBFTDI + return ftd2_capture_main_loop_libftdi(capture_data); + #endif +} + +int ftd2_get_queue_status(void* handle, bool is_libftdi, size_t* bytes_in) { + #ifdef USE_FTD2_DRIVER + if(!is_libftdi) { + DWORD bytesIn = 0; + FT_STATUS ftStatus = FT_GetQueueStatus(handle, &bytesIn); + *bytes_in = bytesIn; + return ftStatus; + } + #endif + #ifdef USE_FTD2_LIBFTDI + return get_libftdi_read_queue_size(handle, bytes_in); + #else + return FT_OK; + #endif +} + +bool ftd2_is_error(int value, bool is_libftdi) { + #ifdef USE_FTD2_DRIVER + if(!is_libftdi) + return FT_FAILED(value); + #endif + #ifdef USE_FTD2_LIBFTDI + return value < 0; + #else + return FT_OK; + #endif +} + +int ftd2_write(void* handle, bool is_libftdi, const uint8_t* data, size_t size, size_t *sent) { + #ifdef USE_FTD2_DRIVER + if(!is_libftdi) { + DWORD inner_sent = 0; + FT_STATUS ftStatus = FT_Write(handle, (void*)data, size, &inner_sent); + *sent = inner_sent; + return ftStatus; + } + #endif + #ifdef USE_FTD2_LIBFTDI + return libftdi_write(handle, data, size, sent); + #else + return FT_OK; + #endif +} + +int ftd2_read(void* handle, bool is_libftdi, uint8_t* data, size_t size, size_t *bytesIn) { + #ifdef USE_FTD2_DRIVER + if(!is_libftdi) { + DWORD inner_bytes_in = 0; + FT_STATUS ftStatus = FT_Read(handle, (void*)data, size, &inner_bytes_in); + *bytesIn = inner_bytes_in; + return ftStatus; + } + #endif + #ifdef USE_FTD2_LIBFTDI + return libftdi_read(handle, data, size, bytesIn); + #else + return FT_OK; + #endif +} + +int ftd2_set_timeouts(void* handle, bool is_libftdi, int timeout_read, int timeout_write) { + #ifdef USE_FTD2_DRIVER + if(!is_libftdi) + return FT_SetTimeouts(handle, timeout_read, timeout_write); + #endif + #ifdef USE_FTD2_LIBFTDI + libftdi_set_timeouts(handle, timeout_read, timeout_write); + return 0; + #else + return FT_OK; + #endif +} + +int ftd2_reset_device(void* handle, bool is_libftdi) { + #ifdef USE_FTD2_DRIVER + if(!is_libftdi) + return FT_ResetDevice(handle); + #endif + #ifdef USE_FTD2_LIBFTDI + return libftdi_reset(handle); + #else + return FT_OK; + #endif +} + +int ftd2_set_usb_parameters(void* handle, bool is_libftdi, size_t size_in, size_t size_out) { + #ifdef USE_FTD2_DRIVER + if(!is_libftdi) + return FT_SetUSBParameters(handle, size_in, size_out); + #endif + #ifdef USE_FTD2_LIBFTDI + return libftdi_set_usb_chunksizes(handle, size_in, size_out); + #else + return FT_OK; + #endif +} + +int ftd2_set_chars(void* handle, bool is_libftdi, unsigned char eventch, unsigned char event_enable, unsigned char errorch, unsigned char error_enable) { + #ifdef USE_FTD2_DRIVER + if(!is_libftdi) + return FT_SetChars(handle, eventch, event_enable, errorch, error_enable); + #endif + #ifdef USE_FTD2_LIBFTDI + return libftdi_set_chars(handle, eventch, event_enable, errorch, error_enable); + #else + return FT_OK; + #endif +} + +int ftd2_set_latency_timer(void* handle, bool is_libftdi, unsigned char latency) { + #ifdef USE_FTD2_DRIVER + if(!is_libftdi) + return FT_SetLatencyTimer(handle, latency); + #endif + #ifdef USE_FTD2_LIBFTDI + return libftdi_set_latency_timer(handle, latency); + #else + return FT_OK; + #endif +} + +int ftd2_set_flow_ctrl_rts_cts(void* handle, bool is_libftdi) { + #ifdef USE_FTD2_DRIVER + if(!is_libftdi) + return FT_SetFlowControl(handle, FT_FLOW_RTS_CTS, 0, 0); + #endif + #ifdef USE_FTD2_LIBFTDI + return libftdi_setflowctrl(handle, SIO_RTS_CTS_HS, 0, 0); + #else + return FT_OK; + #endif +} + +int ftd2_reset_bitmode(void* handle, bool is_libftdi) { + #ifdef USE_FTD2_DRIVER + if(!is_libftdi) + return FT_SetBitMode(handle, 0x00, FT_BITMODE_RESET); + #endif + #ifdef USE_FTD2_LIBFTDI + return libftdi_set_bitmode(handle, 0x00, BITMODE_RESET); + #else + return FT_OK; + #endif +} + +int ftd2_set_mpsse_bitmode(void* handle, bool is_libftdi) { + #ifdef USE_FTD2_DRIVER + if(!is_libftdi) + return FT_SetBitMode(handle, 0x00, FT_BITMODE_MPSSE); + #endif + #ifdef USE_FTD2_LIBFTDI + return libftdi_set_bitmode(handle, 0x00, BITMODE_MPSSE); + #else + return FT_OK; + #endif +} + +int ftd2_set_fifo_bitmode(void* handle, bool is_libftdi) { + #ifdef USE_FTD2_DRIVER + if(!is_libftdi) + return FT_SetBitMode(handle, 0x00, FT_BITMODE_SYNC_FIFO); + #endif + #ifdef USE_FTD2_LIBFTDI + return libftdi_set_bitmode(handle, 0x00, BITMODE_SYNCFF); + #else + return FT_OK; + #endif +} + +int ftd2_purge_all(void* handle, bool is_libftdi) { + #ifdef USE_FTD2_DRIVER + if(!is_libftdi) + return FT_Purge(handle, FT_PURGE_RX | FT_PURGE_TX); + #endif + #ifdef USE_FTD2_LIBFTDI + return libftdi_purge(handle, true, true); + #else + return FT_OK; + #endif +} + +int ftd2_read_ee(void* handle, bool is_libftdi, int eeprom_addr, int *eeprom_val) { + #ifdef USE_FTD2_DRIVER + if(!is_libftdi) { + WORD val = 0; + int retval = FT_ReadEE(handle, eeprom_addr, &val); + *eeprom_val = val; + return retval; + } + #endif + #ifdef USE_FTD2_LIBFTDI + return libftdi_read_eeprom(handle, eeprom_addr, eeprom_val); + #else + return FT_OK; + #endif +} + +int ftd2_close(void* handle, bool is_libftdi) { + #ifdef USE_FTD2_DRIVER + if(!is_libftdi) + return FT_Close(handle); + #endif + #ifdef USE_FTD2_LIBFTDI + return libftdi_close(handle); + #else + return FT_OK; + #endif +} + +int ftd2_open(CaptureDevice* device, void** handle, bool is_libftdi) { + #ifdef USE_FTD2_DRIVER + if(!is_libftdi) + return ftd2_driver_open_serial(device, handle); + #endif + #ifdef USE_FTD2_LIBFTDI + return libftdi_open_serial(device, handle); + #else + return FT_OTHER_ERROR; + #endif +} + +void ftd2_init() { + #ifdef USE_FTD2_LIBFTDI + libftdi_init(); + #endif +} + +void ftd2_end() { + #ifdef USE_FTD2_LIBFTDI + libftdi_end(); + #endif +} diff --git a/source/CaptureDeviceSpecific/DSCapture_FTD2/dscapture_ftd2_driver.cpp b/source/CaptureDeviceSpecific/DSCapture_FTD2/dscapture_ftd2_driver.cpp new file mode 100644 index 0000000..1a62c2a --- /dev/null +++ b/source/CaptureDeviceSpecific/DSCapture_FTD2/dscapture_ftd2_driver.cpp @@ -0,0 +1,110 @@ +#include "dscapture_ftd2_driver.hpp" +#include "devicecapture.hpp" +#include "usb_generic.hpp" +#include "dscapture_ftd2_general.hpp" +#include "dscapture_ftd2_compatibility.hpp" + +#include "ftd2xx_symbols_renames.h" +#define FTD2XX_STATIC +#include + +#include +#include +#include +#include + +#define FT_FAILED(x) ((x) != FT_OK) + +#define REAL_SERIAL_NUMBER_SIZE 16 +#define SERIAL_NUMBER_SIZE (REAL_SERIAL_NUMBER_SIZE+1) + +#define ENABLE_AUDIO true + +// Code based on sample provided by Loopy. + +void list_devices_ftd2_driver(std::vector &devices_list, std::vector &no_access_list) { + FT_STATUS ftStatus; + DWORD numDevs = 0; + 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 < get_num_ftd2_device_types(); j++) { + if(Description == get_ftd2_fw_desc(j)) { + for(int u = 0; u < debug_multiplier; u++) + devices_list.emplace_back(std::string(SerialNumber), "DS.2", "DS.2.d565", CAPTURE_CONN_FTD2, (void*)NULL, false, false, ENABLE_AUDIO, WIDTH_DS, HEIGHT_DS + HEIGHT_DS, get_max_samples(false), 0, 0, 0, 0, HEIGHT_DS, VIDEO_DATA_RGB16, get_ftd2_fw_index(j), false); + break; + } + } + } + } + } +} + +int ftd2_driver_open_serial(CaptureDevice* device, void** handle) { + char SerialNumber[SERIAL_NUMBER_SIZE] = { 0 }; + strncpy(SerialNumber, device->serial_number.c_str(), SERIAL_NUMBER_SIZE); + SerialNumber[REAL_SERIAL_NUMBER_SIZE] = 0; + return FT_OpenEx(SerialNumber, FT_OPEN_BY_SERIAL_NUMBER, handle); +} + +static 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, remove_synch_from_final_length((uint32_t*)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_driver(CaptureData* capture_data) { + bool is_libftdi = false; + // Separate Capture Enable and put it here, for better control + if(!enable_capture(capture_data->handle, is_libftdi)) { + capture_error_print(true, capture_data, "Capture enable error"); + return; + } + int inner_curr_in = 0; + int retval = 0; + auto clock_start = std::chrono::high_resolution_clock::now(); + CaptureReceived* data_buffer = new CaptureReceived[NUM_CAPTURE_RECEIVED_DATA_BUFFERS]; + int curr_data_buffer = 0; + int next_data_buffer = 0; + const size_t full_size = get_capture_size(capture_data->status.device.is_rgb_888); + size_t next_size = full_size; + size_t bytesIn; + + while (capture_data->status.connected && capture_data->status.running) { + curr_data_buffer = next_data_buffer; + retval = ftd2_read(capture_data->handle, is_libftdi, ((uint8_t*)(&data_buffer[curr_data_buffer]) + (full_size - next_size)), next_size, &bytesIn); + if(ftd2_is_error(retval, is_libftdi)) { + capture_error_print(true, capture_data, "Disconnected: Read failed"); + break; + } + if(bytesIn < next_size) + continue; + next_data_buffer = (curr_data_buffer + 1) % NUM_CAPTURE_RECEIVED_DATA_BUFFERS; + bool has_synch_failed = !synchronization_check((uint16_t*)(&data_buffer[curr_data_buffer]), full_size, (uint16_t*)(&data_buffer[next_data_buffer]), &next_size); + if(has_synch_failed) + continue; + data_output_update(&data_buffer[curr_data_buffer], capture_data, bytesIn, clock_start); + } + delete []data_buffer; +} diff --git a/source/CaptureDeviceSpecific/DSCapture_FTD2/dscapture_ftd2_shared.cpp b/source/CaptureDeviceSpecific/DSCapture_FTD2/dscapture_ftd2_shared.cpp new file mode 100644 index 0000000..4473fb4 --- /dev/null +++ b/source/CaptureDeviceSpecific/DSCapture_FTD2/dscapture_ftd2_shared.cpp @@ -0,0 +1,399 @@ +#include "dscapture_ftd2_shared.hpp" +#include "dscapture_ftd2_driver.hpp" +#include "dscapture_ftd2_general.hpp" +#include "dscapture_libftdi2.hpp" +#include "dscapture_ftd2_compatibility.hpp" +#include "devicecapture.hpp" +#include "usb_generic.hpp" + +#include "ftd2_ds2_fw_1.h" +#include "ftd2_ds2_fw_2.h" + + +#include +#include +#include +#include + +#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 + +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, +}; + +const std::string valid_descriptions[] = {"NDS.1", "NDS.2"}; +const int descriptions_firmware_ids[] = {1, 2}; + +// Code based on sample provided by Loopy. + +int get_num_ftd2_device_types() { + return sizeof(descriptions_firmware_ids) / sizeof(descriptions_firmware_ids[0]); +} + +const std::string get_ftd2_fw_desc(int index) { + if((index < 0) || (index >= get_num_ftd2_device_types())) + return ""; + return valid_descriptions[index]; +} + +const int get_ftd2_fw_index(int index) { + if((index < 0) || (index >= get_num_ftd2_device_types())) + return 0; + return descriptions_firmware_ids[index]; +} + +void list_devices_ftd2_shared(std::vector &devices_list, std::vector &no_access_list) { + list_devices_ftd2_compatibility(devices_list, no_access_list); +} + +static uint64_t _ftd2_get_video_in_size(bool is_rgb888) { + return sizeof(USBOldDSVideoInputData); +} + +uint64_t ftd2_get_video_in_size(CaptureData* capture_data) { + return _ftd2_get_video_in_size(capture_data->status.device.is_rgb_888); +} + +uint64_t get_capture_size(bool is_rgb888) { + return (((sizeof(FTD2OldDSCaptureReceived) - EXTRA_DATA_BUFFER_USB_SIZE) + (MAX_PACKET_SIZE_FTD2 - 1)) / MAX_PACKET_SIZE_FTD2) * MAX_PACKET_SIZE_FTD2; // multiple of maxPacketSize +} + +uint64_t get_max_samples(bool is_rgb888) { + return ((get_capture_size(is_rgb888) - _ftd2_get_video_in_size(is_rgb888)) / 2) - 4; // The last 4 bytes should never be different from 0x43214321 +} + +static bool pass_if_FT_queue_empty(void* handle, bool is_libftdi) { + size_t bytesIn = 0; + int retval = ftd2_get_queue_status(handle, is_libftdi, &bytesIn); + if(ftd2_is_error(retval, is_libftdi) || (bytesIn != 0)) //should be empty + return false; + return true; +} + +static bool ftd2_write_all_check(void* handle, bool is_libftdi, const uint8_t* data, size_t size) { + size_t sent = 0; + int retval = ftd2_write(handle, is_libftdi, data, size, &sent); + if(ftd2_is_error(retval, is_libftdi) || (sent != size)) + return false; + return true; +} + +static bool full_ftd2_write(void* handle, bool is_libftdi, const uint8_t* data, size_t size) { + if(!pass_if_FT_queue_empty(handle, is_libftdi)) // maybe MPSSE error? + return false; + return ftd2_write_all_check(handle, is_libftdi, data, size); +} + +//verify CDONE==val +static bool check_cdone(void* handle, bool is_libftdi, bool want_active) { + static const uint8_t cmd[] = { + 0x81, //read D + 0x83, //read C + }; + uint8_t buf[2]; + + if(!full_ftd2_write(handle, is_libftdi, cmd, sizeof(cmd))) + return false; + + size_t bytesIn = 0; + int retval = ftd2_read(handle, is_libftdi, buf, 2, &bytesIn); + if(ftd2_is_error(retval, is_libftdi) || (bytesIn != 2) || (buf[0] == 0xFA)) + return false; + + if(want_active) + return (buf[0] & 0x40); + return !(buf[0] & 0x40); +} + +static int end_spi_tx(uint8_t *txBuf, int retval) { + delete []txBuf; + return retval; +} + +static int ftd2_spi_tx(void* handle, bool is_libftdi, const uint8_t* buf, int size) { + uint8_t *txBuf = new uint8_t[TX_SPI_SIZE + TX_SPI_OFFSET]; + int retval = 0; + int len; + size_t sent; + size_t bytesIn; + size_t wrote = 0; + + if(!pass_if_FT_queue_empty(handle, is_libftdi)) + return end_spi_tx(txBuf, -1); + + 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; + + retval = ftd2_write(handle, is_libftdi, txBuf, len + TX_SPI_OFFSET, &sent); + if(ftd2_is_error(retval, is_libftdi)) + return end_spi_tx(txBuf, retval); + if(sent != (len + TX_SPI_OFFSET)) + return end_spi_tx(txBuf, -2); + + if(!pass_if_FT_queue_empty(handle, is_libftdi)) + return end_spi_tx(txBuf, -1); + + wrote += sent - TX_SPI_OFFSET; + size -= len; + } + return end_spi_tx(txBuf, 0); +} + +static bool fpga_config(void* handle, bool is_libftdi, 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 + }; + + int retval = 0; + retval = ftd2_set_timeouts(handle, is_libftdi, 300, 300); + if(ftd2_is_error(retval, is_libftdi)) + return false; + if(!full_ftd2_write(handle, is_libftdi, cmd0, sizeof(cmd0))) + return false; + + //verify CDONE=0 + if(!check_cdone(handle, is_libftdi, false)) + return false; + + //send configuration + retval = ftd2_spi_tx(handle, is_libftdi, bitstream, size); + if(ftd2_is_error(retval, is_libftdi)) + 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, is_libftdi, cmd1, sizeof(cmd1))) + return false; + + //verify CDONE=1 + if(!check_cdone(handle, is_libftdi, true)) + return false; + + return true; +} + +static bool init_MPSSE(void* handle, bool is_libftdi) { + 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 + }; + + int retval = 0; + retval = ftd2_reset_device(handle, is_libftdi); + if(ftd2_is_error(retval, is_libftdi)) + return false; + retval = ftd2_set_usb_parameters(handle, is_libftdi, FTD2XX_IN_SIZE, FTD2XX_OUT_SIZE); //Multiple of 64 bytes up to 64k + if(ftd2_is_error(retval, is_libftdi)) + return false; + retval = ftd2_set_chars(handle, is_libftdi, 0, 0, 0, 0); + if(ftd2_is_error(retval, is_libftdi)) + return false; + retval = ftd2_set_timeouts(handle, is_libftdi, 300, 300); //read,write timeout (ms) + if(ftd2_is_error(retval, is_libftdi)) + return false; + retval = ftd2_set_latency_timer(handle, is_libftdi, 3); //time to wait before incomplete packet is sent (default=16ms). MPSSE read seems to fail on 2 sometimes, too fast? + if(ftd2_is_error(retval, is_libftdi)) + return false; + retval = ftd2_set_flow_ctrl_rts_cts(handle, is_libftdi); //turn on flow control to synchronize IN requests + if(ftd2_is_error(retval, is_libftdi)) + return false; + retval = ftd2_reset_bitmode(handle, is_libftdi); //performs a general reset on MPSSE + if(ftd2_is_error(retval, is_libftdi)) + return false; + retval = ftd2_set_mpsse_bitmode(handle, is_libftdi); //enable MPSSE mode + if(ftd2_is_error(retval, is_libftdi)) + return false; + + //MPSSE seems to choke on first write sometimes :/ Send, purge, resend. + size_t sent = 0; + retval = ftd2_write(handle, is_libftdi, cmd, 1, &sent); //enable MPSSE mode + if(ftd2_is_error(retval, is_libftdi)) + return false; + default_sleep(); + retval = ftd2_purge_all(handle, is_libftdi); + if(ftd2_is_error(retval, is_libftdi)) + return false; + return full_ftd2_write(handle, is_libftdi, cmd, sizeof(cmd)); +} + +static bool preemptive_close_connection(CaptureData* capture_data, bool is_libftdi) { + ftd2_reset_device(capture_data->handle, is_libftdi); + ftd2_close(capture_data->handle, is_libftdi); + return false; +} + +bool connect_ftd2_shared(bool print_failed, CaptureData* capture_data, CaptureDevice* device) { + bool is_libftdi = device->descriptor != NULL; + if(ftd2_open(device, &capture_data->handle, is_libftdi)) { + capture_error_print(print_failed, capture_data, "Create failed"); + return false; + } + + if(!init_MPSSE(capture_data->handle, is_libftdi)) { + capture_error_print(print_failed, capture_data, "MPSSE init failed"); + return preemptive_close_connection(capture_data, is_libftdi); + } + + if(!fpga_config(capture_data->handle, is_libftdi, ftd2_ds2_fws[device->firmware_id - 1], ftd2_ds2_sizes[device->firmware_id - 1])) { + capture_error_print(print_failed, capture_data, "FPGA config failed"); + return preemptive_close_connection(capture_data, is_libftdi); + } + + int retval = 0; + int val = 0; + retval = ftd2_read_ee(capture_data->handle, is_libftdi, 1, &val); + if(ftd2_is_error(retval, is_libftdi) || (val != 0x0403)) { //=85A8: something went wrong (fpga is configured but FT chip detected wrong eeprom size) + capture_error_print(print_failed, capture_data, "EEPROM read error"); + return preemptive_close_connection(capture_data, is_libftdi); + } + + /* + int Firmware = 0; + int Hardware = 0; + retval = ftd2_read_ee(capture_data->handle, is_libftdi, 0x10, &Firmware); + if(ftd2_is_error(retval, is_libftdi)) { + capture_error_print(print_failed, capture_data, "Firmware ID read error"); + return preemptive_close_connection(capture_data, is_libftdi); + } + retval = ftd2_read_ee(capture_data->handle, is_libftdi, 0x11, &Hardware); + if(ftd2_is_error(retval, is_libftdi)) { + capture_error_print(print_failed, capture_data, "Hardware ID read error"); + return preemptive_close_connection(capture_data, is_libftdi); + } + */ + + retval = ftd2_set_fifo_bitmode(capture_data->handle, is_libftdi); //to FIFO mode. This takes over port B, pins shouldn't get modified though + if(ftd2_is_error(retval, is_libftdi)) { + capture_error_print(print_failed, capture_data, "Bitmode setup error"); + return preemptive_close_connection(capture_data, is_libftdi); + } + + retval = ftd2_set_timeouts(capture_data->handle, is_libftdi, 50, 50); + if(ftd2_is_error(retval, is_libftdi)) { + capture_error_print(print_failed, capture_data, "Timeouts setup error"); + return preemptive_close_connection(capture_data, is_libftdi); + } + + if(!pass_if_FT_queue_empty(capture_data->handle, is_libftdi)) {// maybe MPSSE error? + capture_error_print(print_failed, capture_data, "Intermediate error"); + return preemptive_close_connection(capture_data, is_libftdi); + } + + return true; +} + +bool synchronization_check(uint16_t* data_buffer, size_t size, uint16_t* next_data_buffer, size_t* next_size, bool special_check) { + size_t size_words = size / 2; + *next_size = size; + if((data_buffer[0] != FTD2_OLDDS_SYNCH_VALUES) && (data_buffer[size_words - 1] == FTD2_OLDDS_SYNCH_VALUES)) + return true; + if(special_check && (data_buffer[0] == FTD2_OLDDS_SYNCH_VALUES) && (data_buffer[size_words - 1] == FTD2_OLDDS_SYNCH_VALUES)) + return true; + + //check sync + size_t samples = 0; + + // 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++; + + // Schedule a read to re-synchronize + if(next_data_buffer != NULL) + memcpy(&data_buffer[samples], next_data_buffer, (size_words - samples) * 2); + *next_size = samples * 2; + return false; +} + +size_t remove_synch_from_final_length(uint32_t* out_buffer, size_t real_length) { + // Ignore synch for final length + const uint32_t check_value = FTD2_OLDDS_SYNCH_VALUES | (FTD2_OLDDS_SYNCH_VALUES << 16); + while((real_length >= 4) && ((out_buffer)[(real_length / 4) - 1] == check_value)) + real_length -= 4; + if((real_length < 4) && (out_buffer[0] == check_value)) + real_length = 0; + return real_length; +} + +bool enable_capture(void* handle, bool is_libftdi) { + static const uint8_t cmd[]={ 0x80, 0x01 }; //enable capture + return ftd2_write_all_check(handle, is_libftdi, cmd, sizeof(cmd)); +} + +void ftd2_capture_main_loop_shared(CaptureData* capture_data) { + ftd2_capture_main_loop(capture_data); +} + +void ftd2_capture_cleanup_shared(CaptureData* capture_data) { + bool is_libftdi = capture_data->status.device.descriptor != NULL; + if(ftd2_close(capture_data->handle, is_libftdi)) { + capture_error_print(true, capture_data, "Disconnected: Close failed"); + } +} + +void ftd2_init_shared() { + ftd2_init(); +} + +void ftd2_end_shared() { + ftd2_end(); +} diff --git a/source/CaptureDeviceSpecific/DSCapture_FTD2/dscapture_libftdi2.cpp b/source/CaptureDeviceSpecific/DSCapture_FTD2/dscapture_libftdi2.cpp new file mode 100644 index 0000000..58c0f23 --- /dev/null +++ b/source/CaptureDeviceSpecific/DSCapture_FTD2/dscapture_libftdi2.cpp @@ -0,0 +1,704 @@ +#include "dscapture_libftdi2.hpp" +#include "dscapture_ftd2_general.hpp" +#include "dscapture_ftd2_compatibility.hpp" +#include "devicecapture.hpp" +#include "usb_generic.hpp" + +#include + +#include +#include +#include +#include + +#define FT_FAILED(x) ((x) != FT_OK) + +#define MANUFACTURER_SIZE 128 +#define DESCRIPTION_SIZE 128 +#define SERIAL_NUMBER_SIZE 128 + +#define ENABLE_AUDIO true + +#define FTDI_VID 0x0403 +#define FT232H_PID 0x6014 + +#define EXPECTED_IGNORED_HALFWORDS 1 + +#define IGNORE_FIRST_FEW_FRAMES_SYNC (NUM_CAPTURE_RECEIVED_DATA_BUFFERS * 2) +#define RESYNC_TIMEOUT 0.050 + +struct vid_pid_descriptor { + int vid; + int pid; +}; + +static const vid_pid_descriptor base_device = { + .vid = FTDI_VID, .pid = FT232H_PID +}; + +static const vid_pid_descriptor* accepted_devices[] = { +&base_device, +}; + +static const vid_pid_descriptor* get_device_descriptor(int vid, int pid) { + for(int i = 0; i < sizeof(accepted_devices) / sizeof(*accepted_devices); i++) + if((vid == accepted_devices[i]->vid) && (pid == accepted_devices[i]->pid)) + return accepted_devices[i]; + return NULL; +} + +void libftdi_init() { +} + +void libftdi_end() { +} + +static void libftdi_usb_thread_function(bool* usb_thread_run, libusb_context *usb_ctx) { + 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(usb_ctx, &tv, NULL); +} + +static void libftdi_start_thread(std::thread* thread_ptr, bool* usb_thread_run, libusb_context *usb_ctx) { + if(!usb_is_initialized()) + return; + *usb_thread_run = true; + *thread_ptr = std::thread(libftdi_usb_thread_function, usb_thread_run, usb_ctx); +} + +static void libftdi_close_thread(std::thread* thread_ptr, bool* usb_thread_run) { + if(!usb_is_initialized()) + return; + *usb_thread_run = false; + thread_ptr->join(); +} + +static int check_single_device_valid_libftdi(ftdi_context *handle, libusb_device* dev, char* description, char* SerialNumber, const vid_pid_descriptor** curr_descriptor) { + char manufacturer[MANUFACTURER_SIZE]; + libusb_device_handle *dev_handle = NULL; + int retval = libusb_open(dev, &dev_handle); + if(retval || (dev_handle == NULL)) + return retval; + retval = libusb_claim_interface(dev_handle, handle->interface); + if(retval == LIBUSB_SUCCESS) + libusb_release_interface(dev_handle, handle->interface); + libusb_close(dev_handle); + if(retval < 0) + return retval; + libusb_device_descriptor desc = {0}; + retval = libusb_get_device_descriptor(dev, &desc); + *curr_descriptor = NULL; + if(retval >= 0) + *curr_descriptor = get_device_descriptor(desc.idVendor, desc.idProduct); + if((retval < 0) || ((retval = ftdi_usb_get_strings(handle, dev, manufacturer, MANUFACTURER_SIZE, description, DESCRIPTION_SIZE, SerialNumber, SERIAL_NUMBER_SIZE)) < 0)) + return retval; + if((desc.bcdUSB < 0x0200) || ((*curr_descriptor) == NULL)) + return LIBUSB_ERROR_OTHER; + return LIBUSB_SUCCESS; +} + +void list_devices_libftdi(std::vector &devices_list, std::vector &no_access_list) { + ftdi_device_list *devlist, *curdev; + ftdi_context *handle = ftdi_new(); + char description[DESCRIPTION_SIZE], SerialNumber[SERIAL_NUMBER_SIZE]; + int debug_multiplier = 1; + bool insert_anyway = false; + bool perm_error = false; + const vid_pid_descriptor* curr_descriptor; + + int num_devices = ftdi_usb_find_all(handle, &devlist, 0, 0); + if(num_devices < 0) { + ftdi_free(handle); + return; + } + curdev = devlist; + while(curdev != NULL) + { + int retval = check_single_device_valid_libftdi(handle, curdev->dev, description, SerialNumber, &curr_descriptor); + if(retval < 0) { + if(retval == LIBUSB_ERROR_ACCESS) + perm_error = true; + curdev = curdev->next; + continue; + } + std::string serial_number = std::string(SerialNumber); + bool is_already_inserted = false; + for(int j = 0; j < devices_list.size(); j++) { + if((devices_list[j].cc_type == CAPTURE_CONN_FTD2) && (devices_list[j].serial_number == serial_number)) { + is_already_inserted = true; + break; + } + } + if(is_already_inserted && (!insert_anyway)) { + curdev = curdev->next; + continue; + } + for(int j = 0; j < get_num_ftd2_device_types(); j++) { + if(description == get_ftd2_fw_desc(j)) { + for(int u = 0; u < debug_multiplier; u++) + devices_list.emplace_back(serial_number, "DS.2", "DS.2.l565", std::string(description), CAPTURE_CONN_FTD2, (void*)curr_descriptor, false, false, ENABLE_AUDIO, WIDTH_DS, HEIGHT_DS + HEIGHT_DS, get_max_samples(false), 0, 0, 0, 0, HEIGHT_DS, VIDEO_DATA_RGB16, get_ftd2_fw_index(j), false); + break; + } + } + curdev = curdev->next; + } + ftdi_list_free(&devlist); + ftdi_free(handle); + if(perm_error) + no_access_list.emplace_back("libftdi"); +} + +int libftdi_reset(void* handle) { + return ftdi_usb_reset((ftdi_context*)handle); +} + +int libftdi_set_latency_timer(void* handle, unsigned char latency) { + return ftdi_set_latency_timer((ftdi_context*)handle, latency); +} + +int libftdi_setflowctrl(void* handle, int flowctrl, unsigned char xon, unsigned char xoff) { + if((flowctrl == SIO_DISABLE_FLOW_CTRL) || (flowctrl == SIO_RTS_CTS_HS) || (flowctrl == SIO_DTR_DSR_HS)) + return ftdi_setflowctrl((ftdi_context*)handle, flowctrl); + return ftdi_setflowctrl_xonxoff((ftdi_context*)handle, xon, xoff); +} + +int libftdi_set_bitmode(void* handle, unsigned char bitmask, unsigned char mode) { + return ftdi_set_bitmode((ftdi_context*)handle, bitmask, mode); +} + +int libftdi_purge(void* handle, bool do_read, bool do_write) { + if(do_read && do_write) + return ftdi_tcioflush((ftdi_context*)handle); + if(do_read) + return ftdi_tciflush((ftdi_context*)handle); + if(do_write) + return ftdi_tcoflush((ftdi_context*)handle); + return 0; +} + +int libftdi_read_eeprom(void* handle, int eeprom_addr, int *eeprom_val) { + unsigned short val = 0; + int ret = ftdi_read_eeprom_location((ftdi_context*)handle, eeprom_addr, &val); + *eeprom_val = val; + return ret; +} + +int libftdi_set_chars(void* handle, unsigned char eventch, unsigned char event_enable, unsigned char errorch, unsigned char error_enable) { + int ret = ftdi_set_event_char((ftdi_context*)handle, eventch, event_enable); + if(ret < 0) + return ret; + return ftdi_set_error_char((ftdi_context*)handle, errorch, error_enable); +} + +int libftdi_set_usb_chunksizes(void* handle, unsigned int chunksize_in, unsigned int chunksize_out) { + int ret = ftdi_read_data_set_chunksize((ftdi_context*)handle, chunksize_in); + if(ret < 0) + return ret; + return ftdi_write_data_set_chunksize((ftdi_context*)handle, chunksize_out); +} + +void libftdi_set_timeouts(void* handle, int timeout_in_ms, int timeout_out_ms) { + ftdi_context* in_handle = (ftdi_context*)handle; + in_handle->usb_read_timeout = timeout_in_ms; + in_handle->usb_write_timeout = timeout_out_ms; +} + +int libftdi_write(void* handle, const uint8_t* data, size_t size, size_t* bytesOut) { + *bytesOut = ftdi_write_data((ftdi_context*)handle, data, size); + if((*bytesOut) >= 0) + return 0; + return *bytesOut; +} + +int libftdi_read(void* handle, uint8_t* data, size_t size, size_t* bytesIn) { + *bytesIn = ftdi_read_data((ftdi_context*)handle, data, size); + if((*bytesIn) >= 0) + return 0; + return *bytesIn; +} + +int get_libftdi_read_queue_size(void* handle, size_t* bytesIn) { + uint8_t buffer[64]; + *bytesIn = 0; + ftdi_context* in_handle = (ftdi_context*)handle; + int timeout_in_ms = in_handle->usb_read_timeout; + in_handle->usb_read_timeout = 0; + size_t curr_bytes_in = 0; + bool done = false; + int retval = 0; + while(!done) { + retval = libftdi_read(handle, buffer, 64, &curr_bytes_in); + if(retval <= 0) + done = true; + else + *bytesIn += curr_bytes_in; + } + in_handle->usb_read_timeout = timeout_in_ms; + return LIBUSB_SUCCESS; +} + +int libftdi_open_serial(CaptureDevice* device, void** handle) { + ftdi_device_list *devlist, *curdev; + ftdi_context *curr_handle = ftdi_new(); + char description[DESCRIPTION_SIZE], SerialNumber[SERIAL_NUMBER_SIZE]; + int debug_multiplier = 1; + bool insert_anyway = false; + bool perm_error = false; + const vid_pid_descriptor* curr_descriptor; + int ret = LIBUSB_ERROR_OTHER; + + int num_devices = ftdi_usb_find_all(curr_handle, &devlist, 0, 0); + if(num_devices < 0) { + ftdi_free(curr_handle); + return LIBUSB_ERROR_OTHER; + } + curdev = devlist; + while(curdev != NULL) + { + int retval = check_single_device_valid_libftdi(curr_handle, curdev->dev, description, SerialNumber, &curr_descriptor); + if(retval < 0) { + curdev = curdev->next; + continue; + } + if(curr_descriptor != ((const vid_pid_descriptor*)device->descriptor)) { + curdev = curdev->next; + continue; + } + std::string serial_number = std::string(SerialNumber); + std::string desc = std::string(description); + if((serial_number != device->serial_number) || (desc != device->path)) { + curdev = curdev->next; + continue; + } + ret = ftdi_usb_open_dev(curr_handle, curdev->dev); + if(ret >= 0) + *handle = (void*)curr_handle; + curdev = NULL; + } + ftdi_list_free(&devlist); + if(ret < 0) + ftdi_free(curr_handle); + return ret; +} + +int libftdi_close(void* handle) { + ftdi_usb_close((ftdi_context*)handle); + ftdi_free((ftdi_context*)handle); + return LIBUSB_SUCCESS; +} + +void libftdi_cancel_callback(ftd2_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(); +} + +static void STDCALL libftdi_read_callback(libusb_transfer* transfer) { + ftd2_async_callback_data* cb_data = (ftd2_async_callback_data*)transfer->user_data; + FTD2CaptureReceivedData* user_data = (FTD2CaptureReceivedData*)cb_data->actual_user_data; + cb_data->transfer_data_access.lock(); + cb_data->transfer_data = NULL; + cb_data->is_transfer_done_mutex->specific_unlock(cb_data->internal_index); + cb_data->transfer_data_access.unlock(); + cb_data->function((void*)user_data, transfer->actual_length, transfer->status); +} + +// Read from bulk +static void libftdi_schedule_read(ftd2_async_callback_data* cb_data, int length) { + const int max_packet_size = MAX_PACKET_SIZE_USB2; + libusb_transfer *transfer_in = libusb_alloc_transfer(0); + if(!transfer_in) + return; + cb_data->transfer_data_access.lock(); + cb_data->transfer_data = transfer_in; + cb_data->is_transfer_done_mutex->specific_try_lock(cb_data->internal_index); + length += ((length + (max_packet_size - FTD2_INTRA_PACKET_HEADER_SIZE) - 1) / (max_packet_size - FTD2_INTRA_PACKET_HEADER_SIZE)) * FTD2_INTRA_PACKET_HEADER_SIZE; + cb_data->requested_length = length; + ftdi_context* in_handle = (ftdi_context*)cb_data->handle; + libusb_fill_bulk_transfer(transfer_in, in_handle->usb_dev, in_handle->out_ep, (uint8_t*)&cb_data->buffer_raw, length, libftdi_read_callback, (void*)cb_data, in_handle->usb_read_timeout * NUM_CAPTURE_RECEIVED_DATA_BUFFERS); + transfer_in->flags |= LIBUSB_TRANSFER_FREE_TRANSFER; + libusb_submit_transfer(transfer_in); + cb_data->transfer_data_access.unlock(); +} + +static size_t libftdi_get_actual_length(const int max_packet_size, size_t length, size_t header_packet_size) { + // Remove the small headers every 512 bytes... + // The "- header_packet_size" instead of "-1" covers for partial header transfers... + int num_iters = (length + max_packet_size - header_packet_size) / max_packet_size; + if(num_iters > 0) + length -= (num_iters * header_packet_size); + else + length = 0; + return length; +} + +static void libftdi_copy_buffer_to_target(uint8_t* buffer_written, uint8_t* buffer_target, const int max_packet_size, size_t length, size_t header_packet_size) { + // Remove the small headers every 512 bytes... + // The "- header_packet_size" instead of "-1" covers for partial header transfers... + int num_iters = (length + max_packet_size - header_packet_size) / max_packet_size; + if(num_iters <= 0) + return; + + length -= (num_iters * header_packet_size); + for(int i = 0; i < num_iters; i++) { + int rem_size = length - ((max_packet_size - header_packet_size) * i); + if(rem_size > ((int)(max_packet_size - header_packet_size))) + rem_size = max_packet_size - header_packet_size; + if(rem_size <= 0) + break; + memcpy(buffer_target + ((max_packet_size - header_packet_size) * i), buffer_written + header_packet_size + (max_packet_size * i), rem_size); + } +} + +// Read from bulk +static int libftdi_direct_read(void* handle, uint8_t* buffer_raw, uint8_t* buffer_normal, size_t length, size_t* transferred) { + const int max_packet_size = MAX_PACKET_SIZE_USB2; + length += ((length + (max_packet_size - FTD2_INTRA_PACKET_HEADER_SIZE) - 1) / (max_packet_size - FTD2_INTRA_PACKET_HEADER_SIZE)) * FTD2_INTRA_PACKET_HEADER_SIZE; + ftdi_context* in_handle = (ftdi_context*)handle; + *transferred = 0; + int internal_transferred = 0; + int retval = libusb_bulk_transfer(in_handle->usb_dev, in_handle->out_ep, buffer_raw, length, &internal_transferred, in_handle->usb_read_timeout); + if(retval < 0) + return retval; + libftdi_copy_buffer_to_target(buffer_raw, buffer_normal, max_packet_size, internal_transferred, FTD2_INTRA_PACKET_HEADER_SIZE); + *transferred = libftdi_get_actual_length(max_packet_size, internal_transferred, FTD2_INTRA_PACKET_HEADER_SIZE); + return LIBUSB_SUCCESS; +} + +static int libftdi_full_read(void* handle, uint8_t* buffer_raw, uint8_t* buffer_normal, size_t length, double timeout) { + size_t total_transferred = 0; + const auto start_time = std::chrono::high_resolution_clock::now(); + while(total_transferred < length) { + size_t received = 0; + int retval = libftdi_direct_read(handle, buffer_raw, buffer_normal, length - total_transferred, &received); + if(ftd2_is_error(retval, true)) + return retval; + total_transferred += received; + if(received == 0) + break; + const auto curr_time = std::chrono::high_resolution_clock::now(); + const std::chrono::duration diff = curr_time - start_time; + if(diff.count() > timeout) + return LIBUSB_ERROR_TIMEOUT; + } + return LIBUSB_SUCCESS; +} + +static void libftdi_copy_buffer_to_target_and_skip(uint8_t* buffer_written, uint8_t* buffer_target, const int max_packet_size, size_t length, size_t header_packet_size, size_t ignored_bytes) { + // This could be made faster for small "ignored_bytes", however this scales well... + + // Remove the small headers every 512 bytes... + // The "- header_packet_size" instead of "-1" covers for partial header transfers... + int num_iters = (length + max_packet_size - header_packet_size) / max_packet_size; + if(num_iters <= 0) + return; + + size_t inner_length = length - (num_iters * header_packet_size); + size_t fully_ignored_iters = ignored_bytes / (max_packet_size - header_packet_size); + size_t partially_ignored_iters = (ignored_bytes + (max_packet_size - header_packet_size) - 1) / (max_packet_size - header_packet_size); + num_iters -= fully_ignored_iters; + if(num_iters <= 0) + return; + + buffer_written += fully_ignored_iters * max_packet_size; + // Skip inside a packet, since it's misaligned + if(partially_ignored_iters != fully_ignored_iters) { + size_t offset_bytes = ignored_bytes % (max_packet_size - header_packet_size); + int rem_size = inner_length - ((max_packet_size - header_packet_size) * fully_ignored_iters); + if(rem_size > ((int)((max_packet_size - header_packet_size)))) + rem_size = max_packet_size - header_packet_size; + rem_size -= offset_bytes; + if(rem_size > 0) { + memcpy(buffer_target, buffer_written + header_packet_size + offset_bytes, rem_size); + buffer_written += max_packet_size; + buffer_target += rem_size; + } + } + if(length <= (max_packet_size * partially_ignored_iters)) + return; + libftdi_copy_buffer_to_target(buffer_written, buffer_target, max_packet_size, length - (max_packet_size * partially_ignored_iters), header_packet_size); +} + +static int get_libftdi_status(FTD2CaptureReceivedData* received_data_buffers) { + return *received_data_buffers[0].status; +} + +static void reset_libftdi_status(FTD2CaptureReceivedData* received_data_buffers) { + *received_data_buffers[0].status = 0; +} + +static void error_libftdi_status(FTD2CaptureReceivedData* received_data_buffers, int error) { + *received_data_buffers[0].status = error; +} + +static int libftdi_get_num_free_buffers(FTD2CaptureReceivedData* received_data_buffers) { + int num_free = 0; + for(int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) + if(!received_data_buffers[i].in_use) + num_free += 1; + return num_free; +} + +static void wait_all_libftdi_transfers_done(FTD2CaptureReceivedData* received_data_buffers) { + if (received_data_buffers == NULL) + return; + if (*received_data_buffers[0].status < 0) { + for (int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) + libftdi_cancel_callback(&received_data_buffers[i].cb_data); + } + for (int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) { + void* transfer_data; + do { + received_data_buffers[i].cb_data.transfer_data_access.lock(); + transfer_data = received_data_buffers[i].cb_data.transfer_data; + received_data_buffers[i].cb_data.transfer_data_access.unlock(); + if(transfer_data) + received_data_buffers[i].cb_data.is_transfer_done_mutex->specific_timed_lock(i); + } while(transfer_data); + } +} + +static void wait_all_libftdi_buffers_free(FTD2CaptureReceivedData* received_data_buffers) { + if(received_data_buffers == NULL) + return; + if(*received_data_buffers[0].status < 0) { + for(int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) + libftdi_cancel_callback(&received_data_buffers[i].cb_data); + } + for(int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) + while(received_data_buffers[i].in_use) + received_data_buffers[i].is_buffer_free_shared_mutex->specific_timed_lock(i); +} + +static void wait_one_libftdi_buffer_free(FTD2CaptureReceivedData* received_data_buffers) { + bool done = false; + while(!done) { + for(int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) { + if(!received_data_buffers[i].in_use) + done = true; + } + if(!done) { + if(*received_data_buffers[0].status < 0) + return; + int dummy = 0; + received_data_buffers[0].is_buffer_free_shared_mutex->general_timed_lock(&dummy); + } + } +} + +static bool libftdi_are_buffers_all_free(FTD2CaptureReceivedData* received_data_buffers) { + return libftdi_get_num_free_buffers(received_data_buffers) == NUM_CAPTURE_RECEIVED_DATA_BUFFERS; +} + +static FTD2CaptureReceivedData* libftdi_get_free_buffer(FTD2CaptureReceivedData* received_data_buffers) { + wait_one_libftdi_buffer_free(received_data_buffers); + if(*received_data_buffers[0].status < 0) + return NULL; + for(int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) + if(!received_data_buffers[i].in_use) { + received_data_buffers[i].is_buffer_free_shared_mutex->specific_try_lock(i); + received_data_buffers[i].in_use = true; + return &received_data_buffers[i]; + } + return NULL; +} + +static void libftdi_start_read(FTD2CaptureReceivedData* received_data_buffer, int index, size_t size) { + if(received_data_buffer == NULL) + return; + received_data_buffer->index = index; + libftdi_schedule_read(&received_data_buffer->cb_data, size); +} + +static void end_libftdi_read_frame_cb(FTD2CaptureReceivedData* received_data_buffer) { + received_data_buffer->in_use = false; + received_data_buffer->is_buffer_free_shared_mutex->specific_unlock(received_data_buffer->cb_data.internal_index); +} + +static size_t libftdi_copy_buffer_to_target_and_skip_synch(uint8_t* in_buffer, uint32_t* out_buffer, int read_length, size_t* sync_offset) { + // This is because the actual data seems to always start with a SYNCH + size_t ignored_halfwords = 0; + uint16_t* in_u16 = (uint16_t*)in_buffer; + size_t real_length = libftdi_get_actual_length(MAX_PACKET_SIZE_USB2, read_length, FTD2_INTRA_PACKET_HEADER_SIZE); + while((ignored_halfwords < (real_length / 2)) && (in_u16[ignored_halfwords + 1 + (ignored_halfwords / (MAX_PACKET_SIZE_USB2 / 2))] == FTD2_OLDDS_SYNCH_VALUES)) + ignored_halfwords++; + size_t copy_offset = ignored_halfwords * 2; + if(ignored_halfwords >= ((MAX_PACKET_SIZE_USB2 - FTD2_INTRA_PACKET_HEADER_SIZE) / 2)) + copy_offset = 0; + libftdi_copy_buffer_to_target_and_skip(in_buffer, (uint8_t*)out_buffer, MAX_PACKET_SIZE_USB2, read_length, FTD2_INTRA_PACKET_HEADER_SIZE, copy_offset); + if(copy_offset == 0) { + size_t internal_sync_offset = 0; + bool is_synced = synchronization_check((uint16_t*)out_buffer, real_length, NULL, &internal_sync_offset); + if(!is_synced) { + *sync_offset = (internal_sync_offset / (MAX_PACKET_SIZE_USB2 - FTD2_INTRA_PACKET_HEADER_SIZE)) * (MAX_PACKET_SIZE_USB2 - FTD2_INTRA_PACKET_HEADER_SIZE); + return 0; + } + else + *sync_offset = 0; + } + else + *sync_offset = 0; + uint16_t* out_u16 = (uint16_t*)out_buffer; + for(int i = 0; i < ignored_halfwords; i++) + out_u16[(real_length / 2) - ignored_halfwords + i] = FTD2_OLDDS_SYNCH_VALUES; + return remove_synch_from_final_length(out_buffer, real_length); +} + +static void output_to_thread(CaptureData* capture_data, uint8_t* buffer, std::chrono::time_point &base_time, int read_length, size_t* sync_offset) { + // For some reason, there is usually one. + // Though make this generic enough + const auto curr_time = std::chrono::high_resolution_clock::now(); + const std::chrono::duration diff = curr_time - base_time; + base_time = curr_time; + CaptureDataSingleBuffer* target = capture_data->data_buffers.GetWriterBuffer(); + // Copy data to buffer, with special memcpy which accounts for ftd2 header data and skips synch bytes + size_t real_length = libftdi_copy_buffer_to_target_and_skip_synch(buffer, (uint32_t*)&target->capture_buf, read_length, sync_offset); + target->read = real_length; + target->time_in_buf = diff.count(); + capture_data->data_buffers.ReleaseWriterBuffer(); + + 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 libftdi_capture_process_data(void* in_user_data, int transfer_length, int transfer_status) { + // Note: sometimes the data returned has length 0... + // It's because the code is too fast... + FTD2CaptureReceivedData* user_data = (FTD2CaptureReceivedData*)in_user_data; + if((*user_data->status) < 0) + return end_libftdi_read_frame_cb(user_data); + if(transfer_status != LIBUSB_TRANSFER_COMPLETED) { + *user_data->status = LIBUSB_ERROR_OTHER; + return end_libftdi_read_frame_cb(user_data); + } + if(transfer_length < user_data->cb_data.requested_length) + return end_libftdi_read_frame_cb(user_data); + if(((int32_t)(user_data->index - (*user_data->last_used_index))) <= 0) { + //*user_data->status = LIBUSB_ERROR_INTERRUPTED; + return end_libftdi_read_frame_cb(user_data); + } + *user_data->last_used_index = user_data->index; + + output_to_thread(user_data->capture_data, (uint8_t*)&user_data->cb_data.buffer_raw, *user_data->clock_start, transfer_length, user_data->curr_offset); + end_libftdi_read_frame_cb(user_data); +} + +static void resync_offset(FTD2CaptureReceivedData* received_data_buffers, uint32_t &index, size_t full_size) { + size_t wanted_offset = *received_data_buffers[0].curr_offset; + if(wanted_offset == 0) + return; + wait_all_libftdi_buffers_free(received_data_buffers); + if(get_libftdi_status(received_data_buffers) != 0) + return; + wanted_offset = *received_data_buffers[0].curr_offset; + if(wanted_offset == 0) + return; + *received_data_buffers[0].curr_offset = 0; + #if defined(__APPLE__) || defined(_WIN32) + // Literally throw a die... Seems to work! + default_sleep(1); + return; + #endif + FTD2OldDSCaptureReceivedRaw* buffer_raw = new FTD2OldDSCaptureReceivedRaw; + FTD2OldDSCaptureReceived* buffer = new FTD2OldDSCaptureReceived; + CaptureData* capture_data = received_data_buffers[0].capture_data; + bool is_synced = false; + size_t chosen_transfer_size = (MAX_PACKET_SIZE_USB2 - FTD2_INTRA_PACKET_HEADER_SIZE) * 4; + while((!is_synced) && (capture_data->status.connected && capture_data->status.running)) { + int retval = libftdi_full_read(received_data_buffers[0].cb_data.handle, (uint8_t*)buffer_raw, (uint8_t*)buffer, chosen_transfer_size, RESYNC_TIMEOUT); + if(ftd2_is_error(retval, true)) { + //error_libftdi_status(received_data_buffers, retval); + delete buffer_raw; + delete buffer; + return; + } + size_t internal_sync_offset = 0; + is_synced = synchronization_check((uint16_t*)buffer, chosen_transfer_size, NULL, &internal_sync_offset, true); + if((!is_synced) && (internal_sync_offset < chosen_transfer_size)) + is_synced = true; + else + is_synced = false; + } + int retval = libftdi_full_read(received_data_buffers[0].cb_data.handle, (uint8_t*)buffer_raw, (uint8_t*)buffer, full_size - chosen_transfer_size, RESYNC_TIMEOUT); + if(ftd2_is_error(retval, true)) { + error_libftdi_status(received_data_buffers, retval); + delete buffer_raw; + delete buffer; + return; + } + capture_data->status.cooldown_curr_in = IGNORE_FIRST_FEW_FRAMES_SYNC; + delete buffer_raw; + delete buffer; +} + +void ftd2_capture_main_loop_libftdi(CaptureData* capture_data) { + const bool is_libftdi = true; + bool is_done = false; + int inner_curr_in = 0; + int retval = 0; + auto clock_start = std::chrono::high_resolution_clock::now(); + FTD2CaptureReceivedData* received_data_buffers = new FTD2CaptureReceivedData[NUM_CAPTURE_RECEIVED_DATA_BUFFERS]; + int curr_data_buffer = 0; + int next_data_buffer = 0; + int status = 0; + uint32_t last_used_index = -1; + uint32_t index = 0; + size_t curr_offset = 0; + const size_t full_size = get_capture_size(capture_data->status.device.is_rgb_888); + size_t bytesIn; + bool usb_thread_run = false; + std::thread processing_thread; + libftdi_start_thread(&processing_thread, &usb_thread_run, ((ftdi_context*)capture_data->handle)->usb_ctx); + + SharedConsumerMutex is_buffer_free_shared_mutex(NUM_CAPTURE_RECEIVED_DATA_BUFFERS); + SharedConsumerMutex is_transfer_done_mutex(NUM_CAPTURE_RECEIVED_DATA_BUFFERS); + for(int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) { + received_data_buffers[i].actual_length = 0; + received_data_buffers[i].is_data_ready = false; + received_data_buffers[i].in_use = false; + received_data_buffers[i].is_buffer_free_shared_mutex = &is_buffer_free_shared_mutex; + received_data_buffers[i].status = &status; + received_data_buffers[i].index = 0; + received_data_buffers[i].curr_offset = &curr_offset; + received_data_buffers[i].last_used_index = &last_used_index; + received_data_buffers[i].capture_data = capture_data; + received_data_buffers[i].clock_start = &clock_start; + received_data_buffers[i].cb_data.function = libftdi_capture_process_data; + received_data_buffers[i].cb_data.actual_user_data = &received_data_buffers[i]; + received_data_buffers[i].cb_data.transfer_data = NULL; + received_data_buffers[i].cb_data.handle = capture_data->handle; + received_data_buffers[i].cb_data.is_transfer_done_mutex = &is_transfer_done_mutex; + received_data_buffers[i].cb_data.requested_length = 0; + } + + if(!enable_capture(capture_data->handle, is_libftdi)) { + capture_error_print(true, capture_data, "Capture enable error"); + is_done = true; + } + + for(int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) + libftdi_start_read(libftdi_get_free_buffer(received_data_buffers), index++, full_size); + + + while(capture_data->status.connected && capture_data->status.running) { + if(get_libftdi_status(received_data_buffers) != 0) { + capture_error_print(true, capture_data, "Disconnected: Read error" + std::to_string(get_libftdi_status(received_data_buffers))); + is_done = true; + } + if(is_done) + break; + libftdi_start_read(libftdi_get_free_buffer(received_data_buffers), index++, full_size); + resync_offset(received_data_buffers, index, full_size); + } + wait_all_libftdi_buffers_free(received_data_buffers); + libftdi_close_thread(&processing_thread, &usb_thread_run); + delete []received_data_buffers; +} diff --git a/source/CaptureDeviceSpecific/ISNitro/usb_is_nitro_acquisition.cpp b/source/CaptureDeviceSpecific/ISNitro/usb_is_nitro_acquisition.cpp index 75eface..bb886b9 100644 --- a/source/CaptureDeviceSpecific/ISNitro/usb_is_nitro_acquisition.cpp +++ b/source/CaptureDeviceSpecific/ISNitro/usb_is_nitro_acquisition.cpp @@ -62,11 +62,11 @@ std::string get_serial(const is_nitro_usb_device* usb_device_desc, is_nitro_devi } void is_nitro_insert_device(std::vector& devices_list, is_nitro_device_handlers* handlers, const is_nitro_usb_device* usb_device_desc, int& curr_serial_extra_id_is_nitro, std::string path) { - devices_list.emplace_back(get_serial(usb_device_desc, handlers, curr_serial_extra_id_is_nitro), usb_device_desc->name, path, CAPTURE_CONN_IS_NITRO, (void*)usb_device_desc, false, false, false, WIDTH_DS, HEIGHT_DS + HEIGHT_DS, 0, 0, 0, 0, 0, HEIGHT_DS, VIDEO_DATA_BGR); + devices_list.emplace_back(get_serial(usb_device_desc, handlers, curr_serial_extra_id_is_nitro), usb_device_desc->name, usb_device_desc->long_name, path, CAPTURE_CONN_IS_NITRO, (void*)usb_device_desc, false, false, false, WIDTH_DS, HEIGHT_DS + HEIGHT_DS, 0, 0, 0, 0, 0, HEIGHT_DS, VIDEO_DATA_BGR); } void is_nitro_insert_device(std::vector& devices_list, is_nitro_device_handlers* handlers, const is_nitro_usb_device* usb_device_desc, int& curr_serial_extra_id_is_nitro) { - devices_list.emplace_back(get_serial(usb_device_desc, handlers, curr_serial_extra_id_is_nitro), usb_device_desc->name, CAPTURE_CONN_IS_NITRO, (void*)usb_device_desc, false, false, false, WIDTH_DS, HEIGHT_DS + HEIGHT_DS, 0, 0, 0, 0, 0, HEIGHT_DS, VIDEO_DATA_BGR); + devices_list.emplace_back(get_serial(usb_device_desc, handlers, curr_serial_extra_id_is_nitro), usb_device_desc->name, usb_device_desc->long_name, CAPTURE_CONN_IS_NITRO, (void*)usb_device_desc, false, false, false, WIDTH_DS, HEIGHT_DS + HEIGHT_DS, 0, 0, 0, 0, 0, HEIGHT_DS, VIDEO_DATA_BGR); } static is_nitro_device_handlers* usb_find_by_serial_number(const is_nitro_usb_device* usb_device_desc, CaptureDevice* device) { diff --git a/source/CaptureDeviceSpecific/ISNitro/usb_is_nitro_communications.cpp b/source/CaptureDeviceSpecific/ISNitro/usb_is_nitro_communications.cpp index 9813d4d..cd9216d 100644 --- a/source/CaptureDeviceSpecific/ISNitro/usb_is_nitro_communications.cpp +++ b/source/CaptureDeviceSpecific/ISNitro/usb_is_nitro_communications.cpp @@ -106,7 +106,7 @@ struct PACKED is_nitro_packet_header { #pragma pack(pop) static const is_nitro_usb_device usb_is_nitro_emu_rare_desc = { -.name = "IS Nitro Emulator(R)", +.name = "ISNEr", .long_name = "IS Nitro Emulator(R)", .vid = 0x0f6e, .pid = 0x0400, .default_config = 1, .default_interface = 0, .bulk_timeout = 500, @@ -115,7 +115,7 @@ static const is_nitro_usb_device usb_is_nitro_emu_rare_desc = { }; static const is_nitro_usb_device usb_is_nitro_emu_common_desc = { -.name = "IS Nitro Emulator", +.name = "ISNE", .long_name = "IS Nitro Emulator", .vid = 0x0f6e, .pid = 0x0404, .default_config = 1, .default_interface = 0, .bulk_timeout = 500, @@ -124,7 +124,7 @@ static const is_nitro_usb_device usb_is_nitro_emu_common_desc = { }; static const is_nitro_usb_device usb_is_nitro_cap_desc = { -.name = "IS Nitro Capture", +.name = "ISNC", .long_name = "IS Nitro Capture", .vid = 0x0f6e, .pid = 0x0403, .default_config = 1, .default_interface = 0, .bulk_timeout = 500, @@ -298,16 +298,16 @@ static int SendReadPacket(is_nitro_device_handlers* handlers, uint16_t command, } int SendReadCommand(is_nitro_device_handlers* handlers, uint16_t command, uint8_t* buf, int length, const is_nitro_usb_device* device_desc) { - return SendReadPacket(handlers, command, IS_NITRO_PACKET_TYPE_COMMAND, 0, buf, length, device_desc); + return SendReadPacket(handlers, command, IS_NITRO_PACKET_TYPE_COMMAND, 0, buf, length, device_desc); } int SendWriteCommand(is_nitro_device_handlers* handlers, uint16_t command, uint8_t* buf, int length, const is_nitro_usb_device* device_desc) { - return SendWritePacket(handlers, command, IS_NITRO_PACKET_TYPE_COMMAND, 0, buf, length, device_desc); + return SendWritePacket(handlers, command, IS_NITRO_PACKET_TYPE_COMMAND, 0, buf, length, device_desc); } int SendReadCommandU32(is_nitro_device_handlers* handlers, uint16_t command, uint32_t* out, const is_nitro_usb_device* device_desc) { uint32_t buffer; - int ret = SendReadCommand(handlers, command, (uint8_t*)&buffer, sizeof(uint32_t), device_desc); + int ret = SendReadCommand(handlers, command, (uint8_t*)&buffer, sizeof(uint32_t), device_desc); if(ret < 0) return ret; *out = from_le(buffer); @@ -316,13 +316,13 @@ int SendReadCommandU32(is_nitro_device_handlers* handlers, uint16_t command, uin int SendWriteCommandU32(is_nitro_device_handlers* handlers, uint16_t command, uint32_t value, const is_nitro_usb_device* device_desc) { uint32_t buffer = to_le(value); - return SendWriteCommand(handlers, command, (uint8_t*)&buffer, sizeof(uint32_t), device_desc); + return SendWriteCommand(handlers, command, (uint8_t*)&buffer, sizeof(uint32_t), device_desc); } int GetDeviceSerial(is_nitro_device_handlers* handlers, uint8_t* buf, const is_nitro_usb_device* device_desc) { if(device_desc->is_capture) - return SendReadCommand(handlers, IS_NITRO_CAP_CMD_GET_SERIAL, buf, IS_NITRO_REAL_SERIAL_NUMBER_SIZE, device_desc); - return SendReadCommand(handlers, IS_NITRO_EMU_CMD_GET_SERIAL, buf, IS_NITRO_REAL_SERIAL_NUMBER_SIZE, device_desc); + return SendReadCommand(handlers, IS_NITRO_CAP_CMD_GET_SERIAL, buf, IS_NITRO_REAL_SERIAL_NUMBER_SIZE, device_desc); + return SendReadCommand(handlers, IS_NITRO_EMU_CMD_GET_SERIAL, buf, IS_NITRO_REAL_SERIAL_NUMBER_SIZE, device_desc); } int ReadNecMem(is_nitro_device_handlers* handlers, uint32_t address, uint8_t unit_size, uint8_t* buf, int count, const is_nitro_usb_device* device_desc) { @@ -375,12 +375,12 @@ int WriteNecMem(is_nitro_device_handlers* handlers, uint32_t address, uint8_t un int WriteNecMemU16(is_nitro_device_handlers* handlers, uint32_t address, uint16_t value, const is_nitro_usb_device* device_desc) { uint16_t buffer = to_le(value); - return WriteNecMem(handlers, address, 2, (uint8_t*)&buffer, 1, device_desc); + return WriteNecMem(handlers, address, 2, (uint8_t*)&buffer, 1, device_desc); } int WriteNecMemU32(is_nitro_device_handlers* handlers, uint32_t address, uint32_t value, const is_nitro_usb_device* device_desc) { uint32_t buffer = to_le(value); - return WriteNecMem(handlers, address, 2, (uint8_t*)&buffer, 2, device_desc); + return WriteNecMem(handlers, address, 2, (uint8_t*)&buffer, 2, device_desc); } int DisableLca2(is_nitro_device_handlers* handlers, const is_nitro_usb_device* device_desc) { @@ -403,7 +403,7 @@ int StartUsbCaptureDma(is_nitro_device_handlers* handlers, const is_nitro_usb_de return ret; return WriteNecMemU16(handlers, REG_USB_BIU_CONTROL_2, 1, device_desc); } - return SendReadPacket(handlers, IS_NITRO_CAP_CMD_ENABLE_CAP, IS_NITRO_CAPTURE_PACKET_TYPE_DMA_CONTROL, 0, NULL, 1, device_desc, false); + return SendReadPacket(handlers, IS_NITRO_CAP_CMD_ENABLE_CAP, IS_NITRO_CAPTURE_PACKET_TYPE_DMA_CONTROL, 0, NULL, 1, device_desc, false); } int StopUsbCaptureDma(is_nitro_device_handlers* handlers, const is_nitro_usb_device* device_desc) { @@ -413,7 +413,7 @@ int StopUsbCaptureDma(is_nitro_device_handlers* handlers, const is_nitro_usb_dev return ret; return WriteNecMemU16(handlers, REG_USB_BIU_CONTROL_2, 0, device_desc); } - return SendReadPacket(handlers, IS_NITRO_CAP_CMD_ENABLE_CAP, IS_NITRO_CAPTURE_PACKET_TYPE_DMA_CONTROL, 0, NULL, 0, device_desc); + return SendReadPacket(handlers, IS_NITRO_CAP_CMD_ENABLE_CAP, IS_NITRO_CAPTURE_PACKET_TYPE_DMA_CONTROL, 0, NULL, 0, device_desc); } int SetForwardFrameCount(is_nitro_device_handlers* handlers, uint16_t count, const is_nitro_usb_device* device_desc) { @@ -434,12 +434,12 @@ int GetFrameCounter(is_nitro_device_handlers* handlers, uint16_t* out, const is_ *out = 0; return LIBUSB_SUCCESS; } - uint32_t counter = 0; - int ret = ReadNecMemU32(handlers, 0x08000028, &counter, device_desc); - if(ret < 0) - return ret; - *out = (counter & 0xFF) | ((counter & 0xFF0000) >> 8); - return ret; + uint32_t counter = 0; + int ret = ReadNecMemU32(handlers, 0x08000028, &counter, device_desc); + if(ret < 0) + return ret; + *out = (counter & 0xFF) | ((counter & 0xFF0000) >> 8); + return ret; } int UpdateFrameForwardConfig(is_nitro_device_handlers* handlers, is_nitro_forward_config_values_colors colors, is_nitro_forward_config_values_screens screens, is_nitro_forward_config_values_rate rate, const is_nitro_usb_device* device_desc) { @@ -469,31 +469,31 @@ int UpdateFrameForwardEnable(is_nitro_device_handlers* handlers, bool enable, bo } int ReadLidState(is_nitro_device_handlers* handlers, bool* out, const is_nitro_usb_device* device_desc) { - uint32_t flags = 0; + uint32_t flags = 0; if(device_desc->is_capture) { int ret = SendReadCommandU32(handlers, IS_NITRO_CAP_CMD_GET_LID_STATE, &flags, device_desc); *out = (flags & 1) ? true : false; return ret; } - int ret = ReadNecMemU32(handlers, 0x08000000, &flags, device_desc); - if(ret < 0) - return ret; - *out = (flags & 2) ? true : false; - return ret; + int ret = ReadNecMemU32(handlers, 0x08000000, &flags, device_desc); + if(ret < 0) + return ret; + *out = (flags & 2) ? true : false; + return ret; } int ReadDebugButtonState(is_nitro_device_handlers* handlers, bool* out, const is_nitro_usb_device* device_desc) { - uint32_t flags = 0; + uint32_t flags = 0; if(device_desc->is_capture) { int ret = SendReadCommandU32(handlers, IS_NITRO_CAP_CMD_GET_DEBUG_STATE, &flags, device_desc); *out = (flags & 1) ? true : false; return ret; } - int ret = ReadNecMemU32(handlers, 0x08000000, &flags, device_desc); - if(ret < 0) - return ret; - *out = (flags & 1) ? true : false; - return ret; + int ret = ReadNecMemU32(handlers, 0x08000000, &flags, device_desc); + if(ret < 0) + return ret; + *out = (flags & 1) ? true : false; + return ret; } int ReadPowerButtonState(is_nitro_device_handlers* handlers, bool* out, const is_nitro_usb_device* device_desc) { @@ -553,4 +553,4 @@ void EndISNitroAsyncThread(is_nitro_device_handlers* handlers, void* user_data, if(handlers->usb_handle) return is_nitro_libusb_close_thread(thread_ptr, keep_going); return is_nitro_is_driver_close_thread(thread_ptr, keep_going, (ISNitroCaptureReceivedData*)user_data); -} \ No newline at end of file +} diff --git a/source/CaptureDeviceSpecific/dscapture_ftd2.cpp b/source/CaptureDeviceSpecific/dscapture_ftd2.cpp deleted file mode 100644 index d8bd1e1..0000000 --- a/source/CaptureDeviceSpecific/dscapture_ftd2.cpp +++ /dev/null @@ -1,505 +0,0 @@ -#include "dscapture_ftd2.hpp" -#include "devicecapture.hpp" -#include "usb_generic.hpp" -//#include "ftd2xx_symbols_renames.h" - -#include "ftd2_ds2_fw_1.h" -#include "ftd2_ds2_fw_2.h" - -#define FTD2XX_STATIC -#include - -#include -#include -#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 sizeof(USBOldDSVideoInputData); -} - -static uint64_t get_capture_size(CaptureData* capture_data) { - 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) { - 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/CaptureDeviceSpecific/usb_ds_3ds_capture.cpp b/source/CaptureDeviceSpecific/usb_ds_3ds_capture.cpp index 93a0397..36f8bfe 100644 --- a/source/CaptureDeviceSpecific/usb_ds_3ds_capture.cpp +++ b/source/CaptureDeviceSpecific/usb_ds_3ds_capture.cpp @@ -207,6 +207,13 @@ static int insert_device(std::vector &devices_list, const usb_dev int result = libusb_open(usb_device, &handle); if(result || (handle == NULL)) return result; + result = libusb_claim_interface(handle, usb_device_desc->capture_interface); + if(result == LIBUSB_SUCCESS) + libusb_release_interface(handle, usb_device_desc->capture_interface); + if(result < 0) { + libusb_close(handle); + return result; + } std::string serial_str = get_serial(handle, usb_descriptor, curr_serial_extra_id); if(usb_device_desc->is_3ds) devices_list.emplace_back(serial_str, "3DS", CAPTURE_CONN_USB, (void*)usb_device_desc, true, capture_get_has_3d(handle, usb_device_desc), true, HEIGHT_3DS, TOP_WIDTH_3DS + BOT_WIDTH_3DS, O3DS_SAMPLES_IN, 90, 0, 0, TOP_WIDTH_3DS, 0, VIDEO_DATA_RGB); diff --git a/source/Menus/LicenseMenu.cpp b/source/Menus/LicenseMenu.cpp index fe66af4..3f912b0 100755 --- a/source/Menus/LicenseMenu.cpp +++ b/source/Menus/LicenseMenu.cpp @@ -24,7 +24,7 @@ static const LicenseMenuOptionInfo sfml_license_4_option = { static const LicenseMenuOptionInfo ftd3xx_license_0_option = { .base_name = "This software makes use of"}; -#if defined(USE_FTD3) && defined(USE_FTD2) +#if defined(USE_FTD3) && defined(USE_FTD2_DRIVER) static const LicenseMenuOptionInfo ftd3xx_license_1_option = { .base_name = "FTD3XX and FTD2XX."}; #else @@ -46,6 +46,21 @@ static const LicenseMenuOptionInfo ftd3xx_license_3_option = { static const LicenseMenuOptionInfo ftd3xx_license_4_option = { .base_name = "driver-licence-terms-details/"}; +static const LicenseMenuOptionInfo libftdi_license_0_option = { +.base_name = "This software makes use of"}; + +static const LicenseMenuOptionInfo libftdi_license_1_option = { +.base_name = "libftdi1."}; + +static const LicenseMenuOptionInfo libftdi_license_2_option = { +.base_name = "For its license, check:"}; + +static const LicenseMenuOptionInfo libftdi_license_3_option = { +.base_name = "http://developer.intra2net.com/git/?p="}; + +static const LicenseMenuOptionInfo libftdi_license_4_option = { +.base_name = "libftdi;a=blob_plain;f=LICENSE;hb=HEAD/"}; + static const LicenseMenuOptionInfo libusb_license_0_option = { .base_name = "This software makes use of"}; @@ -127,14 +142,21 @@ static const LicenseMenuOptionInfo* pollable_options[] = { &sfml_license_2_option, &sfml_license_3_option, &sfml_license_4_option, -#if defined(USE_FTD3) || defined(USE_FTD2) +#if defined(USE_FTD3) || defined(USE_FTD2_DRIVER) &ftd3xx_license_0_option, &ftd3xx_license_1_option, &ftd3xx_license_2_option, &ftd3xx_license_3_option, &ftd3xx_license_4_option, #endif -#if defined(USE_DS_3DS_USB) || defined(USE_IS_NITRO_USB) || defined(USE_FTD3) || defined(USE_FTD2) +#ifdef USE_FTD2_LIBFTDI +&libftdi_license_0_option, +&libftdi_license_1_option, +&libftdi_license_2_option, +&libftdi_license_3_option, +&libftdi_license_4_option, +#endif +#if defined(USE_LIBUSB) || defined(USE_FTD3) || defined(USE_FTD2_DRIVER) &libusb_license_0_option, &libusb_license_1_option, &libusb_license_2_option, diff --git a/source/Menus/StatusMenu.cpp b/source/Menus/StatusMenu.cpp index 1150a9b..b1f5dec 100755 --- a/source/Menus/StatusMenu.cpp +++ b/source/Menus/StatusMenu.cpp @@ -143,7 +143,7 @@ void StatusMenu::prepare(float menu_scaling_factor, int view_size_x, int view_si this->labels[index]->setText(this->get_string_option(real_index, DEFAULT_ACTION) + " - V." + get_version_string()); break; case STATUS_MENU_CONNECTION: - this->labels[index]->setText(get_name_of_device(capture_status)); + this->labels[index]->setText(get_name_of_device(capture_status, true)); break; case STATUS_MENU_FPS_IN: this->labels[index + INC_ACTION]->setText(get_float_str_decimals(in_fps, 2)); diff --git a/source/WindowScreen.cpp b/source/WindowScreen.cpp index d61a754..752a7b1 100755 --- a/source/WindowScreen.cpp +++ b/source/WindowScreen.cpp @@ -51,7 +51,7 @@ WindowScreen::WindowScreen(ScreenType stype, CaptureStatus* capture_status, Disp FPSArrayInit(&this->in_fps); FPSArrayInit(&this->draw_fps); FPSArrayInit(&this->poll_fps); - (void)this->in_tex.resize({MAX_IN_VIDEO_WIDTH, MAX_IN_VIDEO_HEIGHT * NUM_FRAMES_BLENDED}); + (void)this->in_tex.resize({MAX_IN_VIDEO_WIDTH * NUM_FRAMES_BLENDED, MAX_IN_VIDEO_HEIGHT}); this->m_in_rect_top.setTexture(&this->in_tex); this->m_in_rect_bot.setTexture(&this->in_tex); this->display_data = display_data; @@ -83,11 +83,11 @@ WindowScreen::WindowScreen(ScreenType stype, CaptureStatus* capture_status, Disp if(current_shader->shader.loadFromMemory(get_shader_string(current_shader->shader_enum), sf::Shader::Type::Fragment)) { current_shader->is_valid = true; auto* const defaultStreamBuffer = sf::err().rdbuf(); - sf::err().rdbuf(nullptr); + sf::err().rdbuf(nullptr); sf::Glsl::Vec2 old_pos = {0.0, 0.0}; current_shader->shader.setUniform("old_frame_offset", old_pos); - sf::err().rdbuf(defaultStreamBuffer); - } + sf::err().rdbuf(defaultStreamBuffer); + } } loaded_shaders = true; } @@ -469,25 +469,25 @@ std::string WindowScreen::title_factory() { void WindowScreen::update_texture() { unsigned int m_texture = this->in_tex.getNativeHandle(); - if (this->saved_buf && m_texture) - { - // Copy pixels from the given array to the texture - glBindTexture(GL_TEXTURE_2D, m_texture); - GLenum format = GL_RGB; - GLenum type = GL_UNSIGNED_BYTE; - if(this->capture_status->device.video_data_type == VIDEO_DATA_BGR) - format = GL_BGR; - if(this->capture_status->device.video_data_type == VIDEO_DATA_RGB16) - type = GL_UNSIGNED_SHORT_5_6_5; - if(this->capture_status->device.video_data_type == VIDEO_DATA_BGR16) - type = GL_UNSIGNED_SHORT_5_6_5_REV; - glTexSubImage2D(GL_TEXTURE_2D, 0, static_cast(0), static_cast(this->curr_frame_texture_pos * MAX_IN_VIDEO_HEIGHT), static_cast(this->capture_status->device.width), static_cast(this->capture_status->device.height), format, type, this->saved_buf); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + if (this->saved_buf && m_texture) + { + // Copy pixels from the given array to the texture + glBindTexture(GL_TEXTURE_2D, m_texture); + GLenum format = GL_RGB; + GLenum type = GL_UNSIGNED_BYTE; + if(this->capture_status->device.video_data_type == VIDEO_DATA_BGR) + format = GL_BGR; + if(this->capture_status->device.video_data_type == VIDEO_DATA_RGB16) + type = GL_UNSIGNED_SHORT_5_6_5; + if(this->capture_status->device.video_data_type == VIDEO_DATA_BGR16) + type = GL_UNSIGNED_SHORT_5_6_5_REV; + glTexSubImage2D(GL_TEXTURE_2D, 0, static_cast(this->curr_frame_texture_pos * MAX_IN_VIDEO_WIDTH), static_cast(0), static_cast(this->capture_status->device.width), static_cast(this->capture_status->device.height), format, type, this->saved_buf); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - // Force an OpenGL flush, so that the texture data will appear updated - // in all contexts immediately (solves problems in multi-threaded apps) - glFlush(); - } + // Force an OpenGL flush, so that the texture data will appear updated + // in all contexts immediately (solves problems in multi-threaded apps) + glFlush(); + } } void WindowScreen::pre_texture_conversion_processing() { @@ -572,17 +572,17 @@ void WindowScreen::post_texture_conversion_processing(out_rect_data &rect_data, rect_data.out_tex.clear(); sf::RectangleShape final_in_rect = in_rect; sf::IntRect text_coords_rect = final_in_rect.getTextureRect(); - text_coords_rect.position.y += this->curr_frame_texture_pos * MAX_IN_VIDEO_HEIGHT; + text_coords_rect.position.x += this->curr_frame_texture_pos * MAX_IN_VIDEO_WIDTH; final_in_rect.setTextureRect(text_coords_rect); if(this->capture_status->connected && actually_draw) { bool use_default_shader = true; if(sf::Shader::isAvailable()) { int chosen_shader = choose_shader(true, is_top); if(chosen_shader >= 0) { - float old_frame_pos_y = 1.0 / NUM_FRAMES_BLENDED; - if(this->curr_frame_texture_pos == 1) - old_frame_pos_y = -1.0 / NUM_FRAMES_BLENDED; - sf::Glsl::Vec2 old_pos = {0.0, old_frame_pos_y}; + float old_frame_pos_x = ((float)(NUM_FRAMES_BLENDED - 1)) / NUM_FRAMES_BLENDED; + if(this->curr_frame_texture_pos > 0) + old_frame_pos_x = -1.0 / NUM_FRAMES_BLENDED; + sf::Glsl::Vec2 old_pos = {old_frame_pos_x, 0.0}; usable_shaders[chosen_shader].shader.setUniform("old_frame_offset", old_pos); rect_data.out_tex.draw(final_in_rect, &usable_shaders[chosen_shader].shader); use_default_shader = false; diff --git a/source/cc3dsfs.cpp b/source/cc3dsfs.cpp index 16bd6c5..3ea88d2 100755 --- a/source/cc3dsfs.cpp +++ b/source/cc3dsfs.cpp @@ -242,7 +242,7 @@ static void soundCall(AudioData *audio_data, CaptureData* capture_data) { if(data_buffer != NULL) { loaded_samples = audio.samples.size(); if((data_buffer->read > get_video_in_size(capture_data)) && (loaded_samples < MAX_MAX_AUDIO_LATENCY)) { - int n_samples = get_audio_n_samples(capture_data, data_buffer->read); + uint64_t n_samples = get_audio_n_samples(capture_data, data_buffer->read); double out_time = data_buffer->time_in_buf; bool conversion_success = convertAudioToOutput(out_buf[audio_buf_counter], n_samples, endianness, data_buffer, &capture_data->status); if(!conversion_success) diff --git a/source/conversions.cpp b/source/conversions.cpp index 9ee52ce..8d43813 100755 --- a/source/conversions.cpp +++ b/source/conversions.cpp @@ -1,7 +1,7 @@ #include "conversions.hpp" #include "devicecapture.hpp" #include "3dscapture_ftd3.hpp" -#include "dscapture_ftd2.hpp" +#include "dscapture_ftd2_shared.hpp" #include "usb_ds_3ds_capture.hpp" #include "usb_is_nitro_acquisition.hpp" @@ -215,7 +215,7 @@ bool convertVideoToOutput(VideoOutputData *p_out, const bool is_big_endian, Capt return converted; } -bool convertAudioToOutput(std::int16_t *p_out, uint64_t n_samples, const bool is_big_endian, CaptureDataSingleBuffer* data_buffer, CaptureStatus* status) { +bool convertAudioToOutput(std::int16_t *p_out, uint64_t &n_samples, const bool is_big_endian, CaptureDataSingleBuffer* data_buffer, CaptureStatus* status) { if(!status->device.has_audio) return true; CaptureReceived *p_in = &data_buffer->capture_buf; @@ -229,13 +229,8 @@ 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) { + 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 if(status->device.cc_type == CAPTURE_CONN_USB) { diff --git a/source/devicecapture.cpp b/source/devicecapture.cpp index 808a55e..09a470b 100755 --- a/source/devicecapture.cpp +++ b/source/devicecapture.cpp @@ -1,6 +1,6 @@ #include "devicecapture.hpp" #include "3dscapture_ftd3.hpp" -#include "dscapture_ftd2.hpp" +#include "dscapture_ftd2_shared.hpp" #include "usb_ds_3ds_capture.hpp" #include "usb_is_nitro_acquisition.hpp" @@ -80,7 +80,7 @@ bool connect(bool print_failed, CaptureData* capture_data, FrontendData* fronten list_devices_ftd3(devices_list, no_access_list); #endif #ifdef USE_FTD2 - list_devices_ftd2(devices_list, no_access_list); + list_devices_ftd2_shared(devices_list, no_access_list); #endif #ifdef USE_DS_3DS_USB list_devices_usb_ds_3ds(devices_list, no_access_list); @@ -118,7 +118,7 @@ bool connect(bool print_failed, CaptureData* capture_data, FrontendData* fronten return false; #endif #ifdef USE_FTD2 - if((devices_list[chosen_device].cc_type == CAPTURE_CONN_FTD2) && (!connect_ftd2(print_failed, capture_data, &devices_list[chosen_device]))) + if((devices_list[chosen_device].cc_type == CAPTURE_CONN_FTD2) && (!connect_ftd2_shared(print_failed, capture_data, &devices_list[chosen_device]))) return false; #endif #ifdef USE_DS_3DS_USB @@ -155,7 +155,7 @@ void captureCall(CaptureData* capture_data) { #endif #ifdef USE_FTD2 if(capture_data->status.device.cc_type == CAPTURE_CONN_FTD2) - ftd2_capture_main_loop(capture_data); + ftd2_capture_main_loop_shared(capture_data); #endif #ifdef USE_DS_3DS_USB if(capture_data->status.device.cc_type == CAPTURE_CONN_USB) @@ -181,7 +181,7 @@ void captureCall(CaptureData* capture_data) { #endif #ifdef USE_FTD2 if(capture_data->status.device.cc_type == CAPTURE_CONN_FTD2) - ftd2_capture_cleanup(capture_data); + ftd2_capture_cleanup_shared(capture_data); #endif #ifdef USE_DS_3DS_USB if(capture_data->status.device.cc_type == CAPTURE_CONN_USB) @@ -228,10 +228,12 @@ uint64_t get_video_in_size(CaptureData* capture_data) { return 0; } -std::string get_name_of_device(CaptureStatus* capture_status) { +std::string get_name_of_device(CaptureStatus* capture_status, bool use_long) { if(!capture_status->connected) return "Not connected"; - return capture_status->device.name + " - " + capture_status->device.serial_number; + if(!use_long) + return capture_status->device.name + " - " + capture_status->device.serial_number; + return capture_status->device.long_name + " - " + capture_status->device.serial_number; } void capture_init() { @@ -241,6 +243,9 @@ void capture_init() { #ifdef USE_IS_NITRO_USB usb_is_nitro_init(); #endif + #ifdef USE_FTD2 + ftd2_init_shared(); + #endif } void capture_close() { @@ -250,4 +255,7 @@ void capture_close() { #ifdef USE_IS_NITRO_USB usb_is_nitro_close(); #endif + #ifdef USE_FTD2 + ftd2_end_shared(); + #endif } diff --git a/source/utils.cpp b/source/utils.cpp index 696e037..5365df3 100755 --- a/source/utils.cpp +++ b/source/utils.cpp @@ -30,14 +30,14 @@ static bool _is_be = false; bool is_big_endian(void) { if(checked_be_once) return _is_be; - union { - uint32_t i; - char c[4]; - } value = {0x01020304}; + union { + uint32_t i; + char c[4]; + } value = {0x01020304}; checked_be_once = true; _is_be = value.c[0] == 1; - return _is_be; + return _is_be; } static uint32_t reverse_endianness(uint32_t value) { diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 4ab3f44..cd86758 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -39,3 +39,29 @@ add_custom_command( POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_BINARY_DIR} VERBATIM ) + +set(OUTPUT_NAME CMakeRenameLibFunctions) +project(${OUTPUT_NAME} VERSION 1.0.0 LANGUAGES CXX) + +add_executable(${OUTPUT_NAME} rename_lib_functions.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 +) + +set(OUTPUT_NAME CMakeRenameSymbols) +project(${OUTPUT_NAME} VERSION 1.0.0 LANGUAGES CXX) + +add_executable(${OUTPUT_NAME} 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/rename_lib_functions.cpp b/tools/rename_lib_functions.cpp new file mode 100644 index 0000000..d27ced9 --- /dev/null +++ b/tools/rename_lib_functions.cpp @@ -0,0 +1,93 @@ +#include +#include +#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 new_start lib_file" << endl; + return -1; + } + + string new_start(argv[2]); + ifstream input(argv[1], ios::in); + if(!input) { + cout << "Couldn't open input file!" << endl; + return -2; + } + vector file_lines; + vector new_start_lines; + string single_str = ""; + while (getline(input, single_str)) { + file_lines.push_back(single_str); + string new_string = single_str; + for(int i = 0; i < new_start.length(); i++) + new_string[i] = new_start[i]; + new_start_lines.push_back(new_string); + } + + input.close(); + + vector buffer; + ifstream lib_in(argv[3], ios::in | ios::binary); + if(!lib_in) { + cout << "Couldn't open in library file!" << endl; + return -2; + } + // Get length of file + lib_in.seekg(0, ios::end); + size_t length = lib_in.tellg(); + lib_in.seekg(0, ios::beg); + + //read file + if (length > 0) { + buffer.resize(length); + lib_in.read((char*)&buffer[0], length); + } + + for(int u = 0; u < new_start_lines.size(); u++) { + const uint8_t* old_data = (const uint8_t*)file_lines[u].c_str(); + const uint8_t* new_data = (const uint8_t*)new_start_lines[u].c_str(); + auto start_iterator = std::begin(buffer); + uint8_t* inner_buffer = &buffer[0]; + size_t old_data_size = strlen((const char*)old_data); + while(1) { + start_iterator = search( + start_iterator, std::end(buffer), + std::begin(file_lines[u]), std::end(file_lines[u])); + + if (start_iterator == std::end(buffer)) + break; + else + { + size_t match_pos = std::distance(std::begin(buffer), start_iterator); + // This is technically wrong, but it works, so... + if((match_pos > 0) && (inner_buffer[match_pos - 1] == 0)) { + for(int i = 0; i < old_data_size; i++) + inner_buffer[match_pos + i] = new_data[i]; + } + start_iterator += old_data_size; + } + } + } + + ofstream lib_out(argv[3], ios::out | ios::binary); + if(!lib_out) { + cout << "Couldn't open out library file!" << endl; + return -2; + } + lib_out.write((char*)&buffer[0], buffer.size()); + lib_out.close(); + + return 0; +} diff --git a/tools/rename_symbols_list.cpp b/tools/rename_symbols_list.cpp new file mode 100644 index 0000000..e596884 --- /dev/null +++ b/tools/rename_symbols_list.cpp @@ -0,0 +1,52 @@ +#include +#include +#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 new_start define_file" << endl; + return -1; + } + + string new_start(argv[2]); + ifstream input(argv[1], ios::in); + if(!input) { + cout << "Couldn't open input file!" << endl; + return -2; + } + vector file_lines; + vector new_start_lines; + string single_str = ""; + while (getline(input, single_str)) { + file_lines.push_back(single_str); + string new_string = single_str; + for(int i = 0; i < new_start.length(); i++) + new_string[i] = new_start[i]; + new_start_lines.push_back(new_string); + } + + input.close(); + + ofstream output_define(argv[3], 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] << " " << new_start_lines[i] << endl; + + output_define.close(); + + return 0; +}