Attempt using libftdi

This commit is contained in:
Lorenzooone 2024-11-29 10:07:51 +01:00
parent e89798b6ec
commit 8da1172b70
46 changed files with 2325 additions and 926 deletions

View File

@ -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$<$<CONFIG:Debug>: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 $<TARGET_FILE:${OUTPUT_NAME}> ${CMAKE_SOURCE_DIR}
VERBATIM
TARGET ${OUTPUT_NAME}
COMMENT "Copy Output"
POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${OUTPUT_NAME}> ${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)

View File

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

View File

@ -0,0 +1,28 @@
#ifndef __DSCAPTURE_FTD2_COMPATIBILITY_HPP
#define __DSCAPTURE_FTD2_COMPATIBILITY_HPP
#include "devicecapture.hpp"
void list_devices_ftd2_compatibility(std::vector<CaptureDevice> &devices_list, std::vector<no_access_recap_data> &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

View File

@ -0,0 +1,17 @@
#ifndef __DSCAPTURE_FTD2_DRIVER_HPP
#define __DSCAPTURE_FTD2_DRIVER_HPP
#include <vector>
#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<CaptureDevice> &devices_list, std::vector<no_access_recap_data> &no_access_list);
int ftd2_driver_open_serial(CaptureDevice* device, void** handle);
void ftd2_capture_main_loop_driver(CaptureData* capture_data);
#endif

View File

@ -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 <chrono>
// 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<std::chrono::high_resolution_clock>* 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

View File

@ -0,0 +1,21 @@
#ifndef __DSCAPTURE_FTD2_SHARED_HPP
#define __DSCAPTURE_FTD2_SHARED_HPP
#include <vector>
#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<CaptureDevice> &devices_list, std::vector<no_access_recap_data> &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

View File

@ -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<CaptureDevice> &devices_list, std::vector<no_access_recap_data> &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

View File

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

View File

@ -1,19 +0,0 @@
#ifndef __DSCAPTURE_FTD2_HPP
#define __DSCAPTURE_FTD2_HPP
#include <vector>
#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<CaptureDevice> &devices_list, std::vector<no_access_recap_data> &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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,8 @@
_FT_ListDevices
_FT_GetVIDPID
_FT_Close
_FT_CreateDeviceInfoList
_FT_GetDeviceInfoList
_FT_GetDeviceInfoDetail
_FT_GetDriverVersion
_FT_GetLibraryVersion

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,4 +2,4 @@ uniform sampler2D Texture0;
void main() {
gl_FragColor = texture2D(Texture0, gl_TexCoord[0].xy);
};
}

View File

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

View File

@ -9,7 +9,7 @@
#define FT_ASYNC_CALL FT_ReadPipeAsync
#endif
#include <ftd3xx.h>
#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<CaptureDevice> &devices_list, std::vector<no_
}
}
if(num_inserted == 0) {
#if defined(USE_IS_NITRO_USB) || defined(USE_DS_3DS_USB)
#ifdef USE_LIBUSB
if(get_usb_total_filtered_devices(ftd3xx_valid_vids, sizeof(ftd3xx_valid_vids) / sizeof(ftd3xx_valid_vids[0]), ftd3xx_valid_pids, sizeof(ftd3xx_valid_pids) / sizeof(ftd3xx_valid_pids[0])) != numDevs)
no_access_list.emplace_back("FTD3XX");
#endif

View File

@ -0,0 +1,273 @@
#include "dscapture_libftdi2.hpp"
#include "dscapture_ftd2_driver.hpp"
#include "devicecapture.hpp"
#include "dscapture_ftd2_compatibility.hpp"
#ifdef USE_FTD2_LIBFTDI
#include <ftdi.h>
#endif
#ifdef USE_FTD2_DRIVER
#define FTD2XX_STATIC
#include "ftd2xx_symbols_renames.h"
#include <ftd2xx.h>
#endif
#include <cstring>
#include <thread>
#include <chrono>
#include <iostream>
#define FT_FAILED(x) ((x) != FT_OK)
void list_devices_ftd2_compatibility(std::vector<CaptureDevice> &devices_list, std::vector<no_access_recap_data> &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
}

View File

@ -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 <ftd2xx.h>
#include <cstring>
#include <thread>
#include <chrono>
#include <iostream>
#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<CaptureDevice> &devices_list, std::vector<no_access_recap_data> &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<std::chrono::high_resolution_clock> &base_time) {
const auto curr_time = std::chrono::high_resolution_clock::now();
const std::chrono::duration<double> diff = curr_time - base_time;
base_time = curr_time;
capture_data->data_buffers.WriteToBuffer(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;
}

View File

@ -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 <cstring>
#include <thread>
#include <chrono>
#include <iostream>
#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<CaptureDevice> &devices_list, std::vector<no_access_recap_data> &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();
}

