Add base ftd2 support (bad performance)

This commit is contained in:
Lorenzooone 2024-11-27 14:23:00 +01:00
parent 5e51295ca5
commit e89798b6ec
17 changed files with 685 additions and 26 deletions

View File

@ -5,7 +5,7 @@ set(TARGET_LANGUAGES CXX C)
project(cc3dsfs VERSION 1.0.0 LANGUAGES ${TARGET_LANGUAGES})
include(ExternalProject)
set(N3DSXL_LOOPY_SUPPORT 1)
set(N3DSXL_LOOPY_SUPPORT 0)
set(NEW_DS_LOOPY_SUPPORT 1)
set(IS_NITRO_SUPPORT 1)
set(OLD_DS_3DS_LOOPY_SUPPORT 1)
@ -172,7 +172,7 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
set(FTD2XX_SUBFOLDER win)
set(FTD2XX_HEADER_PATH ftd2xx.h)
if(${WINDOWS_FTD2XX_USE_SHARED_LIB})
set(FTD2XX_BUILD_COMMAND ${FTD3XX_BUILD_COMMAND}_dll)
set(FTD2XX_BUILD_COMMAND ${FTD2XX_BUILD_COMMAND}_dll)
set(FTD2XX_WINDOWS_PATH_SPECIFIER "")
if(WINDOWS_ARM64)
set(FTD2XX_WINDOWS_PATH_SPECIFIER Release)
@ -266,6 +266,9 @@ if(NEW_DS_LOOPY_SUPPORT)
endif()
endif()
set(TOOLS_DATA_DIR ${CMAKE_BINARY_DIR}/tools_and_data)
file(MAKE_DIRECTORY ${TOOLS_DATA_DIR})
set(FETCH_CONTENT_MAKE_AVAILABLE_LIBRARIES "")
set(SOURCE_CPP_EXTRA_FILES "")
set(EXTRA_DEPENDENCIES "")
@ -283,7 +286,7 @@ if(N3DSXL_LOOPY_SUPPORT)
endif()
if(NEW_DS_LOOPY_SUPPORT)
list(APPEND FETCH_CONTENT_MAKE_AVAILABLE_LIBRARIES FTD2XX)
list(APPEND SOURCE_CPP_EXTRA_FILES ${SOURCE_CPP_DEVICE_FILES_BASE_PATH}/dscapture_ftd2.cpp)
list(APPEND SOURCE_CPP_EXTRA_FILES ${SOURCE_CPP_DEVICE_FILES_BASE_PATH}/dscapture_ftd2.cpp ${TOOLS_DATA_DIR}/ftd2_ds2_fw_1.cpp ${TOOLS_DATA_DIR}/ftd2_ds2_fw_2.cpp)
list(APPEND EXTRA_DEPENDENCIES FTD2XX_BUILD_PROJECT)
if(MSVC)
list(APPEND EXTRA_CXX_FLAGS "/DUSE_FTD2")
@ -360,11 +363,14 @@ else()
set(FTD3XX_BUILD_COMMAND_PARAMETERS ${ftd3xx_SOURCE_DIR} ${ftd3xx_BINARY_DIR}/${FTD3XX_SUBFOLDER} ${FTD3XX_LIB})
set(FTD2XX_BUILD_COMMAND_PARAMETERS ${ftd2xx_SOURCE_DIR} ${ftd2xx_BINARY_DIR}/${FTD2XX_SUBFOLDER} build/${FTD2XX_LIB})
endif()
if(N3DSXL_LOOPY_SUPPORT)
ExternalProject_Add(FTD3XX_BUILD_PROJECT
SOURCE_DIR ${ftd3xx_SOURCE_DIR}
BINARY_DIR ${ftd3xx_BINARY_DIR}
BUILD_COMMAND ${FTD3XX_BUILD_COMMAND}${SCRIPT_EXTENSION} ${FTD3XX_BUILD_COMMAND_PARAMETERS}
#COMMAND ${TOOLS_DATA_DIR}/CMakePrepareRenameSymbols${HOST_FINAL_EXTENSION} ${SETUP_SCRIPTS_DIR}/ftd_shared_symbols.txt ftd3_ ${TOOLS_DATA_DIR}/bad_ftd3_symbols_list.txt ${TOOLS_DATA_DIR}/ftd3xx_symbols_renames.h
#COMMAND ${CMAKE_OBJCOPY} ARGS --redefine-syms=${TOOLS_DATA_DIR}/bad_ftd3_symbols_list.txt ${ftd3xx_BINARY_DIR}/${FTD3XX_SUBFOLDER}/${FTD3XX_LIB}
UPDATE_COMMAND ""
CONFIGURE_COMMAND ""
INSTALL_COMMAND ""
@ -375,6 +381,8 @@ if(NEW_DS_LOOPY_SUPPORT)
SOURCE_DIR ${ftd2xx_SOURCE_DIR}
BINARY_DIR ${ftd2xx_BINARY_DIR}
BUILD_COMMAND ${FTD2XX_BUILD_COMMAND}${SCRIPT_EXTENSION} ${FTD2XX_BUILD_COMMAND_PARAMETERS}
#COMMAND ${TOOLS_DATA_DIR}/CMakePrepareRenameSymbols${HOST_FINAL_EXTENSION} ${SETUP_SCRIPTS_DIR}/ftd_shared_symbols.txt ftd2_ ${TOOLS_DATA_DIR}/bad_ftd2_symbols_list.txt ${TOOLS_DATA_DIR}/ftd2xx_symbols_renames.h
#COMMAND ${CMAKE_OBJCOPY} ARGS --redefine-syms=${TOOLS_DATA_DIR}/bad_ftd2_symbols_list.txt ${ftd2xx_BINARY_DIR}/${FTD2XX_SUBFOLDER}/${FTD2XX_LIB}
UPDATE_COMMAND ""
CONFIGURE_COMMAND ""
INSTALL_COMMAND ""
@ -386,8 +394,6 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# search headers and libraries in the target environment
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(TOOLS_DATA_DIR ${CMAKE_BINARY_DIR}/tools_and_data)
file(MAKE_DIRECTORY ${TOOLS_DATA_DIR})
execute_process(COMMAND ${CMAKE_COMMAND} -B ${TOOLS_DATA_DIR} ${CMAKE_SOURCE_DIR}/tools)
execute_process(COMMAND ${CMAKE_COMMAND} --build ${TOOLS_DATA_DIR})
@ -426,6 +432,20 @@ add_custom_command(
DEPENDS ${CMAKE_SOURCE_DIR}/data/font.ttf ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION}
)
add_custom_command(
OUTPUT ${TOOLS_DATA_DIR}/ftd2_ds2_fw_1.cpp
COMMENT "Convert fw binary to C - FTD2 NDS 1"
COMMAND ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION} ${CMAKE_SOURCE_DIR}/bin/ftd2_ds2_fw_1.bin ${TOOLS_DATA_DIR} ftd2_ds2_fw_1 ftd2_ds2_fw_1
DEPENDS ${CMAKE_SOURCE_DIR}/bin/ftd2_ds2_fw_1.bin ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION}
)
add_custom_command(
OUTPUT ${TOOLS_DATA_DIR}/ftd2_ds2_fw_2.cpp
COMMENT "Convert fw binary to C - FTD2 NDS 2"
COMMAND ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION} ${CMAKE_SOURCE_DIR}/bin/ftd2_ds2_fw_2.bin ${TOOLS_DATA_DIR} ftd2_ds2_fw_2 ftd2_ds2_fw_2
DEPENDS ${CMAKE_SOURCE_DIR}/bin/ftd2_ds2_fw_2.bin ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION}
)
set(SHADERS_LIST "")
list(APPEND SHADERS_LIST ${CMAKE_SOURCE_DIR}/shaders/bit_crusher_fragment_shader.2_to_x_1_7.frag ${CMAKE_SOURCE_DIR}/shaders/bit_merger_crusher_fragment_shader.2_to_x_1_6.frag ${CMAKE_SOURCE_DIR}/shaders/bit_merger_crusher_fragment_shader_7.frag ${CMAKE_SOURCE_DIR}/shaders/bit_merger_fragment_shader.2_to_x_0_6.frag ${CMAKE_SOURCE_DIR}/shaders/bit_merger_fragment_shader_7.frag ${CMAKE_SOURCE_DIR}/shaders/frame_blending_bit_crusher_fragment_shader.2_to_x_1_7.frag ${CMAKE_SOURCE_DIR}/shaders/frame_blending_fragment_shader.frag ${CMAKE_SOURCE_DIR}/shaders/no_effect_fragment_shader.frag)

