diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a28775..67b88fa 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -313,7 +313,7 @@ if(USE_LIBUSB_SUPPORT) endif() 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_0x81_packet.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}/is_twl_cap_crc32_table.cpp ${TOOLS_DATA_DIR}/is_twl_cap_init_seed_table.cpp) if(MSVC) list(APPEND EXTRA_CXX_FLAGS "/DUSE_IS_DEVICES_USB") else() @@ -517,10 +517,17 @@ add_custom_command( ) add_custom_command( - OUTPUT ${TOOLS_DATA_DIR}/is_twl_0x81_packet.cpp - COMMENT "Convert binary to C - IS TWL Capture 0x81 Packet" - COMMAND ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION} ${CMAKE_SOURCE_DIR}/bin/is_twl_0x81_packet.bin ${TOOLS_DATA_DIR} is_twl_0x81_packet is_twl_0x81_packet - DEPENDS ${CMAKE_SOURCE_DIR}/bin/is_twl_0x81_packet.bin ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION} + 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} +) + +add_custom_command( + OUTPUT ${TOOLS_DATA_DIR}/is_twl_cap_init_seed_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_init_seed_table.bin ${TOOLS_DATA_DIR} is_twl_cap_init_seed_table is_twl_cap_init_seed_table + DEPENDS ${CMAKE_SOURCE_DIR}/bin/is_twl_cap_init_seed_table.bin ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION} ) add_custom_command( diff --git a/README.md b/README.md index 4d3ce6f..f29cf9a 100755 --- a/README.md +++ b/README.md @@ -45,7 +45,8 @@ sudo apt install \ libegl1-mesa-dev \ libdrm-dev \ libgbm-dev \ - libfreetype-dev + libfreetype-dev \ + xorg-dev ``` Additionally, when compiling for a Raspberry Pi, install gpiod and libgpiod-dev. diff --git a/bin/is_twl_0x81_packet.bin b/bin/is_twl_0x81_packet.bin deleted file mode 100644 index 832ce99..0000000 --- a/bin/is_twl_0x81_packet.bin +++ /dev/null @@ -1 +0,0 @@ -"RJV1iTE$b.L7mf֫rV&65'EeY@Bx?;}ۺһ:s$1xGaݴ]\˸c @ !?H_O_?mީ~+>ѽHѧ}AeYH<O_N  \ No newline at end of file diff --git a/bin/is_twl_cap_crc32_table.bin b/bin/is_twl_cap_crc32_table.bin new file mode 100644 index 0000000..422f3f4 Binary files /dev/null and b/bin/is_twl_cap_crc32_table.bin differ diff --git a/bin/is_twl_cap_init_seed_table.bin b/bin/is_twl_cap_init_seed_table.bin new file mode 100644 index 0000000..c7eb5be Binary files /dev/null and b/bin/is_twl_cap_init_seed_table.bin differ diff --git a/include/CaptureDeviceSpecific/ISDevices/usb_is_device_communications.hpp b/include/CaptureDeviceSpecific/ISDevices/usb_is_device_communications.hpp index 4671930..6eb4493 100644 --- a/include/CaptureDeviceSpecific/ISDevices/usb_is_device_communications.hpp +++ b/include/CaptureDeviceSpecific/ISDevices/usb_is_device_communications.hpp @@ -78,13 +78,23 @@ struct is_device_device_handlers { libusb_device_handle* usb_handle; void* read_handle; void* write_handle; + void* ctrl_in_handle; void* mutex; + std::string path; +}; + +struct is_device_twl_enc_dec_table { + uint32_t rotating_value; + uint8_t num_values; + uint8_t num_iters_full; + uint8_t num_iters_before_refresh; + uint16_t action_values[8]; }; int GetNumISDeviceDesc(void); const is_device_usb_device* GetISDeviceDesc(int index); int DisableLca2(is_device_device_handlers* handlers, const is_device_usb_device* device_desc); -int StartUsbCaptureDma(is_device_device_handlers* handlers, const is_device_usb_device* device_desc); +int StartUsbCaptureDma(is_device_device_handlers* handlers, const is_device_usb_device* device_desc, bool enable_sound_capture = false, is_device_twl_enc_dec_table* enc_table = NULL, is_device_twl_enc_dec_table* dec_table = NULL); int StopUsbCaptureDma(is_device_device_handlers* handlers, const is_device_usb_device* device_desc); int SetForwardFrameCount(is_device_device_handlers* handlers, uint16_t count, const is_device_usb_device* device_desc); int SetForwardFramePermanent(is_device_device_handlers* handlers, const is_device_usb_device* device_desc); @@ -105,6 +115,7 @@ int ReadFrame(is_device_device_handlers* handlers, uint8_t* buf, int length, con void ReadFrameAsync(is_device_device_handlers* handlers, uint8_t* buf, int length, const is_device_usb_device* device_desc, isd_async_callback_data* cb_data); void CloseAsyncRead(is_device_device_handlers* handlers, isd_async_callback_data* cb_data); int ResetUSBDevice(is_device_device_handlers* handlers); +int PrepareEncDecTable(is_device_device_handlers* handlers, is_device_twl_enc_dec_table* enc_table, is_device_twl_enc_dec_table* dec_table, const is_device_usb_device* device_desc); void SetupISDeviceAsyncThread(is_device_device_handlers* handlers, void* user_data, std::thread* thread_ptr, bool* keep_going, ConsumerMutex* is_data_ready); void EndISDeviceAsyncThread(is_device_device_handlers* handlers, void* user_data, std::thread* thread_ptr, bool* keep_going, ConsumerMutex* is_data_ready); diff --git a/include/CaptureDeviceSpecific/ISDevices/usb_is_device_is_driver.hpp b/include/CaptureDeviceSpecific/ISDevices/usb_is_device_is_driver.hpp index bcb856a..e837e3e 100644 --- a/include/CaptureDeviceSpecific/ISDevices/usb_is_device_is_driver.hpp +++ b/include/CaptureDeviceSpecific/ISDevices/usb_is_device_is_driver.hpp @@ -10,8 +10,11 @@ void is_driver_list_devices(std::vector& devices_list, bool* not_supported_elems, int* curr_serial_extra_id_is_device, const size_t num_is_device_desc); is_device_device_handlers* is_driver_serial_reconnection(CaptureDevice* device); void is_driver_end_connection(is_device_device_handlers* handlers); +bool is_driver_prepare_ctrl_in_handle(is_device_device_handlers* handlers); +void is_driver_close_ctrl_in_handle(is_device_device_handlers* handlers); int is_driver_bulk_out(is_device_device_handlers* handlers, const is_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred); int is_driver_bulk_in(is_device_device_handlers* handlers, const is_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred); +int is_driver_ctrl_in(is_device_device_handlers* handlers, uint8_t* buf, int length, uint8_t request, uint16_t index, int* transferred); int is_drive_async_in_start(is_device_device_handlers* handlers, const is_device_usb_device* usb_device_desc, uint8_t* buf, int length, isd_async_callback_data* cb_data); void is_device_is_driver_cancel_callback(isd_async_callback_data* cb_data); int is_device_is_driver_reset_device(is_device_device_handlers* handlers); diff --git a/include/CaptureDeviceSpecific/ISDevices/usb_is_device_libusb.hpp b/include/CaptureDeviceSpecific/ISDevices/usb_is_device_libusb.hpp index 93f3109..6eebd46 100644 --- a/include/CaptureDeviceSpecific/ISDevices/usb_is_device_libusb.hpp +++ b/include/CaptureDeviceSpecific/ISDevices/usb_is_device_libusb.hpp @@ -10,6 +10,7 @@ is_device_device_handlers* is_device_libusb_serial_reconnection(const is_device_ void is_device_libusb_end_connection(is_device_device_handlers* handlers, const is_device_usb_device* device_desc, bool interface_claimed); int is_device_libusb_bulk_out(is_device_device_handlers* handlers, const is_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred); int is_device_libusb_bulk_in(is_device_device_handlers* handlers, const is_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred); +int is_device_libusb_ctrl_in(is_device_device_handlers* handlers, const is_device_usb_device* usb_device_desc, uint8_t* buf, int length, uint8_t request, uint16_t index, int* transferred); void is_device_libusb_async_in_start(is_device_device_handlers* handlers, const is_device_usb_device* usb_device_desc, uint8_t* buf, int length, isd_async_callback_data* cb_data); void is_device_libusb_cancell_callback(isd_async_callback_data* cb_data); int is_device_libusb_reset_device(is_device_device_handlers* handlers); diff --git a/include/capture_structs.hpp b/include/capture_structs.hpp index 49fcd48..10eef79 100755 --- a/include/capture_structs.hpp +++ b/include/capture_structs.hpp @@ -122,12 +122,20 @@ struct ALIGNED(16) PACKED ISTWLCaptureVideoReceived { ISTWLCaptureVideoInputData video_in; uint32_t time; uint32_t frame; - uint8_t unknown[0x40000 - (sizeof(ISTWLCaptureVideoInputData) + (sizeof(uint32_t) * 2))]; }; -struct ALIGNED(16) PACKED ISTWLCaptureAudioReceived { +struct ALIGNED(16) PACKED ISTWLCaptureVideoInternalReceived { + ISTWLCaptureVideoReceived real_video_in; + uint8_t unknown[0x40000 - sizeof(ISTWLCaptureVideoReceived)]; +}; + +struct ALIGNED(4) PACKED ISTWLCaptureSoundData { + uint16_t data[TWL_CAPTURE_SAMPLES_IN]; +}; + +struct ALIGNED(4) PACKED ISTWLCaptureAudioReceived { uint32_t time; - uint16_t sound_data[TWL_CAPTURE_SAMPLES_IN]; + ISTWLCaptureSoundData sound_data; }; struct ALIGNED(16) PACKED ISTWLCaptureReceived { diff --git a/include/utils.hpp b/include/utils.hpp index 9f207db..efc8243 100755 --- a/include/utils.hpp +++ b/include/utils.hpp @@ -32,15 +32,31 @@ std::string get_version_string(bool get_letter = true); 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); +uint32_t reverse_endianness(uint32_t value); +uint16_t reverse_endianness(uint16_t value); bool is_big_endian(void); uint32_t to_le(uint32_t value); -uint32_t to_be(uint32_t value); uint16_t to_le(uint16_t value); +uint32_t to_be(uint32_t value); uint16_t to_be(uint16_t value); uint32_t from_le(uint32_t value); -uint32_t from_be(uint32_t value); uint16_t from_le(uint16_t value); +uint32_t from_be(uint32_t value); uint16_t from_be(uint16_t value); +uint16_t read_le16(const uint8_t* data, size_t count = 0, size_t multiplier = sizeof(uint16_t)); +uint16_t read_be16(const uint8_t* data, size_t count = 0, size_t multiplier = sizeof(uint16_t)); +uint32_t read_le32(const uint8_t* data, size_t count = 0, size_t multiplier = sizeof(uint32_t)); +uint32_t read_be32(const uint8_t* data, size_t count = 0, size_t multiplier = sizeof(uint32_t)); +void write_le16(uint8_t* data, uint16_t value, size_t count = 0, size_t multiplier = sizeof(uint16_t)); +void write_be16(uint8_t* data, uint16_t value, size_t count = 0, size_t multiplier = sizeof(uint16_t)); +void write_le32(uint8_t* data, uint32_t value, size_t count = 0, size_t multiplier = sizeof(uint32_t)); +void write_be32(uint8_t* data, uint32_t value, size_t count = 0, size_t multiplier = sizeof(uint32_t)); +void write_string(uint8_t* data, std::string text); +std::string read_string(uint8_t* data, size_t size); +uint32_t rotate_bits_left(uint32_t value); +uint32_t rotate_bits_right(uint32_t value); +void init_start_time(); +uint32_t ms_since_start(); std::string to_hex(uint16_t value); std::string get_float_str_decimals(float value, int decimals); void init_threads(void); diff --git a/source/CaptureDeviceSpecific/ISDevices/usb_is_device_acquisition.cpp b/source/CaptureDeviceSpecific/ISDevices/usb_is_device_acquisition.cpp index c228152..d567d6c 100644 --- a/source/CaptureDeviceSpecific/ISDevices/usb_is_device_acquisition.cpp +++ b/source/CaptureDeviceSpecific/ISDevices/usb_is_device_acquisition.cpp @@ -139,7 +139,7 @@ bool is_device_connect_usb(bool print_failed, CaptureData* capture_data, Capture uint64_t usb_is_device_get_video_in_size(CaptureScreensType capture_type, is_device_type device_type) { if(device_type == IS_TWL_CAPTURE_DEVICE) - return sizeof(ISTWLCaptureVideoInputData) + (sizeof(uint32_t) * 2); + return sizeof(ISTWLCaptureVideoReceived); if((capture_type == CAPTURE_SCREENS_TOP) || (capture_type == CAPTURE_SCREENS_BOTTOM)) return sizeof(ISNitroEmulatorVideoInputData) / 2; return sizeof(ISNitroEmulatorVideoInputData); @@ -216,7 +216,21 @@ void output_to_thread(CaptureData* capture_data, CaptureReceived* capture_buf, C const auto curr_time = std::chrono::high_resolution_clock::now(); const std::chrono::duration diff = curr_time - (*clock_start); *clock_start = curr_time; - capture_data->data_buffers.WriteToBuffer(capture_buf, read_size, diff.count(), &capture_data->status.device, curr_capture_type); + if(usb_device_info->device_type == IS_TWL_CAPTURE_DEVICE) { + CaptureDataSingleBuffer* target = capture_data->data_buffers.GetWriterBuffer(); + // Copy data to buffer, with special memcpy which accounts for ftd2 header data and skips synch bytes + size_t video_size = usb_is_device_get_video_in_size(curr_capture_type, usb_device_info->device_type); + memcpy(&target->capture_buf.is_twl_capture_received.video_capture_in, &capture_buf->is_twl_capture_received.video_capture_in, video_size); + if(read_size > video_size) { + size_t audio_size = ((read_size - video_size) / sizeof(ISTWLCaptureSoundData)) * sizeof(ISTWLCaptureAudioReceived); + memcpy(&target->capture_buf.is_twl_capture_received.audio_capture_in, &capture_buf->is_twl_capture_received.audio_capture_in, audio_size); + } + target->read = read_size; + target->time_in_buf = diff.count(); + capture_data->data_buffers.ReleaseWriterBuffer(); + } + else + capture_data->data_buffers.WriteToBuffer(capture_buf, read_size, diff.count(), &capture_data->status.device, curr_capture_type); if (capture_data->status.cooldown_curr_in) capture_data->status.cooldown_curr_in = capture_data->status.cooldown_curr_in - 1; diff --git a/source/CaptureDeviceSpecific/ISDevices/usb_is_device_communications.cpp b/source/CaptureDeviceSpecific/ISDevices/usb_is_device_communications.cpp index c25b570..4faa93a 100644 --- a/source/CaptureDeviceSpecific/ISDevices/usb_is_device_communications.cpp +++ b/source/CaptureDeviceSpecific/ISDevices/usb_is_device_communications.cpp @@ -2,7 +2,8 @@ #include "usb_is_device_communications.hpp" #include "usb_is_device_libusb.hpp" #include "usb_is_device_is_driver.hpp" -#include "is_twl_0x81_packet.h" +#include "is_twl_cap_init_seed_table.h" +#include "is_twl_cap_crc32_table.h" #include #include @@ -37,8 +38,8 @@ #define REG_USB_DMA_CONTROL_2 0x0C000028 #define REG_USB_BIU_CONTROL_2 0x0C0000A4 -#define DEFAULT_MAX_LENGTH_IS_TWL_VIDEO 0x00040000 -#define DEFAULT_MAX_LENGTH_IS_TWL_AUDIO 0x00007800 +#define DEFAULT_MAX_LENGTH_IS_TWL_VIDEO (5 * sizeof(ISTWLCaptureVideoInternalReceived)) +#define DEFAULT_MAX_LENGTH_IS_TWL_AUDIO (5 * 5 * sizeof(ISTWLCaptureAudioReceived)) enum is_nitro_packet_emulator_dir { IS_NITRO_PACKET_EMU_DIR_WRITE = 0x10, @@ -94,16 +95,18 @@ enum is_nitro_capture_command { enum is_twl_capture_command { IS_TWL_CAP_CMD_GET_CAP = 0x00, + IS_TWL_CAP_CMD_GET_ENC_DEC_SEEDS = 0x04, IS_TWL_CAP_CMD_GET_SERIAL = 0x13, IS_TWL_CAP_CMD_UNLOCK_COMMS = 0x1C, - IS_TWL_CAP_CMD_ENABLE_CAP_PRE_3 = 0x80, - IS_TWL_CAP_CMD_ENABLE_CAP_PRE_1 = 0x81, + IS_TWL_CAP_CMD_MNTR = 0x81, IS_TWL_CAP_CMD_ASK_CAPTURE_INFORMATION = 0x83, - IS_TWL_CAP_CMD_ENABLE_CAP = 0x84, - IS_TWL_CAP_CMD_ENABLE_CAP_PRE_2 = 0x85, + IS_TWL_CAP_CMD_SCTG = 0x84, + IS_TWL_CAP_CMD_TCZC = 0x85, IS_TWL_CAP_CMD_STOP_FRAME_READS = 0x88, IS_TWL_CAP_CMD_SET_LAST_FRAME_INFORMATION = 0x8B, - IS_TWL_CAP_CMD_ENABLE_CAP_PART_2 = 0x8C, + IS_TWL_CAP_CMD_ACTS = 0x8C, + IS_TWL_CAP_CMD_EPAC = 0x92, + IS_TWL_CAP_CMD_POST_EPAC = 0x93, }; enum is_nitro_emulator_forward_bits { @@ -207,7 +210,7 @@ static const is_device_usb_device usb_is_twl_cap_desc = { .write_pipe = "Pipe01", .read_pipe = "Pipe03", .product_id = 2, .manufacturer_id = 1, .device_type = IS_TWL_CAPTURE_DEVICE, .video_data_type = VIDEO_DATA_RGB, .max_usb_packet_size = IS_TWL_USB_PACKET_LIMIT, -.do_pipe_clear_reset = false, .audio_enabled = true, .max_audio_samples_size = sizeof(ISTWLCaptureAudioReceived) * TWL_CAPTURE_MAX_SAMPLES_CHUNK_NUM +.do_pipe_clear_reset = false, .audio_enabled = true, .max_audio_samples_size = sizeof(ISTWLCaptureSoundData) * TWL_CAPTURE_MAX_SAMPLES_CHUNK_NUM }; static const is_device_usb_device usb_is_twl_cap_desc_2 = { @@ -219,7 +222,7 @@ static const is_device_usb_device usb_is_twl_cap_desc_2 = { .write_pipe = "Pipe01", .read_pipe = "Pipe03", .product_id = 2, .manufacturer_id = 1, .device_type = IS_TWL_CAPTURE_DEVICE, .video_data_type = VIDEO_DATA_RGB, .max_usb_packet_size = IS_TWL_USB_PACKET_LIMIT, -.do_pipe_clear_reset = false, .audio_enabled = true, .max_audio_samples_size = sizeof(ISTWLCaptureAudioReceived) * TWL_CAPTURE_MAX_SAMPLES_CHUNK_NUM +.do_pipe_clear_reset = false, .audio_enabled = true, .max_audio_samples_size = sizeof(ISTWLCaptureSoundData) * TWL_CAPTURE_MAX_SAMPLES_CHUNK_NUM }; static const is_device_usb_device* all_usb_is_device_devices_desc[] = { @@ -258,6 +261,113 @@ static void fix_endianness_header(is_nitro_nec_packet_header* header) { header->address = to_le(header->address); } +static uint32_t get_crc32_data_comm(uint8_t* data, size_t size) { + uint32_t value = 0xFFFFFFFF; + for(int 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); + } + return ~value; +} + +static void apply_enc_dec_action_value(uint32_t action_value, uint32_t rotating_value, uint8_t* data, size_t size_u16) { + int increment = 0; + bool is_rot_odd = (rotating_value & 1) == 1; + uint16_t first_val = 0; + uint16_t last_val = 0; + if((action_value & 0xF000) == 0x1000) { + if(is_rot_odd) + increment = 0xFFFF6494; + increment += 0xA597; + } + else if((action_value & 0xF000) == 0x2000) { + if(is_rot_odd) + increment = 0x9B6C; + increment += 0x5A69; + } + switch((action_value & 0xFF) - 1) { + case 0: + for(int j = 0; j < size_u16; j++) + write_be16(data, read_le16(data, j), j); + break; + case 1: + for(int j = 0; j < size_u16; j++) { + write_le16(data, read_le16(data, j) ^ rotating_value, j); + rotating_value += increment; + } + break; + case 2: + for(int j = 0; j < size_u16; j++) { + write_le16(data, read_le16(data, j) + rotating_value, j); + rotating_value += increment; + } + break; + case 3: + for(int j = 0; j < size_u16; j++) { + write_le16(data, read_le16(data, j) - rotating_value, j); + rotating_value += increment; + } + break; + case 4: + for(int j = 0; j < (size_u16 / 2); j++) { + first_val = read_le16(data, j); + write_le16(data, read_le16(data, size_u16 - 1 - j), j); + write_le16(data, first_val, size_u16 - 1 - j); + } + break; + case 5: + first_val = read_le16(data); + for(int j = 0; j < (size_u16 - 1); j++) + write_le16(data, read_le16(data, j + 1), j); + write_le16(data, first_val, size_u16 - 1); + break; + case 6: + last_val = read_le16(data, size_u16 - 1); + for(int j = 0; j < (size_u16 - 1); j++) + write_le16(data, read_le16(data, size_u16 - 1 - j - 1), size_u16 - 1 - j); + write_le16(data, last_val); + break; + default: + break; + } +} + +static void enc_dec_table_add_usage(is_device_twl_enc_dec_table* table) { + table->rotating_value = rotate_bits_right(table->rotating_value); + table->num_iters_before_refresh -= 1; + if(table->num_iters_before_refresh > 0) + return; + table->num_iters_before_refresh = table->num_iters_full; + uint16_t base_table_value = table->action_values[0]; + for(int i = 0; i < table->num_values - 1; i++) + table->action_values[i] = table->action_values[i + 1]; + table->action_values[table->num_values - 1] = base_table_value; +} + +static void table_print(uint8_t* data, size_t size) { + /* + for(size_t i = 0; i < size; i++) { + printf("%02x ", data[i]); + if((i % 0x10) == 0xF) + printf("\n"); + } + printf("\n"); + */ +} + +static void enc_dec_table_apply_to_data(is_device_twl_enc_dec_table* table, uint8_t* data, size_t size, bool is_enc) { + table_print(data, size); + for(int i = 0; i < table->num_values; i++) { + int action_value = table->action_values[i]; + if(!is_enc) + action_value = table->action_values[table->num_values - 1 - i]; + apply_enc_dec_action_value(action_value, table->rotating_value, data, size / 2); + table_print(data, size); + } + enc_dec_table_add_usage(table); +} + // Write to bulk endpoint. Returns libusb error code static int bulk_out(is_device_device_handlers* handlers, const is_device_usb_device* usb_device_desc, uint8_t *buf, int length, int *transferred) { if(handlers->usb_handle) @@ -272,6 +382,13 @@ static int bulk_in(is_device_device_handlers* handlers, const is_device_usb_devi return is_driver_bulk_in(handlers, usb_device_desc, buf, length, transferred); } +// Read from ctrl endpoint. Returns libusb error code +static int ctrl_in(is_device_device_handlers* handlers, const is_device_usb_device* usb_device_desc, uint8_t *buf, int length, uint8_t request, uint16_t index, int *transferred) { + if(handlers->usb_handle) + return is_device_libusb_ctrl_in(handlers, usb_device_desc, buf, length, request, index, transferred); + return is_driver_ctrl_in(handlers, buf, length, request, index, transferred); +} + // Read from bulk endpoint. Returns libusb error code static void bulk_in_async(is_device_device_handlers* handlers, const is_device_usb_device* usb_device_desc, uint8_t *buf, int length, isd_async_callback_data* cb_data) { if(handlers->usb_handle) @@ -279,6 +396,20 @@ static void bulk_in_async(is_device_device_handlers* handlers, const is_device_u is_drive_async_in_start(handlers, usb_device_desc, buf, length, cb_data); } +// Prepare ctrl_in pipe, if needed... +static bool prepare_ctrl_in(is_device_device_handlers* handlers) { + if(handlers->usb_handle) + return true; + return is_driver_prepare_ctrl_in_handle(handlers); +} + +// Close ctrl_in pipe, if needed... +static void close_ctrl_in(is_device_device_handlers* handlers) { + if(handlers->usb_handle) + return; + is_driver_close_ctrl_in_handle(handlers); +} + static int return_and_delete(uint8_t* ptr, int value) { delete []ptr; return value; @@ -562,6 +693,39 @@ int SendWriteCommandU32(is_device_device_handlers* handlers, uint16_t command, u return SendWriteCommand(handlers, command, (uint8_t*)&buffer, sizeof(uint32_t), device_desc); } +static int AuthCtrlIn(is_device_device_handlers* handlers, const is_device_usb_device* device_desc) { + int ret = 0; + bool b_ret = true; + int num_bytes = 0; + uint8_t buffer[2]; + uint16_t auth_val = 0; + switch(device_desc->device_type) { + case IS_TWL_CAPTURE_DEVICE: + b_ret = prepare_ctrl_in(handlers); + if(!b_ret) + return LIBUSB_ERROR_INTERRUPTED; + ret = ctrl_in(handlers, device_desc, buffer, 2, 0xDF, 0, &num_bytes); + if(ret < 0) { + close_ctrl_in(handlers); + return ret; + } + if(num_bytes < 2) { + close_ctrl_in(handlers); + return LIBUSB_ERROR_INTERRUPTED; + } + auth_val = read_le16(buffer) - 0x644C; + ret = ctrl_in(handlers, device_desc, buffer, 1, 0xE3, ((auth_val >> 3) & 0x1C92) ^ auth_val, &num_bytes); + close_ctrl_in(handlers); + if(ret < 0) + return ret; + if((num_bytes < 1) || (buffer[0] != 0)) + return LIBUSB_ERROR_INTERRUPTED; + return LIBUSB_SUCCESS; + default: + return 0; + } +} + int GetDeviceSerial(is_device_device_handlers* handlers, uint8_t* buf, const is_device_usb_device* device_desc) { int ret = 0; uint32_t value = 0; @@ -571,6 +735,9 @@ int GetDeviceSerial(is_device_device_handlers* handlers, uint8_t* buf, const is_ case IS_NITRO_CAPTURE_DEVICE: return SendReadCommand(handlers, IS_NITRO_CAP_CMD_GET_SERIAL, buf, IS_DEVICE_REAL_SERIAL_NUMBER_SIZE, device_desc); case IS_TWL_CAPTURE_DEVICE: + ret = AuthCtrlIn(handlers, device_desc); + if(ret < 0) + return ret; ret = SendReadCommandU32(handlers, IS_TWL_CAP_CMD_UNLOCK_COMMS, &value, device_desc); if(ret < 0) return ret; @@ -653,11 +820,48 @@ int DisableLca2(is_device_device_handlers* handlers, const is_device_usb_device* return WriteNecMemU16(handlers, 0x0F84000A, 0, device_desc); } -int StartUsbCaptureDma(is_device_device_handlers* handlers, const is_device_usb_device* device_desc) { +static bool is_string_present_and_same(const std::string text, uint8_t* buffer, size_t text_pos = 0) { + if(text == "") + return true; + // Strings are pain. + // For some reason, under MSVC comparing strings doesn't work, + // but comparing the .c_str() representation does... + // Too bad that same method doesn't work when using GCC... :/ + // Solution? Write the string to a buffer, and compare the two... + uint8_t* str_check = new uint8_t[text.size()]; + write_string(str_check, text); + bool is_different = false; + for(size_t i = 0; i < text.size(); i++) { + if(str_check[i] != buffer[i + text_pos]) { + is_different = true; + break; + } + } + delete []str_check; + return !is_different; +} + +static int data_dec_and_check(is_device_twl_enc_dec_table* dec_table, uint8_t* buffer, size_t total_size, const std::string text = "", size_t text_pos = 0) { + enc_dec_table_apply_to_data(dec_table, buffer, total_size, false); + uint32_t crc32 = get_crc32_data_comm(buffer, total_size - 4); + uint32_t read_crc32 = read_le32(buffer, (total_size - 4) / 4); + if((crc32 != read_crc32) || (!is_string_present_and_same(text, buffer, text_pos))) + return LIBUSB_ERROR_INTERRUPTED; + return LIBUSB_SUCCESS; +} + +static void data_crc32_and_enc(is_device_twl_enc_dec_table* enc_table, uint8_t* buffer, size_t total_size, const std::string text = "", size_t text_pos = 0) { + if(text != "") + write_string(buffer + 4 + text_pos, text); + uint32_t crc32 = get_crc32_data_comm(buffer + 4, total_size - 4); + write_le32(buffer, crc32); + enc_dec_table_apply_to_data(enc_table, buffer, total_size, true); +} + +int StartUsbCaptureDma(is_device_device_handlers* handlers, const is_device_usb_device* device_desc, bool enable_sound_capture, is_device_twl_enc_dec_table* enc_table, is_device_twl_enc_dec_table* dec_table) { int ret = 0; - uint8_t buffer[0x200]; - uint8_t is_twl_handshake_buffer[0x10] = {0x39, 0xC5, 0x5E, 0xC1, 0xA3, 0x02, 0x1D, 0xA1, 0x1E, 0xE9, 0x2F, 0x35, 0x29, 0x98, 0x63, 0x6C}; - uint8_t is_twl_handshake_buffer_pre2[0x10] = {0x0C, 0xF7, 0x48, 0x2B, 0xE9, 0x5A, 0xA2, 0x3C, 0xE5, 0x0E, 0x1F, 0xEB, 0x1C, 0x71, 0xB8, 0xAE}; + uint8_t buffer[0xB4]; + uint32_t enabled_value = 0; switch(device_desc->device_type) { case IS_NITRO_EMULATOR_DEVICE: ret = WriteNecMemU16(handlers, REG_USB_DMA_CONTROL_2, 2, device_desc); @@ -667,22 +871,63 @@ int StartUsbCaptureDma(is_device_device_handlers* handlers, const is_device_usb_ case IS_NITRO_CAPTURE_DEVICE: return SendReadPacket(handlers, IS_NITRO_CAP_CMD_ENABLE_CAP, IS_NITRO_CAPTURE_PACKET_TYPE_DMA_CONTROL, 0, NULL, 1, device_desc, false); case IS_TWL_CAPTURE_DEVICE: - ret = SendWriteCommand(handlers, IS_TWL_CAP_CMD_ENABLE_CAP_PART_2, NULL, 0, device_desc); + if((enc_table == NULL) || (dec_table == NULL)) + return LIBUSB_ERROR_INTERRUPTED; + ret = SendWriteCommand(handlers, IS_TWL_CAP_CMD_ACTS, NULL, 0, device_desc); if(ret < 0) return ret; - ret = SendReadWriteCommand(handlers, IS_TWL_CAP_CMD_ENABLE_CAP_PRE_1, is_twl_0x81_packet, is_twl_0x81_packet_len, buffer, is_twl_0x81_packet_len, device_desc); + memset(buffer, 0, 0xB4); + write_le16(buffer, 0xB0, 2 + 2); + write_le16(buffer, 6, 3 + 2); + data_crc32_and_enc(enc_table, buffer, 0xB4, "MNTR", 8); + ret = SendReadWriteCommand(handlers, IS_TWL_CAP_CMD_MNTR, buffer, 0xB4, buffer, 0xB4, device_desc); if(ret < 0) return ret; - ret = SendWriteCommand(handlers, IS_TWL_CAP_CMD_ENABLE_CAP_PRE_2, is_twl_handshake_buffer_pre2, 0x10, device_desc); + ret = data_dec_and_check(dec_table, buffer, 0xB4, "MNTR", 8); if(ret < 0) return ret; - ret = SendReadCommand(handlers, IS_TWL_CAP_CMD_ENABLE_CAP_PRE_3, buffer, 0x200, device_desc); + ret = SendReadCommand(handlers, IS_TWL_CAP_CMD_EPAC, buffer, 8, device_desc); if(ret < 0) return ret; - ret = SendReadCommand(handlers, IS_TWL_CAP_CMD_ENABLE_CAP, buffer, 0x10, device_desc); + ret = data_dec_and_check(dec_table, buffer, 8, "EPAC"); if(ret < 0) return ret; - ret = SendReadWriteCommand(handlers, IS_TWL_CAP_CMD_ENABLE_CAP_PART_2, is_twl_handshake_buffer, sizeof(is_twl_handshake_buffer), buffer, 8, device_desc); + ret = SendReadCommand(handlers, IS_TWL_CAP_CMD_POST_EPAC, buffer, 8, device_desc); + if(ret < 0) + return ret; + ret = data_dec_and_check(dec_table, buffer, 8); + if(ret < 0) + return ret; + if(read_le32(buffer) != 0) + return LIBUSB_ERROR_INTERRUPTED; + memset(buffer, 0, 0x10); + data_crc32_and_enc(enc_table, buffer, 0x10, "TCZC"); + ret = SendWriteCommand(handlers, IS_TWL_CAP_CMD_TCZC, buffer, 0x10, device_desc); + if(ret < 0) + return ret; + ret = SendReadCommand(handlers, IS_TWL_CAP_CMD_SCTG, buffer, 0x10, device_desc); + if(ret < 0) + return ret; + ret = data_dec_and_check(dec_table, buffer, 0x10, "SCTG"); + if(ret < 0) + return ret; + memset(buffer, 0, 0x10); + enabled_value = 1; + if(enable_sound_capture) + enabled_value |= 0x10; + write_le32(buffer, enabled_value, 2); + // FPS. Seems to do nothing? Set to 60 / multiplier, + // but it has no effect... + write_le32(buffer, 60, 3); + data_crc32_and_enc(enc_table, buffer, 0x10, "ACTS"); + ret = SendReadWriteCommand(handlers, IS_TWL_CAP_CMD_ACTS, buffer, 0x10, buffer, 8, device_desc); + if(ret < 0) + return ret; + ret = data_dec_and_check(dec_table, buffer, 8); + if(ret < 0) + return ret; + if(read_le32(buffer) != 0) + return LIBUSB_ERROR_INTERRUPTED; return ret; default: return 0; @@ -924,6 +1169,61 @@ int ResetUSBDevice(is_device_device_handlers* handlers) { return is_device_is_driver_reset_device(handlers); } +static void prepare_enc_dec_table_data(is_device_twl_enc_dec_table* table, uint32_t seed_1, uint32_t seed_2, uint8_t num_iters, uint8_t num_values, bool is_enc) { + uint32_t rotating_value = seed_1 ^ seed_2 ^ 0x3CF0F03C; + table->rotating_value = rotating_value; + table->num_values = num_values; + table->num_iters_full = num_iters; + table->num_iters_before_refresh = num_iters; + uint8_t buffer[8]; + uint8_t values_buffer[8]; + for(int i = 0; i < 7; i++) + buffer[i] = i + 1; + buffer[7] = 7; + values_buffer[0] = 0; + for(int i = 1; i < num_values; i++) { + int divisor = (7 - (i - 1)); + int mod = rotating_value % divisor; + values_buffer[i] = buffer[mod]; + for(int j = mod; j < 7; j++) + buffer[j] = buffer[j + 1]; + rotating_value = rotate_bits_right(rotating_value); + } + int offset = 0; + if(!is_enc) + offset = 1; + for(int i = 0; i < num_values; i++) + table->action_values[i] = read_le16(is_twl_cap_init_seed_table, (values_buffer[i] * 2) + offset); +} + +int PrepareEncDecTable(is_device_device_handlers* handlers, is_device_twl_enc_dec_table* enc_table, is_device_twl_enc_dec_table* dec_table, const is_device_usb_device* device_desc) { + int ret = 0; + uint8_t buffer[0xC]; + uint32_t system_ms = ms_since_start(); + uint32_t incoming_seed = 0; + switch(device_desc->device_type) { + case IS_TWL_CAPTURE_DEVICE: + ret = AuthCtrlIn(handlers, device_desc); + if(ret < 0) + return ret; + write_le32(buffer, IS_TWL_CAP_CMD_GET_ENC_DEC_SEEDS); + write_le32(buffer, system_ms, 1); + write_le32(buffer, system_ms ^ 0x84327472, 2); + ret = SendWriteCommand(handlers, IS_TWL_CAP_CMD_GET_ENC_DEC_SEEDS, buffer, sizeof(buffer), device_desc); + if(ret < 0) + return ret; + ret = SendReadCommand(handlers, IS_TWL_CAP_CMD_GET_ENC_DEC_SEEDS, buffer, 4, device_desc); + if(ret < 0) + return ret; + incoming_seed = read_le32(buffer); + prepare_enc_dec_table_data(enc_table, system_ms, system_ms ^ 0x84327472 ^ 0xB0762D27, 0x10, 7, true); + prepare_enc_dec_table_data(dec_table, ~system_ms, incoming_seed ^ 0xD13F1EBB, 0x40, 3, false); + return ret; + default: + return 0; + } +} + void SetupISDeviceAsyncThread(is_device_device_handlers* handlers, void* user_data, std::thread* thread_ptr, bool* keep_going, ConsumerMutex* is_data_ready) { if(handlers->usb_handle) return is_device_libusb_start_thread(thread_ptr, keep_going); diff --git a/source/CaptureDeviceSpecific/ISDevices/usb_is_device_is_driver.cpp b/source/CaptureDeviceSpecific/ISDevices/usb_is_device_is_driver.cpp index 14891fb..66129b0 100644 --- a/source/CaptureDeviceSpecific/ISDevices/usb_is_device_is_driver.cpp +++ b/source/CaptureDeviceSpecific/ISDevices/usb_is_device_is_driver.cpp @@ -51,6 +51,16 @@ static bool read_is_driver_device_info(HANDLE handle, uint8_t* buffer, size_t si return DeviceIoControl(handle, 0x22000C, buffer, size, buffer, size, num_read, NULL); } +static bool is_driver_send_ioctl(HANDLE handle, uint8_t* buffer, size_t size, uint8_t request, uint16_t index, DWORD* num_read) { + uint8_t data[0x10]; + memset(data, 0, 0x10); + write_le32(data, 0x17); + write_le32(data, 2, 1); + write_le32(data, ((uint32_t)request) << 8, 2); + write_le32(data, index, 3); + return DeviceIoControl(handle, 0x220020, data, 0x10, 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); @@ -94,8 +104,8 @@ static bool is_driver_get_device_pid_vid(std::string path, uint16_t& out_vid, ui return false; if (num_read < 11) return false; - out_vid = buffer[8] + (buffer[9] << 8); - out_pid = buffer[10] + (buffer[11] << 8); + out_vid = read_le16(buffer, 4); + out_pid = read_le16(buffer, 5); return true; } @@ -104,6 +114,7 @@ static bool is_driver_setup_connection(is_device_device_handlers* handlers, std: handlers->mutex = NULL; handlers->write_handle = INVALID_HANDLE_VALUE; handlers->read_handle = INVALID_HANDLE_VALUE; + handlers->path = path; 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()); @@ -164,8 +175,33 @@ static void STDCALL OverlappedCompletionNothingRoutine(DWORD dwErrorCode, DWORD return; } +static void is_driver_close_handle(void** handle, void* default_value = INVALID_HANDLE_VALUE) { + #ifdef _WIN32 + if ((*handle) == default_value) + return; + CloseHandle(*handle); + *handle = default_value; + #endif +} + #endif +bool is_driver_prepare_ctrl_in_handle(is_device_device_handlers* handlers) { + #ifdef _WIN32 + HANDLE handle = CreateFile(handlers->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; + handlers->ctrl_in_handle = handle; + #endif + return true; +} + +void is_driver_close_ctrl_in_handle(is_device_device_handlers* handlers) { + #ifdef _WIN32 + is_driver_close_handle(&handlers->ctrl_in_handle); + #endif +} + is_device_device_handlers* is_driver_serial_reconnection(CaptureDevice* device) { is_device_device_handlers* final_handlers = NULL; #ifdef _WIN32 @@ -178,6 +214,7 @@ is_device_device_handlers* is_driver_serial_reconnection(CaptureDevice* device) final_handlers->mutex = handlers.mutex; final_handlers->read_handle = handlers.read_handle; final_handlers->write_handle = handlers.write_handle; + final_handlers->path = device->path; } else is_driver_end_connection(&handlers); @@ -188,15 +225,10 @@ is_device_device_handlers* is_driver_serial_reconnection(CaptureDevice* device) void is_driver_end_connection(is_device_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; + is_driver_close_handle(&handlers->write_handle); + is_driver_close_handle(&handlers->read_handle); + is_driver_close_handle(&handlers->ctrl_in_handle); + is_driver_close_handle(&handlers->mutex, NULL); #endif } @@ -265,6 +297,18 @@ int is_driver_bulk_in(is_device_device_handlers* handlers, const is_device_usb_d return LIBUSB_SUCCESS; } +// Read from ctrl, which also sends commands +int is_driver_ctrl_in(is_device_device_handlers* handlers, uint8_t* buf, int length, uint8_t request, uint16_t index, int* transferred) { + #ifdef _WIN32 + DWORD num_read = 0; + bool ret = is_driver_send_ioctl(handlers->ctrl_in_handle, buf, length, request, index, &num_read); + if(!ret) + return LIBUSB_ERROR_BUSY; + *transferred = num_read; + #endif + return LIBUSB_SUCCESS; +} + int is_drive_async_in_start(is_device_device_handlers* handlers, const is_device_usb_device* usb_device_desc, uint8_t* buf, int length, isd_async_callback_data* cb_data) { #ifdef _WIN32 cb_data->transfer_data_access.lock(); diff --git a/source/CaptureDeviceSpecific/ISDevices/usb_is_device_libusb.cpp b/source/CaptureDeviceSpecific/ISDevices/usb_is_device_libusb.cpp index 569e258..bf31edb 100644 --- a/source/CaptureDeviceSpecific/ISDevices/usb_is_device_libusb.cpp +++ b/source/CaptureDeviceSpecific/ISDevices/usb_is_device_libusb.cpp @@ -164,6 +164,14 @@ int is_device_libusb_bulk_in(is_device_device_handlers* handlers, const is_devic return libusb_bulk_transfer(handlers->usb_handle, usb_device_desc->ep_in, buf, length, transferred, usb_device_desc->bulk_timeout); } +// Read from ctrl_in +int is_device_libusb_ctrl_in(is_device_device_handlers* handlers, const is_device_usb_device* usb_device_desc, uint8_t* buf, int length, uint8_t request, uint16_t index, int* transferred) { + int ret = libusb_control_transfer(handlers->usb_handle, 0xC0, request, 0, index, buf, length, usb_device_desc->bulk_timeout); + if(ret >= 0) + *transferred = ret; + return ret; +} + void is_device_libusb_cancell_callback(isd_async_callback_data* cb_data) { cb_data->transfer_data_access.lock(); if(cb_data->transfer_data) diff --git a/source/CaptureDeviceSpecific/ISDevices/usb_is_twl_acquisition_capture.cpp b/source/CaptureDeviceSpecific/ISDevices/usb_is_twl_acquisition_capture.cpp index 3441b6d..cd14041 100644 --- a/source/CaptureDeviceSpecific/ISDevices/usb_is_twl_acquisition_capture.cpp +++ b/source/CaptureDeviceSpecific/ISDevices/usb_is_twl_acquisition_capture.cpp @@ -26,25 +26,26 @@ static int process_frame_and_read(CaptureData* capture_data, CaptureReceived* ca default: break; } - int num_available_frames = multiplier; + int num_available_frames = video_length / sizeof(ISTWLCaptureVideoInternalReceived); if(num_available_frames < multiplier) return 0; processed = true; int frame_next = num_available_frames - 1; last_read_frame_index += num_available_frames; - video_address = video_address + (frame_next * sizeof(ISTWLCaptureVideoReceived)); + video_address = video_address + (frame_next * sizeof(ISTWLCaptureVideoInternalReceived)); is_device_device_handlers* handlers = (is_device_device_handlers*)capture_data->handle; const is_device_usb_device* usb_device_desc = (const is_device_usb_device*)capture_data->status.device.descriptor; size_t video_processed_size = usb_is_device_get_video_in_size(curr_capture_type, IS_TWL_CAPTURE_DEVICE); - int ret = ReadFrame(handlers, (uint8_t*)&capture_buf->is_twl_capture_received.video_capture_in, 0, video_processed_size, usb_device_desc); + int ret = ReadFrame(handlers, (uint8_t*)&capture_buf->is_twl_capture_received.video_capture_in, video_address, video_processed_size, usb_device_desc); if(ret < 0) return ret; - int audio_diff_from_max = usb_device_desc->max_audio_samples_size - audio_length; + int max_audio_length = (multiplier * 5) * sizeof(ISTWLCaptureAudioReceived); + int audio_diff_from_max = max_audio_length - audio_length; if(audio_diff_from_max >= 0) audio_diff_from_max = 0; else { - audio_address -= audio_diff_from_max; - audio_length = usb_device_desc->max_audio_samples_size; + audio_address += audio_diff_from_max; + audio_length = max_audio_length; } ret = ReadFrame(handlers, (uint8_t*)&capture_buf->is_twl_capture_received.audio_capture_in, audio_address, audio_length, usb_device_desc); if(ret < 0) @@ -52,7 +53,7 @@ static int process_frame_and_read(CaptureData* capture_data, CaptureReceived* ca const auto curr_time = std::chrono::high_resolution_clock::now(); const std::chrono::duration diff = curr_time - (*clock_start); last_frame_length = diff.count(); - output_to_thread(capture_data, capture_buf, curr_capture_type, clock_start, video_processed_size + (audio_length / sizeof(ISTWLCaptureAudioReceived)) * (sizeof(ISTWLCaptureAudioReceived) - sizeof(uint32_t))); + output_to_thread(capture_data, capture_buf, curr_capture_type, clock_start, video_processed_size + ((audio_length / sizeof(ISTWLCaptureAudioReceived)) * sizeof(ISTWLCaptureSoundData))); return 0; } @@ -85,12 +86,17 @@ void is_twl_acquisition_capture_main_loop(CaptureData* capture_data, ISDeviceCap uint32_t video_length = 0; uint32_t audio_address = 0; uint32_t audio_length = 0; - ret = StartUsbCaptureDma(handlers, usb_device_desc); + is_device_twl_enc_dec_table enc_table, dec_table; + ret = PrepareEncDecTable(handlers, &enc_table, &dec_table, usb_device_desc); + if(ret < 0) { + capture_error_print(true, capture_data, "Enc Dec Table init: Failed"); + return; + } + ret = StartUsbCaptureDma(handlers, usb_device_desc, audio_enabled, &enc_table, &dec_table); if(ret < 0) { capture_error_print(true, capture_data, "Capture Start: Failed"); return; } - /* ret = AskFrameLengthPos(handlers, &video_address, &video_length, true, &audio_address, &audio_length, audio_enabled, usb_device_desc); if(ret < 0) { capture_error_print(true, capture_data, "Initial Frame Info Read: Failed"); @@ -101,26 +107,23 @@ void is_twl_acquisition_capture_main_loop(CaptureData* capture_data, ISDeviceCap capture_error_print(true, capture_data, "Initial Frame Info Set: Failed"); return; } - */ default_sleep(DEFAULT_FRAME_TIME_MS / SLEEP_FRAME_DIVIDER); while(capture_data->status.connected && capture_data->status.running) { bool processed = false; - /* ret = AskFrameLengthPos(handlers, &video_address, &video_length, true, &audio_address, &audio_length, audio_enabled, usb_device_desc); if(ret < 0) { capture_error_print(true, capture_data, "Frame Info Read: Failed"); return; } if(video_length > 0) { - */ ret = process_frame_and_read(capture_data, &is_device_capture_recv_data[0].buffer, curr_capture_type, curr_capture_speed, &clock_last_frame, last_read_frame_index, video_address, video_length, audio_address, audio_length, processed, last_frame_length); if(ret < 0) { capture_error_print(true, capture_data, "Frame Read: Error " + std::to_string(ret)); return; } - /* if(processed) { + curr_capture_speed = capture_data->status.capture_speed; ret = SetLastFrameInfo(handlers, video_address, video_length, audio_address, audio_length, usb_device_desc); if(ret < 0) { capture_error_print(true, capture_data, "Frame Info Set: Failed"); @@ -128,7 +131,6 @@ void is_twl_acquisition_capture_main_loop(CaptureData* capture_data, ISDeviceCap } } } - */ if(last_frame_length > 0) default_sleep((last_frame_length * 1000) / SLEEP_FRAME_DIVIDER); else diff --git a/source/cc3dsfs.cpp b/source/cc3dsfs.cpp index 22f23ab..5ff13d8 100755 --- a/source/cc3dsfs.cpp +++ b/source/cc3dsfs.cpp @@ -46,6 +46,7 @@ struct override_all_data { int loaded_profile = STARTUP_FILE_INDEX; bool mono_app = false; bool recovery_mode = false; + bool quit_on_first_connection_failure = false; }; static void ConsoleOutText(std::string full_text) { @@ -666,6 +667,7 @@ static bool parse_int_arg(int &index, int argc, char **argv, int &target, std::s int main(int argc, char **argv) { init_threads(); + init_start_time(); int page_up_id = -1; int page_down_id = -1; int enter_id = -1; @@ -710,6 +712,8 @@ int main(int argc, char **argv) { continue; if(parse_existence_arg(i, argv, override_data.auto_connect_to_first, true, "--auto_connect")) continue; + if(parse_existence_arg(i, argv, override_data.quit_on_first_connection_failure, true, "--close_first_on_failure")) + continue; if(parse_int_arg(i, argc, argv, override_data.loaded_profile, "--profile")) continue; #ifdef RASPI diff --git a/source/conversions.cpp b/source/conversions.cpp index ad23d41..4bc4b5d 100755 --- a/source/conversions.cpp +++ b/source/conversions.cpp @@ -315,11 +315,19 @@ bool convertAudioToOutput(std::int16_t *p_out, uint64_t &n_samples, const bool i #ifdef USE_IS_DEVICES_USB if(status->device.cc_type == CAPTURE_CONN_IS_NITRO) { base_ptr = (uint8_t*)p_in->is_twl_capture_received.audio_capture_in; + uint16_t* base_ptr16 = (uint16_t*)base_ptr; size_t size_real = n_samples * 2; - size_t size_packet_converted = sizeof(ISTWLCaptureAudioReceived) - sizeof(uint32_t); + size_t size_packet_converted = sizeof(ISTWLCaptureSoundData); size_t num_packets = size_real / size_packet_converted; for(int i = 0; i < num_packets; i++) - memcpy(base_ptr + (i * size_packet_converted), ((uint8_t*)&p_in->is_twl_capture_received.audio_capture_in[i]) + sizeof(uint32_t), size_packet_converted); + memcpy(base_ptr + (i * size_packet_converted), ((uint8_t*)&p_in->is_twl_capture_received.audio_capture_in[i].sound_data.data), size_packet_converted); + // Inverted L and R... + for(int i = 0; i < n_samples; i++) { + uint16_t r_sample = base_ptr16[(i * 2)]; + base_ptr16[(i * 2)] = base_ptr16[(i * 2) + 1]; + base_ptr16[(i * 2) + 1] = r_sample; + } + } #endif if(base_ptr == NULL) diff --git a/source/utils.cpp b/source/utils.cpp index 31a644d..73340ad 100755 --- a/source/utils.cpp +++ b/source/utils.cpp @@ -26,6 +26,7 @@ static bool checked_be_once = false; static bool _is_be = false; +std::chrono::time_point clock_start_program; bool is_big_endian(void) { if(checked_be_once) @@ -40,11 +41,11 @@ bool is_big_endian(void) { return _is_be; } -static uint32_t reverse_endianness(uint32_t value) { +uint32_t reverse_endianness(uint32_t value) { return ((value & 0xFF) << 24) | ((value & 0xFF00) << 8) | ((value & 0xFF0000) >> 8) | ((value & 0xFF000000) >> 24); } -static uint16_t reverse_endianness(uint16_t value) { +uint16_t reverse_endianness(uint16_t value) { return ((value & 0xFF) << 8) | ((value & 0xFF00) >> 8); } @@ -96,6 +97,85 @@ uint16_t from_be(uint16_t value) { return value; } +uint16_t read_le16(const uint8_t* data, size_t count, size_t multiplier) { + data += count * multiplier; + return data[0] | (data[1] << 8); +} + +uint16_t read_be16(const uint8_t* data, size_t count, size_t multiplier) { + data += count * multiplier; + return data[1] | (data[0] << 8); +} + +uint32_t read_le32(const uint8_t* data, size_t count, size_t multiplier) { + data += count * multiplier; + return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); +} + +uint32_t read_be32(const uint8_t* data, size_t count, size_t multiplier) { + data += count * multiplier; + return data[3] | (data[2] << 8) | (data[1] << 16) | (data[0] << 24); +} + +void write_le16(uint8_t* data, uint16_t value, size_t count, size_t multiplier) { + data += count * multiplier; + data[0] = value & 0xFF; + data[1] = (value >> 8) & 0xFF; +} + +void write_be16(uint8_t* data, uint16_t value, size_t count, size_t multiplier) { + data += count * multiplier; + data[0] = (value >> 8) & 0xFF; + data[1] = value & 0xFF; +} + +void write_le32(uint8_t* data, uint32_t value, size_t count, size_t multiplier) { + data += count * multiplier; + data[0] = value & 0xFF; + data[1] = (value >> 8) & 0xFF; + data[2] = (value >> 16) & 0xFF; + data[3] = (value >> 24) & 0xFF; +} + +void write_be32(uint8_t* data, uint32_t value, size_t count, size_t multiplier) { + data += count * multiplier; + data[0] = (value >> 24) & 0xFF; + data[1] = (value >> 16) & 0xFF; + data[2] = (value >> 8) & 0xFF; + data[3] = value & 0xFF; +} + +void write_string(uint8_t* data, std::string text) { + for(int i = 0; i < text.size(); i++) + data[i] = (uint8_t)text[i]; +} + +std::string read_string(uint8_t* data, size_t size) { + std::string out_str = ""; + out_str.reserve(size); + for(int i = 0; i < size; i++) + out_str[i] = (char)data[i]; + return out_str; +} + +uint32_t rotate_bits_left(uint32_t value) { + return (value << 1) | ((value & 0x80000000) >> 31); +} + +uint32_t rotate_bits_right(uint32_t value) { + return (value >> 1) | ((value & 1) << 31); +} + +void init_start_time() { + clock_start_program = std::chrono::high_resolution_clock::now(); +} + +uint32_t ms_since_start() { + const auto curr_time = std::chrono::high_resolution_clock::now(); + std::chrono::durationdiff = curr_time - clock_start_program; + return (uint32_t)(diff.count() * 1000); +} + std::string to_hex(uint16_t value) { const int num_digits = sizeof(value) * 2; char digits[num_digits];