View File

@ -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 <ftdi.h>
#include <cstring>
#include <thread>
#include <chrono>
#include <iostream>
#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<CaptureDevice> &devices_list, std::vector<no_access_recap_data> &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<double> 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<std::chrono::high_resolution_clock> &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<double> 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;
}

View File

@ -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<CaptureDevice>& 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<CaptureDevice>& 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) {

View File

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

View File

@ -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 <ftd2xx.h>
#include <cstring>
#include <thread>
#include <chrono>
#include <iostream>
#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<CaptureDevice> &devices_list, std::vector<no_access_recap_data> &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(samples<MAX && src[samples]==0x4321)
samples++;
if(samples==MAX) //?? shouldn't happen
DEBUG_TRACE("wut?");
FT_Read(handle, frame->raw, samples*2, &bytesIn);
DEBUG_TRACE("resync(%d)",samples);
return FRAME_SKIP;
} else if(src[MAX-1]!=0x4321) {
samples=0;
while(samples<MAX && src[samples]!=0x4321)
samples++;
while(samples<MAX && src[samples]==0x4321)
samples++;
if(samples==MAX) //?? shouldn't happen
DEBUG_TRACE("wut?");
FT_Read(handle, frame->raw, 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(samples<S_MAX && a[samples]!=0x43214321)
samples++;
//sanity check
if(samples<547 || samples>548)
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<std::chrono::high_resolution_clock> &base_time) {
const auto curr_time = std::chrono::high_resolution_clock::now();
const std::chrono::duration<double> diff = curr_time - base_time;
base_time = curr_time;
capture_data->data_buffers.WriteToBuffer(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");
}
}

View File

@ -207,6 +207,13 @@ static int insert_device(std::vector<CaptureDevice> &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);

View File

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

View File

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

View File

@ -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<GLint>(0), static_cast<GLint>(this->curr_frame_texture_pos * MAX_IN_VIDEO_HEIGHT), static_cast<GLsizei>(this->capture_status->device.width), static_cast<GLsizei>(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<GLint>(this->curr_frame_texture_pos * MAX_IN_VIDEO_WIDTH), static_cast<GLint>(0), static_cast<GLsizei>(this->capture_status->device.width), static_cast<GLsizei>(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;

View File

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

View File

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

View File

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

View File

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

View File

@ -39,3 +39,29 @@ add_custom_command(
POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${OUTPUT_NAME}> ${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 $<TARGET_FILE:${OUTPUT_NAME}> ${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 $<TARGET_FILE:${OUTPUT_NAME}> ${CMAKE_BINARY_DIR}
VERBATIM
)

View File

@ -0,0 +1,93 @@
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <algorithm>
#include <cstring>
#if (!defined(_MSC_VER)) || (_MSC_VER > 1916)
#include <filesystem>
#else
#include <experimental/filesystem>
#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<string> file_lines;
vector<string> 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<uint8_t> 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;
}

View File

@ -0,0 +1,52 @@
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <algorithm>
#include <cstring>
#if (!defined(_MSC_VER)) || (_MSC_VER > 1916)
#include <filesystem>
#else
#include <experimental/filesystem>
#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<string> file_lines;
vector<string> 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;
}