BIN
bin/ftd2_ds2_fw_1.bin Normal file

Binary file not shown.

BIN
bin/ftd2_ds2_fw_2.bin Normal file

Binary file not shown.

View File

@ -8,6 +8,8 @@
#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);

View File

@ -1,12 +1,14 @@
#ifndef __USB_GENERIC_HPP
#define __USB_GENERIC_HPP
#if defined(USE_IS_NITRO_USB) || defined(USE_DS_3DS_USB)
#include <libusb.h>
libusb_context* get_usb_ctx();
#endif
void usb_init();
void usb_close();
bool usb_is_initialized();
libusb_context* get_usb_ctx();
int get_usb_total_filtered_devices(const uint16_t valid_vids[], size_t num_vids, const uint16_t valid_pids[], size_t num_pids);
#endif

View File

@ -94,6 +94,12 @@ struct ALIGNED(16) PACKED USBOldDSCaptureReceived {
USBOldDSFrameInfo frameinfo;
};
struct ALIGNED(16) PACKED FTD2OldDSCaptureReceived {
USBOldDSVideoInputData video_in;
uint16_t audio_data[DS_SAMPLES_IN];
uint8_t unused_buffer[EXTRA_DATA_BUFFER_USB_SIZE];
};
struct ALIGNED(16) PACKED ISNitroCaptureReceived {
ISNitroEmulatorVideoInputData video_in;
};
@ -106,13 +112,15 @@ union CaptureReceived {
USB3DSCaptureReceived usb_received_3ds;
USB3DSCaptureReceived_3D usb_received_3ds_3d;
USBOldDSCaptureReceived usb_received_old_ds;
FTD2OldDSCaptureReceived ftd2_received_old_ds;
ISNitroCaptureReceived is_nitro_capture_received;
};
struct CaptureDevice {
CaptureDevice(std::string serial_number, std::string name, CaptureConnectionType cc_type, const void* descriptor, bool is_3ds, bool has_3d, bool has_audio, int width, int height, int max_samples_in, int base_rotation, int top_screen_x, int top_screen_y, int bot_screen_x, int bot_screen_y, InputVideoDataType video_data_type) : serial_number(serial_number), name(name), cc_type(cc_type), descriptor(descriptor), is_3ds(is_3ds), has_3d(has_3d), has_audio(has_audio), width(width), height(height), max_samples_in(max_samples_in), base_rotation(base_rotation), top_screen_x(top_screen_x), top_screen_y(top_screen_y), bot_screen_x(bot_screen_x), bot_screen_y(bot_screen_y), path(""), video_data_type(video_data_type) {}
CaptureDevice(std::string serial_number, std::string name, std::string path, CaptureConnectionType cc_type, const void* descriptor, bool is_3ds, bool has_3d, bool has_audio, int width, int height, int max_samples_in, int base_rotation, int top_screen_x, int top_screen_y, int bot_screen_x, int bot_screen_y, InputVideoDataType video_data_type) : serial_number(serial_number), name(name), cc_type(cc_type), descriptor(descriptor), is_3ds(is_3ds), has_3d(has_3d), has_audio(has_audio), width(width), height(height), max_samples_in(max_samples_in), base_rotation(base_rotation), top_screen_x(top_screen_x), top_screen_y(top_screen_y), bot_screen_x(bot_screen_x), bot_screen_y(bot_screen_y), path(path), video_data_type(video_data_type) {}
CaptureDevice(): serial_number(""), name(""), cc_type(CAPTURE_CONN_USB), descriptor(NULL), is_3ds(false), has_3d(false), has_audio(false), width(0), height(0), max_samples_in(0), base_rotation(0), top_screen_x(0), top_screen_y(0), bot_screen_x(0), bot_screen_y(0), path(""), video_data_type(VIDEO_DATA_RGB) {}
CaptureDevice(std::string serial_number, std::string name, CaptureConnectionType cc_type, const void* descriptor, bool is_3ds, bool has_3d, bool has_audio, int width, int height, int max_samples_in, int base_rotation, int top_screen_x, int top_screen_y, int bot_screen_x, int bot_screen_y, InputVideoDataType video_data_type) : serial_number(serial_number), name(name), cc_type(cc_type), descriptor(descriptor), is_3ds(is_3ds), has_3d(has_3d), has_audio(has_audio), width(width), height(height), max_samples_in(max_samples_in), base_rotation(base_rotation), top_screen_x(top_screen_x), top_screen_y(top_screen_y), bot_screen_x(bot_screen_x), bot_screen_y(bot_screen_y), path(""), video_data_type(video_data_type), firmware_id(0), is_rgb_888(false) {}
CaptureDevice(std::string serial_number, std::string name, CaptureConnectionType cc_type, const void* descriptor, bool is_3ds, bool has_3d, bool has_audio, int width, int height, int max_samples_in, int base_rotation, int top_screen_x, int top_screen_y, int bot_screen_x, int bot_screen_y, InputVideoDataType video_data_type, int firmware_id, bool is_rgb_888) : serial_number(serial_number), name(name), cc_type(cc_type), descriptor(descriptor), is_3ds(is_3ds), has_3d(has_3d), has_audio(has_audio), width(width), height(height), max_samples_in(max_samples_in), base_rotation(base_rotation), top_screen_x(top_screen_x), top_screen_y(top_screen_y), bot_screen_x(bot_screen_x), bot_screen_y(bot_screen_y), path(""), video_data_type(video_data_type), firmware_id(firmware_id), is_rgb_888(is_rgb_888) {}
CaptureDevice(std::string serial_number, std::string name, std::string path, CaptureConnectionType cc_type, const void* descriptor, bool is_3ds, bool has_3d, bool has_audio, int width, int height, int max_samples_in, int base_rotation, int top_screen_x, int top_screen_y, int bot_screen_x, int bot_screen_y, InputVideoDataType video_data_type) : serial_number(serial_number), name(name), cc_type(cc_type), descriptor(descriptor), is_3ds(is_3ds), has_3d(has_3d), has_audio(has_audio), width(width), height(height), max_samples_in(max_samples_in), base_rotation(base_rotation), top_screen_x(top_screen_x), top_screen_y(top_screen_y), bot_screen_x(bot_screen_x), bot_screen_y(bot_screen_y), path(path), video_data_type(video_data_type), firmware_id(0), is_rgb_888(false) {}
CaptureDevice(): serial_number(""), name(""), cc_type(CAPTURE_CONN_USB), descriptor(NULL), is_3ds(false), has_3d(false), has_audio(false), width(0), height(0), max_samples_in(0), base_rotation(0), top_screen_x(0), top_screen_y(0), bot_screen_x(0), bot_screen_y(0), path(""), firmware_id(0), video_data_type(VIDEO_DATA_RGB), is_rgb_888(false) {}
std::string serial_number;
std::string name;
@ -131,6 +139,8 @@ struct CaptureDevice {
int top_screen_y;
int bot_screen_x;
int bot_screen_y;
int firmware_id;
bool is_rgb_888;
};
struct CaptureStatus {

View File

@ -71,7 +71,7 @@
// In general, it should be less than * 2, but you never know. For now, go for safety at x16...
#define O3DS_SAMPLES_IN (1096 * 16)
#define N3DSXL_SAMPLES_IN (1096 * 16)
#define DS_SAMPLES_IN (1096 * 16)
#define DS_SAMPLES_IN (1096)
#define MAX_SAMPLES_IN O3DS_SAMPLES_IN
#endif

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,69 @@
usbi_hotplug_notification
usbi_default_context
usbi_log
usbi_alloc_device
usbi_connect_device
usbi_disconnect_device
usbi_sanitize_device
usbi_get_device_by_session_id
usbi_signal_event
usbi_clear_event
active_contexts_lock
discovered_devs_append
libusb_get_version
libusb_error_name
libusb_exit
libusb_init
libusb_set_option
libusb_set_debug
libusb_set_auto_detach_kernel_driver
libusb_attach_kernel_driver
libusb_detach_kernel_driver
libusb_kernel_driver_active
libusb_dev_mem_free
libusb_dev_mem_alloc
libusb_free_streams
libusb_alloc_streams
libusb_reset_device
libusb_clear_halt
libusb_unref_device
libusb_ref_device
libusb_has_capability
libusb_get_device_list
libusb_free_device_list
libusb_get_bus_number
libusb_get_port_number
libusb_get_port_numbers
libusb_get_port_path
libusb_get_parent
libusb_get_device_address
libusb_get_device_speed
libusb_get_max_packet_size
libusb_get_max_iso_packet_size
libusb_open
libusb_open_device_with_vid_pid
libusb_close
libusb_get_device
libusb_get_configuration
libusb_set_configuration
libusb_claim_interface
libusb_release_interface
libusb_set_interface_alt_setting
libusb_hotplug_register_callback
libusb_hotplug_deregister_callback
libusb_get_device_descriptor
libusb_get_active_config_descriptor
libusb_get_config_descriptor
libusb_get_config_descriptor_by_value
libusb_free_config_descriptor
libusb_get_ss_endpoint_companion_descriptor
libusb_free_ss_endpoint_companion_descriptor
libusb_free_bos_descriptor
libusb_get_bos_descriptor
libusb_get_usb_2_0_extension_descriptor
libusb_free_usb_2_0_extension_descriptor
libusb_get_ss_usb_device_capability_descriptor
libusb_free_ss_usb_device_capability_descriptor
libusb_get_container_id_descriptor
libusb_free_container_id_descriptor
libusb_get_string_descriptor_ascii

View File

@ -1,5 +1,6 @@
#include "3dscapture_ftd3.hpp"
#include "devicecapture.hpp"
//#include "ftd3xx_symbols_renames.h"
#ifdef _WIN32
#define FTD3XX_STATIC
@ -103,7 +104,7 @@ void list_devices_ftd3(std::vector<CaptureDevice> &devices_list, std::vector<no_
DWORD Type = 0;
DWORD ID = 0;
char SerialNumber[SERIAL_NUMBER_SIZE] = { 0 };
char Description[33] = { 0 };
char Description[65] = { 0 };
for (DWORD i = 0; i < numDevs; i++)
{
ftStatus = FT_GetDeviceInfoDetail(i, &Flags, &Type, &ID, NULL,

View File

@ -1,5 +1,10 @@
#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>
@ -9,23 +14,492 @@
#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 0;
return sizeof(USBOldDSVideoInputData);
}
static uint64_t get_capture_size(CaptureData* capture_data) {
return 0;
return (((sizeof(FTD2OldDSCaptureReceived) - EXTRA_DATA_BUFFER_USB_SIZE) + (MAX_PACKET_SIZE_FTD2 - 1)) / MAX_PACKET_SIZE_FTD2) * MAX_PACKET_SIZE_FTD2; // multiple of maxPacketSize
}
static bool pass_if_FT_queue_empty(FT_HANDLE handle) {
DWORD bytesIn = 0;
FT_STATUS ftStatus;
ftStatus = FT_GetQueueStatus(handle, &bytesIn);
if(FT_FAILED(ftStatus) || (bytesIn != 0)) //should be empty
return false;
return true;
}
static bool full_ftd2_write(FT_HANDLE handle, const uint8_t* data, size_t size) {
FT_STATUS ftStatus;
if(!pass_if_FT_queue_empty(handle)) // maybe MPSSE error?
return false;
DWORD sent;
ftStatus = FT_Write(handle, (void*)data, size, &sent);
if(FT_FAILED(ftStatus) || (sent != size))
return false;
return true;
}
//verify CDONE==val
static bool check_cdone(FT_HANDLE handle, bool want_active) {
static const uint8_t cmd[] = {
0x81, //read D
0x83, //read C
};
uint8_t buf[2];
if(!full_ftd2_write(handle, cmd, sizeof(cmd)))
return false;
DWORD bytesIn;
FT_STATUS ftStatus = FT_Read(handle, buf, 2, &bytesIn);
if(FT_FAILED(ftStatus) || (bytesIn != 2) || (buf[0] == 0xFA))
return false;
if(want_active)
return (buf[0] & 0x40);
return !(buf[0] & 0x40);
}
static FT_STATUS end_spi_tx(uint8_t *txBuf, FT_STATUS ftStatus) {
delete []txBuf;
return ftStatus;
}
static FT_STATUS ftd2_spi_tx(FT_HANDLE handle, const uint8_t* buf, int size) {
uint8_t *txBuf = new uint8_t[TX_SPI_SIZE + TX_SPI_OFFSET];
FT_STATUS ftStatus;
int len;
DWORD sent;
DWORD bytesIn;
DWORD wrote = 0;
if(!pass_if_FT_queue_empty(handle))
return end_spi_tx(txBuf, FT_OTHER_ERROR);
while(size > 0) {
len = size;
if(len > TX_SPI_SIZE)
len = TX_SPI_SIZE;
memcpy(&txBuf[TX_SPI_OFFSET], &buf[wrote], len);
txBuf[0] = 0x11;
txBuf[1] = (len - 1) & 0xFF;
txBuf[2] = ((len - 1) >> 8) & 0xFF;
ftStatus = FT_Write(handle, (void*)txBuf, len + TX_SPI_OFFSET, &sent);
if(FT_FAILED(ftStatus))
return end_spi_tx(txBuf, ftStatus);
if(sent != (len + TX_SPI_OFFSET))
return end_spi_tx(txBuf, FT_INSUFFICIENT_RESOURCES);
if(!pass_if_FT_queue_empty(handle))
return end_spi_tx(txBuf, FT_OTHER_ERROR);
wrote += sent - TX_SPI_OFFSET;
size -= len;
}
return end_spi_tx(txBuf, FT_OK);
}
static bool fpga_config(FT_HANDLE handle, const uint8_t* bitstream, int size) {
//D6=CDONE (in)
//D3=SS (out)
//D2=TDO (in)
//D1=TDI (out)
//D0=TCK (out)
//C7=reset (out)
//Lattice programming:
// hold SS low
// pulse reset 200ns
// wait 1200us
// release SS
// send 8 clocks
// hold SS low
// send configuration MSB first, sampled on +clk
// release SS
// CDONE should go high within 100 clocks
// send >49 clocks after CDONE=1
static const uint8_t cmd0[] = { //configure for lattice SPI:
0x82, 0x7f, 0x80, //set Cx pins {val,dir:1=out}: reset=0
0x80, 0xf0, 0x0b, //set Dx pins {val,dir:1=out}: SS=0, clk idle low, TDI out, TCK out
0x8f, LE16(RESETDELAY), //reset delay
0x82, 0xff, 0x00, //set Cx pins: reset=PU (does val=1 enable pullups? seems to...)
0x8f, LE16(INITDELAY), //init delay
0x80, 0xf8, 0x0b, //set Dx pins: SS=1
0x8f, LE16(1), //16 dummy clocks
0x80, 0xf0, 0x0b, //set Dx pins: SS=0
};
FT_STATUS ftStatus;
ftStatus = FT_SetTimeouts(handle, 300, 300);
if(FT_FAILED(ftStatus))
return false;
if(!full_ftd2_write(handle, cmd0, sizeof(cmd0)))
return false;
//verify CDONE=0
if(!check_cdone(handle, false))
return false;
//send configuration
ftStatus = ftd2_spi_tx(handle, bitstream, size);
if(FT_FAILED(ftStatus))
return false;
//finish up
static const uint8_t cmd1[] = {
0x80, 0xf8, 0x0b, //set Dx pins: SS=1
0x8f, LE16(20), //>150 dummy clocks
0x80, 0x00, 0x00, //float Dx
0x82, 0x00, 0x00, //float Cx
};
if(!full_ftd2_write(handle, cmd1, sizeof(cmd1)))
return false;
//verify CDONE=1
if(!check_cdone(handle, true))
return false;
return true;
}
static bool init_MPSSE(FT_HANDLE handle) {
static const uint8_t cmd[] = {
0x85, //no loopback
0x8d, //disable 3-phase clocking
0x8a, //disable clk divide-by-5
0x97, //disable adaptive clocking
0x86, LE16(CLKDIV), //set clock rate
};
FT_STATUS ftStatus;
ftStatus = FT_ResetDevice(handle);
if(FT_FAILED(ftStatus))
return false;
ftStatus = FT_SetUSBParameters(handle, FTD2XX_IN_SIZE, FTD2XX_OUT_SIZE); //Multiple of 64 bytes up to 64k
if(FT_FAILED(ftStatus))
return false;
ftStatus = FT_SetChars(handle, 0, 0, 0, 0);
if(FT_FAILED(ftStatus))
return false;
ftStatus = FT_SetTimeouts(handle, 300, 300); //read,write timeout (ms)
if(FT_FAILED(ftStatus))
return false;
ftStatus = FT_SetLatencyTimer(handle, 3); //time to wait before incomplete packet is sent (default=16ms). MPSSE read seems to fail on 2 sometimes, too fast?
if(FT_FAILED(ftStatus))
return false;
ftStatus = FT_SetFlowControl(handle, FT_FLOW_RTS_CTS, 0, 0); //turn on flow control to synchronize IN requests
if(FT_FAILED(ftStatus))
return false;
ftStatus = FT_SetBitMode(handle, 0x00, FT_BITMODE_RESET); //performs a general reset on MPSSE
if(FT_FAILED(ftStatus))
return false;
ftStatus = FT_SetBitMode(handle, 0x00, FT_BITMODE_MPSSE); //enable MPSSE mode
if(FT_FAILED(ftStatus))
return false;
//MPSSE seems to choke on first write sometimes :/ Send, purge, resend.
DWORD sent;
ftStatus = FT_Write(handle, (void*)cmd, 1, &sent); //enable MPSSE mode
if(FT_FAILED(ftStatus))
return false;
default_sleep();
ftStatus = FT_Purge(handle, FT_PURGE_RX | FT_PURGE_TX);
if(FT_FAILED(ftStatus))
return false;
return full_ftd2_write(handle, cmd, sizeof(cmd));
}
static void preemptive_close_connection(CaptureData* capture_data) {
FT_ResetDevice(capture_data->handle);
FT_Close(capture_data->handle);
}
bool connect_ftd2(bool print_failed, CaptureData* capture_data, CaptureDevice* device) {
return false;
char SerialNumber[SERIAL_NUMBER_SIZE] = { 0 };
strncpy(SerialNumber, device->serial_number.c_str(), REAL_SERIAL_NUMBER_SIZE);
SerialNumber[REAL_SERIAL_NUMBER_SIZE] = 0;
if(FT_OpenEx(SerialNumber, FT_OPEN_BY_SERIAL_NUMBER, &capture_data->handle)) {
capture_error_print(print_failed, capture_data, "Create failed");
return false;
}
if(!init_MPSSE(capture_data->handle)) {
preemptive_close_connection(capture_data);
capture_error_print(print_failed, capture_data, "MPSSE init failed");
return false;
}
if(!fpga_config(capture_data->handle, ftd2_ds2_fws[device->firmware_id - 1], ftd2_ds2_sizes[device->firmware_id - 1])) {
preemptive_close_connection(capture_data);
capture_error_print(print_failed, capture_data, "FPGA config failed");
return false;
}
FT_STATUS ftStatus;
WORD val=0;
ftStatus = FT_ReadEE(capture_data->handle, 1, &val);
if(FT_FAILED(ftStatus) || (val != 0x0403)) { //=85A8: something went wrong (fpga is configured but FT chip detected wrong eeprom size)
preemptive_close_connection(capture_data);
capture_error_print(print_failed, capture_data, "EEPROM read error");
return false;
}
/*
WORD Firmware = 0;
WORD Hardware = 0;
ftStatus = FT_ReadEE(capture_data->handle, 0x10, &Firmware);
if(FT_FAILED(ftStatus)) {
preemptive_close_connection(capture_data);
capture_error_print(print_failed, capture_data, "Firmware ID read error");
return false;
}
ftStatus = FT_ReadEE(capture_data->handle, 0x11, &Hardware);
if(FT_FAILED(ftStatus)) {
preemptive_close_connection(capture_data);
capture_error_print(print_failed, capture_data, "Hardware ID read error");
return false;
}
*/
ftStatus = FT_SetBitMode(capture_data->handle, 0x00, FT_BITMODE_SYNC_FIFO); //to FIFO mode. This takes over port B, pins shouldn't get modified though
if(FT_FAILED(ftStatus)) {
preemptive_close_connection(capture_data);
capture_error_print(print_failed, capture_data, "Bitmode setup error");
return false;
}
ftStatus = FT_SetTimeouts(capture_data->handle, 50, 50);
if(FT_FAILED(ftStatus)) {
preemptive_close_connection(capture_data);
capture_error_print(print_failed, capture_data, "Timeouts setup error");
return false;
}
static const uint8_t cmd[]={ 0x80, 0x01 }; //enable capture
if(!full_ftd2_write(capture_data->handle, cmd, sizeof(cmd))) {
preemptive_close_connection(capture_data);
capture_error_print(print_failed, capture_data, "Capture enable error");
return false;
}
return true;
}
/*
//DS frame:
// video (top|bottom interleaved RGB16), 256*192*2*2 bytes
// audio (16bit stereo, approx. 32729 Hz), 0x8F4 bytes
// actual number of samples varies, audio is padded with 0x4321
FrameResult DS2Device::getFrame(DSFrame *frame) {
enum {
FRAMESIZE = ndsWidth*ndsHeight*2*2,
S_MAX = 0x47A/2, //#audiosamples(dword) aligns frame to 510 bytes..
READSIZE = FRAMESIZE + S_MAX*4,
MAX = READSIZE/2, //(usbFifoWords)
};
FT_STATUS status;
DWORD bytesIn;
status=FT_Read(handle, frame->raw, READSIZE, &bytesIn);
if(status!=FT_OK) {
DEBUG_TRACE("err %d\n",status); //disconnected = FT_IO_ERROR
usb_close();
return FRAME_ERROR;
}
if(bytesIn!=READSIZE) { //stream stopped (lid closed / DS is off)
DEBUG_TRACE(".");
return FRAME_SKIP;
}
//check sync
uint16_t *src=(uint16_t*)frame->raw;
int samples;
if(src[0]==0x4321) {
samples=0;
while(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

@ -25,7 +25,6 @@ struct deinterleaved_ds_pixels_le {
uint64_t fourth : 16;
};
#ifdef USE_FTD3
static inline void convertVideoToOutputChunk(RGB83DSVideoInputData *p_in, VideoOutputData *p_out, int iters, int start_in, int start_out) {
memcpy(&p_out->screen_data[start_out], &p_in->screen_data[start_in], iters * 3);
}
@ -62,14 +61,7 @@ static void ftd3_convertVideoToOutput(CaptureReceived *p_in, VideoOutputData *p_
convertVideoToOutputChunk_3D(&p_in->ftd3_received_3d.video_in, p_out, IN_VIDEO_WIDTH_3DS_3D, (((i * 3) + 1) * IN_VIDEO_WIDTH_3DS_3D) + IN_VIDEO_NO_BOTTOM_SIZE_3DS_3D, TOP_SIZE_3DS + (i * IN_VIDEO_WIDTH_3DS_3D));
}
}
#endif
#ifdef USE_FTD2
static void ftd2_convertVideoToOutput(CaptureReceived *p_in, VideoOutputData *p_out) {
}
#endif
#ifdef USE_DS_3DS_USB
static inline void usb_oldDSconvertVideoToOutputHalfLineDirectOptLE(USBOldDSCaptureReceived *p_in, VideoOutputData *p_out, int input_halfline, int output_halfline) {
//de-interleave pixels
deinterleaved_ds_pixels_le* out_ptr_top = (deinterleaved_ds_pixels_le*)p_out->screen_data;
@ -162,6 +154,10 @@ static void usb_oldDSconvertVideoToOutput(USBOldDSCaptureReceived *p_in, VideoOu
#endif
}
static void ftd2_convertVideoToOutput(CaptureReceived *p_in, VideoOutputData *p_out, const bool is_big_endian) {
usb_oldDSconvertVideoToOutput(&p_in->usb_received_old_ds, p_out, is_big_endian);
}
static void usb_3DSconvertVideoToOutput(USB3DSCaptureReceived *p_in, VideoOutputData *p_out) {
memcpy(p_out->screen_data, p_in->video_in.screen_data, IN_VIDEO_HEIGHT_3DS * IN_VIDEO_WIDTH_3DS * 3);
}
@ -174,9 +170,7 @@ static void usb_convertVideoToOutput(CaptureReceived *p_in, VideoOutputData *p_o
else
usb_oldDSconvertVideoToOutput(&p_in->usb_received_old_ds, p_out, is_big_endian);
}
#endif
#ifdef USE_IS_NITRO_USB
static void usb_is_nitro_convertVideoToOutput(CaptureReceived *p_in, VideoOutputData *p_out, CaptureScreensType capture_type) {
int num_pixels = usb_is_nitro_get_video_in_size(capture_type) / 3;
int out_start_pos = 0;
@ -189,7 +183,6 @@ static void usb_is_nitro_convertVideoToOutput(CaptureReceived *p_in, VideoOutput
memset(p_out->screen_data[out_clear_pos], 0, num_pixels * 3);
memcpy(p_out->screen_data[out_start_pos], p_in->is_nitro_capture_received.video_in.screen_data, num_pixels * 3);
}
#endif
bool convertVideoToOutput(VideoOutputData *p_out, const bool is_big_endian, CaptureDataSingleBuffer* data_buffer, CaptureStatus* status) {
CaptureReceived *p_in = &data_buffer->capture_buf;
@ -203,7 +196,7 @@ bool convertVideoToOutput(VideoOutputData *p_out, const bool is_big_endian, Capt
#endif
#ifdef USE_FTD2
if(chosen_device->cc_type == CAPTURE_CONN_FTD2) {
ftd2_convertVideoToOutput(p_in, p_out);
ftd2_convertVideoToOutput(p_in, p_out, is_big_endian);
converted = true;
}
#endif
@ -237,6 +230,11 @@ bool convertAudioToOutput(std::int16_t *p_out, uint64_t n_samples, const bool is
#endif
#ifdef USE_FTD2
if(status->device.cc_type == CAPTURE_CONN_FTD2) {
base_ptr = (uint8_t*)p_in->ftd2_received_old_ds.audio_data;
int real_samples = 0;
while((real_samples < n_samples) && (((uint32_t*)base_ptr)[real_samples] != (FTD2_OLDDS_SYNCH_VALUES | (FTD2_OLDDS_SYNCH_VALUES << 16))))
real_samples++;
n_samples = real_samples;
}
#endif
#ifdef USE_DS_3DS_USB

View File

@ -26,3 +26,16 @@ add_custom_command(
POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${OUTPUT_NAME}> ${CMAKE_BINARY_DIR}
VERBATIM
)
set(OUTPUT_NAME CMakePrepareRenameSymbols)
project(${OUTPUT_NAME} VERSION 1.0.0 LANGUAGES CXX)
add_executable(${OUTPUT_NAME} prepare_rename_symbols_list.cpp)
target_compile_features(${OUTPUT_NAME} PRIVATE cxx_std_17)
add_custom_command(
TARGET ${OUTPUT_NAME}
COMMENT "Copy Output"
POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${OUTPUT_NAME}> ${CMAKE_BINARY_DIR}
VERBATIM
)

View File

@ -0,0 +1,57 @@
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#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 prefix new_file define_file" << endl;
return -1;
}
ifstream input(argv[1], ios::in);
if(!input) {
cout << "Couldn't open input file!" << endl;
return -2;
}
vector<string> file_lines;
string single_str = "";
while (getline(input, single_str))
file_lines.push_back(single_str);
input.close();
string prefix(argv[2]);
ofstream output(argv[3], ios::out);
if(!output) {
cout << "Couldn't open output file!" << endl;
return -2;
}
for(int i = 0; i < file_lines.size(); i++)
output << file_lines[i] << " " << prefix << file_lines[i] << endl;
output.close();
if(argc > 4) {
ofstream output_define(argv[4], ios::out);
if(!output_define) {
cout << "Couldn't open output define file!" << endl;
return -2;
}
for(int i = 0; i < file_lines.size(); i++)
output_define << "#define " << file_lines[i] << " " << prefix << file_lines[i] << endl;
output_define.close();
}
return 0;
}

View File

@ -0,0 +1,4 @@
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6014", PROGRAM="/bin/sh -c '\
echo -n $id:1.0 > /sys/bus/usb/drivers/ftdi_sio/unbind;\
echo -n $id:1.1 > /sys/bus/usb/drivers/ftdi_sio/unbind\
'"

View File

@ -0,0 +1 @@
SUBSYSTEM=="usb", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6014", MODE="0666"