diff --git a/.gitignore b/.gitignore index 7db0cdd..c333855 100755 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ cc3dsfs cc3dsfs.exe *.conf +*.cfg +keys/ *.a *.zip ftd3xx/ @@ -13,4 +15,5 @@ build*/ .config/ out/ .vs/ -CMakeSettings.json \ No newline at end of file +CMakeSettings.json +*_icon_* diff --git a/CMakeLists.txt b/CMakeLists.txt index 670724f..0d057cd 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -357,7 +357,7 @@ if(USE_LIBUSB_SUPPORT) add_compile_flag("USE_LIBUSB") endif() if(IS_DEVICES_SUPPORT) - list(APPEND SOURCE_CPP_EXTRA_FILES ${SOURCE_CPP_IS_DEVICES_FILES_BASE_PATH}/usb_is_device_communications.cpp ${SOURCE_CPP_IS_DEVICES_FILES_BASE_PATH}/usb_is_device_acquisition.cpp ${SOURCE_CPP_IS_DEVICES_FILES_BASE_PATH}/usb_is_nitro_acquisition_capture.cpp ${SOURCE_CPP_IS_DEVICES_FILES_BASE_PATH}/usb_is_twl_acquisition_capture.cpp ${SOURCE_CPP_IS_DEVICES_FILES_BASE_PATH}/usb_is_nitro_acquisition_emulator.cpp ${SOURCE_CPP_IS_DEVICES_FILES_BASE_PATH}/usb_is_device_is_driver.cpp ${SOURCE_CPP_IS_DEVICES_FILES_BASE_PATH}/usb_is_device_libusb.cpp ${TOOLS_DATA_DIR}/is_twl_cap_crc32_table.cpp ${TOOLS_DATA_DIR}/is_twl_cap_init_seed_table.cpp) + list(APPEND SOURCE_CPP_EXTRA_FILES ${SOURCE_CPP_IS_DEVICES_FILES_BASE_PATH}/usb_is_device_communications.cpp ${SOURCE_CPP_IS_DEVICES_FILES_BASE_PATH}/usb_is_device_acquisition.cpp ${SOURCE_CPP_IS_DEVICES_FILES_BASE_PATH}/usb_is_nitro_acquisition_capture.cpp ${SOURCE_CPP_IS_DEVICES_FILES_BASE_PATH}/usb_is_twl_acquisition_capture.cpp ${SOURCE_CPP_IS_DEVICES_FILES_BASE_PATH}/usb_is_nitro_acquisition_emulator.cpp ${SOURCE_CPP_IS_DEVICES_FILES_BASE_PATH}/usb_is_device_is_driver.cpp ${SOURCE_CPP_IS_DEVICES_FILES_BASE_PATH}/usb_is_device_libusb.cpp ${TOOLS_DATA_DIR}/ccitt32_crc32_table.cpp ${TOOLS_DATA_DIR}/is_twl_cap_init_seed_table.cpp) add_compile_flag("USE_IS_DEVICES_USB") endif() if(OLD_DS_3DS_LOOPY_SUPPORT) @@ -372,7 +372,7 @@ if(CYPRESS_NISETRO_SUPPORT) add_compile_flag("USE_CYNI_USB") endif() if(OPTIMIZE_3DS_SUPPORT) - list(APPEND SOURCE_CPP_EXTRA_FILES ${SOURCE_CPP_CYPRESS_OPTIMIZE_3DS_FILES_BASE_PATH}/cypress_optimize_3ds_communications.cpp ${SOURCE_CPP_CYPRESS_OPTIMIZE_3DS_FILES_BASE_PATH}/cypress_optimize_3ds_acquisition.cpp ${TOOLS_DATA_DIR}/optimize_new_3ds_fw.cpp ${TOOLS_DATA_DIR}/optimize_new_3ds_565_fpga_pl.cpp ${TOOLS_DATA_DIR}/optimize_new_3ds_888_fpga_pl.cpp ${TOOLS_DATA_DIR}/optimize_old_3ds_fw.cpp ${TOOLS_DATA_DIR}/optimize_old_3ds_565_fpga_pl.cpp ${TOOLS_DATA_DIR}/optimize_old_3ds_888_fpga_pl.cpp) + list(APPEND SOURCE_CPP_EXTRA_FILES ${SOURCE_CPP_CYPRESS_OPTIMIZE_3DS_FILES_BASE_PATH}/cypress_optimize_3ds_communications.cpp ${SOURCE_CPP_CYPRESS_OPTIMIZE_3DS_FILES_BASE_PATH}/cypress_optimize_3ds_acquisition.cpp ${TOOLS_DATA_DIR}/optimize_new_3ds_fw.cpp ${TOOLS_DATA_DIR}/optimize_new_3ds_565_fpga_pl.cpp ${TOOLS_DATA_DIR}/optimize_new_3ds_888_fpga_pl.cpp ${TOOLS_DATA_DIR}/optimize_old_3ds_fw.cpp ${TOOLS_DATA_DIR}/optimize_old_3ds_565_fpga_pl.cpp ${TOOLS_DATA_DIR}/optimize_old_3ds_888_fpga_pl.cpp ${TOOLS_DATA_DIR}/adler_crc32_table_sp.cpp ${TOOLS_DATA_DIR}/optimize_key_to_byte_table.cpp) add_compile_flag("USE_CYPRESS_OPTIMIZE") endif() if(NEW_DS_LOOPY_SUPPORT) @@ -578,10 +578,17 @@ add_custom_command( ) add_custom_command( - OUTPUT ${TOOLS_DATA_DIR}/is_twl_cap_crc32_table.cpp - COMMENT "Convert binary to C - IS TWL CRC32 table" - COMMAND ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION} ${CMAKE_SOURCE_DIR}/bin/is_twl_cap_crc32_table.bin ${TOOLS_DATA_DIR} is_twl_cap_crc32_table is_twl_cap_crc32_table - DEPENDS ${CMAKE_SOURCE_DIR}/bin/is_twl_cap_crc32_table.bin ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION} + OUTPUT ${TOOLS_DATA_DIR}/adler_crc32_table_sp.cpp + COMMENT "Convert binary to C - Adler CRC32 Special table" + COMMAND ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION} ${CMAKE_SOURCE_DIR}/bin/adler_crc32_table_sp.bin ${TOOLS_DATA_DIR} adler_crc32_table_sp adler_crc32_table_sp + DEPENDS ${CMAKE_SOURCE_DIR}/bin/adler_crc32_table_sp.bin ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION} +) + +add_custom_command( + OUTPUT ${TOOLS_DATA_DIR}/ccitt32_crc32_table.cpp + COMMENT "Convert binary to C - CCITT32 CRC32 table" + COMMAND ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION} ${CMAKE_SOURCE_DIR}/bin/ccitt32_crc32_table.bin ${TOOLS_DATA_DIR} ccitt32_crc32_table ccitt32_crc32_table + DEPENDS ${CMAKE_SOURCE_DIR}/bin/ccitt32_crc32_table.bin ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION} ) add_custom_command( @@ -647,6 +654,13 @@ add_custom_command( DEPENDS ${CMAKE_SOURCE_DIR}/bin/optimize_old_3ds_888_fpga_pl.bin ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION} ) +add_custom_command( + OUTPUT ${TOOLS_DATA_DIR}/optimize_key_to_byte_table.cpp + COMMENT "Convert table to C - Optimize Key to 5 bits" + COMMAND ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION} ${CMAKE_SOURCE_DIR}/bin/optimize_key_to_byte_table.bin ${TOOLS_DATA_DIR} optimize_key_to_byte_table optimize_key_to_byte_table + DEPENDS ${CMAKE_SOURCE_DIR}/bin/optimize_key_to_byte_table.bin ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION} +) + set(SHADERS_LIST "") list(APPEND SHADERS_LIST ${CMAKE_SOURCE_DIR}/shaders/bit_crusher_fragment_shader.2_to_x_1_7.frag ${CMAKE_SOURCE_DIR}/shaders/bit_merger_crusher_fragment_shader.2_to_x_1_6.frag ${CMAKE_SOURCE_DIR}/shaders/bit_merger_crusher_fragment_shader_7.frag ${CMAKE_SOURCE_DIR}/shaders/bit_merger_fragment_shader.2_to_x_0_6.frag ${CMAKE_SOURCE_DIR}/shaders/bit_merger_fragment_shader_7.frag ${CMAKE_SOURCE_DIR}/shaders/frame_blending_bit_crusher_fragment_shader.2_to_x_1_7.frag ${CMAKE_SOURCE_DIR}/shaders/frame_blending_fragment_shader.frag ${CMAKE_SOURCE_DIR}/shaders/no_effect_fragment_shader.frag ${CMAKE_SOURCE_DIR}/shaders/color_emulation_fragment_shader.frag) diff --git a/README.md b/README.md index b6cd8cb..7a802f0 100755 --- a/README.md +++ b/README.md @@ -152,3 +152,5 @@ On Windows, the profiles can be found in the ".config/cc3dsfs" folder inside the - When using IS Nitro Emulator, IS Nitro Capture or IS TWL Capture devices on Windows, cc3dsfs is compatible with both the official driver and WinUSB, with the latter being useful if you don't have access to the official driver. To install and use WinUSB, plug in your device, download a software to install drivers like [Zadig](https://zadig.akeo.ie/), select the device in question and select WinUSB. Then install the driver and wait for it to finish. The devices should now work properly with this application. - When using the new 2024 Loopy DS Capture Card on Windows, the default driver (FTD2XX) adds one extra frame of latency. To remove that, consider switching to WinUSB as the driver. To change driver, download a software to install drivers like [Zadig](https://zadig.akeo.ie/), select the device in question and select WinUSB. Then install the driver and wait for it to finish. The application will now use WinUSB, with better latency (the serial shown in the Status menu will have an l where there previously was a d). - There are multiple capture cards which use the same EZ-USB FX2LP board, creating a conflict. This means that when the user connects a device which uses the EZ-USB FX2LP board, they need to select one capture card among the possible ones. To avoid this extra step, the user can disable scanning for the conflicting capture cards they do not intend to use. The settings to do this are available under Extra Settings -> USB Conflict Resolution. +- MacOS does not allow running multiple instances of the same application, normally. If you want to run multiple instances of cc3dsfs on MacOS, open the terminal in the folder where cc3dsfs is and type `open -n cc3dsfs.app`. +- The CC3DSFS\_CFG\_DIR environment variable can be used to specify where cc3dsfs will store its data. diff --git a/bin/adler_crc32_table_sp.bin b/bin/adler_crc32_table_sp.bin new file mode 100644 index 0000000..e78af77 Binary files /dev/null and b/bin/adler_crc32_table_sp.bin differ diff --git a/bin/is_twl_cap_crc32_table.bin b/bin/ccitt32_crc32_table.bin similarity index 100% rename from bin/is_twl_cap_crc32_table.bin rename to bin/ccitt32_crc32_table.bin diff --git a/bin/optimize_key_to_byte_table.bin b/bin/optimize_key_to_byte_table.bin new file mode 100644 index 0000000..a7f0672 Binary files /dev/null and b/bin/optimize_key_to_byte_table.bin differ diff --git a/include/CaptureDeviceSpecific/Optimize_3DS/cypress_optimize_3ds_acquisition.hpp b/include/CaptureDeviceSpecific/Optimize_3DS/cypress_optimize_3ds_acquisition.hpp index 845f62f..27ba5fe 100644 --- a/include/CaptureDeviceSpecific/Optimize_3DS/cypress_optimize_3ds_acquisition.hpp +++ b/include/CaptureDeviceSpecific/Optimize_3DS/cypress_optimize_3ds_acquisition.hpp @@ -17,6 +17,7 @@ void usb_cyop_device_acquisition_cleanup(CaptureData* capture_data); bool is_device_optimize_3ds(CaptureDevice* device); bool is_device_optimize_o3ds(CaptureDevice* device); bool is_device_optimize_n3ds(CaptureDevice* device); +bool cyop_is_key_for_device_id(CaptureDevice* device, std::string key); void usb_cyop_device_init(); void usb_cyop_device_close(); diff --git a/include/CaptureDeviceSpecific/Optimize_3DS/cypress_optimize_3ds_communications.hpp b/include/CaptureDeviceSpecific/Optimize_3DS/cypress_optimize_3ds_communications.hpp index 875784b..ce573b0 100644 --- a/include/CaptureDeviceSpecific/Optimize_3DS/cypress_optimize_3ds_communications.hpp +++ b/include/CaptureDeviceSpecific/Optimize_3DS/cypress_optimize_3ds_communications.hpp @@ -40,10 +40,14 @@ const cyop_device_usb_device* GetNextDeviceDesc(const cyop_device_usb_device* de const cy_device_usb_device* get_cy_usb_info(const cyop_device_usb_device* usb_device_desc); bool has_to_load_firmware(const cyop_device_usb_device* device); bool load_firmware(cy_device_device_handlers* handlers, const cyop_device_usb_device* device, uint8_t patch_id); -int capture_start(cy_device_device_handlers* handlers, const cyop_device_usb_device* device, bool is_first_load, bool is_rgb888); -int StartCaptureDma(cy_device_device_handlers* handlers, const cyop_device_usb_device* device, bool is_rgb888, bool is_3d); +int capture_start(cy_device_device_handlers* handlers, const cyop_device_usb_device* device, bool is_first_load, bool is_rgb888, uint64_t &device_id, std::string &read_key); +int StartCaptureDma(cy_device_device_handlers* handlers, const cyop_device_usb_device* device, bool is_rgb888, bool is_3d, std::string key); int capture_end(cy_device_device_handlers* handlers, const cyop_device_usb_device* device); int ReadFrame(cy_device_device_handlers* handlers, uint8_t* buf, int length, const cyop_device_usb_device* device_desc); int ReadFrameAsync(cy_device_device_handlers* handlers, uint8_t* buf, int length, const cyop_device_usb_device* device_desc, cy_async_callback_data* cb_data); +bool check_key_matches_device_id(uint64_t device_id, std::string key, bool is_new_device); +bool check_key_matches_device_id(uint64_t device_id, std::string key, const cyop_device_usb_device* device); +bool check_key_valid(std::string key, bool is_new_device); +bool check_key_valid(std::string key, const cyop_device_usb_device* device); #endif diff --git a/include/capture_structs.hpp b/include/capture_structs.hpp index 7f45c20..79ee1ad 100755 --- a/include/capture_structs.hpp +++ b/include/capture_structs.hpp @@ -288,9 +288,11 @@ struct CaptureDevice { std::string name = ""; std::string long_name = ""; std::string path = ""; + std::string key = ""; CaptureConnectionType cc_type = CAPTURE_CONN_USB; InputVideoDataType video_data_type = VIDEO_DATA_RGB; const void* descriptor = NULL; + uint64_t device_id = 0; // Different from serial_number... bool is_3ds = false; bool has_3d = false; bool has_audio = false; @@ -316,7 +318,8 @@ struct CaptureStatus { CaptureDevice device; std::string graphical_error_text; std::string detailed_error_text; - bool new_error_text; + bool new_error_text = false; + int title_check_id = 0; volatile int cooldown_curr_in = FIX_PARTIAL_FIRST_FRAME_NUM; volatile bool connected = false; volatile bool running = true; diff --git a/include/devicecapture.hpp b/include/devicecapture.hpp index 758f7d3..df7f42c 100755 --- a/include/devicecapture.hpp +++ b/include/devicecapture.hpp @@ -21,9 +21,12 @@ bool connect(bool print_failed, CaptureData* capture_data, FrontendData* fronten void captureCall(CaptureData* capture_data); void capture_error_print(bool print_failed, CaptureData* capture_data, std::string error_string); void capture_error_print(bool print_failed, CaptureData* capture_data, std::string graphical_string, std::string detailed_string); +void capture_warning_print(CaptureData* capture_data, std::string warning_string); +void capture_warning_print(CaptureData* capture_data, std::string graphical_string, std::string detailed_string); uint64_t get_audio_n_samples(CaptureData* capture_data, CaptureDataSingleBuffer* data_buffer); uint64_t get_video_in_size(CaptureData* capture_data, bool is_3d, InputVideoDataType video_data_type); -std::string get_name_of_device(CaptureStatus* capture_status, bool use_long = false); +std::string get_device_id_string(CaptureStatus* capture_status); +std::string get_name_of_device(CaptureStatus* capture_status, bool use_long = false, bool want_real_serial = false); int get_usb_speed_of_device(CaptureStatus* capture_status); bool get_device_can_do_3d(CaptureStatus* capture_status); bool get_device_3d_implemented(CaptureStatus* capture_status); diff --git a/include/frontend.hpp b/include/frontend.hpp index d23ea5c..ad09a57 100755 --- a/include/frontend.hpp +++ b/include/frontend.hpp @@ -67,7 +67,7 @@ class WindowScreen { public: ScreenInfo m_info; - WindowScreen(ScreenType stype, CaptureStatus* capture_status, DisplayData* display_data, SharedData* shared_data, AudioData* audio_data, ConsumerMutex *draw_lock, bool created_proper_folder, bool disable_frame_blending); + WindowScreen(ScreenType stype, CaptureStatus* capture_status, DisplayData* display_data, SharedData* shared_data, AudioData* audio_data, ConsumerMutex *draw_lock, bool disable_frame_blending); ~WindowScreen(); void build(); @@ -122,7 +122,6 @@ private: InputVideoDataType curr_video_data_type; InputVideoDataType last_update_texture_data_type; PossibleSoftwareConvTypes texture_software_based_conv; - bool created_proper_folder; CaptureStatus* capture_status; std::string win_title; sf::RenderWindow m_win; @@ -135,6 +134,7 @@ private: int m_prepare_load; int m_prepare_save; bool last_connected_status; + int last_title_check_id; bool last_enabled_3d; bool last_interleaved_3d; bool m_prepare_open; diff --git a/include/utils.hpp b/include/utils.hpp index 6bed4bd..e1ebe5f 100755 --- a/include/utils.hpp +++ b/include/utils.hpp @@ -55,11 +55,14 @@ ANativeActivity* getAndroidNativeActivity(); std::string get_version_string(bool get_letter = true); void ActualConsoleOutTextError(std::string out_string); void ActualConsoleOutText(std::string out_string); +std::string get_base_path(bool for_presets, bool do_existence_check=true); +std::string get_base_path_keys(); std::string LayoutNameGenerator(int index); -std::string LayoutPathGenerator(int index, bool created_proper_folder); -std::string load_layout_name(int index, bool created_proper_folder, bool &success); +std::string LayoutPathGenerator(int index); +std::string load_layout_name(int index, bool &success); uint32_t reverse_endianness(uint32_t value); uint16_t reverse_endianness(uint16_t value); +uint8_t reverse_u8(uint8_t data); bool is_big_endian(void); uint32_t to_le(uint32_t value); uint16_t to_le(uint16_t value); @@ -89,6 +92,9 @@ void init_start_time(); uint32_t ms_since_start(); std::string to_hex_u8(const uint8_t value); std::string to_hex_u16(uint16_t value); +std::string to_hex_u32(const uint32_t value); +std::string to_hex_u60(const uint64_t value); +std::string to_hex_u64(const uint64_t value); std::string get_float_str_decimals(float value, int decimals); void init_threads(void); void complete_threads(void); diff --git a/source/CaptureDeviceSpecific/ISDevices/usb_is_device_communications.cpp b/source/CaptureDeviceSpecific/ISDevices/usb_is_device_communications.cpp index b3d91b7..060bfe7 100644 --- a/source/CaptureDeviceSpecific/ISDevices/usb_is_device_communications.cpp +++ b/source/CaptureDeviceSpecific/ISDevices/usb_is_device_communications.cpp @@ -3,7 +3,8 @@ #include "usb_is_device_libusb.hpp" #include "usb_is_device_is_driver.hpp" #include "is_twl_cap_init_seed_table.h" -#include "is_twl_cap_crc32_table.h" +// From web.mit.edu/wwwdev/src/harvest-1.3.pl3/components/gatherer/standard/unbinhex/crc/ccitt32.c +#include "ccitt32_crc32_table.h" #include "usb_generic.hpp" #include @@ -278,7 +279,7 @@ static uint32_t get_crc32_data_comm(uint8_t* data, size_t size) { for(size_t i = 0; i < size; i++) { uint8_t inner_value = (value >> 24) ^ data[i]; value <<= 8; - value ^= read_le32(is_twl_cap_crc32_table, inner_value); + value ^= read_le32(ccitt32_crc32_table, inner_value); } return ~value; } diff --git a/source/CaptureDeviceSpecific/Nisetro/cypress_nisetro_acquisition.cpp b/source/CaptureDeviceSpecific/Nisetro/cypress_nisetro_acquisition.cpp index fe9e7a5..98d0abb 100644 --- a/source/CaptureDeviceSpecific/Nisetro/cypress_nisetro_acquisition.cpp +++ b/source/CaptureDeviceSpecific/Nisetro/cypress_nisetro_acquisition.cpp @@ -95,7 +95,11 @@ static std::string _cypress_nisetro_get_serial(const cyni_device_usb_device* usb std::string cypress_nisetro_get_serial(const void* usb_device_desc, std::string serial, uint16_t bcd_device, int& curr_serial_extra_id) { if(usb_device_desc == NULL) return ""; - return _cypress_nisetro_get_serial((const cyni_device_usb_device*)usb_device_desc, serial, bcd_device, curr_serial_extra_id); + const cyni_device_usb_device* in_usb_device_desc = (const cyni_device_usb_device*)usb_device_desc; + std::string preamble = ""; + if(in_usb_device_desc->has_bcd_device_serial) + preamble = "USB "; + return preamble + _cypress_nisetro_get_serial(in_usb_device_desc, serial, bcd_device, curr_serial_extra_id); } static CaptureDevice _cypress_nisetro_create_device(const cyni_device_usb_device* usb_device_desc, std::string serial, std::string path) { diff --git a/source/CaptureDeviceSpecific/Nisetro/cypress_nisetro_communications.cpp b/source/CaptureDeviceSpecific/Nisetro/cypress_nisetro_communications.cpp index c920b5d..566a85a 100644 --- a/source/CaptureDeviceSpecific/Nisetro/cypress_nisetro_communications.cpp +++ b/source/CaptureDeviceSpecific/Nisetro/cypress_nisetro_communications.cpp @@ -33,7 +33,7 @@ #define NISETRO_DS_WANTED_VALUE_BASE 0xFF00 static const cyni_device_usb_device cypress_fx2_generic_device = { -.name = "FX2LP -> NiseTro DS", .long_name = "EZ-USB FX2LP ->NiseTro DS(i)", +.name = "FX2LP -> NiseTro DS", .long_name = "EZ-USB FX2LP -> NiseTro DS(i)", .device_type = CYPRESS_NISETRO_BLANK_DEVICE, .video_data_type = VIDEO_DATA_RGB, .firmware_to_load = nisetro_ds_fw, .firmware_size = nisetro_ds_fw_len, diff --git a/source/CaptureDeviceSpecific/Optimize_3DS/cypress_optimize_3ds_acquisition.cpp b/source/CaptureDeviceSpecific/Optimize_3DS/cypress_optimize_3ds_acquisition.cpp index 9a87cfc..7417a54 100644 --- a/source/CaptureDeviceSpecific/Optimize_3DS/cypress_optimize_3ds_acquisition.cpp +++ b/source/CaptureDeviceSpecific/Optimize_3DS/cypress_optimize_3ds_acquisition.cpp @@ -26,6 +26,7 @@ #define NUM_TOTAL_OPTIMIZE_3DS_CYPRESS_BUFFERS (3 * NUM_OPTIMIZE_3DS_CYPRESS_CONCURRENTLY_RUNNING_BUFFERS) #define MAX_TIME_WAIT 1.0 +#define CAPTURE_START_AGAIN_NO_KEY_TIME 260.0 #define OPTIMIZE_3DS_CYPRESS_USB_WINDOWS_DRIVER CYPRESS_WINDOWS_OPTIMIZE_USB_DRIVER @@ -59,6 +60,8 @@ struct CypressOptimize3DSDeviceCaptureReceivedData { static void cypress_device_read_frame_cb(void* user_data, int transfer_length, int transfer_status); static int get_cypress_device_status(CypressOptimize3DSDeviceCaptureReceivedData* cypress_device_capture_recv_data); static void error_cypress_device_status(CypressOptimize3DSDeviceCaptureReceivedData* cypress_device_capture_recv_data, int error_val); +static std::string read_key_for_device_id_from_file(uint64_t device_id, const cyop_device_usb_device* usb_device_desc); +static void add_key_for_device_id_to_file(uint64_t device_id, std::string key, const cyop_device_usb_device* usb_device_desc); static cy_device_device_handlers* usb_find_by_serial_number(const cyop_device_usb_device* usb_device_desc, std::string wanted_serial_number, CaptureDevice* new_device) { cy_device_device_handlers* final_handlers = NULL; @@ -106,7 +109,11 @@ static std::string _cypress_optimize_3ds_get_serial(const cyop_device_usb_device std::string cypress_optimize_3ds_get_serial(const void* usb_device_desc, std::string serial, uint16_t bcd_device, int& curr_serial_extra_id) { if(usb_device_desc == NULL) return ""; - return _cypress_optimize_3ds_get_serial((const cyop_device_usb_device*)usb_device_desc, serial, bcd_device, curr_serial_extra_id); + const cyop_device_usb_device* in_usb_device_desc = (const cyop_device_usb_device*)usb_device_desc; + std::string preamble = ""; + if(in_usb_device_desc->has_bcd_device_serial) + preamble = "USB "; + return preamble + _cypress_optimize_3ds_get_serial(in_usb_device_desc, serial, bcd_device, curr_serial_extra_id); } static CaptureDevice _cypress_optimize_3ds_create_device(const cyop_device_usb_device* usb_device_desc, std::string serial, std::string path) { @@ -261,6 +268,12 @@ static InputVideoDataType extract_wanted_input_video_data_type(CaptureData* capt return extract_wanted_input_video_data_type(&capture_data->status); } +static bool key_missing_capture_start_again_check_time(const std::chrono::time_point &start_time) { + const auto curr_time = std::chrono::high_resolution_clock::now(); + const std::chrono::duration diff = curr_time - start_time; + return diff.count() > CAPTURE_START_AGAIN_NO_KEY_TIME; +} + static int cypress_device_read_frame_request(CaptureData* capture_data, CypressOptimize3DSDeviceCaptureReceivedData* cypress_device_capture_recv_data, uint32_t index, bool is_3d, InputVideoDataType video_data_type) { if(cypress_device_capture_recv_data == NULL) return LIBUSB_SUCCESS; @@ -651,7 +664,7 @@ static void reset_buffer_processing_data(CypressOptimize3DSDeviceCaptureReceived } } -static int restart_captures_cc_reads(CaptureData* capture_data, CypressOptimize3DSDeviceCaptureReceivedData* cypress_device_capture_recv_data, uint32_t &index, InputVideoDataType &stored_video_data_type, bool &stored_is_3d, bool could_use_3d) { +static int restart_captures_cc_reads(CaptureData* capture_data, CypressOptimize3DSDeviceCaptureReceivedData* cypress_device_capture_recv_data, uint32_t &index, InputVideoDataType &stored_video_data_type, bool &stored_is_3d, bool could_use_3d, bool force_capture_start, std::string read_key, std::chrono::time_point &clock_last_capture_start) { cy_device_device_handlers* handlers = (cy_device_device_handlers*)capture_data->handle; const cyop_device_usb_device* usb_device_desc = (const cyop_device_usb_device*)capture_data->status.device.descriptor; int retval = end_capture_from_capture_data(capture_data); @@ -662,10 +675,13 @@ static int restart_captures_cc_reads(CaptureData* capture_data, CypressOptimize3 InputVideoDataType wanted_input_video_data_type = extract_wanted_input_video_data_type(capture_data); bool set_max_again = false; - if(wanted_input_video_data_type != stored_video_data_type) { + if((wanted_input_video_data_type != stored_video_data_type) || force_capture_start){ set_max_again = true; stored_video_data_type = wanted_input_video_data_type; - retval = capture_start(handlers, usb_device_desc, true, stored_video_data_type == OPTIMIZE_RGB888_FORMAT); + uint64_t device_id_dummy; + std::string read_key_dummy; + retval = capture_start(handlers, usb_device_desc, true, stored_video_data_type == OPTIMIZE_RGB888_FORMAT, device_id_dummy, read_key_dummy); + clock_last_capture_start = std::chrono::high_resolution_clock::now(); capture_data->status.device.video_data_type = stored_video_data_type; if(retval < 0) return retval; @@ -686,15 +702,33 @@ static int restart_captures_cc_reads(CaptureData* capture_data, CypressOptimize3 if(!schedule_all_reads(capture_data, cypress_device_capture_recv_data, index, stored_video_data_type, stored_is_3d, "")) return -1; capture_data->status.cooldown_curr_in = FIX_PARTIAL_FIRST_FRAME_NUM; - StartCaptureDma(handlers, usb_device_desc, stored_video_data_type == OPTIMIZE_RGB888_FORMAT, stored_is_3d); + StartCaptureDma(handlers, usb_device_desc, stored_video_data_type == OPTIMIZE_RGB888_FORMAT, stored_is_3d, read_key); return 0; } +static void cyop_key_missing_warning_message(CaptureData* capture_data) { + capture_warning_print(capture_data, "Key missing!\nClose to Timeout!\nReconfigured FPGA!", "Key missing! Close to Timeout! Reconfigured FPGA!"); +} + static bool cyop_device_acquisition_loop(CaptureData* capture_data, CypressOptimize3DSDeviceCaptureReceivedData* cypress_device_capture_recv_data, InputVideoDataType &stored_video_data_type, bool &stored_is_3d, bool could_use_3d) { cy_device_device_handlers* handlers = (cy_device_device_handlers*)capture_data->handle; const cyop_device_usb_device* usb_device_desc = (const cyop_device_usb_device*)capture_data->status.device.descriptor; uint32_t index = 0; - int ret = capture_start(handlers, usb_device_desc, true, stored_video_data_type == OPTIMIZE_RGB888_FORMAT); + uint64_t device_id = 0; + std::string read_key = ""; + bool force_capture_start_key = false; + int ret = capture_start(handlers, usb_device_desc, true, stored_video_data_type == OPTIMIZE_RGB888_FORMAT, device_id, read_key); + capture_data->status.title_check_id += 1; + std::chrono::time_point clock_last_capture_start = std::chrono::high_resolution_clock::now(); + bool is_key_valid = check_key_matches_device_id(device_id, read_key, usb_device_desc); + + if(is_key_valid) + add_key_for_device_id_to_file(device_id, read_key, usb_device_desc); + else + read_key = read_key_for_device_id_from_file(device_id, usb_device_desc); + + capture_data->status.device.device_id = device_id; + capture_data->status.device.key = read_key; capture_data->status.device.video_data_type = stored_video_data_type; if (ret < 0) { capture_error_print(true, capture_data, "Capture Start: Failed"); @@ -704,7 +738,7 @@ static bool cyop_device_acquisition_loop(CaptureData* capture_data, CypressOptim if(!schedule_all_reads(capture_data, cypress_device_capture_recv_data, index, stored_video_data_type, stored_is_3d, "Initial Reads: Failed")) return false; - StartCaptureDma(handlers, usb_device_desc, stored_video_data_type == OPTIMIZE_RGB888_FORMAT, stored_is_3d); + StartCaptureDma(handlers, usb_device_desc, stored_video_data_type == OPTIMIZE_RGB888_FORMAT, stored_is_3d, read_key); while (capture_data->status.connected && capture_data->status.running) { ret = get_cypress_device_status(cypress_device_capture_recv_data); if(ret < 0) { @@ -713,9 +747,13 @@ static bool cyop_device_acquisition_loop(CaptureData* capture_data, CypressOptim wait_all_cypress_device_buffers_free(capture_data, cypress_device_capture_recv_data); bool has_recovered = false; if(cause_error == LIBUSB_ERROR_TIMEOUT) { - int timeout_ret = restart_captures_cc_reads(capture_data, cypress_device_capture_recv_data, index, stored_video_data_type, stored_is_3d, could_use_3d); - if(timeout_ret >= 0) + force_capture_start_key = (!check_key_matches_device_id(device_id, read_key, usb_device_desc)) && key_missing_capture_start_again_check_time(clock_last_capture_start); + int timeout_ret = restart_captures_cc_reads(capture_data, cypress_device_capture_recv_data, index, stored_video_data_type, stored_is_3d, could_use_3d, force_capture_start_key, read_key, clock_last_capture_start); + if(timeout_ret >= 0) { has_recovered = true; + if(force_capture_start_key) + cyop_key_missing_warning_message(capture_data); + } } if(!has_recovered) { capture_error_print(true, capture_data, "Disconnected: Read error"); @@ -724,14 +762,17 @@ static bool cyop_device_acquisition_loop(CaptureData* capture_data, CypressOptim } bool is_new_3d = could_use_3d && get_3d_enabled(&capture_data->status); InputVideoDataType wanted_input_video_data_type = extract_wanted_input_video_data_type(capture_data); - if((wanted_input_video_data_type != stored_video_data_type) || (is_new_3d != stored_is_3d)) { + force_capture_start_key = (!check_key_matches_device_id(device_id, read_key, usb_device_desc)) && key_missing_capture_start_again_check_time(clock_last_capture_start); + if((wanted_input_video_data_type != stored_video_data_type) || (is_new_3d != stored_is_3d) || force_capture_start_key) { capture_data->status.cooldown_curr_in = FIX_PARTIAL_FIRST_FRAME_NUM + NUM_OPTIMIZE_3DS_CYPRESS_CONCURRENTLY_RUNNING_BUFFERS; wait_all_cypress_device_buffers_free(capture_data, cypress_device_capture_recv_data); - ret = restart_captures_cc_reads(capture_data, cypress_device_capture_recv_data, index, stored_video_data_type, stored_is_3d, could_use_3d); + ret = restart_captures_cc_reads(capture_data, cypress_device_capture_recv_data, index, stored_video_data_type, stored_is_3d, could_use_3d, force_capture_start_key, read_key, clock_last_capture_start); if(ret < 0) { capture_error_print(true, capture_data, "Disconnected: Update mode error"); return false; } + if(force_capture_start_key) + cyop_key_missing_warning_message(capture_data); } if(!get_buffer_and_schedule_read(capture_data, cypress_device_capture_recv_data, index, stored_video_data_type, stored_is_3d, "Setup Read: Failed")) return false; @@ -825,6 +866,65 @@ void usb_cyop_device_acquisition_cleanup(CaptureData* capture_data) { cypress_optimize_3ds_connection_end((cy_device_device_handlers*)capture_data->handle, (const cyop_device_usb_device*)capture_data->status.device.descriptor); capture_data->handle = NULL; } + +bool cyop_is_key_for_device(CaptureDevice* device, std::string key) { + return check_key_matches_device_id(device->device_id, key, (const cyop_device_usb_device*)device->descriptor); +} + +static std::string get_keys_file_path(const cyop_device_usb_device* usb_device_desc) { + std::string path = get_base_path_keys(); + + if(usb_device_desc->is_new_device) + path += "optimize_new_3ds.txt"; + else + path += "optimize_old_3ds.txt"; + return path; +} + +static std::string read_key_for_device_id_from_file(uint64_t device_id, const cyop_device_usb_device* usb_device_desc) { + if(usb_device_desc == NULL) + return ""; + + std::ifstream file(get_keys_file_path(usb_device_desc)); + std::string line; + std::string out_key = ""; + + if((!file) || (!file.is_open()) || (!file.good())) + return out_key; + + try { + while(std::getline(file, line)) { + std::istringstream kvp(line); + std::string value; + if(!std::getline(kvp, value)) + continue; + if(check_key_matches_device_id(device_id, value, usb_device_desc)) { + out_key = value; + break; + } + } + } + catch(...) { + out_key = ""; + } + + file.close(); + return out_key; +} + +static void add_key_for_device_id_to_file(uint64_t device_id, std::string key, const cyop_device_usb_device* usb_device_desc) { + if(usb_device_desc == NULL) + return; + if(key == "") + return; + if(read_key_for_device_id_from_file(device_id, usb_device_desc) == key) + return; + + std::ofstream file(get_keys_file_path(usb_device_desc), std::ios_base::app | std::ios_base::out); + file << key << std::endl; + file.close(); +} + void usb_cyop_device_init() { return usb_init(); } diff --git a/source/CaptureDeviceSpecific/Optimize_3DS/cypress_optimize_3ds_communications.cpp b/source/CaptureDeviceSpecific/Optimize_3DS/cypress_optimize_3ds_communications.cpp index c4be0f8..b842cda 100644 --- a/source/CaptureDeviceSpecific/Optimize_3DS/cypress_optimize_3ds_communications.cpp +++ b/source/CaptureDeviceSpecific/Optimize_3DS/cypress_optimize_3ds_communications.cpp @@ -12,11 +12,18 @@ #include "optimize_old_3ds_565_fpga_pl.h" #include "optimize_old_3ds_888_fpga_pl.h" +#include "optimize_key_to_byte_table.h" + +// CRC32 table is a slightly edited crc32-adler. +// First entry all FFs instead of 00s. +#include "adler_crc32_table_sp.h" + #include #include #include #include #include +#include // This code was developed by exclusively looking at Wireshark USB packet // captures to learn the USB device's protocol. @@ -32,14 +39,23 @@ #define OPTIMIZE_NEW_3DS_WANTED_VALUE_BASE 0xFE00 #define OPTIMIZE_OLD_3DS_WANTED_VALUE_BASE 0xFD00 -const uint8_t start_capture_third_buffer_565_new[] = { 0x61, 0x07, 0x00, 0x0F, 0x00, 0x3E, 0x00, 0xF8, 0x00, 0x38, 0x00, 0x51, 0x80, 0x5C, 0x01, 0x00 }; -const uint8_t start_capture_third_buffer_565_3d_new[] = { 0x61, 0x07, 0x00, 0x0F, 0x00, 0x3E, 0x00, 0xF8, 0x00, 0x3C, 0x00, 0x51, 0x80, 0x5C, 0x01, 0x00 }; -const uint8_t start_capture_third_buffer_888_new[] = { 0x61, 0x07, 0x00, 0xA6, 0x00, 0x28, 0x00, 0x62, 0x00, 0x3A, 0x00, 0x51, 0x80, 0x5C, 0x01, 0x00 }; -const uint8_t start_capture_third_buffer_888_3d_new[] = { 0x61, 0x07, 0x00, 0xA6, 0x00, 0x28, 0x00, 0x62, 0x00, 0x16, 0x00, 0x51, 0x80, 0x5C, 0x01, 0x00 }; -const uint8_t start_capture_third_buffer_565_old[] = { 0x61, 0x07, 0x00, 0x26, 0x00, 0x22, 0x00, 0x98, 0x00, 0x08, 0x00, 0xDE, 0x00, 0xF9, 0x18, 0x0F }; -const uint8_t start_capture_third_buffer_565_3d_old[] = { 0x61, 0x07, 0x00, 0x26, 0x00, 0x22, 0x00, 0x98, 0x00, 0x08, 0x00, 0xDF, 0x00, 0xF9, 0x18, 0x0F }; -const uint8_t start_capture_third_buffer_888_old[] = { 0x61, 0x07, 0x00, 0xA6, 0x00, 0x20, 0x00, 0x98, 0x00, 0x08, 0x00, 0xDE, 0x00, 0xF9, 0x18, 0x0F }; -const uint8_t start_capture_third_buffer_888_3d_old[] = { 0x61, 0x07, 0x00, 0xA6, 0x00, 0x20, 0x00, 0x98, 0x00, 0x08, 0x00, 0xD5, 0x00, 0xF9, 0x18, 0x0F }; +#define OPTIMIZE_NUM_KEY_CHARS 20 +#define OPTIMIZE_NUM_KEY_CHARS_WITH_DASHES (OPTIMIZE_NUM_KEY_CHARS + 4) +#define OPTIMIZE_NUM_KEY_BYTES 12 + +#define OPTIMIZE_EEPROM_NEW_SIZE 0x80 +#define OPTIMIZE_EEPROM_STRUCT_SIZE 0x79 + +const size_t key_bytes_to_serial_bytes_map[OPTIMIZE_NUM_KEY_BYTES] = {0, 7, 8, 9, 1, 4, 6, 3, 10, 2, 11, 5}; + +const uint8_t start_capture_setup_key_buffer_565_new[] = { 0x61, 0x07, 0x00, 0x0F, 0x00, 0x3E, 0x00, 0xF8, 0x00, 0x38, 0x00, 0x00, 0x80, 0x00, 0x01, 0x00 }; +const uint8_t start_capture_setup_key_buffer_565_3d_new[] = { 0x61, 0x07, 0x00, 0x0F, 0x00, 0x3E, 0x00, 0xF8, 0x00, 0x3C, 0x00, 0x00, 0x80, 0x00, 0x01, 0x00 }; +const uint8_t start_capture_setup_key_buffer_888_new[] = { 0x61, 0x07, 0x00, 0xA6, 0x00, 0x28, 0x00, 0x62, 0x00, 0x3A, 0x00, 0x00, 0x80, 0x00, 0x01, 0x00 }; +const uint8_t start_capture_setup_key_buffer_888_3d_new[] = { 0x61, 0x07, 0x00, 0xA6, 0x00, 0x28, 0x00, 0x62, 0x00, 0x16, 0x00, 0x00, 0x80, 0x00, 0x01, 0x00 }; +const uint8_t start_capture_setup_key_buffer_565_old[] = { 0x61, 0x07, 0x00, 0x26, 0x00, 0x22, 0x00, 0x98, 0x00, 0x08, 0x00, 0x0E, 0x00, 0x00, 0x18, 0x00 }; +const uint8_t start_capture_setup_key_buffer_565_3d_old[] = { 0x61, 0x07, 0x00, 0x26, 0x00, 0x22, 0x00, 0x98, 0x00, 0x08, 0x00, 0x0F, 0x00, 0x00, 0x18, 0x00 }; +const uint8_t start_capture_setup_key_buffer_888_old[] = { 0x61, 0x07, 0x00, 0xA6, 0x00, 0x20, 0x00, 0x98, 0x00, 0x08, 0x00, 0x0E, 0x00, 0x00, 0x18, 0x00 }; +const uint8_t start_capture_setup_key_buffer_888_3d_old[] = { 0x61, 0x07, 0x00, 0xA6, 0x00, 0x20, 0x00, 0x98, 0x00, 0x08, 0x00, 0x05, 0x00, 0x00, 0x18, 0x00 }; static const cyop_device_usb_device cypress_optimize_new_3ds_generic_device = { .name = "FX2LP-O -> Opt. N3DS", .long_name = "EZ-USB FX2LP-O -> Optimize New 3DS", @@ -69,7 +85,7 @@ static const cyop_device_usb_device cypress_optimize_new_3ds_generic_device = { }; static const cyop_device_usb_device cypress_optimize_new_3ds_instantiated_device = { -.name = "Optimize New 3DS", .long_name = "Optimize New 3DS", +.name = "Optimize N3DS", .long_name = "Optimize New 3DS", .device_type = CYPRESS_OPTIMIZE_NEW_3DS_INSTANTIATED_DEVICE, .firmware_to_load = NULL, .firmware_size = 0, .fpga_pl_565 = optimize_new_3ds_565_fpga_pl, .fpga_pl_565_size = optimize_new_3ds_565_fpga_pl_len, @@ -123,7 +139,7 @@ static const cyop_device_usb_device cypress_optimize_old_3ds_generic_device = { }; static const cyop_device_usb_device cypress_optimize_old_3ds_instantiated_device = { -.name = "Optimize Old 3DS", .long_name = "Optimize Old 3DS", +.name = "Optimize O3DS", .long_name = "Optimize Old 3DS", .device_type = CYPRESS_OPTIMIZE_OLD_3DS_INSTANTIATED_DEVICE, .firmware_to_load = NULL, .firmware_size = 0, .fpga_pl_565 = optimize_old_3ds_565_fpga_pl, .fpga_pl_565_size = optimize_old_3ds_565_fpga_pl_len, @@ -156,6 +172,16 @@ static const cyop_device_usb_device* all_usb_cyop_device_devices_desc[] = { &cypress_optimize_old_3ds_instantiated_device, }; +static uint32_t calc_crc32_adler(uint8_t* data, size_t size) { + uint32_t value = 0xFFFFFFFF; + for(size_t i = 0; i < size; i++) { + uint8_t inner_value = data[i] ^ value; + value >>= 8; + value ^= read_le32(adler_crc32_table_sp, inner_value); + } + return ~value; +} + const cy_device_usb_device* get_cy_usb_info(const cyop_device_usb_device* usb_device_desc) { return &usb_device_desc->usb_device_info; } @@ -188,6 +214,71 @@ static bool free_firmware_and_return(uint8_t* fw_data, bool retval) { return retval; } +static bool key_to_key_bytes(uint8_t* in, uint8_t* out) { + uint16_t value_converted = 0; + size_t converted_pos = 0; + size_t out_index = 0; + + for(size_t i = 0; i < OPTIMIZE_NUM_KEY_CHARS; i++) { + uint8_t character = in[i]; + if(optimize_key_to_byte_table[character] == 0xFF) + return false; + value_converted |= optimize_key_to_byte_table[character] << converted_pos; + converted_pos += 5; + if(converted_pos >= 8) { + out[out_index++] = value_converted & 0xFF; + converted_pos -= 8; + value_converted >>= 8; + } + } + if(converted_pos > 0) + out[out_index++] = value_converted & 0xFF; + return true; +} + +static bool key_bytes_to_serial_bytes(uint8_t* in, uint8_t* out, bool is_new_cc) { + uint8_t xor_factor = 0xAB; + if(is_new_cc) + xor_factor = 0x5A; + int table_accessing_base_value = 0x22; + if(is_new_cc) + table_accessing_base_value = -0x45; + + for(int i = 0; i < OPTIMIZE_NUM_KEY_BYTES; i++) + out[key_bytes_to_serial_bytes_map[i]] = in[i]; + uint8_t checksum_byte = (out[0] ^ xor_factor) & 0xFE; + out[0] = out[0] & 1; + + for(int i = 1; i < 8; i++) { + uint32_t xor_val = read_le32(adler_crc32_table_sp, (checksum_byte + (i * table_accessing_base_value)) & 0xFF); + write_le32(out + i, read_le32(out + i) ^ xor_val); + } + + uint8_t sum = 0; + // The last one is skipped... For whatever reason? + for(int i = 0; i < OPTIMIZE_NUM_KEY_BYTES - 1; i++) + sum += out[i]; + return (read_le32(adler_crc32_table_sp, sum) & 0xFE) == checksum_byte; +} + +static bool key_to_data(std::string in_str, uint8_t* out, bool is_new_cc) { + in_str.erase(std::remove(in_str.begin(), in_str.end(), '-'), in_str.end()); + in_str.erase(std::remove(in_str.begin(), in_str.end(), '&'), in_str.end()); + in_str.erase(std::remove(in_str.begin(), in_str.end(), ':'), in_str.end()); + + if(in_str.length() != OPTIMIZE_NUM_KEY_CHARS) + return false; + + uint8_t key_string_bytes[OPTIMIZE_NUM_KEY_CHARS]; + uint8_t key_bytes[OPTIMIZE_NUM_KEY_BYTES + 1]; // The last 4 bits of the key are ignored?! + + write_string(key_string_bytes, in_str); + if(!key_to_key_bytes(key_string_bytes, key_bytes)) + return false; + + return key_bytes_to_serial_bytes(key_bytes, out, is_new_cc); +} + bool load_firmware(cy_device_device_handlers* handlers, const cyop_device_usb_device* device, uint8_t patch_id) { if(!has_to_load_firmware(device)) return true; @@ -233,28 +324,56 @@ bool load_firmware(cy_device_device_handlers* handlers, const cyop_device_usb_de return free_firmware_and_return(fw_data, true); } -static int read_device_info(cy_device_device_handlers* handlers, const cyop_device_usb_device* device) { - const int read_block_size = 0x10; - const int num_reads = 8; - uint8_t in_buffer[read_block_size * num_reads]; +static bool is_eeprom_data_valid(uint8_t* eeprom_data) { + uint32_t crc = calc_crc32_adler(eeprom_data, OPTIMIZE_EEPROM_STRUCT_SIZE); + return crc == read_le32(eeprom_data + 0x7C); +} + +static std::string extract_key_from_eeprom(uint8_t* eeprom_data) { + if(!is_eeprom_data_valid(eeprom_data)) + return ""; + if(eeprom_data[8] != 0x66) // Key ID byte + return ""; + return read_string(eeprom_data + 0x10, OPTIMIZE_NUM_KEY_CHARS_WITH_DASHES); +} + +static int read_device_info(cy_device_device_handlers* handlers, const cyop_device_usb_device* device, uint8_t* in_buffer, size_t read_size) { + const size_t read_block_size = 0x10; + const size_t num_reads = (read_size + read_block_size - 1) / read_block_size; int transferred = 0; int ret = 0; uint8_t first_out_buffer[] = { 0x38, 0x00, 0x10, 0x30 }; - for(int i = 0; i < num_reads; i++) { - first_out_buffer[1] = i * read_block_size; + for(size_t i = 0; i < num_reads; i++) { + size_t single_read_size = read_size - (i * read_block_size); + if(single_read_size > read_block_size) + single_read_size = read_block_size; + first_out_buffer[1] = (uint8_t)(i * read_block_size); ret = cypress_ctrl_bulk_out_transfer(handlers, get_cy_usb_info(device), first_out_buffer, sizeof(first_out_buffer), &transferred); if(ret < 0) return ret; - ret = cypress_ctrl_bulk_in_transfer(handlers, get_cy_usb_info(device), in_buffer + (i * read_block_size), read_block_size, &transferred); + ret = cypress_ctrl_bulk_in_transfer(handlers, get_cy_usb_info(device), in_buffer + ((int)(i * read_block_size)), single_read_size, &transferred); if(ret < 0) return ret; - if(transferred < read_block_size) + if(transferred < ((int)single_read_size)) return -1; } return ret; } -static int read_second_device_id(cy_device_device_handlers* handlers, const cyop_device_usb_device* device, uint64_t &second_device_id) { +static uint64_t bytes_to_serial_device_id(uint8_t* in_buffer) { + // From multiple dumps, this seems to be the algorithm. + // There may be something missing. + uint8_t in_transformed_buffer[sizeof(uint64_t)]; + + for(size_t i = 0; i < (sizeof(in_transformed_buffer) - 1); i++) + in_transformed_buffer[i] = (reverse_u8(in_buffer[sizeof(in_transformed_buffer) - 1 - i]) >> 7) | (reverse_u8(in_buffer[sizeof(in_transformed_buffer) - 1 - i - 1]) << 1); + // Bugged?! Why doesn't it use in_buffer[7]'s first 7 bits?! + in_transformed_buffer[sizeof(in_transformed_buffer) - 1] = (reverse_u8(in_buffer[0]) >> 7); + + return read_le64(in_transformed_buffer); +} + +static int read_direct_serial_device_id(cy_device_device_handlers* handlers, const cyop_device_usb_device* device, uint64_t &device_id) { const uint8_t first_out_buffer[] = { 0x60, 0x02, 0x30, 0xFF, 0x60, 0xD0, 0x60, 0x02, 0x30, 0xFF, 0x60, 0xCB, 0x60, 0x02, 0x00, 0xFF, 0x00, 0xFF }; uint8_t in_buffer[sizeof(uint64_t)]; int transferred = 0; @@ -270,11 +389,12 @@ static int read_second_device_id(cy_device_device_handlers* handlers, const cyop return ret; if(((size_t)transferred) < sizeof(in_buffer)) return -1; - second_device_id = read_le64(in_buffer); + + device_id = bytes_to_serial_device_id(in_buffer); return ret; } -static int read_device_id(cy_device_device_handlers* handlers, const cyop_device_usb_device* device, uint64_t &device_id, bool &is_full_0s) { +static int read_cached_device_id(cy_device_device_handlers* handlers, const cyop_device_usb_device* device, uint64_t &device_id, bool &is_full_0s) { const uint8_t out_buffer[] = { 0x70 }; uint8_t in_buffer[0x10]; int transferred = 0; @@ -321,7 +441,7 @@ static int start_command_send(cy_device_device_handlers* handlers, const cyop_de return ret; } -static int dual_first_unk_value_setup_read(cy_device_device_handlers* handlers, const cyop_device_usb_device* device, uint32_t &value32, uint64_t &device_id, uint64_t &second_device_id) { +static int read_device_id_serial(cy_device_device_handlers* handlers, const cyop_device_usb_device* device, uint32_t &value32, uint64_t &device_id) { const uint8_t first_buffer[] = { 0x64, 0x60, 0x01, 0xFF, 0xFF, 0x60, 0x02, 0x00, 0xFF, 0x00, 0xFF }; int transferred = 0; int ret = cypress_ctrl_bulk_out_transfer(handlers, get_cy_usb_info(device), first_buffer, sizeof(first_buffer), &transferred); @@ -336,11 +456,11 @@ static int dual_first_unk_value_setup_read(cy_device_device_handlers* handlers, return ret; } bool is_full_0s = false; - ret = read_device_id(handlers, device, device_id, is_full_0s); + ret = read_cached_device_id(handlers, device, device_id, is_full_0s); if(ret < 0) return ret; if(is_full_0s) - ret = read_second_device_id(handlers, device, second_device_id); + ret = read_direct_serial_device_id(handlers, device, device_id); if(ret < 0) return ret; return ret; @@ -440,17 +560,15 @@ static int final_capture_start_transfer(cy_device_device_handlers* handlers, con return ret; } -int capture_start(cy_device_device_handlers* handlers, const cyop_device_usb_device* device, bool is_first_load, bool is_rgb888) { +int capture_start(cy_device_device_handlers* handlers, const cyop_device_usb_device* device, bool is_first_load, bool is_rgb888, uint64_t &device_id, std::string &read_key) { int ret = 0; uint32_t value32 = 0; - uint64_t device_id = 0; - uint64_t second_device_id = 0; if(is_first_load) { for(int i = 0; i < 3; i++) { cypress_pipe_reset_ctrl_bulk_in(handlers, get_cy_usb_info(device)); cypress_pipe_reset_ctrl_bulk_out(handlers, get_cy_usb_info(device)); } - ret = dual_first_unk_value_setup_read(handlers, device, value32, device_id, second_device_id); + ret = read_device_id_serial(handlers, device, value32, device_id); if(ret < 0) return ret; } @@ -458,13 +576,15 @@ int capture_start(cy_device_device_handlers* handlers, const cyop_device_usb_dev if(ret < 0) return ret; if(device->is_new_device) { - ret = read_device_info(handlers, device); + uint8_t eeprom_data[OPTIMIZE_EEPROM_NEW_SIZE]; + ret = read_device_info(handlers, device, eeprom_data, OPTIMIZE_EEPROM_NEW_SIZE); if(ret < 0) return ret; + read_key = extract_key_from_eeprom(eeprom_data); } cypress_pipe_reset_ctrl_bulk_in(handlers, get_cy_usb_info(device)); cypress_pipe_reset_ctrl_bulk_out(handlers, get_cy_usb_info(device)); - ret = dual_first_unk_value_setup_read(handlers, device, value32, device_id, second_device_id); + ret = read_device_id_serial(handlers, device, value32, device_id); if(ret < 0) return ret; @@ -478,9 +598,6 @@ int capture_start(cy_device_device_handlers* handlers, const cyop_device_usb_dev if(ret < 0) return ret; - // No clue about the algorithm to determine this... - // Would need different examples to understand it. - device_id = 0; ret = insert_device_id(handlers, device, device_id); if(ret < 0) return ret; @@ -492,28 +609,75 @@ int capture_start(cy_device_device_handlers* handlers, const cyop_device_usb_dev return ret; } -static const uint8_t* get_start_capture_third_buffer(const cyop_device_usb_device* device, bool is_rgb888, bool is_3d) { +static const uint8_t* get_start_capture_setup_key_buffer(const cyop_device_usb_device* device, bool is_rgb888, bool is_3d) { if(device->is_new_device) { if(is_rgb888) { if(is_3d) - return start_capture_third_buffer_888_3d_new; - return start_capture_third_buffer_888_new; + return start_capture_setup_key_buffer_888_3d_new; + return start_capture_setup_key_buffer_888_new; } if(is_3d) - return start_capture_third_buffer_565_3d_new; - return start_capture_third_buffer_565_new; + return start_capture_setup_key_buffer_565_3d_new; + return start_capture_setup_key_buffer_565_new; } if(is_rgb888) { if(is_3d) - return start_capture_third_buffer_888_3d_old; - return start_capture_third_buffer_888_old; + return start_capture_setup_key_buffer_888_3d_old; + return start_capture_setup_key_buffer_888_old; } if(is_3d) - return start_capture_third_buffer_565_3d_old; - return start_capture_third_buffer_565_old; + return start_capture_setup_key_buffer_565_3d_old; + return start_capture_setup_key_buffer_565_old; } -int StartCaptureDma(cy_device_device_handlers* handlers, const cyop_device_usb_device* device, bool is_rgb888, bool is_3d) { +bool check_key_matches_device_id(uint64_t device_id, std::string key, bool is_new_device) { + uint8_t key_bytes[OPTIMIZE_NUM_KEY_BYTES]; + bool is_key_valid = key_to_data(key, key_bytes, is_new_device); + if(!is_key_valid) + return false; + return device_id == read_be64(key_bytes); +} + +bool check_key_matches_device_id(uint64_t device_id, std::string key, const cyop_device_usb_device* device) { + if(device == NULL) + return false; + return check_key_matches_device_id(device_id, key, device->is_new_device); +} + +bool check_key_valid(std::string key, bool is_new_device) { + uint8_t key_bytes[OPTIMIZE_NUM_KEY_BYTES]; + bool is_key_valid = key_to_data(key, key_bytes, is_new_device); + // Extra checks here, if I ever feel like it. + return is_key_valid; +} + +bool check_key_valid(std::string key, const cyop_device_usb_device* device) { + if(device == NULL) + return false; + return check_key_valid(key, device->is_new_device); +} + +static void populate_capture_setup_key_buffer(const cyop_device_usb_device* device, uint8_t* setup_key_buffer, std::string key) { + if(key == "") + return; + + uint8_t key_bytes[OPTIMIZE_NUM_KEY_BYTES]; + bool is_key_valid = key_to_data(key, key_bytes, device->is_new_device); + + if(!is_key_valid) + return; + + if(device->is_new_device) { + setup_key_buffer[11] = key_bytes[11]; + setup_key_buffer[13] = key_bytes[10]; + return; + } + setup_key_buffer[11] |= key_bytes[10] & 0xF0; + setup_key_buffer[13] = ((key_bytes[10] & 0xF) << 4) | (key_bytes[11] >> 4); + setup_key_buffer[15] = key_bytes[11] & 0xF; +} + +int StartCaptureDma(cy_device_device_handlers* handlers, const cyop_device_usb_device* device, bool is_rgb888, bool is_3d, std::string key) { const uint8_t mono_buffer[] = { 0x40 }; int transferred = 0; int ret = cypress_ctrl_bulk_out_transfer(handlers, get_cy_usb_info(device), mono_buffer, sizeof(mono_buffer), &transferred); @@ -523,10 +687,11 @@ int StartCaptureDma(cy_device_device_handlers* handlers, const cyop_device_usb_d ret = cypress_ctrl_bulk_out_transfer(handlers, get_cy_usb_info(device), second_buffer, sizeof(second_buffer), &transferred); if(ret < 0) return ret; - const uint8_t* third_buffer = get_start_capture_third_buffer(device, is_rgb888, is_3d); - uint8_t real_third_buffer[sizeof(start_capture_third_buffer_888_new)]; - memcpy(real_third_buffer, third_buffer, sizeof(real_third_buffer)); - ret = cypress_ctrl_bulk_out_transfer(handlers, get_cy_usb_info(device), real_third_buffer, sizeof(real_third_buffer), &transferred); + const uint8_t* base_setup_key_buffer = get_start_capture_setup_key_buffer(device, is_rgb888, is_3d); + uint8_t setup_key_buffer[sizeof(start_capture_setup_key_buffer_888_new)]; + memcpy(setup_key_buffer, base_setup_key_buffer, sizeof(setup_key_buffer)); + populate_capture_setup_key_buffer(device, setup_key_buffer, key); + ret = cypress_ctrl_bulk_out_transfer(handlers, get_cy_usb_info(device), setup_key_buffer, sizeof(setup_key_buffer), &transferred); if(ret < 0) return ret; uint8_t in_buffer[7]; diff --git a/source/WindowScreen.cpp b/source/WindowScreen.cpp index 3447900..d293b0f 100755 --- a/source/WindowScreen.cpp +++ b/source/WindowScreen.cpp @@ -37,7 +37,7 @@ static bool is_size_valid(sf::Vector2f size) { return (size.x > 0.0) && (size.y > 0.0); } -WindowScreen::WindowScreen(ScreenType stype, CaptureStatus* capture_status, DisplayData* display_data, SharedData* shared_data, AudioData* audio_data, ConsumerMutex *draw_lock, bool created_proper_folder, bool disable_frame_blending) { +WindowScreen::WindowScreen(ScreenType stype, CaptureStatus* capture_status, DisplayData* display_data, SharedData* shared_data, AudioData* audio_data, ConsumerMutex *draw_lock, bool disable_frame_blending) { this->draw_lock = draw_lock; this->m_stype = stype; insert_basic_crops(this->possible_crops, this->m_stype, false, false); @@ -133,6 +133,7 @@ WindowScreen::WindowScreen(ScreenType stype, CaptureStatus* capture_status, Disp if(this->m_stype == ScreenType::JOINT) this->own_out_text_data.preamble_name += " joint window"; this->last_connected_status = false; + this->last_title_check_id = 0; this->last_enabled_3d = false; this->last_interleaved_3d = false; this->capture_status = capture_status; @@ -157,7 +158,6 @@ WindowScreen::WindowScreen(ScreenType stype, CaptureStatus* capture_status, Disp n_shader_refs += 1; this->was_last_frame_null = true; this->main_thread_owns_window = true; - this->created_proper_folder = created_proper_folder; this->is_window_windowed = false; this->saved_windowed_pos = sf::Vector2i(0, 0); this->was_windowed_pos_saved = false; @@ -361,9 +361,10 @@ void WindowScreen::draw(double frame_time, VideoOutputData* out_buf, InputVideoD } void WindowScreen::update_connection() { - if(this->last_connected_status == this->capture_status->connected) - return; + if((this->last_connected_status == this->capture_status->connected) && (this->last_title_check_id == this->capture_status->title_check_id)) + return; this->last_connected_status = this->capture_status->connected; + this->last_title_check_id = this->capture_status->title_check_id; if(this->m_win.isOpen()) { this->m_win.setTitle(this->title_factory()); } @@ -566,7 +567,7 @@ void WindowScreen::window_factory(bool is_main_thread) { std::string WindowScreen::_title_factory() { std::string title = this->win_title; if(this->capture_status->connected) - title += " - " + get_name_of_device(this->capture_status); + title += " - " + get_name_of_device(this->capture_status, false, true); return title; } diff --git a/source/WindowScreen_Menu.cpp b/source/WindowScreen_Menu.cpp index 39c47dd..14b8f82 100755 --- a/source/WindowScreen_Menu.cpp +++ b/source/WindowScreen_Menu.cpp @@ -998,18 +998,18 @@ void WindowScreen::setup_fileconfig_menu(bool is_save, bool reset_data, bool ski this->possible_files.push_back(file_data); } file_data.index = STARTUP_FILE_INDEX; - file_data.name = load_layout_name(file_data.index, this->created_proper_folder, success); + file_data.name = load_layout_name(file_data.index, success); this->possible_files.push_back(file_data); for(int i = 1; i <= 4; i++) { file_data.index = i; - file_data.name = load_layout_name(file_data.index, this->created_proper_folder, success); + file_data.name = load_layout_name(file_data.index, success); this->possible_files.push_back(file_data); } int first_free; bool failed = false; for(first_free = 5; first_free <= 100; first_free++) { file_data.index = first_free; - file_data.name = load_layout_name(file_data.index, this->created_proper_folder, success); + file_data.name = load_layout_name(file_data.index, success); if(!success) { failed = true; break; diff --git a/source/cc3dsfs.cpp b/source/cc3dsfs.cpp index 36cb00e..b52b2c5 100755 --- a/source/cc3dsfs.cpp +++ b/source/cc3dsfs.cpp @@ -254,7 +254,7 @@ static void defaults_reload(FrontendData *frontend_data, AudioData* audio_data, frontend_data->reload = true; } -static void load_layout_file(int load_index, FrontendData *frontend_data, AudioData* audio_data, OutTextData &out_text_data, CaptureStatus* capture_status, bool skip_io, bool do_print, bool created_proper_folder, bool is_first_load) { +static void load_layout_file(int load_index, FrontendData *frontend_data, AudioData* audio_data, OutTextData &out_text_data, CaptureStatus* capture_status, bool skip_io, bool do_print, bool is_first_load) { if(skip_io) return; @@ -269,12 +269,12 @@ static void load_layout_file(int load_index, FrontendData *frontend_data, AudioD bool name_load_success = false; std::string layout_name = LayoutNameGenerator(load_index); - std::string layout_path = LayoutPathGenerator(load_index, created_proper_folder); - std::string shared_layout_path = LayoutPathGenerator(STARTUP_FILE_INDEX, created_proper_folder); + std::string layout_path = LayoutPathGenerator(load_index); + std::string shared_layout_path = get_base_path(false); std::string shared_layout_name = "shared.cfg"; bool op_success = load(layout_path, layout_name, frontend_data->top_screen->m_info, frontend_data->bot_screen->m_info, frontend_data->joint_screen->m_info, frontend_data->display_data, audio_data, out_text_data, capture_status); if(do_print && op_success) { - std::string load_name = load_layout_name(load_index, created_proper_folder, name_load_success); + std::string load_name = load_layout_name(load_index, name_load_success); UpdateOutText(out_text_data, "Layout loaded from: " + layout_path + layout_name, "Layout " + load_name + " loaded", TEXT_KIND_SUCCESS); } else if(!op_success) { @@ -339,7 +339,7 @@ static bool save(const std::string path, const std::string name, const std::stri return true; } -static void save_layout_file(int save_index, FrontendData *frontend_data, AudioData* audio_data, OutTextData &out_text_data, CaptureStatus* capture_status, bool skip_io, bool do_print, bool created_proper_folder) { +static void save_layout_file(int save_index, FrontendData *frontend_data, AudioData* audio_data, OutTextData &out_text_data, CaptureStatus* capture_status, bool skip_io, bool do_print) { if(skip_io) return; @@ -347,10 +347,10 @@ static void save_layout_file(int save_index, FrontendData *frontend_data, AudioD return; bool name_load_success = false; - std::string save_name = load_layout_name(save_index, created_proper_folder, name_load_success); + std::string save_name = load_layout_name(save_index, name_load_success); std::string layout_name = LayoutNameGenerator(save_index); - std::string layout_path = LayoutPathGenerator(save_index, created_proper_folder); - std::string shared_layout_path = LayoutPathGenerator(STARTUP_FILE_INDEX, created_proper_folder); + std::string layout_path = LayoutPathGenerator(save_index); + std::string shared_layout_path = LayoutPathGenerator(STARTUP_FILE_INDEX); std::string shared_layout_name = "shared.cfg"; bool op_success = save(layout_path, layout_name, save_name, frontend_data->top_screen->m_info, frontend_data->bot_screen->m_info, frontend_data->joint_screen->m_info, frontend_data->display_data, audio_data, out_text_data, capture_status); if(do_print && op_success) { @@ -541,7 +541,7 @@ static float get_time_multiplier(CaptureData* capture_data, bool should_ignore_d } } -static int mainVideoOutputCall(AudioData* audio_data, CaptureData* capture_data, bool created_proper_folder, override_all_data &override_data, volatile bool* can_do_output) { +static int mainVideoOutputCall(AudioData* audio_data, CaptureData* capture_data, override_all_data &override_data, volatile bool* can_do_output) { VideoOutputData *out_buf; double last_frame_time = 0.0; FrontendData frontend_data; @@ -563,15 +563,15 @@ static int mainVideoOutputCall(AudioData* audio_data, CaptureData* capture_data, memset(out_buf, 0, sizeof(VideoOutputData)); draw_lock.unlock(); - WindowScreen *top_screen = new WindowScreen(ScreenType::TOP, &capture_data->status, &frontend_data.display_data, &frontend_data.shared_data, audio_data, &draw_lock, created_proper_folder, override_data.disable_frame_blending); - WindowScreen *bot_screen = new WindowScreen(ScreenType::BOTTOM, &capture_data->status, &frontend_data.display_data, &frontend_data.shared_data, audio_data, &draw_lock, created_proper_folder, override_data.disable_frame_blending); - WindowScreen *joint_screen = new WindowScreen(ScreenType::JOINT, &capture_data->status, &frontend_data.display_data, &frontend_data.shared_data, audio_data, &draw_lock, created_proper_folder, override_data.disable_frame_blending); + WindowScreen *top_screen = new WindowScreen(ScreenType::TOP, &capture_data->status, &frontend_data.display_data, &frontend_data.shared_data, audio_data, &draw_lock, override_data.disable_frame_blending); + WindowScreen *bot_screen = new WindowScreen(ScreenType::BOTTOM, &capture_data->status, &frontend_data.display_data, &frontend_data.shared_data, audio_data, &draw_lock, override_data.disable_frame_blending); + WindowScreen *joint_screen = new WindowScreen(ScreenType::JOINT, &capture_data->status, &frontend_data.display_data, &frontend_data.shared_data, audio_data, &draw_lock, override_data.disable_frame_blending); frontend_data.top_screen = top_screen; frontend_data.bot_screen = bot_screen; frontend_data.joint_screen = joint_screen; if(!override_data.recovery_mode) - load_layout_file(override_data.loaded_profile, &frontend_data, audio_data, out_text_data, &capture_data->status, skip_io, false, created_proper_folder, true); + load_layout_file(override_data.loaded_profile, &frontend_data, audio_data, out_text_data, &capture_data->status, skip_io, false, true); if(override_data.volume != DEFAULT_NO_VOLUME_VALUE) audio_data->set_audio_volume(override_data.volume); override_set_data_to_screen_info(override_data.override_top_bot_data, frontend_data.joint_screen->m_info); @@ -710,12 +710,12 @@ static int mainVideoOutputCall(AudioData* audio_data, CaptureData* capture_data, if((load_index = top_screen->load_data()) || (load_index = bot_screen->load_data()) || (load_index = joint_screen->load_data())) { // This value should only be loaded when starting the program... bool previous_last_connected_ds = frontend_data.display_data.last_connected_ds; - load_layout_file(load_index, &frontend_data, audio_data, out_text_data, &capture_data->status, skip_io, true, created_proper_folder, false); + load_layout_file(load_index, &frontend_data, audio_data, out_text_data, &capture_data->status, skip_io, true, false); frontend_data.display_data.last_connected_ds = previous_last_connected_ds; } if((save_index = top_screen->save_data()) || (save_index = bot_screen->save_data()) || (save_index = joint_screen->save_data())) { - save_layout_file(save_index, &frontend_data, audio_data, out_text_data, &capture_data->status, skip_io, true, created_proper_folder); + save_layout_file(save_index, &frontend_data, audio_data, out_text_data, &capture_data->status, skip_io, true); top_screen->update_save_menu(); bot_screen->update_save_menu(); joint_screen->update_save_menu(); @@ -755,7 +755,7 @@ static int mainVideoOutputCall(AudioData* audio_data, CaptureData* capture_data, joint_screen->after_thread_join(); if(override_data.auto_save) - save_layout_file(override_data.loaded_profile, &frontend_data, audio_data, out_text_data, &capture_data->status, skip_io, false, created_proper_folder); + save_layout_file(override_data.loaded_profile, &frontend_data, audio_data, out_text_data, &capture_data->status, skip_io, false); top_screen->process_own_out_text_data(false); bot_screen->process_own_out_text_data(false); @@ -782,10 +782,11 @@ static bool create_folder(const std::string path) { } static bool create_out_folder() { - bool success = create_folder(LayoutPathGenerator(STARTUP_FILE_INDEX, true)); + bool success = create_folder(get_base_path(false, false)); if(!success) - create_folder(LayoutPathGenerator(STARTUP_FILE_INDEX, false)); - create_folder(LayoutPathGenerator(1, success)); + create_folder(get_base_path(false)); + create_folder(get_base_path(true)); + create_folder(get_base_path_keys()); return success; } @@ -832,7 +833,6 @@ int main(int argc, char **argv) { int enter_id = -1; int power_id = -1; bool use_pud_up = true; - bool created_proper_folder = create_out_folder(); volatile bool can_do_output = true; bool mono_app_default_value = false; #ifdef ANDROID_COMPILATION @@ -950,6 +950,7 @@ int main(int argc, char **argv) { #endif return 0; } + create_out_folder(); init_extra_buttons_poll(page_up_id, page_down_id, enter_id, power_id, use_pud_up); AudioData audio_data; audio_data.reset(); @@ -961,7 +962,7 @@ int main(int argc, char **argv) { if(!override_data.no_audio) audio_thread = std::thread(soundCall, &audio_data, capture_data, &can_do_output); - int ret_val = mainVideoOutputCall(&audio_data, capture_data, created_proper_folder, override_data, &can_do_output); + int ret_val = mainVideoOutputCall(&audio_data, capture_data, override_data, &can_do_output); if(!override_data.no_audio) audio_thread.join(); capture_thread.join(); diff --git a/source/devicecapture.cpp b/source/devicecapture.cpp index df4cdc7..2eef368 100755 --- a/source/devicecapture.cpp +++ b/source/devicecapture.cpp @@ -69,6 +69,16 @@ void capture_error_print(bool print_failed, CaptureData* capture_data, std::stri } } +void capture_warning_print(CaptureData* capture_data, std::string graphical_string, std::string detailed_string) { + capture_data->status.graphical_error_text = graphical_string; + capture_data->status.detailed_error_text = detailed_string; + capture_data->status.new_error_text = true; +} + +void capture_warning_print(CaptureData* capture_data, std::string warning_string) { + capture_warning_print(capture_data, warning_string, warning_string); +} + bool connect(bool print_failed, CaptureData* capture_data, FrontendData* frontend_data, bool auto_connect_to_first) { capture_data->status.new_error_text = false; if (capture_data->status.connected) { @@ -286,12 +296,28 @@ uint64_t get_video_in_size(CaptureData* capture_data, bool is_3d, InputVideoData return 0; } -std::string get_name_of_device(CaptureStatus* capture_status, bool use_long) { +std::string get_device_id_string(CaptureStatus* capture_status) { + if(!capture_status->connected) + return ""; + if(capture_status->device.device_id == 0) + return ""; + + if(capture_status->device.cc_type == CAPTURE_CONN_CYPRESS_OPTIMIZE) + return to_hex_u60(capture_status->device.device_id); + + return ""; +} + +std::string get_name_of_device(CaptureStatus* capture_status, bool use_long, bool want_real_serial) { if(!capture_status->connected) return "Not connected"; + std:: string serial_str = " - " + capture_status->device.serial_number; + std::string device_id_string = get_device_id_string(capture_status); + if(want_real_serial && (device_id_string != "")) + serial_str = " - " + device_id_string; if(!use_long) - return capture_status->device.name + " - " + capture_status->device.serial_number; - return capture_status->device.long_name + " - " + capture_status->device.serial_number; + return capture_status->device.name + serial_str; + return capture_status->device.long_name + serial_str; } int get_usb_speed_of_device(CaptureStatus* capture_status) { diff --git a/source/utils.cpp b/source/utils.cpp index 7484145..e70889f 100755 --- a/source/utils.cpp +++ b/source/utils.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -64,6 +65,17 @@ uint16_t reverse_endianness(uint16_t value) { return ((value & 0xFF) << 8) | ((value & 0xFF00) >> 8); } +static uint64_t reverse_ux(uint64_t data, int bits_num) { + uint64_t out_data = 0; + for(int i = 0; i < bits_num; i++) + out_data |= ((data >> i) & 1) << (bits_num - 1 - i); + return out_data; +} + +uint8_t reverse_u8(uint8_t data) { + return (uint8_t)reverse_ux(data, sizeof(uint8_t) * 8); +} + uint32_t to_le(uint32_t value) { if(is_big_endian()) value = reverse_endianness(value); @@ -250,6 +262,24 @@ std::string to_hex_u16(const uint16_t value) { return to_hex_base(value, digits, num_digits); } +std::string to_hex_u32(const uint32_t value) { + const int num_digits = sizeof(value) * 2; + char digits[num_digits + 1]; + return to_hex_base(value, digits, num_digits); +} + +std::string to_hex_u60(const uint64_t value) { + const int num_digits = (sizeof(value) * 2) - 1; + char digits[num_digits + 1]; + return to_hex_base(value, digits, num_digits); +} + +std::string to_hex_u64(const uint64_t value) { + const int num_digits = sizeof(value) * 2; + char digits[num_digits + 1]; + return to_hex_base(value, digits, num_digits); +} + void init_threads(void) { #if defined(__linux__) && defined(XLIB_BASED) XInitThreads(); @@ -330,39 +360,54 @@ ANativeActivity* getAndroidNativeActivity() { } #endif -std::string LayoutPathGenerator(int index, bool created_proper_folder) { - bool success = false; - std::string cfg_dir; +std::string get_base_path(bool for_presets, bool do_existence_check) { + std::string cfg_dir = "./"; const char* env_p = NULL; + bool add_config = true; #ifdef ANDROID_COMPILATION ANativeActivity* native_activity_ptr = getAndroidNativeActivity(); if(native_activity_ptr) env_p = native_activity_ptr->internalDataPath; #elif !(defined(_WIN32) || defined(_WIN64)) - env_p = std::getenv("HOME"); + std::string folder_env = std::string(NAME) + "_CFG_DIR"; + std::transform(folder_env.begin(), folder_env.end(), folder_env.begin(), ::toupper); + env_p = std::getenv(folder_env.c_str()); + if(env_p == NULL) + env_p = std::getenv("HOME"); + else + add_config = false; #endif - if(!created_proper_folder) - env_p = NULL; + if(env_p != NULL) { + std::string target_folder = std::string(env_p); + if((target_folder != "") && ((!do_existence_check) || std::filesystem::is_directory(std::filesystem::path(target_folder)))) + cfg_dir = std::string(env_p) + "/"; + } - if(env_p != NULL) - cfg_dir = std::string(env_p) + "/"; + if(add_config) + cfg_dir += ".config/" + std::string(NAME); - cfg_dir += ".config/" + std::string(NAME); - - if(index == STARTUP_FILE_INDEX) + if(!for_presets) return cfg_dir + "/"; return cfg_dir + "/presets/"; } -std::string load_layout_name(int index, bool created_proper_folder, bool &success) { +std::string get_base_path_keys() { + return get_base_path(false) + "keys/"; +} + +std::string LayoutPathGenerator(int index) { + return get_base_path(index != STARTUP_FILE_INDEX); +} + +std::string load_layout_name(int index, bool &success) { if(index == STARTUP_FILE_INDEX) { success = true; return "Initial"; } std::string name = LayoutNameGenerator(index); - std::string path = LayoutPathGenerator(index, created_proper_folder); + std::string path = LayoutPathGenerator(index); std::ifstream file(path + name); std::string line;