mirror of
https://github.com/Lorenzooone/cc3dsfs.git
synced 2025-06-18 08:35:33 -04:00
Add IS Nitro Driver compatibility
This commit is contained in:
parent
7c3cc5fee8
commit
5d710d5b70
2
.gitignore
vendored
2
.gitignore
vendored
@ -12,3 +12,5 @@ build*/
|
||||
!build-dockers/
|
||||
.config/
|
||||
out/
|
||||
.vs/
|
||||
CMakeSettings.json
|
@ -269,9 +269,11 @@ endif()
|
||||
set(FETCH_CONTENT_MAKE_AVAILABLE_LIBRARIES "")
|
||||
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")
|
||||
if(N3DSXL_LOOPY_SUPPORT)
|
||||
list(APPEND FETCH_CONTENT_MAKE_AVAILABLE_LIBRARIES FTD3XX)
|
||||
list(APPEND SOURCE_CPP_EXTRA_FILES source/3dscapture_ftd3.cpp)
|
||||
list(APPEND SOURCE_CPP_EXTRA_FILES ${SOURCE_CPP_DEVICE_FILES_BASE_PATH}/3dscapture_ftd3.cpp)
|
||||
list(APPEND EXTRA_DEPENDENCIES FTD3XX_BUILD_PROJECT)
|
||||
if(MSVC)
|
||||
list(APPEND EXTRA_CXX_FLAGS "/DUSE_FTD3")
|
||||
@ -281,7 +283,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/dscapture_ftd2.cpp)
|
||||
list(APPEND SOURCE_CPP_EXTRA_FILES ${SOURCE_CPP_DEVICE_FILES_BASE_PATH}/dscapture_ftd2.cpp)
|
||||
list(APPEND EXTRA_DEPENDENCIES FTD2XX_BUILD_PROJECT)
|
||||
if(MSVC)
|
||||
list(APPEND EXTRA_CXX_FLAGS "/DUSE_FTD2")
|
||||
@ -291,9 +293,9 @@ if(NEW_DS_LOOPY_SUPPORT)
|
||||
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/usb_generic.cpp)
|
||||
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/usb_is_nitro.cpp source/usb_is_nitro_capture.cpp)
|
||||
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()
|
||||
@ -301,7 +303,7 @@ if(IS_NITRO_SUPPORT OR OLD_DS_3DS_LOOPY_SUPPORT)
|
||||
endif()
|
||||
endif()
|
||||
if(OLD_DS_3DS_LOOPY_SUPPORT)
|
||||
list(APPEND SOURCE_CPP_EXTRA_FILES source/usb_ds_3ds_capture.cpp)
|
||||
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()
|
||||
@ -406,7 +408,7 @@ endif()
|
||||
if(NEW_DS_LOOPY_SUPPORT)
|
||||
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)
|
||||
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_compile_features(${OUTPUT_NAME} PRIVATE cxx_std_20)
|
||||
target_compile_options(${OUTPUT_NAME} PRIVATE ${EXTRA_CXX_FLAGS})
|
||||
|
||||
|
0
include/3dscapture_ftd3.hpp → include/CaptureDeviceSpecific/3dscapture_ftd3.hpp
Executable file → Normal file
0
include/3dscapture_ftd3.hpp → include/CaptureDeviceSpecific/3dscapture_ftd3.hpp
Executable file → Normal file
@ -1,5 +1,5 @@
|
||||
#ifndef __USB_IS_NITRO_CAPTURE_HPP
|
||||
#define __USB_IS_NITRO_CAPTURE_HPP
|
||||
#ifndef __USB_IS_NITRO_ACQUISITION_HPP
|
||||
#define __USB_IS_NITRO_ACQUISITION_HPP
|
||||
|
||||
#include <vector>
|
||||
#include "utils.hpp"
|
||||
@ -9,10 +9,10 @@
|
||||
|
||||
void list_devices_is_nitro(std::vector<CaptureDevice> &devices_list);
|
||||
bool is_nitro_connect_usb(bool print_failed, CaptureData* capture_data, CaptureDevice* device);
|
||||
void is_nitro_capture_main_loop(CaptureData* capture_data);
|
||||
void usb_is_nitro_capture_cleanup(CaptureData* capture_data);
|
||||
void is_nitro_acquisition_main_loop(CaptureData* capture_data);
|
||||
void usb_is_nitro_acquisition_cleanup(CaptureData* capture_data);
|
||||
void usb_is_nitro_convertVideoToOutput(CaptureReceived *p_in, VideoOutputData *p_out, CaptureScreensType capture_type);
|
||||
uint64_t usb_is_nitro_emulator_get_video_in_size(CaptureData* capture_data);
|
||||
uint64_t usb_is_nitro_get_video_in_size(CaptureData* capture_data);
|
||||
void usb_is_nitro_init();
|
||||
void usb_is_nitro_close();
|
||||
|
@ -0,0 +1,11 @@
|
||||
#ifndef __USB_IS_NITRO_ACQUISITION_CAPTURE_HPP
|
||||
#define __USB_IS_NITRO_ACQUISITION_CAPTURE_HPP
|
||||
|
||||
#include "usb_is_nitro_communications.hpp"
|
||||
#include "capture_structs.hpp"
|
||||
|
||||
int initial_cleanup_capture(const is_nitro_usb_device* usb_device_desc, is_nitro_device_handlers* handlers);
|
||||
int EndAcquisitionCapture(is_nitro_device_handlers* handlers, const is_nitro_usb_device* usb_device_desc);
|
||||
void is_nitro_acquisition_capture_main_loop(CaptureData* capture_data);
|
||||
|
||||
#endif
|
@ -0,0 +1,11 @@
|
||||
#ifndef __USB_IS_NITRO_ACQUISITION_EMULATOR_HPP
|
||||
#define __USB_IS_NITRO_ACQUISITION_EMULATOR_HPP
|
||||
|
||||
#include "usb_is_nitro_communications.hpp"
|
||||
#include "capture_structs.hpp"
|
||||
|
||||
int initial_cleanup_emulator(const is_nitro_usb_device* usb_device_desc, is_nitro_device_handlers* handlers);
|
||||
int EndAcquisitionEmulator(is_nitro_device_handlers* handlers, bool do_drain_frames, int start_frames, CaptureScreensType capture_type, const is_nitro_usb_device* usb_device_desc);
|
||||
void is_nitro_acquisition_emulator_main_loop(CaptureData* capture_data);
|
||||
|
||||
#endif
|
@ -0,0 +1,13 @@
|
||||
#ifndef __USB_IS_NITRO_ACQUISITION_GENERAL_HPP
|
||||
#define __USB_IS_NITRO_ACQUISITION_GENERAL_HPP
|
||||
|
||||
#include "usb_is_nitro_communications.hpp"
|
||||
#include "capture_structs.hpp"
|
||||
#include "display_structs.hpp"
|
||||
|
||||
uint64_t _is_nitro_get_video_in_size(CaptureScreensType capture_type);
|
||||
int set_acquisition_mode(is_nitro_device_handlers* handlers, CaptureScreensType capture_type, const is_nitro_usb_device* usb_device_desc);
|
||||
int EndAcquisition(is_nitro_device_handlers* handlers, bool do_drain_frames, int start_frames, CaptureScreensType capture_type, const is_nitro_usb_device* usb_device_desc);
|
||||
int is_nitro_read_frame_and_output(CaptureData* capture_data, int& inner_curr_in, CaptureScreensType curr_capture_type, std::chrono::time_point<std::chrono::high_resolution_clock> &clock_start);
|
||||
|
||||
#endif
|
@ -0,0 +1,63 @@
|
||||
#ifndef __USB_IS_NITRO_COMMUNICATIONS_HPP
|
||||
#define __USB_IS_NITRO_COMMUNICATIONS_HPP
|
||||
|
||||
#include <libusb.h>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include "utils.hpp"
|
||||
|
||||
#define IS_NITRO_REAL_SERIAL_NUMBER_SIZE 10
|
||||
|
||||
enum is_nitro_forward_config_values_colors {
|
||||
IS_NITRO_FORWARD_CONFIG_COLOR_RGB24 = 0,
|
||||
};
|
||||
|
||||
enum is_nitro_forward_config_values_screens {
|
||||
IS_NITRO_FORWARD_CONFIG_MODE_BOTH = 0,
|
||||
IS_NITRO_FORWARD_CONFIG_MODE_TOP = 1,
|
||||
IS_NITRO_FORWARD_CONFIG_MODE_BOTTOM = 2,
|
||||
};
|
||||
|
||||
enum is_nitro_forward_config_values_rate {
|
||||
IS_NITRO_FORWARD_CONFIG_RATE_FULL = 0,
|
||||
IS_NITRO_FORWARD_CONFIG_RATE_HALF = 1,
|
||||
IS_NITRO_FORWARD_CONFIG_RATE_THIRD = 2,
|
||||
IS_NITRO_FORWARD_CONFIG_RATE_QUARTER = 3,
|
||||
};
|
||||
|
||||
struct is_nitro_usb_device {
|
||||
std::string name;
|
||||
int vid;
|
||||
int pid;
|
||||
int default_config;
|
||||
int default_interface;
|
||||
int bulk_timeout;
|
||||
int ep2_in;
|
||||
int ep1_out;
|
||||
int product_id;
|
||||
int manufacturer_id;
|
||||
bool is_capture;
|
||||
};
|
||||
|
||||
struct is_nitro_device_handlers {
|
||||
libusb_device_handle* usb_handle;
|
||||
void* read_handle;
|
||||
void* write_handle;
|
||||
void* mutex;
|
||||
};
|
||||
|
||||
int GetNumISNitroDesc(void);
|
||||
const is_nitro_usb_device* GetISNitroDesc(int index);
|
||||
int DisableLca2(is_nitro_device_handlers* handlers, const is_nitro_usb_device* device_desc);
|
||||
int StartUsbCaptureDma(is_nitro_device_handlers* handlers, const is_nitro_usb_device* device_desc);
|
||||
int StopUsbCaptureDma(is_nitro_device_handlers* handlers, const is_nitro_usb_device* device_desc);
|
||||
int SetForwardFrameCount(is_nitro_device_handlers* handlers, uint16_t count, const is_nitro_usb_device* device_desc);
|
||||
int SetForwardFramePermanent(is_nitro_device_handlers* handlers, const is_nitro_usb_device* device_desc);
|
||||
int GetFrameCounter(is_nitro_device_handlers* handlers, uint16_t* out, const is_nitro_usb_device* device_desc);
|
||||
int GetDeviceSerial(is_nitro_device_handlers* handlers, uint8_t* buf, const is_nitro_usb_device* device_desc);
|
||||
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);
|
||||
int UpdateFrameForwardEnable(is_nitro_device_handlers* handlers, bool enable, bool restart, const is_nitro_usb_device* device_desc);
|
||||
int ReadLidState(is_nitro_device_handlers* handlers, uint32_t* out, const is_nitro_usb_device* device_desc);
|
||||
int ReadFrame(is_nitro_device_handlers* handlers, uint8_t* buf, int length, const is_nitro_usb_device* device_desc);
|
||||
|
||||
#endif
|
@ -0,0 +1,14 @@
|
||||
#ifndef __USB_IS_NITRO_IS_DRIVER_HPP
|
||||
#define __USB_IS_NITRO_IS_DRIVER_HPP
|
||||
|
||||
#include <vector>
|
||||
#include "capture_structs.hpp"
|
||||
#include "usb_is_nitro_communications.hpp"
|
||||
|
||||
void is_driver_list_devices(std::vector<CaptureDevice>& devices_list, bool* not_supported_elems, int* curr_serial_extra_id_is_nitro, const size_t num_is_nitro_desc);
|
||||
is_nitro_device_handlers* is_driver_serial_reconnection(const is_nitro_usb_device* usb_device_desc, CaptureDevice* device);
|
||||
void is_driver_end_connection(is_nitro_device_handlers* handlers);
|
||||
int is_driver_bulk_out(is_nitro_device_handlers* handlers, uint8_t* buf, int length, int* transferred);
|
||||
int is_driver_bulk_in(is_nitro_device_handlers* handlers, uint8_t* buf, int length, int* transferred);
|
||||
|
||||
#endif
|
@ -0,0 +1,14 @@
|
||||
#ifndef __USB_IS_NITRO_LIBUSB_HPP
|
||||
#define __USB_IS_NITRO_LIBUSB_HPP
|
||||
|
||||
#include <vector>
|
||||
#include "capture_structs.hpp"
|
||||
#include "usb_is_nitro_communications.hpp"
|
||||
|
||||
void is_nitro_libusb_list_devices(std::vector<CaptureDevice>& devices_list, bool* no_access_elems, bool* not_supported_elems, int* curr_serial_extra_id_is_nitro, const size_t num_is_nitro_desc);
|
||||
is_nitro_device_handlers* is_nitro_libusb_serial_reconnection(const is_nitro_usb_device* usb_device_desc, CaptureDevice* device, int& curr_serial_extra_id);
|
||||
void is_nitro_libusb_end_connection(is_nitro_device_handlers* handlers, const is_nitro_usb_device* device_desc, bool interface_claimed);
|
||||
int is_nitro_libusb_bulk_out(is_nitro_device_handlers* handlers, const is_nitro_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred);
|
||||
int is_nitro_libusb_bulk_in(is_nitro_device_handlers* handlers, const is_nitro_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred);
|
||||
|
||||
#endif
|
@ -0,0 +1,12 @@
|
||||
#ifndef __USB_IS_NITRO_SETUP_GENERAL_HPP
|
||||
#define __USB_IS_NITRO_SETUP_GENERAL_HPP
|
||||
|
||||
#include <vector>
|
||||
#include "capture_structs.hpp"
|
||||
#include "usb_is_nitro_communications.hpp"
|
||||
|
||||
std::string get_serial(const is_nitro_usb_device* usb_device_desc, is_nitro_device_handlers* handlers, int& curr_serial_extra_id);
|
||||
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);
|
||||
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);
|
||||
|
||||
#endif
|
0
include/dscapture_ftd2.hpp → include/CaptureDeviceSpecific/dscapture_ftd2.hpp
Executable file → Normal file
0
include/dscapture_ftd2.hpp → include/CaptureDeviceSpecific/dscapture_ftd2.hpp
Executable file → Normal file
0
include/usb_ds_3ds_capture.hpp → include/CaptureDeviceSpecific/usb_ds_3ds_capture.hpp
Executable file → Normal file
0
include/usb_ds_3ds_capture.hpp → include/CaptureDeviceSpecific/usb_ds_3ds_capture.hpp
Executable file → Normal file
@ -102,11 +102,13 @@ union CaptureReceived {
|
||||
};
|
||||
|
||||
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): 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) {}
|
||||
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) {}
|
||||
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) : 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("") {}
|
||||
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) : 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) {}
|
||||
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("") {}
|
||||
|
||||
std::string serial_number;
|
||||
std::string name;
|
||||
std::string path;
|
||||
CaptureConnectionType cc_type;
|
||||
const void* descriptor;
|
||||
bool is_3ds;
|
||||
|
@ -1,61 +0,0 @@
|
||||
#ifndef __USB_IS_NITRO_HPP
|
||||
#define __USB_IS_NITRO_HPP
|
||||
|
||||
#include <libusb.h>
|
||||
#include <vector>
|
||||
#include "utils.hpp"
|
||||
|
||||
#define IS_NITRO_REAL_SERIAL_NUMBER_SIZE 10
|
||||
|
||||
enum is_nitro_forward_config_values_colors {
|
||||
IS_NITRO_FORWARD_CONFIG_COLOR_RGB24 = 0,
|
||||
};
|
||||
|
||||
enum is_nitro_forward_config_values_screens {
|
||||
IS_NITRO_FORWARD_CONFIG_MODE_BOTH = 0,
|
||||
IS_NITRO_FORWARD_CONFIG_MODE_TOP = 1,
|
||||
IS_NITRO_FORWARD_CONFIG_MODE_BOTTOM = 2,
|
||||
};
|
||||
|
||||
enum is_nitro_forward_config_values_rate {
|
||||
IS_NITRO_FORWARD_CONFIG_RATE_FULL = 0,
|
||||
IS_NITRO_FORWARD_CONFIG_RATE_HALF = 1,
|
||||
IS_NITRO_FORWARD_CONFIG_RATE_THIRD = 2,
|
||||
IS_NITRO_FORWARD_CONFIG_RATE_QUARTER = 3,
|
||||
};
|
||||
|
||||
enum is_nitro_possible_devices {
|
||||
IS_NITRO_EMULATOR_COMMON_ID,
|
||||
IS_NITRO_EMULATOR_RARE_ID,
|
||||
IS_NITRO_CAPTURE_ID,
|
||||
};
|
||||
|
||||
#define FIRST_IS_NITRO_DEVICE_ID IS_NITRO_EMULATOR_COMMON_ID
|
||||
|
||||
struct is_nitro_usb_device {
|
||||
std::string name;
|
||||
int vid;
|
||||
int pid;
|
||||
int default_config;
|
||||
int default_interface;
|
||||
int bulk_timeout;
|
||||
int ep2_in;
|
||||
int ep1_out;
|
||||
int product_id;
|
||||
int manufacturer_id;
|
||||
bool is_capture;
|
||||
};
|
||||
|
||||
const is_nitro_usb_device* GetISNitroDesc(is_nitro_possible_devices wanted_device_id);
|
||||
int DisableLca2(libusb_device_handle *handle, const is_nitro_usb_device* device_desc);
|
||||
int StartUsbCaptureDma(libusb_device_handle *handle, const is_nitro_usb_device* device_desc);
|
||||
int StopUsbCaptureDma(libusb_device_handle *handle, const is_nitro_usb_device* device_desc);
|
||||
int SetForwardFrameCount(libusb_device_handle *handle, uint16_t count, const is_nitro_usb_device* device_desc);
|
||||
int SetForwardFramePermanent(libusb_device_handle *handle, const is_nitro_usb_device* device_desc);
|
||||
int GetFrameCounter(libusb_device_handle *handle, uint16_t* out, const is_nitro_usb_device* device_desc);
|
||||
int GetDeviceSerial(libusb_device_handle *handle, uint8_t* buf, const is_nitro_usb_device* device_desc);
|
||||
int UpdateFrameForwardConfig(libusb_device_handle *handle, 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);
|
||||
int UpdateFrameForwardEnable(libusb_device_handle *handle, bool enable, bool restart, const is_nitro_usb_device* device_desc);
|
||||
int ReadFrame(libusb_device_handle *handle, uint8_t* buf, int length, const is_nitro_usb_device* device_desc);
|
||||
|
||||
#endif
|
0
source/3dscapture_ftd3.cpp → source/CaptureDeviceSpecific/3dscapture_ftd3.cpp
Executable file → Normal file
0
source/3dscapture_ftd3.cpp → source/CaptureDeviceSpecific/3dscapture_ftd3.cpp
Executable file → Normal file
@ -0,0 +1,213 @@
|
||||
#include "devicecapture.hpp"
|
||||
#include "usb_is_nitro_communications.hpp"
|
||||
#include "usb_is_nitro_acquisition.hpp"
|
||||
#include "usb_is_nitro_acquisition_general.hpp"
|
||||
#include "usb_is_nitro_acquisition_capture.hpp"
|
||||
#include "usb_is_nitro_acquisition_emulator.hpp"
|
||||
#include "usb_is_nitro_setup_general.hpp"
|
||||
#include "usb_is_nitro_libusb.hpp"
|
||||
#include "usb_is_nitro_is_driver.hpp"
|
||||
#include "usb_generic.hpp"
|
||||
|
||||
#include <libusb.h>
|
||||
#include <chrono>
|
||||
#include <cstring>
|
||||
|
||||
// Code based off of Gericom's sample code. Distributed under the MIT License. Copyright (c) 2024 Gericom
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
|
||||
#define SERIAL_NUMBER_SIZE (IS_NITRO_REAL_SERIAL_NUMBER_SIZE + 1)
|
||||
|
||||
#define FRAME_BUFFER_SIZE 32
|
||||
|
||||
static bool initial_cleanup(const is_nitro_usb_device* usb_device_desc, is_nitro_device_handlers* handlers) {
|
||||
if(!usb_device_desc->is_capture)
|
||||
return initial_cleanup_emulator(usb_device_desc, handlers) != LIBUSB_SUCCESS;
|
||||
return initial_cleanup_capture(usb_device_desc, handlers) != LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
std::string get_serial(const is_nitro_usb_device* usb_device_desc, is_nitro_device_handlers* handlers, int& curr_serial_extra_id) {
|
||||
uint8_t data[SERIAL_NUMBER_SIZE];
|
||||
std::string serial_str = std::to_string(curr_serial_extra_id);
|
||||
bool conn_success = true;
|
||||
if(initial_cleanup(usb_device_desc, handlers))
|
||||
conn_success = false;
|
||||
if (conn_success && (GetDeviceSerial(handlers, data, usb_device_desc) != LIBUSB_SUCCESS))
|
||||
conn_success = false;
|
||||
if (conn_success) {
|
||||
data[IS_NITRO_REAL_SERIAL_NUMBER_SIZE] = '\0';
|
||||
serial_str = std::string((const char*)data);
|
||||
}
|
||||
else
|
||||
curr_serial_extra_id += 1;
|
||||
return serial_str;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static is_nitro_device_handlers* usb_find_by_serial_number(const is_nitro_usb_device* usb_device_desc, CaptureDevice* device) {
|
||||
is_nitro_device_handlers* final_handlers = NULL;
|
||||
int curr_serial_extra_id = 0;
|
||||
final_handlers = is_nitro_libusb_serial_reconnection(usb_device_desc, device, curr_serial_extra_id);
|
||||
|
||||
if (final_handlers == NULL)
|
||||
final_handlers = is_driver_serial_reconnection(usb_device_desc, device);
|
||||
return final_handlers;
|
||||
}
|
||||
|
||||
void list_devices_is_nitro(std::vector<CaptureDevice> &devices_list) {
|
||||
const size_t num_is_nitro_desc = GetNumISNitroDesc();
|
||||
int* curr_serial_extra_id_is_nitro = new int[num_is_nitro_desc];
|
||||
bool* no_access_elems = new bool[num_is_nitro_desc];
|
||||
bool* not_supported_elems = new bool[num_is_nitro_desc];
|
||||
for (int i = 0; i < num_is_nitro_desc; i++) {
|
||||
no_access_elems[i] = false;
|
||||
not_supported_elems[i] = false;
|
||||
curr_serial_extra_id_is_nitro[i] = 0;
|
||||
}
|
||||
is_nitro_libusb_list_devices(devices_list, no_access_elems, not_supported_elems, curr_serial_extra_id_is_nitro, num_is_nitro_desc);
|
||||
|
||||
bool any_not_supported = false;
|
||||
for (int i = 0; i < num_is_nitro_desc; i++)
|
||||
any_not_supported |= not_supported_elems[i];
|
||||
if (any_not_supported)
|
||||
is_driver_list_devices(devices_list, not_supported_elems, curr_serial_extra_id_is_nitro, num_is_nitro_desc);
|
||||
|
||||
delete[] curr_serial_extra_id_is_nitro;
|
||||
delete[] no_access_elems;
|
||||
delete[] not_supported_elems;
|
||||
}
|
||||
|
||||
static void is_nitro_connection_end(is_nitro_device_handlers* handlers, const is_nitro_usb_device *device_desc, bool interface_claimed = true) {
|
||||
if (handlers == NULL)
|
||||
return;
|
||||
if (handlers->usb_handle)
|
||||
is_nitro_libusb_end_connection(handlers, device_desc, interface_claimed);
|
||||
else
|
||||
is_driver_end_connection(handlers);
|
||||
delete handlers;
|
||||
}
|
||||
|
||||
bool is_nitro_connect_usb(bool print_failed, CaptureData* capture_data, CaptureDevice* device) {
|
||||
const is_nitro_usb_device* usb_device_info = (const is_nitro_usb_device*)device->descriptor;
|
||||
is_nitro_device_handlers* handlers = usb_find_by_serial_number(usb_device_info, device);
|
||||
if(handlers == NULL) {
|
||||
capture_error_print(true, capture_data, "Device not found");
|
||||
return false;
|
||||
}
|
||||
capture_data->handle = (void*)handlers;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t _is_nitro_get_video_in_size(CaptureScreensType capture_type) {
|
||||
if((capture_type == CAPTURE_SCREENS_TOP) || (capture_type == CAPTURE_SCREENS_BOTTOM))
|
||||
return sizeof(ISNitroEmulatorVideoInputData) / 2;
|
||||
return sizeof(ISNitroEmulatorVideoInputData);
|
||||
}
|
||||
|
||||
uint64_t usb_is_nitro_get_video_in_size(CaptureData* capture_data) {
|
||||
return _is_nitro_get_video_in_size(capture_data->status.capture_type);
|
||||
}
|
||||
|
||||
int set_acquisition_mode(is_nitro_device_handlers* handlers, CaptureScreensType capture_type, const is_nitro_usb_device* usb_device_desc) {
|
||||
is_nitro_forward_config_values_screens capture_mode_flag = IS_NITRO_FORWARD_CONFIG_MODE_BOTH;
|
||||
if(capture_type == CAPTURE_SCREENS_TOP)
|
||||
capture_mode_flag = IS_NITRO_FORWARD_CONFIG_MODE_TOP;
|
||||
if(capture_type == CAPTURE_SCREENS_BOTTOM)
|
||||
capture_mode_flag = IS_NITRO_FORWARD_CONFIG_MODE_BOTTOM;
|
||||
return UpdateFrameForwardConfig(handlers, IS_NITRO_FORWARD_CONFIG_COLOR_RGB24, capture_mode_flag, IS_NITRO_FORWARD_CONFIG_RATE_FULL, usb_device_desc);
|
||||
}
|
||||
|
||||
int EndAcquisition(is_nitro_device_handlers* handlers, bool do_drain_frames, int start_frames, CaptureScreensType capture_type, const is_nitro_usb_device* usb_device_desc) {
|
||||
if(usb_device_desc->is_capture)
|
||||
return EndAcquisitionCapture(handlers, usb_device_desc);
|
||||
return EndAcquisitionEmulator(handlers, do_drain_frames, start_frames, capture_type, usb_device_desc);
|
||||
}
|
||||
|
||||
int is_nitro_read_frame_and_output(CaptureData* capture_data, int &inner_curr_in, CaptureScreensType curr_capture_type, std::chrono::time_point<std::chrono::high_resolution_clock> &clock_start) {
|
||||
int ret = ReadFrame((is_nitro_device_handlers*)capture_data->handle, (uint8_t*)&capture_data->capture_buf[inner_curr_in], _is_nitro_get_video_in_size(curr_capture_type), (const is_nitro_usb_device*)capture_data->status.device.descriptor);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
// Output to the other threads...
|
||||
const auto curr_time = std::chrono::high_resolution_clock::now();
|
||||
const std::chrono::duration<double> diff = curr_time - clock_start;
|
||||
clock_start = curr_time;
|
||||
capture_data->time_in_buf[inner_curr_in] = diff.count();
|
||||
capture_data->read[inner_curr_in] = _is_nitro_get_video_in_size(curr_capture_type);
|
||||
capture_data->capture_type[inner_curr_in] = curr_capture_type;
|
||||
|
||||
inner_curr_in = (inner_curr_in + 1) % NUM_CONCURRENT_DATA_BUFFERS;
|
||||
if (capture_data->status.cooldown_curr_in)
|
||||
capture_data->status.cooldown_curr_in = capture_data->status.cooldown_curr_in - 1;
|
||||
capture_data->status.curr_in = inner_curr_in;
|
||||
capture_data->status.video_wait.unlock();
|
||||
capture_data->status.audio_wait.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void is_nitro_acquisition_main_loop(CaptureData* capture_data) {
|
||||
if(!usb_is_initialized())
|
||||
return;
|
||||
if(((const is_nitro_usb_device*)(capture_data->status.device.descriptor))->is_capture)
|
||||
is_nitro_acquisition_capture_main_loop(capture_data);
|
||||
else
|
||||
is_nitro_acquisition_emulator_main_loop(capture_data);
|
||||
}
|
||||
|
||||
void usb_is_nitro_acquisition_cleanup(CaptureData* capture_data) {
|
||||
if(!usb_is_initialized())
|
||||
return;
|
||||
is_nitro_connection_end((is_nitro_device_handlers*)capture_data->handle, (const is_nitro_usb_device*)capture_data->status.device.descriptor);
|
||||
capture_data->handle = NULL;
|
||||
}
|
||||
|
||||
void usb_is_nitro_convertVideoToOutput(CaptureReceived *p_in, VideoOutputData *p_out, CaptureScreensType capture_type) {
|
||||
if(!usb_is_initialized())
|
||||
return;
|
||||
int num_pixels = _is_nitro_get_video_in_size(capture_type) / 3;
|
||||
int out_start_pos = 0;
|
||||
int out_clear_pos = num_pixels;
|
||||
if(capture_type == CAPTURE_SCREENS_BOTTOM) {
|
||||
out_start_pos = num_pixels;
|
||||
out_clear_pos = 0;
|
||||
}
|
||||
if((capture_type == CAPTURE_SCREENS_BOTTOM) || (capture_type == CAPTURE_SCREENS_TOP))
|
||||
memset(p_out->screen_data[out_clear_pos], 0, num_pixels * 3);
|
||||
for(int i = 0; i < num_pixels; i++) {
|
||||
p_out->screen_data[i + out_start_pos][0] = p_in->is_nitro_capture_received.video_in.screen_data[i][2];
|
||||
p_out->screen_data[i + out_start_pos][1] = p_in->is_nitro_capture_received.video_in.screen_data[i][1];
|
||||
p_out->screen_data[i + out_start_pos][2] = p_in->is_nitro_capture_received.video_in.screen_data[i][0];
|
||||
}
|
||||
}
|
||||
|
||||
void usb_is_nitro_init() {
|
||||
return usb_init();
|
||||
}
|
||||
|
||||
void usb_is_nitro_close() {
|
||||
usb_close();
|
||||
}
|
||||
|
@ -0,0 +1,109 @@
|
||||
#include "devicecapture.hpp"
|
||||
#include "usb_is_nitro_communications.hpp"
|
||||
#include "usb_is_nitro_acquisition_general.hpp"
|
||||
#include "usb_is_nitro_acquisition_capture.hpp"
|
||||
|
||||
// Code created by analyzing the USB packets sent and received by the IS Nitro Capture device.
|
||||
|
||||
// The code for video capture of the IS Nitro Emulator and of the IS Nitro Capture is wildly different.
|
||||
// For this reason, the code was split into two device-specific files.
|
||||
|
||||
#define CAPTURE_SKIP_LID_REOPEN_FRAMES 32
|
||||
|
||||
static int StartAcquisitionCapture(is_nitro_device_handlers* handlers, CaptureScreensType capture_type, uint32_t* lid_state, const is_nitro_usb_device* usb_device_desc) {
|
||||
int ret = 0;
|
||||
ret = ReadLidState(handlers, lid_state, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
if((*lid_state) & 1)
|
||||
return LIBUSB_SUCCESS;
|
||||
ret = set_acquisition_mode(handlers, capture_type, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
ret = SetForwardFramePermanent(handlers, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
ret = UpdateFrameForwardEnable(handlers, true, true, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
return StartUsbCaptureDma(handlers, usb_device_desc);
|
||||
}
|
||||
|
||||
static int LidReopenCaptureCheck(CaptureData* capture_data, CaptureScreensType &curr_capture_type, uint32_t* lid_state) {
|
||||
is_nitro_device_handlers* handlers = (is_nitro_device_handlers*)capture_data->handle;
|
||||
const is_nitro_usb_device* usb_device_desc = (const is_nitro_usb_device*)capture_data->status.device.descriptor;
|
||||
curr_capture_type = capture_data->status.capture_type;
|
||||
int ret = StartAcquisitionCapture(handlers, curr_capture_type, lid_state, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
if(!((*lid_state) & 1))
|
||||
capture_data->status.cooldown_curr_in = CAPTURE_SKIP_LID_REOPEN_FRAMES;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int initial_cleanup_capture(const is_nitro_usb_device* usb_device_desc, is_nitro_device_handlers* handlers) {
|
||||
//EndAcquisition(handlers, false, 0, CAPTURE_SCREENS_BOTH, usb_device_desc);
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
int EndAcquisitionCapture(is_nitro_device_handlers* handlers, const is_nitro_usb_device* usb_device_desc) {
|
||||
return StopUsbCaptureDma(handlers, usb_device_desc);
|
||||
}
|
||||
|
||||
void is_nitro_acquisition_capture_main_loop(CaptureData* capture_data) {
|
||||
is_nitro_device_handlers* handlers = (is_nitro_device_handlers*)capture_data->handle;
|
||||
const is_nitro_usb_device* usb_device_desc = (const is_nitro_usb_device*)capture_data->status.device.descriptor;
|
||||
uint32_t lid_state = 0;
|
||||
CaptureScreensType curr_capture_type = capture_data->status.capture_type;
|
||||
int ret = StartAcquisitionCapture(handlers, curr_capture_type, &lid_state, usb_device_desc);
|
||||
if(ret < 0) {
|
||||
capture_error_print(true, capture_data, "Capture Start: Failed");
|
||||
return;
|
||||
}
|
||||
int inner_curr_in = 0;
|
||||
auto clock_start = std::chrono::high_resolution_clock::now();
|
||||
auto clock_last_reset = std::chrono::high_resolution_clock::now();
|
||||
|
||||
while(capture_data->status.connected && capture_data->status.running) {
|
||||
if(lid_state & 1) {
|
||||
default_sleep(20);
|
||||
ret = LidReopenCaptureCheck(capture_data, curr_capture_type, &lid_state);
|
||||
if(ret < 0) {
|
||||
capture_error_print(true, capture_data, "Lid Reopen: Failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(lid_state & 1)
|
||||
continue;
|
||||
ret = is_nitro_read_frame_and_output(capture_data, inner_curr_in, curr_capture_type, clock_start);
|
||||
if(ret < 0) {
|
||||
ret = EndAcquisition(handlers, true, 0, curr_capture_type, usb_device_desc);
|
||||
if(ret < 0) {
|
||||
capture_error_print(true, capture_data, "Disconnected: Read error");
|
||||
return;
|
||||
}
|
||||
ret = LidReopenCaptureCheck(capture_data, curr_capture_type, &lid_state);
|
||||
if(ret < 0) {
|
||||
capture_error_print(true, capture_data, "Lid Reopen: Failed");
|
||||
return;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if(curr_capture_type != capture_data->status.capture_type) {
|
||||
ret = EndAcquisition(handlers, true, 0, curr_capture_type, usb_device_desc);
|
||||
if(ret < 0) {
|
||||
capture_error_print(true, capture_data, "Capture End: Failed");
|
||||
return;
|
||||
}
|
||||
curr_capture_type = capture_data->status.capture_type;
|
||||
ret = StartAcquisitionCapture(handlers, curr_capture_type, &lid_state, usb_device_desc);
|
||||
if(ret < 0) {
|
||||
capture_error_print(true, capture_data, "Capture Restart: Failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!(lid_state & 1))
|
||||
EndAcquisition(handlers, true, 0, curr_capture_type, usb_device_desc);
|
||||
}
|
@ -0,0 +1,287 @@
|
||||
#include "devicecapture.hpp"
|
||||
#include "usb_is_nitro_communications.hpp"
|
||||
#include "usb_is_nitro_acquisition_general.hpp"
|
||||
#include "usb_is_nitro_acquisition_emulator.hpp"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
// Code based off of Gericom's sample code. Distributed under the MIT License. Copyright (c) 2024 Gericom
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
|
||||
// The code for video capture of the IS Nitro Emulator and of the IS Nitro Capture is wildly different.
|
||||
// For this reason, the code was split into two device-specific files.
|
||||
|
||||
#define FRAME_BUFFER_SIZE 32
|
||||
|
||||
static int drain_frames(is_nitro_device_handlers* handlers, int num_frames, int start_frames, CaptureScreensType capture_type, const is_nitro_usb_device* usb_device_desc) {
|
||||
ISNitroEmulatorVideoInputData* video_in_buffer = new ISNitroEmulatorVideoInputData;
|
||||
for (int i = start_frames; i < num_frames; i++) {
|
||||
int ret = ReadFrame(handlers, (uint8_t*)video_in_buffer, _is_nitro_get_video_in_size(capture_type), usb_device_desc);
|
||||
if(ret < 0) {
|
||||
delete video_in_buffer;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
delete video_in_buffer;
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
static int StartAcquisitionEmulator(is_nitro_device_handlers* handlers, uint16_t &out_frame_count, float &single_frame_time, CaptureScreensType capture_type, const is_nitro_usb_device* usb_device_desc) {
|
||||
int ret = 0;
|
||||
ret = DisableLca2(handlers, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
ret = set_acquisition_mode(handlers, capture_type, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
ret = SetForwardFrameCount(handlers, FRAME_BUFFER_SIZE, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
// Reset this in case it's high. At around 0xFFFF, reading from the USB DMA seems to fail...
|
||||
ret = UpdateFrameForwardEnable(handlers, true, true, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
ret = UpdateFrameForwardEnable(handlers, true, false, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
|
||||
// Get to the closest next frame
|
||||
auto clock_start = std::chrono::high_resolution_clock::now();
|
||||
uint16_t oldFrameCount;
|
||||
uint16_t newFrameCount;
|
||||
ret = GetFrameCounter(handlers, &oldFrameCount, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
newFrameCount = oldFrameCount;
|
||||
while(newFrameCount == oldFrameCount) {
|
||||
ret = GetFrameCounter(handlers, &newFrameCount, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
const auto curr_time = std::chrono::high_resolution_clock::now();
|
||||
const std::chrono::duration<double> diff = curr_time - clock_start;
|
||||
// If too much time has passed, the DS is probably either turned off or sleeping. If so, avoid locking up
|
||||
if(diff.count() > 0.2)
|
||||
break;
|
||||
}
|
||||
|
||||
// Get to the next modulo 32 frame.
|
||||
// We also do this to measure the time that is needed for each frame...
|
||||
// To do so, a minimum of 4 frames is required (FRAME_BUFFER_SIZE - 1 + 4)
|
||||
clock_start = std::chrono::high_resolution_clock::now();
|
||||
ret = GetFrameCounter(handlers, &oldFrameCount, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
uint16_t targetFrameCount = (newFrameCount + FRAME_BUFFER_SIZE + 3) & (~(FRAME_BUFFER_SIZE - 1));
|
||||
while(oldFrameCount != targetFrameCount) {
|
||||
ret = GetFrameCounter(handlers, &oldFrameCount, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
// Placing a sleep of some kind here would be much better...
|
||||
// Though this is only executed for a small time when first connecting...
|
||||
const auto curr_time = std::chrono::high_resolution_clock::now();
|
||||
const std::chrono::duration<double> diff = curr_time - clock_start;
|
||||
// If too much time has passed, the DS is probably either turned off or sleeping. If so, avoid locking up
|
||||
if(diff.count() > 1.0)
|
||||
break;
|
||||
}
|
||||
const auto curr_time = std::chrono::high_resolution_clock::now();
|
||||
const std::chrono::duration<double> diff = curr_time - clock_start;
|
||||
// Sometimes the upper 8 bits aren't updated... Use only the lower 8 bits.
|
||||
newFrameCount &= 0xFF;
|
||||
oldFrameCount &= 0xFF;
|
||||
int frame_diff = ((int)oldFrameCount) - ((int)newFrameCount);
|
||||
if(frame_diff < 0)
|
||||
frame_diff += 1 << 8;
|
||||
out_frame_count = oldFrameCount;
|
||||
// Determine how much time a single frame takes. We'll use it for sleeps
|
||||
if(frame_diff == 0)
|
||||
single_frame_time = 0;
|
||||
else
|
||||
single_frame_time = diff.count() / frame_diff;
|
||||
|
||||
// Start the actual DMA
|
||||
if(single_frame_time > 0) {
|
||||
ret = StartUsbCaptureDma(handlers, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool do_sleep(float single_frame_time, std::chrono::time_point<std::chrono::high_resolution_clock> clock_last_reset, int curr_frame_counter, int last_frame_counter, float* out_time) {
|
||||
auto curr_time = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double> diff = curr_time - clock_last_reset;
|
||||
float expected_time = single_frame_time * curr_frame_counter;
|
||||
float low_single_frame_time = 1.0 / ((int)((1.0 / single_frame_time) + 1));
|
||||
float low_expected_time = low_single_frame_time * curr_frame_counter;
|
||||
// If the current time is too low, sleep a bit to make sure we don't overrun the framerate counter
|
||||
// Don't do it regardless of the situation, and only in small increments...
|
||||
// Otherwise there is the risk of sleeping too much
|
||||
bool result = (diff.count() < expected_time) && ((expected_time - diff.count()) > (single_frame_time / 4)) && (!(last_frame_counter & (FRAME_BUFFER_SIZE - 1)));
|
||||
*out_time = (expected_time - diff.count()) / 4;
|
||||
if(last_frame_counter & (FRAME_BUFFER_SIZE - 1)) {
|
||||
result = (diff.count() < low_expected_time) && ((low_expected_time - diff.count()) > (low_single_frame_time / 4));
|
||||
*out_time = (low_expected_time - diff.count()) / 4;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void frame_wait(float single_frame_time, std::chrono::time_point<std::chrono::high_resolution_clock> clock_last_reset, int curr_frame_counter, int last_frame_counter) {
|
||||
if(curr_frame_counter == 0)
|
||||
return;
|
||||
float sleep_time = 0;
|
||||
while(do_sleep(single_frame_time, clock_last_reset, curr_frame_counter, last_frame_counter, &sleep_time))
|
||||
default_sleep(sleep_time);
|
||||
}
|
||||
|
||||
static int reset_acquisition_frames(is_nitro_device_handlers* handlers, uint16_t &curr_frame_counter, uint16_t &last_frame_counter, float &single_frame_time, std::chrono::time_point<std::chrono::high_resolution_clock> &clock_last_reset, CaptureScreensType &curr_capture_type, CaptureScreensType wanted_capture_type, int multiplier, const is_nitro_usb_device* usb_device_desc) {
|
||||
curr_frame_counter += 1;
|
||||
|
||||
if(curr_frame_counter == FRAME_BUFFER_SIZE) {
|
||||
int ret = StopUsbCaptureDma(handlers, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
|
||||
// If the user requests a mode change, accomodate them.
|
||||
// Though it may lag for a bit...
|
||||
if(wanted_capture_type != curr_capture_type) {
|
||||
curr_capture_type = wanted_capture_type;
|
||||
ret = set_acquisition_mode(handlers, curr_capture_type, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint16_t internalFrameCount = 0;
|
||||
uint16_t full_internalFrameCount = 0;
|
||||
int frame_diff = 0;
|
||||
int diff_target = FRAME_BUFFER_SIZE * multiplier;
|
||||
do {
|
||||
// Check how many frames have passed...
|
||||
ret = GetFrameCounter(handlers, &internalFrameCount, usb_device_desc);
|
||||
full_internalFrameCount = internalFrameCount;
|
||||
// Sometimes the upper 8 bits aren't updated... Use only the lower 8 bits.
|
||||
internalFrameCount &= 0xFF;
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
frame_diff = internalFrameCount - last_frame_counter;
|
||||
if(frame_diff < 0)
|
||||
frame_diff += 1 << 8;
|
||||
// If the frames haven't advanced, the DS is either turned off or sleeping. If so, avoid locking up
|
||||
if(frame_diff == 0)
|
||||
break;
|
||||
const auto curr_time = std::chrono::high_resolution_clock::now();
|
||||
const std::chrono::duration<double> diff = curr_time - clock_last_reset;
|
||||
// If too much time has passed, the DS is probably either turned off or sleeping. If so, avoid locking up
|
||||
if(diff.count() > (1.0 * multiplier)) {
|
||||
frame_diff = 0;
|
||||
break;
|
||||
}
|
||||
// Exit if enough frames have passed, or if there currently is some delay.
|
||||
// Exiting early makes it possible to catch up to the DMA, if we're behind.
|
||||
} while((frame_diff < diff_target) && ((!(last_frame_counter & (FRAME_BUFFER_SIZE - 1))) || ((internalFrameCount & (FRAME_BUFFER_SIZE - 1)) >= (FRAME_BUFFER_SIZE - 2))));
|
||||
// Determine how much time a single frame takes. We'll use it for sleeps
|
||||
const auto curr_time = std::chrono::high_resolution_clock::now();
|
||||
const std::chrono::duration<double> diff = curr_time - clock_last_reset;
|
||||
if(frame_diff == 0)
|
||||
single_frame_time = 0;
|
||||
else
|
||||
single_frame_time = diff.count() / (frame_diff / ((float)multiplier));
|
||||
clock_last_reset = curr_time;
|
||||
|
||||
// Save the current frame counter's 8 LSB
|
||||
last_frame_counter = internalFrameCount;
|
||||
|
||||
// If we're nearing 0xFFFF for the frame counter, reset it.
|
||||
// It's a problematic value for DMA reading
|
||||
if(frame_diff && (full_internalFrameCount >= 0xF000)) {
|
||||
ret = UpdateFrameForwardEnable(handlers, true, true, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
clock_last_reset = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
ret = UpdateFrameForwardEnable(handlers, true, false, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
curr_frame_counter = 0;
|
||||
|
||||
// Start the actual DMA
|
||||
if(single_frame_time > 0) {
|
||||
ret = StartUsbCaptureDma(handlers, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
int initial_cleanup_emulator(const is_nitro_usb_device* usb_device_desc, is_nitro_device_handlers* handlers) {
|
||||
return EndAcquisition(handlers, false, 0, CAPTURE_SCREENS_BOTH, usb_device_desc);
|
||||
}
|
||||
|
||||
int EndAcquisitionEmulator(is_nitro_device_handlers* handlers, bool do_drain_frames, int start_frames, CaptureScreensType capture_type, const is_nitro_usb_device* usb_device_desc) {
|
||||
int ret = 0;
|
||||
if (do_drain_frames)
|
||||
ret = drain_frames(handlers, FRAME_BUFFER_SIZE, start_frames, capture_type, usb_device_desc);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = StopUsbCaptureDma(handlers, usb_device_desc);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return UpdateFrameForwardEnable(handlers, false, false, usb_device_desc);
|
||||
}
|
||||
|
||||
void is_nitro_acquisition_emulator_main_loop(CaptureData* capture_data) {
|
||||
is_nitro_device_handlers* handlers = (is_nitro_device_handlers*)capture_data->handle;
|
||||
const is_nitro_usb_device* usb_device_desc = (const is_nitro_usb_device*)capture_data->status.device.descriptor;
|
||||
uint16_t last_frame_counter = 0;
|
||||
float single_frame_time = 0;
|
||||
uint16_t curr_frame_counter = 0;
|
||||
CaptureScreensType curr_capture_type = capture_data->status.capture_type;
|
||||
int ret = StartAcquisitionEmulator(handlers, last_frame_counter, single_frame_time, curr_capture_type, usb_device_desc);
|
||||
if (ret < 0) {
|
||||
capture_error_print(true, capture_data, "Capture Start: Failed");
|
||||
return;
|
||||
}
|
||||
int inner_curr_in = 0;
|
||||
auto clock_start = std::chrono::high_resolution_clock::now();
|
||||
auto clock_last_reset = std::chrono::high_resolution_clock::now();
|
||||
|
||||
while (capture_data->status.connected && capture_data->status.running) {
|
||||
frame_wait(single_frame_time, clock_last_reset, curr_frame_counter, last_frame_counter);
|
||||
|
||||
if (single_frame_time > 0) {
|
||||
ret = is_nitro_read_frame_and_output(capture_data, inner_curr_in, curr_capture_type, clock_start);
|
||||
if (ret < 0) {
|
||||
capture_error_print(true, capture_data, "Disconnected: Read error");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
capture_data->status.cooldown_curr_in = FIX_PARTIAL_FIRST_FRAME_NUM;
|
||||
default_sleep(20);
|
||||
}
|
||||
capture_data->status.curr_delay = last_frame_counter % FRAME_BUFFER_SIZE;
|
||||
ret = reset_acquisition_frames(handlers, curr_frame_counter, last_frame_counter, single_frame_time, clock_last_reset, curr_capture_type, capture_data->status.capture_type, 1, usb_device_desc);
|
||||
if (ret < 0) {
|
||||
capture_error_print(true, capture_data, "Disconnected: Frame counter reset error");
|
||||
break;
|
||||
}
|
||||
}
|
||||
EndAcquisition(handlers, true, curr_frame_counter, curr_capture_type, usb_device_desc);
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
#include "frontend.hpp"
|
||||
#include "usb_is_nitro.hpp"
|
||||
#include "usb_is_nitro_communications.hpp"
|
||||
#include "usb_is_nitro_libusb.hpp"
|
||||
#include "usb_is_nitro_is_driver.hpp"
|
||||
|
||||
#include <libusb.h>
|
||||
#include <cstring>
|
||||
@ -66,6 +68,7 @@ enum is_nitro_capture_command {
|
||||
IS_NITRO_CAP_CMD_SET_FWD_MODE = 0x13,
|
||||
IS_NITRO_CAP_CMD_SET_FWD_COLOURS = 0x14,
|
||||
IS_NITRO_CAP_CMD_SET_FWD_FRAMES = 0x15,
|
||||
IS_NITRO_CAP_CMD_GET_LID_STATE = 0x19,
|
||||
IS_NITRO_CAP_CMD_SET_FWD_RESTART = 0x1C,
|
||||
};
|
||||
|
||||
@ -96,7 +99,7 @@ struct PACKED is_nitro_packet_header {
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
const is_nitro_usb_device usb_is_nitro_emu_rare_desc = {
|
||||
static const is_nitro_usb_device usb_is_nitro_emu_rare_desc = {
|
||||
.name = "IS Nitro Emulator(R)",
|
||||
.vid = 0x0f6e, .pid = 0x0400,
|
||||
.default_config = 1, .default_interface = 0,
|
||||
@ -105,7 +108,7 @@ const is_nitro_usb_device usb_is_nitro_emu_rare_desc = {
|
||||
.product_id = 2, .manufacturer_id = 1, .is_capture = false
|
||||
};
|
||||
|
||||
const is_nitro_usb_device usb_is_nitro_emu_common_desc = {
|
||||
static const is_nitro_usb_device usb_is_nitro_emu_common_desc = {
|
||||
.name = "IS Nitro Emulator",
|
||||
.vid = 0x0f6e, .pid = 0x0404,
|
||||
.default_config = 1, .default_interface = 0,
|
||||
@ -114,7 +117,7 @@ const is_nitro_usb_device usb_is_nitro_emu_common_desc = {
|
||||
.product_id = 2, .manufacturer_id = 1, .is_capture = false
|
||||
};
|
||||
|
||||
const is_nitro_usb_device usb_is_nitro_cap_desc = {
|
||||
static const is_nitro_usb_device usb_is_nitro_cap_desc = {
|
||||
.name = "IS Nitro Capture",
|
||||
.vid = 0x0f6e, .pid = 0x0403,
|
||||
.default_config = 1, .default_interface = 0,
|
||||
@ -123,17 +126,20 @@ const is_nitro_usb_device usb_is_nitro_cap_desc = {
|
||||
.product_id = 2, .manufacturer_id = 1, .is_capture = true
|
||||
};
|
||||
|
||||
const is_nitro_usb_device* GetISNitroDesc(is_nitro_possible_devices wanted_device_id) {
|
||||
switch(wanted_device_id) {
|
||||
case IS_NITRO_EMULATOR_COMMON_ID:
|
||||
return &usb_is_nitro_emu_common_desc;
|
||||
case IS_NITRO_EMULATOR_RARE_ID:
|
||||
return &usb_is_nitro_emu_rare_desc;
|
||||
case IS_NITRO_CAPTURE_ID:
|
||||
return &usb_is_nitro_cap_desc;
|
||||
default:
|
||||
return &usb_is_nitro_emu_common_desc;
|
||||
}
|
||||
static const is_nitro_usb_device* all_usb_is_nitro_devices_desc[] = {
|
||||
&usb_is_nitro_emu_rare_desc,
|
||||
&usb_is_nitro_emu_common_desc,
|
||||
&usb_is_nitro_cap_desc,
|
||||
};
|
||||
|
||||
int GetNumISNitroDesc() {
|
||||
return sizeof(all_usb_is_nitro_devices_desc) / sizeof(all_usb_is_nitro_devices_desc[0]);
|
||||
}
|
||||
|
||||
const is_nitro_usb_device* GetISNitroDesc(int index) {
|
||||
if((index < 0) || (index >= GetNumISNitroDesc()))
|
||||
index = 0;
|
||||
return all_usb_is_nitro_devices_desc[index];
|
||||
}
|
||||
|
||||
static void fix_endianness_header(is_nitro_packet_header* header) {
|
||||
@ -148,16 +154,20 @@ static void fix_endianness_header(is_nitro_nec_packet_header* header) {
|
||||
}
|
||||
|
||||
// Write to bulk endpoint. Returns libusb error code
|
||||
static int bulk_out(libusb_device_handle *handle, const is_nitro_usb_device* usb_device_desc, uint8_t *buf, int length, int *transferred) {
|
||||
return libusb_bulk_transfer(handle, usb_device_desc->ep1_out, buf, length, transferred, usb_device_desc->bulk_timeout);
|
||||
static int bulk_out(is_nitro_device_handlers* handlers, const is_nitro_usb_device* usb_device_desc, uint8_t *buf, int length, int *transferred) {
|
||||
if(handlers->usb_handle)
|
||||
return is_nitro_libusb_bulk_out(handlers, usb_device_desc, buf, length, transferred);
|
||||
return is_driver_bulk_out(handlers, buf, length, transferred);
|
||||
}
|
||||
|
||||
// Read from bulk endpoint. Returns libusb error code
|
||||
static int bulk_in(libusb_device_handle *handle, const is_nitro_usb_device* usb_device_desc, uint8_t *buf, int length, int *transferred) {
|
||||
return libusb_bulk_transfer(handle, usb_device_desc->ep2_in, buf, length, transferred, usb_device_desc->bulk_timeout);
|
||||
static int bulk_in(is_nitro_device_handlers* handlers, const is_nitro_usb_device* usb_device_desc, uint8_t *buf, int length, int *transferred) {
|
||||
if(handlers->usb_handle)
|
||||
return is_nitro_libusb_bulk_in(handlers, usb_device_desc, buf, length, transferred);
|
||||
return is_driver_bulk_in(handlers, buf, length, transferred);
|
||||
}
|
||||
|
||||
static int SendWritePacket(libusb_device_handle *handle, uint16_t command, is_nitro_packet_type type, uint32_t address, uint8_t* buf, int length, const is_nitro_usb_device* device_desc, bool expect_result = true) {
|
||||
static int SendWritePacket(is_nitro_device_handlers* handlers, uint16_t command, is_nitro_packet_type type, uint32_t address, uint8_t* buf, int length, const is_nitro_usb_device* device_desc, bool expect_result = true) {
|
||||
is_nitro_packet_header header;
|
||||
bool append_mode = true;
|
||||
if(device_desc->is_capture)
|
||||
@ -192,17 +202,17 @@ static int SendWritePacket(libusb_device_handle *handle, uint16_t command, is_ni
|
||||
if(append_mode && (buf != NULL)) {
|
||||
for(int j = 0; j < transfer_size; j++)
|
||||
single_usb_packet[sizeof(is_nitro_packet_header) + j] = buf[(i * single_packet_covered_size) + j];
|
||||
ret = bulk_out(handle, device_desc, single_usb_packet, transfer_size + sizeof(is_nitro_packet_header), &num_bytes);
|
||||
ret = bulk_out(handlers, device_desc, single_usb_packet, transfer_size + sizeof(is_nitro_packet_header), &num_bytes);
|
||||
}
|
||||
else {
|
||||
int header_bytes = 0;
|
||||
ret = bulk_out(handle, device_desc, single_usb_packet, sizeof(is_nitro_packet_header), &header_bytes);
|
||||
ret = bulk_out(handlers, device_desc, single_usb_packet, sizeof(is_nitro_packet_header), &header_bytes);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
if(header_bytes != sizeof(is_nitro_packet_header))
|
||||
return LIBUSB_ERROR_INTERRUPTED;
|
||||
if((buf != NULL) && (transfer_size > 0))
|
||||
ret = bulk_out(handle, device_desc, &buf[(i * single_packet_covered_size)], transfer_size, &num_bytes);
|
||||
ret = bulk_out(handlers, device_desc, &buf[(i * single_packet_covered_size)], transfer_size, &num_bytes);
|
||||
num_bytes += header_bytes;
|
||||
}
|
||||
if(ret < 0)
|
||||
@ -213,7 +223,7 @@ static int SendWritePacket(libusb_device_handle *handle, uint16_t command, is_ni
|
||||
if(device_desc->is_capture && expect_result) {
|
||||
uint8_t status[16];
|
||||
int status_bytes = 0;
|
||||
int ret = bulk_in(handle, device_desc, status, sizeof(status), &status_bytes);
|
||||
int ret = bulk_in(handlers, device_desc, status, sizeof(status), &status_bytes);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
if(status_bytes != sizeof(status))
|
||||
@ -224,7 +234,7 @@ static int SendWritePacket(libusb_device_handle *handle, uint16_t command, is_ni
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
static int SendReadPacket(libusb_device_handle *handle, uint16_t command, is_nitro_packet_type type, uint32_t address, uint8_t* buf, int length, const is_nitro_usb_device* device_desc, bool expect_result = true) {
|
||||
static int SendReadPacket(is_nitro_device_handlers* handlers, uint16_t command, is_nitro_packet_type type, uint32_t address, uint8_t* buf, int length, const is_nitro_usb_device* device_desc, bool expect_result = true) {
|
||||
is_nitro_packet_header header;
|
||||
int single_packet_covered_size = USB_PACKET_LIMIT;
|
||||
int num_iters = (length + single_packet_covered_size - 1) / single_packet_covered_size;
|
||||
@ -247,13 +257,13 @@ static int SendReadPacket(libusb_device_handle *handle, uint16_t command, is_nit
|
||||
header.padding = 0;
|
||||
fix_endianness_header(&header);
|
||||
int num_bytes = 0;
|
||||
int ret = bulk_out(handle, device_desc, (uint8_t*)&header, sizeof(is_nitro_packet_header), &num_bytes);
|
||||
int ret = bulk_out(handlers, device_desc, (uint8_t*)&header, sizeof(is_nitro_packet_header), &num_bytes);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
if(num_bytes != sizeof(is_nitro_packet_header))
|
||||
return LIBUSB_ERROR_INTERRUPTED;
|
||||
if(buf != NULL) {
|
||||
ret = bulk_in(handle, device_desc, buf + (i * single_packet_covered_size), transfer_size, &num_bytes);
|
||||
ret = bulk_in(handlers, device_desc, buf + (i * single_packet_covered_size), transfer_size, &num_bytes);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
if(num_bytes != transfer_size)
|
||||
@ -263,7 +273,7 @@ static int SendReadPacket(libusb_device_handle *handle, uint16_t command, is_nit
|
||||
if(device_desc->is_capture && expect_result) {
|
||||
uint8_t status[16];
|
||||
int status_bytes = 0;
|
||||
int ret = bulk_in(handle, device_desc, status, sizeof(status), &status_bytes);
|
||||
int ret = bulk_in(handlers, device_desc, status, sizeof(status), &status_bytes);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
if(status_bytes != sizeof(status))
|
||||
@ -274,66 +284,66 @@ static int SendReadPacket(libusb_device_handle *handle, uint16_t command, is_nit
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
int SendReadCommand(libusb_device_handle *handle, uint16_t command, uint8_t* buf, int length, const is_nitro_usb_device* device_desc) {
|
||||
return SendReadPacket(handle, command, IS_NITRO_PACKET_TYPE_COMMAND, 0, buf, length, device_desc);
|
||||
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);
|
||||
}
|
||||
|
||||
int SendWriteCommand(libusb_device_handle *handle, uint16_t command, uint8_t* buf, int length, const is_nitro_usb_device* device_desc) {
|
||||
return SendWritePacket(handle, 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);
|
||||
}
|
||||
|
||||
int SendReadCommandU32(libusb_device_handle *handle, uint16_t command, uint32_t* out, const is_nitro_usb_device* 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(handle, 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);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SendWriteCommandU32(libusb_device_handle *handle, uint16_t command, uint32_t value, const is_nitro_usb_device* device_desc) {
|
||||
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(handle, command, (uint8_t*)&buffer, sizeof(uint32_t), device_desc);
|
||||
return SendWriteCommand(handlers, command, (uint8_t*)&buffer, sizeof(uint32_t), device_desc);
|
||||
}
|
||||
|
||||
int GetDeviceSerial(libusb_device_handle *handle, uint8_t* buf, const is_nitro_usb_device* 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(handle, IS_NITRO_CAP_CMD_GET_SERIAL, buf, IS_NITRO_REAL_SERIAL_NUMBER_SIZE, device_desc);
|
||||
return SendReadCommand(handle, 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(libusb_device_handle *handle, uint32_t address, uint8_t unit_size, uint8_t* buf, int count, const is_nitro_usb_device* 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) {
|
||||
is_nitro_nec_packet_header header;
|
||||
header.command = IS_NITRO_EMU_CMD_SET_READ_NEC_MEM;
|
||||
header.unit_size = unit_size;
|
||||
header.count = count;
|
||||
header.address = address;
|
||||
fix_endianness_header(&header);
|
||||
int ret = SendWriteCommand(handle, header.command, (uint8_t*)&header, sizeof(is_nitro_nec_packet_header), device_desc);
|
||||
int ret = SendWriteCommand(handlers, header.command, (uint8_t*)&header, sizeof(is_nitro_nec_packet_header), device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
return SendReadCommand(handle, IS_NITRO_EMU_CMD_READ_NEC_MEM, buf, count * unit_size, device_desc);
|
||||
return SendReadCommand(handlers, IS_NITRO_EMU_CMD_READ_NEC_MEM, buf, count * unit_size, device_desc);
|
||||
}
|
||||
|
||||
int ReadNecMemU16(libusb_device_handle *handle, uint32_t address, uint16_t* out, const is_nitro_usb_device* device_desc) {
|
||||
int ReadNecMemU16(is_nitro_device_handlers* handlers, uint32_t address, uint16_t* out, const is_nitro_usb_device* device_desc) {
|
||||
uint16_t buffer;
|
||||
int ret = ReadNecMem(handle, address, 2, (uint8_t*)&buffer, 1, device_desc);
|
||||
int ret = ReadNecMem(handlers, address, 2, (uint8_t*)&buffer, 1, device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
*out = from_le(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ReadNecMemU32(libusb_device_handle *handle, uint32_t address, uint32_t* out, const is_nitro_usb_device* device_desc) {
|
||||
int ReadNecMemU32(is_nitro_device_handlers* handlers, uint32_t address, uint32_t* out, const is_nitro_usb_device* device_desc) {
|
||||
uint32_t buffer;
|
||||
int ret = ReadNecMem(handle, address, 2, (uint8_t*)&buffer, 2, device_desc);
|
||||
int ret = ReadNecMem(handlers, address, 2, (uint8_t*)&buffer, 2, device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
*out = from_le(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WriteNecMem(libusb_device_handle *handle, uint32_t address, uint8_t unit_size, uint8_t* buf, int count, const is_nitro_usb_device* device_desc) {
|
||||
int WriteNecMem(is_nitro_device_handlers* handlers, uint32_t address, uint8_t unit_size, uint8_t* buf, int count, const is_nitro_usb_device* device_desc) {
|
||||
uint8_t* buffer = new uint8_t[(count * unit_size) + sizeof(is_nitro_nec_packet_header)];
|
||||
is_nitro_nec_packet_header header;
|
||||
header.command = IS_NITRO_EMU_CMD_WRITE_NEC_MEM;
|
||||
@ -345,106 +355,121 @@ int WriteNecMem(libusb_device_handle *handle, uint32_t address, uint8_t unit_siz
|
||||
buffer[i] = ((uint8_t*)&header)[i];
|
||||
for(int i = 0; i < count * unit_size; i++)
|
||||
buffer[i + sizeof(is_nitro_nec_packet_header)] = buf[i];
|
||||
int ret = SendWriteCommand(handle, header.command, buffer, (count * unit_size) + sizeof(is_nitro_nec_packet_header), device_desc);
|
||||
int ret = SendWriteCommand(handlers, header.command, buffer, (count * unit_size) + sizeof(is_nitro_nec_packet_header), device_desc);
|
||||
delete []buffer;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int WriteNecMemU16(libusb_device_handle *handle, uint32_t address, uint16_t value, const is_nitro_usb_device* device_desc) {
|
||||
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(handle, address, 2, (uint8_t*)&buffer, 1, device_desc);
|
||||
return WriteNecMem(handlers, address, 2, (uint8_t*)&buffer, 1, device_desc);
|
||||
}
|
||||
|
||||
int WriteNecMemU32(libusb_device_handle *handle, uint32_t address, uint32_t value, const is_nitro_usb_device* 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(handle, address, 2, (uint8_t*)&buffer, 2, device_desc);
|
||||
return WriteNecMem(handlers, address, 2, (uint8_t*)&buffer, 2, device_desc);
|
||||
}
|
||||
|
||||
int DisableLca2(libusb_device_handle *handle, const is_nitro_usb_device* device_desc) {
|
||||
int DisableLca2(is_nitro_device_handlers* handlers, const is_nitro_usb_device* device_desc) {
|
||||
if(device_desc->is_capture)
|
||||
return LIBUSB_SUCCESS;
|
||||
int ret = WriteNecMemU16(handle, 0x00805180, 0, device_desc);
|
||||
int ret = WriteNecMemU16(handlers, 0x00805180, 0, device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
ret = WriteNecMemU16(handle, 0x0F84000A, 1, device_desc);
|
||||
ret = WriteNecMemU16(handlers, 0x0F84000A, 1, device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
//default_sleep(2000);
|
||||
return WriteNecMemU16(handle, 0x0F84000A, 0, device_desc);
|
||||
return WriteNecMemU16(handlers, 0x0F84000A, 0, device_desc);
|
||||
}
|
||||
|
||||
int StartUsbCaptureDma(libusb_device_handle *handle, const is_nitro_usb_device* device_desc) {
|
||||
int StartUsbCaptureDma(is_nitro_device_handlers* handlers, const is_nitro_usb_device* device_desc) {
|
||||
if(!device_desc->is_capture) {
|
||||
int ret = WriteNecMemU16(handle, REG_USB_DMA_CONTROL_2, 2, device_desc);
|
||||
int ret = WriteNecMemU16(handlers, REG_USB_DMA_CONTROL_2, 2, device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
return WriteNecMemU16(handle, REG_USB_BIU_CONTROL_2, 1, device_desc);
|
||||
return WriteNecMemU16(handlers, REG_USB_BIU_CONTROL_2, 1, device_desc);
|
||||
}
|
||||
return SendReadPacket(handle, 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(libusb_device_handle *handle, const is_nitro_usb_device* device_desc) {
|
||||
int StopUsbCaptureDma(is_nitro_device_handlers* handlers, const is_nitro_usb_device* device_desc) {
|
||||
if(!device_desc->is_capture) {
|
||||
int ret = WriteNecMemU16(handle, REG_USB_DMA_CONTROL_2, 0, device_desc);
|
||||
int ret = WriteNecMemU16(handlers, REG_USB_DMA_CONTROL_2, 0, device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
return WriteNecMemU16(handle, REG_USB_BIU_CONTROL_2, 0, device_desc);
|
||||
return WriteNecMemU16(handlers, REG_USB_BIU_CONTROL_2, 0, device_desc);
|
||||
}
|
||||
return SendReadPacket(handle, 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(libusb_device_handle *handle, uint16_t count, const is_nitro_usb_device* device_desc) {
|
||||
int SetForwardFrameCount(is_nitro_device_handlers* handlers, uint16_t count, const is_nitro_usb_device* device_desc) {
|
||||
if(!count)
|
||||
return LIBUSB_ERROR_INTERRUPTED;
|
||||
count -= 1;
|
||||
if(!device_desc->is_capture)
|
||||
return WriteNecMemU32(handle, 0x0800000C, (count >> 8) | ((count & 0xFF) << 16), device_desc);
|
||||
return SendWriteCommandU32(handle, IS_NITRO_CAP_CMD_SET_FWD_FRAMES, count, device_desc);
|
||||
return WriteNecMemU32(handlers, 0x0800000C, (count >> 8) | ((count & 0xFF) << 16), device_desc);
|
||||
return SendWriteCommandU32(handlers, IS_NITRO_CAP_CMD_SET_FWD_FRAMES, count, device_desc);
|
||||
}
|
||||
|
||||
int SetForwardFramePermanent(libusb_device_handle *handle, const is_nitro_usb_device* device_desc) {
|
||||
return SetForwardFrameCount(handle, 0x4001, device_desc);
|
||||
int SetForwardFramePermanent(is_nitro_device_handlers* handlers, const is_nitro_usb_device* device_desc) {
|
||||
return SetForwardFrameCount(handlers, 0x4001, device_desc);
|
||||
}
|
||||
|
||||
int GetFrameCounter(libusb_device_handle *handle, uint16_t* out, const is_nitro_usb_device* device_desc) {
|
||||
int GetFrameCounter(is_nitro_device_handlers* handlers, uint16_t* out, const is_nitro_usb_device* device_desc) {
|
||||
if(device_desc->is_capture) {
|
||||
*out = 0;
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
uint32_t counter = 0;
|
||||
int ret = ReadNecMemU32(handle, 0x08000028, &counter, device_desc);
|
||||
int ret = ReadNecMemU32(handlers, 0x08000028, &counter, device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
*out = (counter & 0xFF) | ((counter & 0xFF0000) >> 8);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int UpdateFrameForwardConfig(libusb_device_handle *handle, 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) {
|
||||
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) {
|
||||
if(!device_desc->is_capture)
|
||||
return WriteNecMemU16(handle, 0x0800000A, ((colors & 1) << 4) | ((screens & 3) << 2) | ((rate & 3) << 0), device_desc);
|
||||
int ret = SendWriteCommandU32(handle, IS_NITRO_CAP_CMD_SET_FWD_COLOURS, colors & 1, device_desc);
|
||||
return WriteNecMemU16(handlers, 0x0800000A, ((colors & 1) << 4) | ((screens & 3) << 2) | ((rate & 3) << 0), device_desc);
|
||||
int ret = SendWriteCommandU32(handlers, IS_NITRO_CAP_CMD_SET_FWD_COLOURS, colors & 1, device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
ret = SendWriteCommandU32(handle, IS_NITRO_CAP_CMD_SET_FWD_RATE, rate & 3, device_desc);
|
||||
ret = SendWriteCommandU32(handlers, IS_NITRO_CAP_CMD_SET_FWD_RATE, rate & 3, device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
return SendWriteCommandU32(handle, IS_NITRO_CAP_CMD_SET_FWD_MODE, screens & 3, device_desc);
|
||||
return SendWriteCommandU32(handlers, IS_NITRO_CAP_CMD_SET_FWD_MODE, screens & 3, device_desc);
|
||||
}
|
||||
|
||||
int UpdateFrameForwardEnable(libusb_device_handle *handle, bool enable, bool restart, const is_nitro_usb_device* device_desc) {
|
||||
int UpdateFrameForwardEnable(is_nitro_device_handlers* handlers, bool enable, bool restart, const is_nitro_usb_device* device_desc) {
|
||||
uint32_t value = 0;
|
||||
if(!device_desc->is_capture) {
|
||||
if(enable)
|
||||
value |= (1 << IS_NITRO_EMULATOR_FORWARD_ENABLE_BIT);
|
||||
if(restart)
|
||||
value |= (1 << IS_NITRO_EMULATOR_FORWARD_COUNTER_RESTART_BIT);
|
||||
return WriteNecMemU16(handle, 0x08000008, value, device_desc);
|
||||
return WriteNecMemU16(handlers, 0x08000008, value, device_desc);
|
||||
}
|
||||
if(restart)
|
||||
value |= (1 << IS_NITRO_CAPTURE_FORWARD_COUNTER_RESTART_BIT);
|
||||
return SendWriteCommandU32(handle, IS_NITRO_CAP_CMD_SET_FWD_RESTART, value, device_desc);
|
||||
return SendWriteCommandU32(handlers, IS_NITRO_CAP_CMD_SET_FWD_RESTART, value, device_desc);
|
||||
}
|
||||
|
||||
int ReadFrame(libusb_device_handle *handle, uint8_t* buf, int length, const is_nitro_usb_device* device_desc) {
|
||||
int ReadLidState(is_nitro_device_handlers* handlers, uint32_t* out, const is_nitro_usb_device* device_desc) {
|
||||
if(device_desc->is_capture)
|
||||
return SendReadCommandU32(handlers, IS_NITRO_CAP_CMD_GET_LID_STATE, out, device_desc);
|
||||
uint16_t flags = 0;
|
||||
int ret = ReadNecMemU16(handlers, 0x08000000, &flags, device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
*out = (flags & 2) >> 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ReadFrame(is_nitro_device_handlers* handlers, uint8_t* buf, int length, const is_nitro_usb_device* device_desc) {
|
||||
// Maybe making this async would be better for lower end hardware...
|
||||
int num_bytes = 0;
|
||||
int ret = bulk_in(handle, device_desc, buf, length, &num_bytes);
|
||||
int ret = bulk_in(handlers, device_desc, buf, length, &num_bytes);
|
||||
if(num_bytes != length)
|
||||
return LIBUSB_ERROR_INTERRUPTED;
|
||||
return ret;
|
213
source/CaptureDeviceSpecific/ISNitro/usb_is_nitro_is_driver.cpp
Normal file
213
source/CaptureDeviceSpecific/ISNitro/usb_is_nitro_is_driver.cpp
Normal file
@ -0,0 +1,213 @@
|
||||
#include "usb_is_nitro_communications.hpp"
|
||||
#include "usb_is_nitro_setup_general.hpp"
|
||||
#include "usb_is_nitro_is_driver.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#ifdef _WIN32
|
||||
#include <setupapi.h>
|
||||
|
||||
// Code based off of Gericom's sample code. Distributed under the MIT License. Copyright (c) 2024 Gericom
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
|
||||
const GUID is_nitro_driver_guid = { .Data1 = 0xB78D7ADA, .Data2 = 0xDDF4, .Data3 = 0x418F, .Data4 = {0x8C, 0x7C, 0x4A, 0xC8, 0x80, 0x30, 0xF5, 0x42} };
|
||||
|
||||
static bool read_is_driver_device_info(HANDLE handle, uint8_t* buffer, size_t size, DWORD* num_read) {
|
||||
return DeviceIoControl(handle, 0x22000C, buffer, size, buffer, size, num_read, NULL);
|
||||
}
|
||||
|
||||
static bool is_driver_device_reset(HANDLE handle) {
|
||||
DWORD num_read;
|
||||
return DeviceIoControl(handle, 0x220004, NULL, 0, NULL, 0, &num_read, NULL);
|
||||
}
|
||||
|
||||
static bool is_driver_pipe_reset(HANDLE handle) {
|
||||
DWORD num_read;
|
||||
return DeviceIoControl(handle, 0x220008, NULL, 0, NULL, 0, &num_read, NULL);
|
||||
}
|
||||
|
||||
static std::string is_driver_get_device_path(HDEVINFO DeviceInfoSet, SP_DEVICE_INTERFACE_DATA* DeviceInterfaceData) {
|
||||
std::string result = "";
|
||||
// Call this with an empty buffer to the required size of the structure.
|
||||
ULONG requiredSize;
|
||||
SetupDiGetDeviceInterfaceDetail(DeviceInfoSet, DeviceInterfaceData, NULL, 0, &requiredSize, NULL);
|
||||
if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
||||
return result;
|
||||
|
||||
PSP_DEVICE_INTERFACE_DETAIL_DATA devInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)(new uint8_t[requiredSize]);
|
||||
if(!devInterfaceDetailData)
|
||||
return result;
|
||||
|
||||
devInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
|
||||
if(SetupDiGetDeviceInterfaceDetail(DeviceInfoSet, DeviceInterfaceData, devInterfaceDetailData, requiredSize, &requiredSize, NULL))
|
||||
result = (std::string)(devInterfaceDetailData->DevicePath);
|
||||
|
||||
delete []((uint8_t*)devInterfaceDetailData);
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool is_driver_get_device_pid_vid(std::string path, uint16_t& out_vid, uint16_t& out_pid) {
|
||||
HANDLE handle = CreateFile(path.c_str(), (GENERIC_READ | GENERIC_WRITE), (FILE_SHARE_READ | FILE_SHARE_WRITE), NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
uint8_t buffer[0x412];
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
DWORD num_read = 0;
|
||||
bool result = read_is_driver_device_info(handle, buffer, sizeof(buffer), &num_read);
|
||||
CloseHandle(handle);
|
||||
if(!result)
|
||||
return false;
|
||||
if (num_read < 11)
|
||||
return false;
|
||||
out_vid = buffer[8] + (buffer[9] << 8);
|
||||
out_pid = buffer[10] + (buffer[11] << 8);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void set_handle_timeout(HANDLE handle, int timeout) {
|
||||
COMMTIMEOUTS timeouts;
|
||||
if (GetCommTimeouts(handle, &timeouts)) {
|
||||
timeouts.ReadTotalTimeoutConstant = timeout;
|
||||
timeouts.ReadTotalTimeoutMultiplier = 0;
|
||||
SetCommTimeouts(handle, &timeouts);
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_driver_setup_connection(is_nitro_device_handlers* handlers, const is_nitro_usb_device* usb_device_desc, std::string path) {
|
||||
handlers->usb_handle = NULL;
|
||||
handlers->mutex = NULL;
|
||||
handlers->write_handle = INVALID_HANDLE_VALUE;
|
||||
handlers->read_handle = INVALID_HANDLE_VALUE;
|
||||
std::string mutex_name = "Global\\ISU_" + path.substr(4);
|
||||
std::replace(mutex_name.begin(), mutex_name.end(), '\\', '@');
|
||||
handlers->mutex = CreateMutex(NULL, true, mutex_name.c_str());
|
||||
if ((handlers->mutex != NULL) && (GetLastError() == ERROR_ALREADY_EXISTS)) {
|
||||
CloseHandle(handlers->mutex);
|
||||
handlers->mutex = NULL;
|
||||
}
|
||||
if (handlers->mutex == NULL)
|
||||
return false;
|
||||
handlers->write_handle = CreateFile((path + (char)(std::filesystem::path::preferred_separator)+"Pipe00").c_str(), (GENERIC_READ | GENERIC_WRITE), (FILE_SHARE_READ | FILE_SHARE_WRITE), NULL, OPEN_EXISTING, 0, NULL);
|
||||
handlers->read_handle = CreateFile((path + (char)(std::filesystem::path::preferred_separator)+"Pipe01").c_str(), (GENERIC_READ | GENERIC_WRITE), (FILE_SHARE_READ | FILE_SHARE_WRITE), NULL, OPEN_EXISTING, 0, NULL);
|
||||
if ((handlers->write_handle == INVALID_HANDLE_VALUE) || (handlers->read_handle == INVALID_HANDLE_VALUE))
|
||||
return false;
|
||||
if (!is_driver_device_reset(handlers->write_handle))
|
||||
return false;
|
||||
if (!is_driver_pipe_reset(handlers->write_handle))
|
||||
return false;
|
||||
if (!is_driver_pipe_reset(handlers->read_handle))
|
||||
return false;
|
||||
set_handle_timeout(handlers->read_handle, usb_device_desc->bulk_timeout);
|
||||
set_handle_timeout(handlers->write_handle, usb_device_desc->bulk_timeout);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
is_nitro_device_handlers* is_driver_serial_reconnection(const is_nitro_usb_device* usb_device_desc, CaptureDevice* device) {
|
||||
is_nitro_device_handlers* final_handlers = NULL;
|
||||
#ifdef _WIN32
|
||||
if (device->path != "") {
|
||||
is_nitro_device_handlers handlers;
|
||||
if (is_driver_setup_connection(&handlers, usb_device_desc, device->path)) {
|
||||
final_handlers = new is_nitro_device_handlers;
|
||||
final_handlers->usb_handle = NULL;
|
||||
final_handlers->mutex = handlers.mutex;
|
||||
final_handlers->read_handle = handlers.read_handle;
|
||||
final_handlers->write_handle = handlers.write_handle;
|
||||
}
|
||||
else
|
||||
is_driver_end_connection(&handlers);
|
||||
}
|
||||
#endif
|
||||
return final_handlers;
|
||||
}
|
||||
|
||||
void is_driver_end_connection(is_nitro_device_handlers* handlers) {
|
||||
#ifdef _WIN32
|
||||
if (handlers->write_handle != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(handlers->write_handle);
|
||||
handlers->write_handle = INVALID_HANDLE_VALUE;
|
||||
if (handlers->read_handle != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(handlers->read_handle);
|
||||
handlers->read_handle = INVALID_HANDLE_VALUE;
|
||||
if(handlers->mutex != NULL)
|
||||
CloseHandle(handlers->mutex);
|
||||
handlers->mutex = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void is_driver_list_devices(std::vector<CaptureDevice> &devices_list, bool* not_supported_elems, int *curr_serial_extra_id_is_nitro, const size_t num_is_nitro_desc) {
|
||||
#ifdef _WIN32
|
||||
HDEVINFO DeviceInfoSet = SetupDiGetClassDevs(
|
||||
&is_nitro_driver_guid,
|
||||
NULL,
|
||||
NULL,
|
||||
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
|
||||
|
||||
SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
|
||||
ZeroMemory(&DeviceInterfaceData, sizeof(SP_DEVICE_INTERFACE_DATA));
|
||||
DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
|
||||
uint32_t i = 0;
|
||||
while (SetupDiEnumDeviceInterfaces(DeviceInfoSet, NULL, &is_nitro_driver_guid, i++, &DeviceInterfaceData)) {
|
||||
std::string path = is_driver_get_device_path(DeviceInfoSet, &DeviceInterfaceData);
|
||||
if (path == "")
|
||||
continue;
|
||||
uint16_t vid = 0;
|
||||
uint16_t pid = 0;
|
||||
if(!is_driver_get_device_pid_vid(path, vid, pid))
|
||||
continue;
|
||||
for (int j = 0; j < num_is_nitro_desc; j++) {
|
||||
const is_nitro_usb_device* usb_device_desc = GetISNitroDesc(j);
|
||||
if(not_supported_elems[j] && (usb_device_desc->vid == vid) && (usb_device_desc->pid == pid)) {
|
||||
is_nitro_device_handlers handlers;
|
||||
if(is_driver_setup_connection(&handlers, usb_device_desc, path))
|
||||
is_nitro_insert_device(devices_list, &handlers, usb_device_desc, curr_serial_extra_id_is_nitro[j], path);
|
||||
is_driver_end_connection(&handlers);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DeviceInfoSet) {
|
||||
SetupDiDestroyDeviceInfoList(DeviceInfoSet);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Write to bulk
|
||||
int is_driver_bulk_out(is_nitro_device_handlers* handlers, uint8_t* buf, int length, int* transferred) {
|
||||
bool result = true;
|
||||
#ifdef _WIN32
|
||||
DWORD num_bytes = 0;
|
||||
result = WriteFile(handlers->write_handle, buf, length, &num_bytes, NULL);
|
||||
*transferred = num_bytes;
|
||||
#endif
|
||||
return result ? LIBUSB_SUCCESS : LIBUSB_ERROR_OTHER;
|
||||
}
|
||||
|
||||
// Read from bulk
|
||||
int is_driver_bulk_in(is_nitro_device_handlers* handlers, uint8_t* buf, int length, int* transferred) {
|
||||
bool result = true;
|
||||
#ifdef _WIN32
|
||||
DWORD num_bytes = 0;
|
||||
result = ReadFile(handlers->read_handle, buf, length, &num_bytes, NULL);
|
||||
*transferred = num_bytes;
|
||||
#endif
|
||||
return result ? LIBUSB_SUCCESS : LIBUSB_ERROR_OTHER;
|
||||
}
|
138
source/CaptureDeviceSpecific/ISNitro/usb_is_nitro_libusb.cpp
Normal file
138
source/CaptureDeviceSpecific/ISNitro/usb_is_nitro_libusb.cpp
Normal file
@ -0,0 +1,138 @@
|
||||
#include "usb_is_nitro_communications.hpp"
|
||||
#include "usb_is_nitro_setup_general.hpp"
|
||||
#include "usb_is_nitro_libusb.hpp"
|
||||
#include "usb_generic.hpp"
|
||||
|
||||
#include <libusb.h>
|
||||
|
||||
// Code based off of Gericom's sample code. Distributed under the MIT License. Copyright (c) 2024 Gericom
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
|
||||
static bool is_nitro_libusb_setup_connection(libusb_device_handle* handle, const is_nitro_usb_device* usb_device_desc) {
|
||||
if (libusb_set_configuration(handle, usb_device_desc->default_config) != LIBUSB_SUCCESS)
|
||||
return false;
|
||||
if(libusb_claim_interface(handle, usb_device_desc->default_interface) != LIBUSB_SUCCESS)
|
||||
return false;
|
||||
if(libusb_clear_halt(handle, usb_device_desc->ep1_out) != LIBUSB_SUCCESS)
|
||||
return false;
|
||||
if(libusb_clear_halt(handle, usb_device_desc->ep2_in) != LIBUSB_SUCCESS)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int is_nitro_libusb_insert_device(std::vector<CaptureDevice> &devices_list, const is_nitro_usb_device* usb_device_desc, libusb_device *usb_device, libusb_device_descriptor *usb_descriptor, int &curr_serial_extra_id) {
|
||||
libusb_device_handle *handle = NULL;
|
||||
if((usb_descriptor->idVendor != usb_device_desc->vid) || (usb_descriptor->idProduct != usb_device_desc->pid))
|
||||
return LIBUSB_ERROR_NOT_FOUND;
|
||||
if((usb_descriptor->iManufacturer != usb_device_desc->manufacturer_id) || (usb_descriptor->iProduct != usb_device_desc->product_id))
|
||||
return LIBUSB_ERROR_NOT_FOUND;
|
||||
int result = libusb_open(usb_device, &handle);
|
||||
if((result < 0) || (handle == NULL))
|
||||
return result;
|
||||
if(is_nitro_libusb_setup_connection(handle, usb_device_desc)) {
|
||||
is_nitro_device_handlers handlers;
|
||||
handlers.usb_handle = handle;
|
||||
is_nitro_insert_device(devices_list, &handlers, usb_device_desc, curr_serial_extra_id);
|
||||
libusb_release_interface(handle, usb_device_desc->default_interface);
|
||||
}
|
||||
libusb_close(handle);
|
||||
return result;
|
||||
}
|
||||
|
||||
is_nitro_device_handlers* is_nitro_libusb_serial_reconnection(const is_nitro_usb_device* usb_device_desc, CaptureDevice* device, int &curr_serial_extra_id) {
|
||||
if(!usb_is_initialized())
|
||||
return NULL;
|
||||
libusb_device **usb_devices;
|
||||
int num_devices = libusb_get_device_list(get_usb_ctx(), &usb_devices);
|
||||
libusb_device_descriptor usb_descriptor{};
|
||||
is_nitro_device_handlers* final_handlers = NULL;
|
||||
|
||||
for(int i = 0; i < num_devices; i++) {
|
||||
is_nitro_device_handlers handlers;
|
||||
int result = libusb_get_device_descriptor(usb_devices[i], &usb_descriptor);
|
||||
if(result < 0)
|
||||
continue;
|
||||
if((usb_descriptor.idVendor != usb_device_desc->vid) || (usb_descriptor.idProduct != usb_device_desc->pid))
|
||||
continue;
|
||||
if((usb_descriptor.iManufacturer != usb_device_desc->manufacturer_id) || (usb_descriptor.iProduct != usb_device_desc->product_id))
|
||||
continue;
|
||||
result = libusb_open(usb_devices[i], &handlers.usb_handle);
|
||||
if(result || (handlers.usb_handle == NULL))
|
||||
continue;
|
||||
if (is_nitro_libusb_setup_connection(handlers.usb_handle, usb_device_desc)) {
|
||||
std::string device_serial_number = get_serial(usb_device_desc, &handlers, curr_serial_extra_id);
|
||||
if (device->serial_number == device_serial_number) {
|
||||
final_handlers = new is_nitro_device_handlers;
|
||||
final_handlers->usb_handle = handlers.usb_handle;
|
||||
break;
|
||||
}
|
||||
libusb_release_interface(handlers.usb_handle, usb_device_desc->default_interface);
|
||||
}
|
||||
libusb_close(handlers.usb_handle);
|
||||
}
|
||||
|
||||
if(num_devices >= 0)
|
||||
libusb_free_device_list(usb_devices, 1);
|
||||
|
||||
return final_handlers;
|
||||
}
|
||||
|
||||
void is_nitro_libusb_end_connection(is_nitro_device_handlers* handlers, const is_nitro_usb_device* device_desc, bool interface_claimed) {
|
||||
if (interface_claimed)
|
||||
libusb_release_interface(handlers->usb_handle, device_desc->default_interface);
|
||||
libusb_close(handlers->usb_handle);
|
||||
handlers->usb_handle = NULL;
|
||||
}
|
||||
|
||||
void is_nitro_libusb_list_devices(std::vector<CaptureDevice> &devices_list, bool* no_access_elems, bool* not_supported_elems, int* curr_serial_extra_id_is_nitro, const size_t num_is_nitro_desc) {
|
||||
if(!usb_is_initialized())
|
||||
return;
|
||||
libusb_device **usb_devices;
|
||||
int num_devices = libusb_get_device_list(get_usb_ctx(), &usb_devices);
|
||||
libusb_device_descriptor usb_descriptor{};
|
||||
|
||||
for(int i = 0; i < num_devices; i++) {
|
||||
int result = libusb_get_device_descriptor(usb_devices[i], &usb_descriptor);
|
||||
if(result < 0)
|
||||
continue;
|
||||
for (int j = 0; j < num_is_nitro_desc; j++) {
|
||||
result = is_nitro_libusb_insert_device(devices_list, GetISNitroDesc(j), usb_devices[i], &usb_descriptor, curr_serial_extra_id_is_nitro[j]);
|
||||
if (result != LIBUSB_ERROR_NOT_FOUND) {
|
||||
if (result == LIBUSB_ERROR_ACCESS)
|
||||
no_access_elems[j] = true;
|
||||
if (result == LIBUSB_ERROR_NOT_SUPPORTED)
|
||||
not_supported_elems[j] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(num_devices >= 0)
|
||||
libusb_free_device_list(usb_devices, 1);
|
||||
}
|
||||
|
||||
// Write to bulk
|
||||
int is_nitro_libusb_bulk_out(is_nitro_device_handlers* handlers, const is_nitro_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred) {
|
||||
return libusb_bulk_transfer(handlers->usb_handle, usb_device_desc->ep1_out, buf, length, transferred, usb_device_desc->bulk_timeout);
|
||||
}
|
||||
|
||||
// Read from bulk
|
||||
int is_nitro_libusb_bulk_in(is_nitro_device_handlers* handlers, const is_nitro_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred) {
|
||||
return libusb_bulk_transfer(handlers->usb_handle, usb_device_desc->ep2_in, buf, length, transferred, usb_device_desc->bulk_timeout);
|
||||
}
|
0
source/dscapture_ftd2.cpp → source/CaptureDeviceSpecific/dscapture_ftd2.cpp
Executable file → Normal file
0
source/dscapture_ftd2.cpp → source/CaptureDeviceSpecific/dscapture_ftd2.cpp
Executable file → Normal file
34
source/usb_ds_3ds_capture.cpp → source/CaptureDeviceSpecific/usb_ds_3ds_capture.cpp
Executable file → Normal file
34
source/usb_ds_3ds_capture.cpp → source/CaptureDeviceSpecific/usb_ds_3ds_capture.cpp
Executable file → Normal file
@ -73,6 +73,11 @@ static const usb_device usb_old_ds_desc = {
|
||||
.i2caddr_3dsconfig = 0, .bitstream_3dscfg_ver = 0
|
||||
};
|
||||
|
||||
static const usb_device* usb_devices_desc_list[] = {
|
||||
&usb_3ds_desc,
|
||||
&usb_old_ds_desc,
|
||||
};
|
||||
|
||||
// Read vendor request from control endpoint. Returns bytes transferred (<0 = libusb error)
|
||||
static int vend_in(libusb_device_handle *handle, const usb_device* usb_device_desc, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint16_t wLength, uint8_t *buf) {
|
||||
return libusb_control_transfer(handle, ((uint8_t)LIBUSB_REQUEST_TYPE_VENDOR | (uint8_t)LIBUSB_ENDPOINT_IN), bRequest, wValue, wIndex, buf, wLength, usb_device_desc->control_timeout);
|
||||
@ -133,21 +138,21 @@ static std::string get_serial(libusb_device_handle *handle, libusb_device_descri
|
||||
return serial_str;
|
||||
}
|
||||
|
||||
static bool insert_device(std::vector<CaptureDevice> &devices_list, const usb_device* usb_device_desc, libusb_device *usb_device, libusb_device_descriptor *usb_descriptor, int &curr_serial_extra_id) {
|
||||
static int insert_device(std::vector<CaptureDevice> &devices_list, const usb_device* usb_device_desc, libusb_device *usb_device, libusb_device_descriptor *usb_descriptor, int &curr_serial_extra_id) {
|
||||
libusb_device_handle *handle = NULL;
|
||||
uint8_t data[SERIAL_NUMBER_SIZE];
|
||||
if((usb_descriptor->idVendor != usb_device_desc->vid) || (usb_descriptor->idProduct != usb_device_desc->pid))
|
||||
return false;
|
||||
return LIBUSB_ERROR_NOT_FOUND;
|
||||
int result = libusb_open(usb_device, &handle);
|
||||
if(result || (handle == NULL))
|
||||
return true;
|
||||
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);
|
||||
else
|
||||
devices_list.emplace_back(serial_str, "DS", CAPTURE_CONN_USB, (void*)usb_device_desc, false, false, false, WIDTH_DS, HEIGHT_DS + HEIGHT_DS, 0, 0, 0, 0, 0, HEIGHT_DS);
|
||||
libusb_close(handle);
|
||||
return true;
|
||||
return result;
|
||||
}
|
||||
|
||||
static libusb_device_handle* usb_find_by_serial_number(const usb_device* usb_device_desc, std::string &serial_number) {
|
||||
@ -309,17 +314,24 @@ void list_devices_usb_ds_3ds(std::vector<CaptureDevice> &devices_list) {
|
||||
libusb_device **usb_devices;
|
||||
int num_devices = libusb_get_device_list(get_usb_ctx(), &usb_devices);
|
||||
libusb_device_descriptor usb_descriptor{};
|
||||
|
||||
int curr_serial_extra_id_3ds = 0;
|
||||
int curr_serial_extra_id_old_ds = 0;
|
||||
|
||||
const size_t num_usb_desc = sizeof(usb_devices_desc_list) / sizeof(usb_devices_desc_list[0]);
|
||||
bool no_access_elems[num_usb_desc];
|
||||
int curr_serial_extra_ids[num_usb_desc];
|
||||
for (int i = 0; i < num_usb_desc; i++) {
|
||||
no_access_elems[i] = false;
|
||||
curr_serial_extra_ids[i] = 0;
|
||||
}
|
||||
for(int i = 0; i < num_devices; i++) {
|
||||
int result = libusb_get_device_descriptor(usb_devices[i], &usb_descriptor);
|
||||
if(result < 0)
|
||||
continue;
|
||||
if(insert_device(devices_list, &usb_3ds_desc, usb_devices[i], &usb_descriptor, curr_serial_extra_id_3ds))
|
||||
continue;
|
||||
if(insert_device(devices_list, &usb_old_ds_desc, usb_devices[i], &usb_descriptor, curr_serial_extra_id_old_ds))
|
||||
continue;
|
||||
for(int j = 0; j < num_usb_desc; j++)
|
||||
if(insert_device(devices_list, usb_devices_desc_list[j], usb_devices[i], &usb_descriptor, curr_serial_extra_ids[j]) != LIBUSB_ERROR_NOT_FOUND) {
|
||||
if (result == LIBUSB_ERROR_ACCESS)
|
||||
no_access_elems[j] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(num_devices >= 0)
|
@ -3,7 +3,7 @@
|
||||
#include "3dscapture_ftd3.hpp"
|
||||
#include "dscapture_ftd2.hpp"
|
||||
#include "usb_ds_3ds_capture.hpp"
|
||||
#include "usb_is_nitro_capture.hpp"
|
||||
#include "usb_is_nitro_acquisition.hpp"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include "3dscapture_ftd3.hpp"
|
||||
#include "dscapture_ftd2.hpp"
|
||||
#include "usb_ds_3ds_capture.hpp"
|
||||
#include "usb_is_nitro_capture.hpp"
|
||||
#include "usb_is_nitro_acquisition.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
@ -147,7 +147,7 @@ void captureCall(CaptureData* capture_data) {
|
||||
#endif
|
||||
#ifdef USE_IS_NITRO_USB
|
||||
if(capture_data->status.device.cc_type == CAPTURE_CONN_IS_NITRO)
|
||||
is_nitro_capture_main_loop(capture_data);
|
||||
is_nitro_acquisition_main_loop(capture_data);
|
||||
#endif
|
||||
|
||||
capture_data->status.close_success = false;
|
||||
@ -173,7 +173,7 @@ void captureCall(CaptureData* capture_data) {
|
||||
#endif
|
||||
#ifdef USE_IS_NITRO_USB
|
||||
if(capture_data->status.device.cc_type == CAPTURE_CONN_IS_NITRO)
|
||||
usb_is_nitro_capture_cleanup(capture_data);
|
||||
usb_is_nitro_acquisition_cleanup(capture_data);
|
||||
#endif
|
||||
|
||||
capture_data->status.close_success = false;
|
||||
@ -207,7 +207,7 @@ uint64_t get_video_in_size(CaptureData* capture_data) {
|
||||
#endif
|
||||
#ifdef USE_IS_NITRO_USB
|
||||
if(capture_data->status.device.cc_type == CAPTURE_CONN_IS_NITRO)
|
||||
return usb_is_nitro_emulator_get_video_in_size(capture_data);
|
||||
return usb_is_nitro_get_video_in_size(capture_data);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,567 +0,0 @@
|
||||
#include "devicecapture.hpp"
|
||||
#include "usb_is_nitro.hpp"
|
||||
#include "usb_is_nitro_capture.hpp"
|
||||
#include "usb_generic.hpp"
|
||||
|
||||
#include <libusb.h>
|
||||
#include <cstring>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
|
||||
// Code based off of Gericom's sample code. Distributed under the MIT License. Copyright (c) 2024 Gericom
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
|
||||
#define SERIAL_NUMBER_SIZE (IS_NITRO_REAL_SERIAL_NUMBER_SIZE + 1)
|
||||
|
||||
#define FRAME_BUFFER_SIZE 32
|
||||
|
||||
enum usb_capture_status {
|
||||
USB_CAPTURE_SUCCESS = 0,
|
||||
USB_CAPTURE_SKIP,
|
||||
USB_CAPTURE_PIPE_ERROR,
|
||||
USB_CAPTURE_FRAMEINFO_ERROR,
|
||||
USB_CAPTURE_ERROR
|
||||
};
|
||||
|
||||
static int drain_frames(libusb_device_handle *handle, int num_frames, int start_frames, CaptureScreensType capture_type, const is_nitro_usb_device* usb_device_desc);
|
||||
static int EndCapture(libusb_device_handle *handle, bool do_drain_frames, int start_frames, CaptureScreensType capture_type, const is_nitro_usb_device* usb_device_desc);
|
||||
static void is_nitro_capture_capture_main_loop(CaptureData* capture_data);
|
||||
static void is_nitro_emulator_capture_main_loop(CaptureData* capture_data);
|
||||
static int StartEmulatorCapture(libusb_device_handle *handle, uint16_t &out_frame_count, float &single_frame_time, CaptureScreensType capture_type, const is_nitro_usb_device* usb_device_desc);
|
||||
static int StartCaptureCapture(libusb_device_handle *handle, CaptureScreensType capture_type, const is_nitro_usb_device* usb_device_desc);
|
||||
|
||||
static std::string get_serial(const is_nitro_usb_device* usb_device_desc, libusb_device_handle *handle, int &curr_serial_extra_id) {
|
||||
uint8_t data[SERIAL_NUMBER_SIZE];
|
||||
std::string serial_str = std::to_string(curr_serial_extra_id);
|
||||
bool conn_success = true;
|
||||
if(libusb_set_configuration(handle, usb_device_desc->default_config) != LIBUSB_SUCCESS)
|
||||
conn_success = false;
|
||||
if(conn_success && libusb_claim_interface(handle, usb_device_desc->default_interface) != LIBUSB_SUCCESS)
|
||||
conn_success = false;
|
||||
if((!usb_device_desc->is_capture) && conn_success && EndCapture(handle, false, 0, CAPTURE_SCREENS_BOTH, usb_device_desc) != LIBUSB_SUCCESS)
|
||||
conn_success = false;
|
||||
if(conn_success && (GetDeviceSerial(handle, data, usb_device_desc) != LIBUSB_SUCCESS)) {
|
||||
int ret = 0;
|
||||
while(ret >= 0)
|
||||
ret = drain_frames(handle, FRAME_BUFFER_SIZE * 2, 0, CAPTURE_SCREENS_TOP, usb_device_desc);
|
||||
if((GetDeviceSerial(handle, data, usb_device_desc) != LIBUSB_SUCCESS))
|
||||
conn_success = false;
|
||||
}
|
||||
if(conn_success) {
|
||||
data[IS_NITRO_REAL_SERIAL_NUMBER_SIZE] = '\0';
|
||||
serial_str = std::string((const char*)data);
|
||||
}
|
||||
else
|
||||
curr_serial_extra_id += 1;
|
||||
if(conn_success)
|
||||
libusb_release_interface(handle, usb_device_desc->default_interface);
|
||||
return serial_str;
|
||||
}
|
||||
|
||||
static int insert_device(std::vector<CaptureDevice> &devices_list, const is_nitro_usb_device* usb_device_desc, libusb_device *usb_device, libusb_device_descriptor *usb_descriptor, int &curr_serial_extra_id) {
|
||||
libusb_device_handle *handle = NULL;
|
||||
if((usb_descriptor->idVendor != usb_device_desc->vid) || (usb_descriptor->idProduct != usb_device_desc->pid))
|
||||
return LIBUSB_ERROR_NOT_FOUND;
|
||||
if((usb_descriptor->iManufacturer != usb_device_desc->manufacturer_id) || (usb_descriptor->iProduct != usb_device_desc->product_id))
|
||||
return LIBUSB_ERROR_NOT_FOUND;
|
||||
int result = libusb_open(usb_device, &handle);
|
||||
if((result < 0) || (handle == NULL))
|
||||
return result;
|
||||
devices_list.emplace_back(get_serial(usb_device_desc, handle, curr_serial_extra_id), 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);
|
||||
libusb_close(handle);
|
||||
return result;
|
||||
}
|
||||
|
||||
static libusb_device_handle* usb_find_by_serial_number(const is_nitro_usb_device* usb_device_desc, std::string &serial_number) {
|
||||
if(!usb_is_initialized())
|
||||
return NULL;
|
||||
libusb_device **usb_devices;
|
||||
int num_devices = libusb_get_device_list(get_usb_ctx(), &usb_devices);
|
||||
libusb_device_descriptor usb_descriptor{};
|
||||
libusb_device_handle *final_handle = NULL;
|
||||
|
||||
int curr_serial_extra_id = 0;
|
||||
for(int i = 0; i < num_devices; i++) {
|
||||
libusb_device_handle *handle = NULL;
|
||||
uint8_t data[SERIAL_NUMBER_SIZE];
|
||||
int result = libusb_get_device_descriptor(usb_devices[i], &usb_descriptor);
|
||||
if(result < 0)
|
||||
continue;
|
||||
if((usb_descriptor.idVendor != usb_device_desc->vid) || (usb_descriptor.idProduct != usb_device_desc->pid))
|
||||
continue;
|
||||
if((usb_descriptor.iManufacturer != usb_device_desc->manufacturer_id) || (usb_descriptor.iProduct != usb_device_desc->product_id))
|
||||
continue;
|
||||
result = libusb_open(usb_devices[i], &handle);
|
||||
if(result || (handle == NULL))
|
||||
continue;
|
||||
std::string device_serial_number = get_serial(usb_device_desc, handle, curr_serial_extra_id);
|
||||
if(serial_number == device_serial_number) {
|
||||
final_handle = handle;
|
||||
break;
|
||||
}
|
||||
libusb_close(handle);
|
||||
}
|
||||
|
||||
if(num_devices >= 0)
|
||||
libusb_free_device_list(usb_devices, 1);
|
||||
return final_handle;
|
||||
}
|
||||
|
||||
void list_devices_is_nitro(std::vector<CaptureDevice> &devices_list) {
|
||||
if(!usb_is_initialized())
|
||||
return;
|
||||
libusb_device **usb_devices;
|
||||
int num_devices = libusb_get_device_list(get_usb_ctx(), &usb_devices);
|
||||
libusb_device_descriptor usb_descriptor{};
|
||||
|
||||
int curr_serial_extra_id_is_nitro_emulator = 0;
|
||||
for(int i = 0; i < num_devices; i++) {
|
||||
int result = libusb_get_device_descriptor(usb_devices[i], &usb_descriptor);
|
||||
if(result < 0)
|
||||
continue;
|
||||
result = insert_device(devices_list, GetISNitroDesc(IS_NITRO_EMULATOR_COMMON_ID), usb_devices[i], &usb_descriptor, curr_serial_extra_id_is_nitro_emulator);
|
||||
if(result != LIBUSB_ERROR_NOT_FOUND) {
|
||||
continue;
|
||||
}
|
||||
result = insert_device(devices_list, GetISNitroDesc(IS_NITRO_EMULATOR_RARE_ID), usb_devices[i], &usb_descriptor, curr_serial_extra_id_is_nitro_emulator);
|
||||
if(result != LIBUSB_ERROR_NOT_FOUND) {
|
||||
continue;
|
||||
}
|
||||
result = insert_device(devices_list, GetISNitroDesc(IS_NITRO_CAPTURE_ID), usb_devices[i], &usb_descriptor, curr_serial_extra_id_is_nitro_emulator);
|
||||
if(result != LIBUSB_ERROR_NOT_FOUND) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if(num_devices >= 0)
|
||||
libusb_free_device_list(usb_devices, 1);
|
||||
}
|
||||
|
||||
static void is_nitro_connection_end(libusb_device_handle *dev, const is_nitro_usb_device *device_desc, bool interface_claimed = true) {
|
||||
if(interface_claimed)
|
||||
libusb_release_interface(dev, device_desc->default_interface);
|
||||
libusb_close(dev);
|
||||
}
|
||||
|
||||
bool is_nitro_connect_usb(bool print_failed, CaptureData* capture_data, CaptureDevice* device) {
|
||||
if(!usb_is_initialized())
|
||||
return false;
|
||||
const is_nitro_usb_device* usb_device_info = (const is_nitro_usb_device*)device->descriptor;
|
||||
libusb_device_handle *dev = usb_find_by_serial_number(usb_device_info, device->serial_number);
|
||||
if(!dev) {
|
||||
capture_error_print(true, capture_data, "Device not found");
|
||||
return false;
|
||||
}
|
||||
if(libusb_set_configuration(dev, usb_device_info->default_config) != LIBUSB_SUCCESS) {
|
||||
capture_error_print(true, capture_data, "Configuration failed");
|
||||
is_nitro_connection_end(dev, usb_device_info, false);
|
||||
return false;
|
||||
}
|
||||
if(libusb_claim_interface(dev, usb_device_info->default_interface) != LIBUSB_SUCCESS) {
|
||||
capture_error_print(true, capture_data, "Interface claim failed");
|
||||
is_nitro_connection_end(dev, usb_device_info, false);
|
||||
return false;
|
||||
}
|
||||
capture_data->handle = (void*)dev;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint64_t _is_nitro_emulator_get_video_in_size(CaptureScreensType capture_type) {
|
||||
if((capture_type == CAPTURE_SCREENS_TOP) || (capture_type == CAPTURE_SCREENS_BOTTOM))
|
||||
return sizeof(ISNitroEmulatorVideoInputData) / 2;
|
||||
return sizeof(ISNitroEmulatorVideoInputData);
|
||||
}
|
||||
|
||||
uint64_t usb_is_nitro_emulator_get_video_in_size(CaptureData* capture_data) {
|
||||
return _is_nitro_emulator_get_video_in_size(capture_data->status.capture_type);
|
||||
}
|
||||
|
||||
static int drain_frames(libusb_device_handle *handle, int num_frames, int start_frames, CaptureScreensType capture_type, const is_nitro_usb_device* usb_device_desc) {
|
||||
ISNitroEmulatorVideoInputData video_in_buffer;
|
||||
for (int i = start_frames; i < num_frames; i++) {
|
||||
int ret = ReadFrame(handle, (uint8_t*)&video_in_buffer, _is_nitro_emulator_get_video_in_size(capture_type), usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
}
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
static int set_capture_mode(libusb_device_handle *handle, CaptureScreensType capture_type, const is_nitro_usb_device* usb_device_desc) {
|
||||
is_nitro_forward_config_values_screens capture_mode_flag = IS_NITRO_FORWARD_CONFIG_MODE_BOTH;
|
||||
if(capture_type == CAPTURE_SCREENS_TOP)
|
||||
capture_mode_flag = IS_NITRO_FORWARD_CONFIG_MODE_TOP;
|
||||
if(capture_type == CAPTURE_SCREENS_BOTTOM)
|
||||
capture_mode_flag = IS_NITRO_FORWARD_CONFIG_MODE_BOTTOM;
|
||||
return UpdateFrameForwardConfig(handle, IS_NITRO_FORWARD_CONFIG_COLOR_RGB24, capture_mode_flag, IS_NITRO_FORWARD_CONFIG_RATE_FULL, usb_device_desc);
|
||||
}
|
||||
|
||||
static int StartEmulatorCapture(libusb_device_handle *handle, uint16_t &out_frame_count, float &single_frame_time, CaptureScreensType capture_type, const is_nitro_usb_device* usb_device_desc) {
|
||||
int ret = 0;
|
||||
ret = DisableLca2(handle, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
ret = set_capture_mode(handle, capture_type, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
ret = SetForwardFrameCount(handle, FRAME_BUFFER_SIZE, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
// Reset this in case it's high. At around 0xFFFF, reading from the USB DMA seems to fail...
|
||||
ret = UpdateFrameForwardEnable(handle, true, true, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
ret = UpdateFrameForwardEnable(handle, true, false, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
|
||||
// Get to the closest next frame
|
||||
auto clock_start = std::chrono::high_resolution_clock::now();
|
||||
uint16_t oldFrameCount;
|
||||
uint16_t newFrameCount;
|
||||
ret = GetFrameCounter(handle, &oldFrameCount, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
newFrameCount = oldFrameCount;
|
||||
while(newFrameCount == oldFrameCount) {
|
||||
ret = GetFrameCounter(handle, &newFrameCount, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
const auto curr_time = std::chrono::high_resolution_clock::now();
|
||||
const std::chrono::duration<double> diff = curr_time - clock_start;
|
||||
// If too much time has passed, the DS is probably either turned off or sleeping. If so, avoid locking up
|
||||
if(diff.count() > 0.2)
|
||||
break;
|
||||
}
|
||||
|
||||
// Get to the next modulo 32 frame.
|
||||
// We also do this to measure the time that is needed for each frame...
|
||||
// To do so, a minimum of 4 frames is required (FRAME_BUFFER_SIZE - 1 + 4)
|
||||
clock_start = std::chrono::high_resolution_clock::now();
|
||||
ret = GetFrameCounter(handle, &oldFrameCount, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
uint16_t targetFrameCount = (newFrameCount + FRAME_BUFFER_SIZE + 3) & (~(FRAME_BUFFER_SIZE - 1));
|
||||
while(oldFrameCount != targetFrameCount) {
|
||||
ret = GetFrameCounter(handle, &oldFrameCount, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
// Placing a sleep of some kind here would be much better...
|
||||
// Though this is only executed for a small time when first connecting...
|
||||
const auto curr_time = std::chrono::high_resolution_clock::now();
|
||||
const std::chrono::duration<double> diff = curr_time - clock_start;
|
||||
// If too much time has passed, the DS is probably either turned off or sleeping. If so, avoid locking up
|
||||
if(diff.count() > 1.0)
|
||||
break;
|
||||
}
|
||||
const auto curr_time = std::chrono::high_resolution_clock::now();
|
||||
const std::chrono::duration<double> diff = curr_time - clock_start;
|
||||
// Sometimes the upper 8 bits aren't updated... Use only the lower 8 bits.
|
||||
newFrameCount &= 0xFF;
|
||||
oldFrameCount &= 0xFF;
|
||||
int frame_diff = ((int)oldFrameCount) - ((int)newFrameCount);
|
||||
if(frame_diff < 0)
|
||||
frame_diff += 1 << 8;
|
||||
out_frame_count = oldFrameCount;
|
||||
// Determine how much time a single frame takes. We'll use it for sleeps
|
||||
if(frame_diff == 0)
|
||||
single_frame_time = 0;
|
||||
else
|
||||
single_frame_time = diff.count() / frame_diff;
|
||||
|
||||
// Start the actual DMA
|
||||
if(single_frame_time > 0) {
|
||||
ret = StartUsbCaptureDma(handle, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int StartCaptureCapture(libusb_device_handle *handle, CaptureScreensType capture_type, const is_nitro_usb_device* usb_device_desc) {
|
||||
int ret = 0;
|
||||
ret = set_capture_mode(handle, capture_type, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
ret = SetForwardFramePermanent(handle, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
ret = UpdateFrameForwardEnable(handle, true, true, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
return StartUsbCaptureDma(handle, usb_device_desc);
|
||||
}
|
||||
|
||||
static int EndCapture(libusb_device_handle *handle, bool do_drain_frames, int start_frames, CaptureScreensType capture_type, const is_nitro_usb_device* usb_device_desc) {
|
||||
if(usb_device_desc->is_capture)
|
||||
return StopUsbCaptureDma(handle, usb_device_desc);
|
||||
int ret = 0;
|
||||
if(do_drain_frames)
|
||||
ret = drain_frames(handle, FRAME_BUFFER_SIZE, start_frames, capture_type, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
ret = StopUsbCaptureDma(handle, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
return UpdateFrameForwardEnable(handle, false, false, usb_device_desc);
|
||||
}
|
||||
|
||||
static void frame_wait(float single_frame_time, std::chrono::time_point<std::chrono::high_resolution_clock> clock_last_reset, int curr_frame_counter, int last_frame_counter) {
|
||||
if(curr_frame_counter == 0)
|
||||
return;
|
||||
auto curr_time = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double> diff = curr_time - clock_last_reset;
|
||||
float expected_time = single_frame_time * curr_frame_counter;
|
||||
// If the current time is too low, sleep a bit to make sure we don't overrun the framerate counter
|
||||
// Don't do it regardless of the situation, and only in small increments...
|
||||
// Otherwise there is the risk of sleeping too much
|
||||
while((diff.count() < expected_time) && ((expected_time - diff.count()) > (single_frame_time / 4)) && (!(last_frame_counter & (FRAME_BUFFER_SIZE - 1)))) {
|
||||
default_sleep((expected_time - diff.count()) / 4);
|
||||
curr_time = std::chrono::high_resolution_clock::now();
|
||||
diff = curr_time - clock_last_reset;
|
||||
}
|
||||
}
|
||||
|
||||
static int reset_capture_frames(libusb_device_handle* handle, uint16_t &curr_frame_counter, uint16_t &last_frame_counter, float &single_frame_time, std::chrono::time_point<std::chrono::high_resolution_clock> &clock_last_reset, CaptureScreensType &curr_capture_type, CaptureScreensType wanted_capture_type, int multiplier, const is_nitro_usb_device* usb_device_desc) {
|
||||
curr_frame_counter += 1;
|
||||
|
||||
if(curr_frame_counter == FRAME_BUFFER_SIZE) {
|
||||
int ret = StopUsbCaptureDma(handle, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
|
||||
// If the user requests a mode change, accomodate them.
|
||||
// Though it may lag for a bit...
|
||||
if(wanted_capture_type != curr_capture_type) {
|
||||
curr_capture_type = wanted_capture_type;
|
||||
ret = set_capture_mode(handle, curr_capture_type, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint16_t internalFrameCount = 0;
|
||||
uint16_t full_internalFrameCount = 0;
|
||||
int frame_diff = 0;
|
||||
int diff_target = FRAME_BUFFER_SIZE * multiplier;
|
||||
do {
|
||||
// Check how many frames have passed...
|
||||
ret = GetFrameCounter(handle, &internalFrameCount, usb_device_desc);
|
||||
full_internalFrameCount = internalFrameCount;
|
||||
// Sometimes the upper 8 bits aren't updated... Use only the lower 8 bits.
|
||||
internalFrameCount &= 0xFF;
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
frame_diff = internalFrameCount - last_frame_counter;
|
||||
if(frame_diff < 0)
|
||||
frame_diff += 1 << 8;
|
||||
// If the frames haven't advanced, the DS is either turned off or sleeping. If so, avoid locking up
|
||||
if(frame_diff == 0)
|
||||
break;
|
||||
const auto curr_time = std::chrono::high_resolution_clock::now();
|
||||
const std::chrono::duration<double> diff = curr_time - clock_last_reset;
|
||||
// If too much time has passed, the DS is probably either turned off or sleeping. If so, avoid locking up
|
||||
if(diff.count() > (1.0 * multiplier)) {
|
||||
frame_diff = 0;
|
||||
break;
|
||||
}
|
||||
// Exit if enough frames have passed, or if there currently is some delay.
|
||||
// Exiting early makes it possible to catch up to the DMA, if we're behind.
|
||||
} while((frame_diff < diff_target) && (!(last_frame_counter & (FRAME_BUFFER_SIZE - 1))));
|
||||
// Determine how much time a single frame takes. We'll use it for sleeps
|
||||
const auto curr_time = std::chrono::high_resolution_clock::now();
|
||||
const std::chrono::duration<double> diff = curr_time - clock_last_reset;
|
||||
if(frame_diff == 0)
|
||||
single_frame_time = 0;
|
||||
else
|
||||
single_frame_time = diff.count() / (frame_diff / ((float)multiplier));
|
||||
clock_last_reset = curr_time;
|
||||
|
||||
// Save the current frame counter's 8 LSB
|
||||
last_frame_counter = internalFrameCount;
|
||||
|
||||
// If we're nearing 0xFFFF for the frame counter, reset it.
|
||||
// It's a problematic value for DMA reading
|
||||
if(frame_diff && (full_internalFrameCount >= 0xF000)) {
|
||||
ret = UpdateFrameForwardEnable(handle, true, true, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
clock_last_reset = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
ret = UpdateFrameForwardEnable(handle, true, false, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
curr_frame_counter = 0;
|
||||
|
||||
// Start the actual DMA
|
||||
if(single_frame_time > 0) {
|
||||
ret = StartUsbCaptureDma(handle, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
static void is_nitro_capture_capture_main_loop(CaptureData* capture_data) {
|
||||
libusb_device_handle *handle = (libusb_device_handle*)capture_data->handle;
|
||||
const is_nitro_usb_device* usb_device_desc = (const is_nitro_usb_device*)capture_data->status.device.descriptor;
|
||||
CaptureScreensType curr_capture_type = capture_data->status.capture_type;
|
||||
int ret = StartCaptureCapture(handle, curr_capture_type, usb_device_desc);
|
||||
if(ret < 0) {
|
||||
capture_error_print(true, capture_data, "Capture Start: Failed");
|
||||
return;
|
||||
}
|
||||
int inner_curr_in = 0;
|
||||
auto clock_start = std::chrono::high_resolution_clock::now();
|
||||
auto clock_last_reset = std::chrono::high_resolution_clock::now();
|
||||
|
||||
while(capture_data->status.connected && capture_data->status.running) {
|
||||
ret = ReadFrame(handle, (uint8_t*)&capture_data->capture_buf[inner_curr_in], _is_nitro_emulator_get_video_in_size(curr_capture_type), usb_device_desc);
|
||||
if(ret < 0) {
|
||||
capture_error_print(true, capture_data, "Disconnected: Read error");
|
||||
break;
|
||||
}
|
||||
// Output to the other threads...
|
||||
const auto curr_time = std::chrono::high_resolution_clock::now();
|
||||
const std::chrono::duration<double> diff = curr_time - clock_start;
|
||||
clock_start = curr_time;
|
||||
capture_data->time_in_buf[inner_curr_in] = diff.count();
|
||||
capture_data->read[inner_curr_in] = _is_nitro_emulator_get_video_in_size(curr_capture_type);
|
||||
capture_data->capture_type[inner_curr_in] = curr_capture_type;
|
||||
|
||||
inner_curr_in = (inner_curr_in + 1) % NUM_CONCURRENT_DATA_BUFFERS;
|
||||
if(capture_data->status.cooldown_curr_in)
|
||||
capture_data->status.cooldown_curr_in = capture_data->status.cooldown_curr_in - 1;
|
||||
capture_data->status.curr_in = inner_curr_in;
|
||||
capture_data->status.video_wait.unlock();
|
||||
capture_data->status.audio_wait.unlock();
|
||||
if(curr_capture_type != capture_data->status.capture_type) {
|
||||
ret = EndCapture(handle, true, 0, curr_capture_type, usb_device_desc);
|
||||
if(ret < 0) {
|
||||
capture_error_print(true, capture_data, "Capture End: Failed");
|
||||
return;
|
||||
}
|
||||
curr_capture_type = capture_data->status.capture_type;
|
||||
ret = StartCaptureCapture(handle, curr_capture_type, usb_device_desc);
|
||||
if(ret < 0) {
|
||||
capture_error_print(true, capture_data, "Capture Restart: Failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
EndCapture(handle, true, 0, curr_capture_type, usb_device_desc);
|
||||
}
|
||||
|
||||
static void is_nitro_emulator_capture_main_loop(CaptureData* capture_data) {
|
||||
libusb_device_handle *handle = (libusb_device_handle*)capture_data->handle;
|
||||
const is_nitro_usb_device* usb_device_desc = (const is_nitro_usb_device*)capture_data->status.device.descriptor;
|
||||
uint16_t last_frame_counter = 0;
|
||||
float single_frame_time = 0;
|
||||
uint16_t curr_frame_counter = 0;
|
||||
CaptureScreensType curr_capture_type = capture_data->status.capture_type;
|
||||
int ret = StartEmulatorCapture(handle, last_frame_counter, single_frame_time, curr_capture_type, usb_device_desc);
|
||||
if(ret < 0) {
|
||||
capture_error_print(true, capture_data, "Capture Start: Failed");
|
||||
return;
|
||||
}
|
||||
int inner_curr_in = 0;
|
||||
auto clock_start = std::chrono::high_resolution_clock::now();
|
||||
auto clock_last_reset = std::chrono::high_resolution_clock::now();
|
||||
|
||||
while(capture_data->status.connected && capture_data->status.running) {
|
||||
frame_wait(single_frame_time, clock_last_reset, curr_frame_counter, last_frame_counter);
|
||||
|
||||
if(single_frame_time > 0) {
|
||||
ret = ReadFrame(handle, (uint8_t*)&capture_data->capture_buf[inner_curr_in], _is_nitro_emulator_get_video_in_size(curr_capture_type), usb_device_desc);
|
||||
if(ret < 0) {
|
||||
capture_error_print(true, capture_data, "Disconnected: Read error");
|
||||
break;
|
||||
}
|
||||
// Output to the other threads...
|
||||
const auto curr_time = std::chrono::high_resolution_clock::now();
|
||||
const std::chrono::duration<double> diff = curr_time - clock_start;
|
||||
clock_start = curr_time;
|
||||
capture_data->time_in_buf[inner_curr_in] = diff.count();
|
||||
capture_data->read[inner_curr_in] = _is_nitro_emulator_get_video_in_size(curr_capture_type);
|
||||
capture_data->capture_type[inner_curr_in] = curr_capture_type;
|
||||
|
||||
inner_curr_in = (inner_curr_in + 1) % NUM_CONCURRENT_DATA_BUFFERS;
|
||||
if(capture_data->status.cooldown_curr_in)
|
||||
capture_data->status.cooldown_curr_in = capture_data->status.cooldown_curr_in - 1;
|
||||
capture_data->status.curr_in = inner_curr_in;
|
||||
capture_data->status.video_wait.unlock();
|
||||
capture_data->status.audio_wait.unlock();
|
||||
}
|
||||
else {
|
||||
capture_data->status.cooldown_curr_in = FIX_PARTIAL_FIRST_FRAME_NUM;
|
||||
default_sleep(20);
|
||||
}
|
||||
capture_data->status.curr_delay = last_frame_counter % FRAME_BUFFER_SIZE;
|
||||
ret = reset_capture_frames(handle, curr_frame_counter, last_frame_counter, single_frame_time, clock_last_reset, curr_capture_type, capture_data->status.capture_type, 1, usb_device_desc);
|
||||
if(ret < 0) {
|
||||
capture_error_print(true, capture_data, "Disconnected: Frame counter reset error");
|
||||
break;
|
||||
}
|
||||
}
|
||||
EndCapture(handle, true, curr_frame_counter, curr_capture_type, usb_device_desc);
|
||||
}
|
||||
|
||||
void is_nitro_capture_main_loop(CaptureData* capture_data) {
|
||||
if(!usb_is_initialized())
|
||||
return;
|
||||
if(((const is_nitro_usb_device*)(capture_data->status.device.descriptor))->is_capture)
|
||||
is_nitro_capture_capture_main_loop(capture_data);
|
||||
else
|
||||
is_nitro_emulator_capture_main_loop(capture_data);
|
||||
}
|
||||
|
||||
void usb_is_nitro_capture_cleanup(CaptureData* capture_data) {
|
||||
if(!usb_is_initialized())
|
||||
return;
|
||||
is_nitro_connection_end((libusb_device_handle*)capture_data->handle, (const is_nitro_usb_device*)capture_data->status.device.descriptor);
|
||||
}
|
||||
|
||||
void usb_is_nitro_convertVideoToOutput(CaptureReceived *p_in, VideoOutputData *p_out, CaptureScreensType capture_type) {
|
||||
if(!usb_is_initialized())
|
||||
return;
|
||||
int num_pixels = _is_nitro_emulator_get_video_in_size(capture_type) / 3;
|
||||
int out_start_pos = 0;
|
||||
int out_clear_pos = num_pixels;
|
||||
if(capture_type == CAPTURE_SCREENS_BOTTOM) {
|
||||
out_start_pos = num_pixels;
|
||||
out_clear_pos = 0;
|
||||
}
|
||||
if((capture_type == CAPTURE_SCREENS_BOTTOM) || (capture_type == CAPTURE_SCREENS_TOP))
|
||||
memset(p_out->screen_data[out_clear_pos], 0, num_pixels * 3);
|
||||
for(int i = 0; i < num_pixels; i++) {
|
||||
p_out->screen_data[i + out_start_pos][0] = p_in->is_nitro_capture_received.video_in.screen_data[i][2];
|
||||
p_out->screen_data[i + out_start_pos][1] = p_in->is_nitro_capture_received.video_in.screen_data[i][1];
|
||||
p_out->screen_data[i + out_start_pos][2] = p_in->is_nitro_capture_received.video_in.screen_data[i][0];
|
||||
}
|
||||
}
|
||||
|
||||
void usb_is_nitro_init() {
|
||||
return usb_init();
|
||||
}
|
||||
|
||||
void usb_is_nitro_close() {
|
||||
usb_close();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user