mirror of
https://github.com/Lorenzooone/cc3dsfs.git
synced 2026-09-14 11:35:24 -05:00
Really basic frame read implementation for IS TWL Capture
Some checks are pending
CD / ${{ matrix.platform.name }} ${{ matrix.config.name }} (map[flags:-DBUILD_SHARED_LIBS=FALSE name:Static], map[artifact_name:linux32 flags:32 name:Linux GCC 32 os:ubuntu-latest]) (push) Waiting to run
CD / ${{ matrix.platform.name }} ${{ matrix.config.name }} (map[flags:-DBUILD_SHARED_LIBS=FALSE name:Static], map[artifact_name:linux64 flags:64 name:Linux GCC x64 os:ubuntu-latest]) (push) Waiting to run
CD / ${{ matrix.platform.name }} ${{ matrix.config.name }} (map[flags:-DBUILD_SHARED_LIBS=FALSE name:Static], map[artifact_name:linuxarm32 flags:arm32 name:Linux GCC ARM 32 os:ubuntu-latest]) (push) Waiting to run
CD / ${{ matrix.platform.name }} ${{ matrix.config.name }} (map[flags:-DBUILD_SHARED_LIBS=FALSE name:Static], map[artifact_name:linuxarm64 flags:arm64 name:Linux GCC ARM 64 os:ubuntu-latest]) (push) Waiting to run
CD / ${{ matrix.platform.name }} ${{ matrix.config.name }} (map[flags:-DBUILD_SHARED_LIBS=FALSE name:Static], map[artifact_name:macos name:macOS Apple Silicon os:macos-14]) (push) Waiting to run
CD / ${{ matrix.platform.name }} ${{ matrix.config.name }} (map[flags:-DBUILD_SHARED_LIBS=FALSE name:Static], map[artifact_name:win32 flags:-A Win32 name:Windows VS2022 Win32 os:windows-2022]) (push) Waiting to run
CD / ${{ matrix.platform.name }} ${{ matrix.config.name }} (map[flags:-DBUILD_SHARED_LIBS=FALSE name:Static], map[artifact_name:win64 flags:-A x64 name:Windows VS2022 x64 os:windows-2022]) (push) Waiting to run
CD / ${{ matrix.platform.name }} ${{ matrix.config.name }} (map[flags:-DBUILD_SHARED_LIBS=FALSE name:Static], map[artifact_name:winarm64 flags:-A ARM64 name:Windows VS2022 ARM os:windows-2022]) (push) Waiting to run
CD / Create Pi Mono Setup (push) Blocked by required conditions
CD / Publishing (push) Blocked by required conditions
Some checks are pending
CD / ${{ matrix.platform.name }} ${{ matrix.config.name }} (map[flags:-DBUILD_SHARED_LIBS=FALSE name:Static], map[artifact_name:linux32 flags:32 name:Linux GCC 32 os:ubuntu-latest]) (push) Waiting to run
CD / ${{ matrix.platform.name }} ${{ matrix.config.name }} (map[flags:-DBUILD_SHARED_LIBS=FALSE name:Static], map[artifact_name:linux64 flags:64 name:Linux GCC x64 os:ubuntu-latest]) (push) Waiting to run
CD / ${{ matrix.platform.name }} ${{ matrix.config.name }} (map[flags:-DBUILD_SHARED_LIBS=FALSE name:Static], map[artifact_name:linuxarm32 flags:arm32 name:Linux GCC ARM 32 os:ubuntu-latest]) (push) Waiting to run
CD / ${{ matrix.platform.name }} ${{ matrix.config.name }} (map[flags:-DBUILD_SHARED_LIBS=FALSE name:Static], map[artifact_name:linuxarm64 flags:arm64 name:Linux GCC ARM 64 os:ubuntu-latest]) (push) Waiting to run
CD / ${{ matrix.platform.name }} ${{ matrix.config.name }} (map[flags:-DBUILD_SHARED_LIBS=FALSE name:Static], map[artifact_name:macos name:macOS Apple Silicon os:macos-14]) (push) Waiting to run
CD / ${{ matrix.platform.name }} ${{ matrix.config.name }} (map[flags:-DBUILD_SHARED_LIBS=FALSE name:Static], map[artifact_name:win32 flags:-A Win32 name:Windows VS2022 Win32 os:windows-2022]) (push) Waiting to run
CD / ${{ matrix.platform.name }} ${{ matrix.config.name }} (map[flags:-DBUILD_SHARED_LIBS=FALSE name:Static], map[artifact_name:win64 flags:-A x64 name:Windows VS2022 x64 os:windows-2022]) (push) Waiting to run
CD / ${{ matrix.platform.name }} ${{ matrix.config.name }} (map[flags:-DBUILD_SHARED_LIBS=FALSE name:Static], map[artifact_name:winarm64 flags:-A ARM64 name:Windows VS2022 ARM os:windows-2022]) (push) Waiting to run
CD / Create Pi Mono Setup (push) Blocked by required conditions
CD / Publishing (push) Blocked by required conditions
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
#include "usb_is_device_acquisition_general.hpp"
|
||||
#include "usb_is_nitro_acquisition_capture.hpp"
|
||||
#include "usb_is_nitro_acquisition_emulator.hpp"
|
||||
#include "usb_is_twl_acquisition_capture.hpp"
|
||||
#include "usb_generic.hpp"
|
||||
|
||||
#include <libusb.h>
|
||||
@@ -44,6 +45,8 @@ static bool initial_cleanup(const is_device_usb_device* usb_device_desc, is_devi
|
||||
return initial_cleanup_emulator(usb_device_desc, handlers) != LIBUSB_SUCCESS;
|
||||
case IS_NITRO_CAPTURE_DEVICE:
|
||||
return initial_cleanup_capture(usb_device_desc, handlers) != LIBUSB_SUCCESS;
|
||||
case IS_TWL_CAPTURE_DEVICE:
|
||||
return initial_cleanup_twl_capture(usb_device_desc, handlers) != LIBUSB_SUCCESS;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -67,11 +70,11 @@ std::string get_serial(const is_device_usb_device* usb_device_desc, is_device_de
|
||||
}
|
||||
|
||||
void is_device_insert_device(std::vector<CaptureDevice>& devices_list, is_device_device_handlers* handlers, const is_device_usb_device* usb_device_desc, int& curr_serial_extra_id_is_device, std::string path) {
|
||||
devices_list.emplace_back(get_serial(usb_device_desc, handlers, curr_serial_extra_id_is_device), usb_device_desc->name, usb_device_desc->long_name, path, CAPTURE_CONN_IS_NITRO, (void*)usb_device_desc, false, false, false, WIDTH_DS, HEIGHT_DS + HEIGHT_DS, 0, 0, 0, 0, 0, HEIGHT_DS, usb_device_desc->video_data_type);
|
||||
devices_list.emplace_back(get_serial(usb_device_desc, handlers, curr_serial_extra_id_is_device), usb_device_desc->name, usb_device_desc->long_name, path, CAPTURE_CONN_IS_NITRO, (void*)usb_device_desc, false, false, usb_device_desc->audio_enabled, WIDTH_DS, HEIGHT_DS + HEIGHT_DS, usb_device_desc->max_audio_samples_size, 0, 0, 0, 0, HEIGHT_DS, usb_device_desc->video_data_type);
|
||||
}
|
||||
|
||||
void is_device_insert_device(std::vector<CaptureDevice>& devices_list, is_device_device_handlers* handlers, const is_device_usb_device* usb_device_desc, int& curr_serial_extra_id_is_device) {
|
||||
devices_list.emplace_back(get_serial(usb_device_desc, handlers, curr_serial_extra_id_is_device), usb_device_desc->name, usb_device_desc->long_name, CAPTURE_CONN_IS_NITRO, (void*)usb_device_desc, false, false, false, WIDTH_DS, HEIGHT_DS + HEIGHT_DS, 0, 0, 0, 0, 0, HEIGHT_DS, usb_device_desc->video_data_type);
|
||||
devices_list.emplace_back(get_serial(usb_device_desc, handlers, curr_serial_extra_id_is_device), usb_device_desc->name, usb_device_desc->long_name, CAPTURE_CONN_IS_NITRO, (void*)usb_device_desc, false, false, usb_device_desc->audio_enabled, WIDTH_DS, HEIGHT_DS + HEIGHT_DS, usb_device_desc->max_audio_samples_size, 0, 0, 0, 0, HEIGHT_DS, usb_device_desc->video_data_type);
|
||||
}
|
||||
|
||||
static is_device_device_handlers* usb_find_by_serial_number(const is_device_usb_device* usb_device_desc, CaptureDevice* device) {
|
||||
@@ -135,6 +138,8 @@ 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);
|
||||
if((capture_type == CAPTURE_SCREENS_TOP) || (capture_type == CAPTURE_SCREENS_BOTTOM))
|
||||
return sizeof(ISNitroEmulatorVideoInputData) / 2;
|
||||
return sizeof(ISNitroEmulatorVideoInputData);
|
||||
@@ -185,6 +190,8 @@ int EndAcquisition(CaptureData* capture_data, ISDeviceCaptureReceivedData* is_de
|
||||
return EndAcquisitionEmulator(capture_data, is_device_capture_recv_data, do_drain_frames, start_frames, capture_type);
|
||||
case IS_NITRO_CAPTURE_DEVICE:
|
||||
return EndAcquisitionCapture(capture_data, is_device_capture_recv_data);
|
||||
case IS_TWL_CAPTURE_DEVICE:
|
||||
return EndAcquisitionTWLCapture(capture_data, is_device_capture_recv_data);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -196,18 +203,20 @@ int EndAcquisition(const is_device_usb_device* usb_device_desc, is_device_device
|
||||
return EndAcquisitionEmulator(usb_device_desc, handlers, do_drain_frames, start_frames, capture_type);
|
||||
case IS_NITRO_CAPTURE_DEVICE:
|
||||
return EndAcquisitionCapture(usb_device_desc, handlers);
|
||||
case IS_TWL_CAPTURE_DEVICE:
|
||||
return EndAcquisitionTWLCapture(usb_device_desc, handlers);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void output_to_thread(CaptureData* capture_data, CaptureReceived* capture_buf, CaptureScreensType curr_capture_type, std::chrono::time_point<std::chrono::high_resolution_clock>* clock_start) {
|
||||
void output_to_thread(CaptureData* capture_data, CaptureReceived* capture_buf, CaptureScreensType curr_capture_type, std::chrono::time_point<std::chrono::high_resolution_clock>* clock_start, size_t read_size) {
|
||||
// Output to the other threads...
|
||||
const is_device_usb_device* usb_device_info = (const is_device_usb_device*)capture_data->status.device.descriptor;
|
||||
const auto curr_time = std::chrono::high_resolution_clock::now();
|
||||
const std::chrono::duration<double> diff = curr_time - (*clock_start);
|
||||
*clock_start = curr_time;
|
||||
capture_data->data_buffers.WriteToBuffer(capture_buf, usb_is_device_get_video_in_size(curr_capture_type, usb_device_info->device_type), diff.count(), &capture_data->status.device, curr_capture_type);
|
||||
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;
|
||||
@@ -215,6 +224,11 @@ static void output_to_thread(CaptureData* capture_data, CaptureReceived* capture
|
||||
capture_data->status.audio_wait.unlock();
|
||||
}
|
||||
|
||||
static void output_to_thread(CaptureData* capture_data, CaptureReceived* capture_buf, CaptureScreensType curr_capture_type, std::chrono::time_point<std::chrono::high_resolution_clock>* clock_start) {
|
||||
const is_device_usb_device* usb_device_info = (const is_device_usb_device*)capture_data->status.device.descriptor;
|
||||
output_to_thread(capture_data, capture_buf, curr_capture_type, clock_start, usb_is_device_get_video_in_size(curr_capture_type, usb_device_info->device_type));
|
||||
}
|
||||
|
||||
int is_device_read_frame_and_output(CaptureData* capture_data, CaptureReceived* capture_buf, CaptureScreensType curr_capture_type, std::chrono::time_point<std::chrono::high_resolution_clock> &clock_start) {
|
||||
const is_device_usb_device* usb_device_info = (const is_device_usb_device*)capture_data->status.device.descriptor;
|
||||
int ret = ReadFrame((is_device_device_handlers*)capture_data->handle, (uint8_t*)capture_buf, usb_is_device_get_video_in_size(curr_capture_type, usb_device_info->device_type), usb_device_info);
|
||||
@@ -428,6 +442,9 @@ void is_device_acquisition_main_loop(CaptureData* capture_data) {
|
||||
case IS_NITRO_CAPTURE_DEVICE:
|
||||
is_nitro_acquisition_capture_main_loop(capture_data, is_device_capture_recv_data);
|
||||
break;
|
||||
case IS_TWL_CAPTURE_DEVICE:
|
||||
is_twl_acquisition_capture_main_loop(capture_data, is_device_capture_recv_data);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#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 <libusb.h>
|
||||
#include <cstring>
|
||||
@@ -36,6 +37,9 @@
|
||||
#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
|
||||
|
||||
enum is_nitro_packet_emulator_dir {
|
||||
IS_NITRO_PACKET_EMU_DIR_WRITE = 0x10,
|
||||
IS_NITRO_PACKET_EMU_DIR_READ = 0x11
|
||||
@@ -59,7 +63,8 @@ enum is_device_packet_type {
|
||||
IS_NITRO_CAPTURE_PACKET_TYPE_DMA_CONTROL = 2,
|
||||
IS_NITRO_PACKET_TYPE_CAPTURE = 3,
|
||||
IS_NITRO_PACKET_TYPE_AGB_CART_ROM = 4,
|
||||
IS_NITRO_PACKET_TYPE_AGB_BUS2 = 5
|
||||
IS_NITRO_PACKET_TYPE_AGB_BUS2 = 5,
|
||||
IS_TWL_PACKET_TYPE_FRAME = 7,
|
||||
};
|
||||
|
||||
enum is_nitro_emulator_command {
|
||||
@@ -88,8 +93,17 @@ enum is_nitro_capture_command {
|
||||
};
|
||||
|
||||
enum is_twl_capture_command {
|
||||
IS_TWL_CAP_CMD_GET_CAP = 0x00,
|
||||
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_ASK_CAPTURE_INFORMATION = 0x83,
|
||||
IS_TWL_CAP_CMD_ENABLE_CAP = 0x84,
|
||||
IS_TWL_CAP_CMD_ENABLE_CAP_PRE_2 = 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,
|
||||
};
|
||||
|
||||
enum is_nitro_emulator_forward_bits {
|
||||
@@ -126,6 +140,26 @@ struct PACKED is_device_rw_packet_header {
|
||||
uint32_t length_w;
|
||||
uint32_t length_r;
|
||||
};
|
||||
|
||||
struct PACKED is_twl_ask_capture_information_packet {
|
||||
uint32_t unk[2];
|
||||
uint32_t max_length_video;
|
||||
uint32_t unk2[2];
|
||||
uint32_t max_length_audio;
|
||||
uint32_t unk3[0x10];
|
||||
};
|
||||
// These two are probably the same struct, with different fields used for
|
||||
// different packets...
|
||||
// I say probably, that's why I keep them separate.
|
||||
struct PACKED is_twl_capture_information_packet {
|
||||
uint32_t available_video_length;
|
||||
uint32_t video_start_address;
|
||||
uint32_t unk;
|
||||
uint32_t available_audio_length;
|
||||
uint32_t audio_start_address;
|
||||
uint32_t unk2;
|
||||
uint32_t unk3[0x10];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
static const is_device_usb_device usb_is_nitro_emu_rare_desc = {
|
||||
@@ -137,7 +171,7 @@ static const is_device_usb_device usb_is_nitro_emu_rare_desc = {
|
||||
.write_pipe = "Pipe00", .read_pipe = "Pipe01",
|
||||
.product_id = 2, .manufacturer_id = 1, .device_type = IS_NITRO_EMULATOR_DEVICE,
|
||||
.video_data_type = VIDEO_DATA_BGR, .max_usb_packet_size = IS_NITRO_USB_PACKET_LIMIT,
|
||||
.do_pipe_clear_reset = true
|
||||
.do_pipe_clear_reset = true, .audio_enabled = false, .max_audio_samples_size = 0
|
||||
};
|
||||
|
||||
static const is_device_usb_device usb_is_nitro_emu_common_desc = {
|
||||
@@ -149,7 +183,7 @@ static const is_device_usb_device usb_is_nitro_emu_common_desc = {
|
||||
.write_pipe = "Pipe00", .read_pipe = "Pipe01",
|
||||
.product_id = 2, .manufacturer_id = 1, .device_type = IS_NITRO_EMULATOR_DEVICE,
|
||||
.video_data_type = VIDEO_DATA_BGR, .max_usb_packet_size = IS_NITRO_USB_PACKET_LIMIT,
|
||||
.do_pipe_clear_reset = true
|
||||
.do_pipe_clear_reset = true, .audio_enabled = false, .max_audio_samples_size = 0
|
||||
};
|
||||
|
||||
static const is_device_usb_device usb_is_nitro_cap_desc = {
|
||||
@@ -161,11 +195,11 @@ static const is_device_usb_device usb_is_nitro_cap_desc = {
|
||||
.write_pipe = "Pipe00", .read_pipe = "Pipe01",
|
||||
.product_id = 2, .manufacturer_id = 1, .device_type = IS_NITRO_CAPTURE_DEVICE,
|
||||
.video_data_type = VIDEO_DATA_BGR, .max_usb_packet_size = IS_NITRO_USB_PACKET_LIMIT,
|
||||
.do_pipe_clear_reset = true
|
||||
.do_pipe_clear_reset = true, .audio_enabled = false, .max_audio_samples_size = 0
|
||||
};
|
||||
|
||||
static const is_device_usb_device usb_is_twl_cap_desc = {
|
||||
.name = "ISTC", .long_name = "IS TWL Capture",
|
||||
.name = "ISTCD", .long_name = "IS TWL Capture (Dev)",
|
||||
.vid = 0x0f6e, .pid = 0x0501,
|
||||
.default_config = 1, .default_interface = 0,
|
||||
.bulk_timeout = 500,
|
||||
@@ -173,11 +207,11 @@ 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
|
||||
.do_pipe_clear_reset = false, .audio_enabled = true, .max_audio_samples_size = sizeof(ISTWLCaptureAudioReceived) * TWL_CAPTURE_MAX_SAMPLES_CHUNK_NUM
|
||||
};
|
||||
|
||||
static const is_device_usb_device usb_is_twl_cap_desc_2 = {
|
||||
.name = "ISTC", .long_name = "IS TWL Capture",
|
||||
.name = "ISTCR", .long_name = "IS TWL Capture (Retail)",
|
||||
.vid = 0x0f6e, .pid = 0x0502,
|
||||
.default_config = 1, .default_interface = 0,
|
||||
.bulk_timeout = 500,
|
||||
@@ -185,7 +219,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
|
||||
.do_pipe_clear_reset = false, .audio_enabled = true, .max_audio_samples_size = sizeof(ISTWLCaptureAudioReceived) * TWL_CAPTURE_MAX_SAMPLES_CHUNK_NUM
|
||||
};
|
||||
|
||||
static const is_device_usb_device* all_usb_is_device_devices_desc[] = {
|
||||
@@ -510,6 +544,10 @@ int SendWriteCommand(is_device_device_handlers* handlers, uint16_t command, uint
|
||||
return SendWritePacket(handlers, command, IS_NITRO_PACKET_TYPE_COMMAND, 0, buf, length, device_desc);
|
||||
}
|
||||
|
||||
int SendReadWriteCommand(is_device_device_handlers* handlers, uint16_t command, uint8_t* out_buf, int out_length, uint8_t* in_buf, int in_length, const is_device_usb_device* device_desc) {
|
||||
return SendReadWritePacket(handlers, command, IS_NITRO_PACKET_TYPE_COMMAND, 0, out_buf, out_length, in_buf, in_length, device_desc);
|
||||
}
|
||||
|
||||
int SendReadCommandU32(is_device_device_handlers* handlers, uint16_t command, uint32_t* out, const is_device_usb_device* device_desc) {
|
||||
uint32_t buffer;
|
||||
int ret = SendReadCommand(handlers, command, (uint8_t*)&buffer, sizeof(uint32_t), device_desc);
|
||||
@@ -617,6 +655,9 @@ int DisableLca2(is_device_device_handlers* handlers, const is_device_usb_device*
|
||||
|
||||
int StartUsbCaptureDma(is_device_device_handlers* handlers, const is_device_usb_device* device_desc) {
|
||||
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};
|
||||
switch(device_desc->device_type) {
|
||||
case IS_NITRO_EMULATOR_DEVICE:
|
||||
ret = WriteNecMemU16(handlers, REG_USB_DMA_CONTROL_2, 2, device_desc);
|
||||
@@ -625,6 +666,24 @@ int StartUsbCaptureDma(is_device_device_handlers* handlers, const is_device_usb_
|
||||
return WriteNecMemU16(handlers, REG_USB_BIU_CONTROL_2, 1, device_desc);
|
||||
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(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);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
ret = SendWriteCommand(handlers, IS_TWL_CAP_CMD_ENABLE_CAP_PRE_2, is_twl_handshake_buffer_pre2, 0x10, device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
ret = SendReadCommand(handlers, IS_TWL_CAP_CMD_ENABLE_CAP_PRE_3, buffer, 0x200, device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
ret = SendReadCommand(handlers, IS_TWL_CAP_CMD_ENABLE_CAP, buffer, 0x10, device_desc);
|
||||
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);
|
||||
return ret;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -640,6 +699,8 @@ int StopUsbCaptureDma(is_device_device_handlers* handlers, const is_device_usb_d
|
||||
return WriteNecMemU16(handlers, REG_USB_BIU_CONTROL_2, 0, device_desc);
|
||||
case IS_NITRO_CAPTURE_DEVICE:
|
||||
return SendReadPacket(handlers, IS_NITRO_CAP_CMD_ENABLE_CAP, IS_NITRO_CAPTURE_PACKET_TYPE_DMA_CONTROL, 0, NULL, 0, device_desc);
|
||||
case IS_TWL_CAPTURE_DEVICE:
|
||||
return SendWriteCommand(handlers, IS_TWL_CAP_CMD_STOP_FRAME_READS, NULL, 0, device_desc);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -798,6 +859,46 @@ int ResetFullHardware(is_device_device_handlers* handlers, const is_device_usb_d
|
||||
}
|
||||
}
|
||||
|
||||
int AskFrameLengthPos(is_device_device_handlers* handlers, uint32_t* video_address, uint32_t* video_length, bool video_enabled, uint32_t* audio_address, uint32_t* audio_length, bool audio_enabled, const is_device_usb_device* device_desc) {
|
||||
if(device_desc->device_type != IS_TWL_CAPTURE_DEVICE)
|
||||
return 0;
|
||||
is_twl_ask_capture_information_packet out_packet;
|
||||
is_twl_capture_information_packet in_packet;
|
||||
memset(&out_packet, 0, sizeof(out_packet));
|
||||
if(video_enabled)
|
||||
out_packet.max_length_video = to_le((uint32_t)DEFAULT_MAX_LENGTH_IS_TWL_VIDEO);
|
||||
if(audio_enabled)
|
||||
out_packet.max_length_audio = to_le((uint32_t)DEFAULT_MAX_LENGTH_IS_TWL_AUDIO);
|
||||
int ret = SendReadWriteCommand(handlers, IS_TWL_CAP_CMD_ASK_CAPTURE_INFORMATION, (uint8_t*)&out_packet, sizeof(out_packet), (uint8_t*)&in_packet, sizeof(in_packet), device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
*video_length = from_le(in_packet.available_video_length);
|
||||
*video_address = from_le(in_packet.video_start_address);
|
||||
*audio_length = from_le(in_packet.available_audio_length);
|
||||
*audio_address = from_le(in_packet.audio_start_address);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SetLastFrameInfo(is_device_device_handlers* handlers, uint32_t video_address, uint32_t video_length, uint32_t audio_address, uint32_t audio_length, const is_device_usb_device* device_desc) {
|
||||
if(device_desc->device_type != IS_TWL_CAPTURE_DEVICE)
|
||||
return 0;
|
||||
is_twl_capture_information_packet out_packet;
|
||||
memset(&out_packet, 0, sizeof(out_packet));
|
||||
out_packet.available_video_length = to_le(video_length);
|
||||
out_packet.video_start_address = to_le(video_address);
|
||||
out_packet.available_audio_length = to_le(audio_length);
|
||||
out_packet.audio_start_address = to_le(audio_address);
|
||||
return SendWriteCommand(handlers, IS_TWL_CAP_CMD_SET_LAST_FRAME_INFORMATION, (uint8_t*)&out_packet, sizeof(out_packet), device_desc);
|
||||
}
|
||||
|
||||
int ReadFrame(is_device_device_handlers* handlers, uint8_t* buf, uint32_t address, uint32_t length, const is_device_usb_device* device_desc) {
|
||||
if(device_desc->device_type != IS_TWL_CAPTURE_DEVICE)
|
||||
return 0;
|
||||
if(length == 0)
|
||||
return 0;
|
||||
return SendReadPacket(handlers, IS_TWL_CAP_CMD_GET_CAP, IS_TWL_PACKET_TYPE_FRAME, address, buf, length, device_desc);
|
||||
}
|
||||
|
||||
int ReadFrame(is_device_device_handlers* handlers, uint8_t* buf, int length, const is_device_usb_device* device_desc) {
|
||||
// Maybe making this async would be better for lower end hardware...
|
||||
int num_bytes = 0;
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
#include "devicecapture.hpp"
|
||||
#include "usb_is_device_communications.hpp"
|
||||
#include "usb_is_device_acquisition_general.hpp"
|
||||
#include "usb_is_twl_acquisition_capture.hpp"
|
||||
|
||||
// Code created by analyzing the USB packets sent and received by the IS TWL Capture device.
|
||||
|
||||
#define RESET_TIMEOUT 4.0
|
||||
#define SLEEP_RESET_TIME_MS 2000
|
||||
#define DEFAULT_FRAME_TIME_MS 16.7
|
||||
#define SLEEP_FRAME_DIVIDER 4
|
||||
|
||||
static int process_frame_and_read(CaptureData* capture_data, CaptureReceived* capture_buf, CaptureScreensType curr_capture_type, CaptureSpeedsType curr_capture_speed, std::chrono::time_point<std::chrono::high_resolution_clock>* clock_start, uint32_t &last_read_frame_index, uint32_t video_address, uint32_t video_length, uint32_t audio_address, uint32_t audio_length, bool &processed, float &last_frame_length) {
|
||||
processed = false;
|
||||
int multiplier = 1;
|
||||
switch(curr_capture_speed) {
|
||||
case CAPTURE_SPEEDS_HALF:
|
||||
multiplier = 2;
|
||||
break;
|
||||
case CAPTURE_SPEEDS_THIRD:
|
||||
multiplier = 3;
|
||||
break;
|
||||
case CAPTURE_SPEEDS_QUARTER:
|
||||
multiplier = 4;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
int num_available_frames = multiplier;
|
||||
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));
|
||||
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);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
int audio_diff_from_max = usb_device_desc->max_audio_samples_size - 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;
|
||||
}
|
||||
ret = ReadFrame(handlers, (uint8_t*)&capture_buf->is_twl_capture_received.audio_capture_in, audio_address, audio_length, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
const auto curr_time = std::chrono::high_resolution_clock::now();
|
||||
const std::chrono::duration<double> diff = curr_time - (*clock_start);
|
||||
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)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int initial_cleanup_twl_capture(const is_device_usb_device* usb_device_desc, is_device_device_handlers* handlers) {
|
||||
//EndAcquisition(handlers, usb_device_desc, false, 0, CAPTURE_SCREENS_BOTH);
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
int EndAcquisitionTWLCapture(CaptureData* capture_data, ISDeviceCaptureReceivedData* is_device_capture_recv_data) {
|
||||
wait_all_is_device_transfers_done(capture_data, is_device_capture_recv_data);
|
||||
return EndAcquisitionTWLCapture((const is_device_usb_device*)capture_data->status.device.descriptor, (is_device_device_handlers*)capture_data->handle);
|
||||
}
|
||||
|
||||
int EndAcquisitionTWLCapture(const is_device_usb_device* usb_device_desc, is_device_device_handlers* handlers) {
|
||||
return StopUsbCaptureDma(handlers, usb_device_desc);
|
||||
}
|
||||
|
||||
void is_twl_acquisition_capture_main_loop(CaptureData* capture_data, ISDeviceCaptureReceivedData* is_device_capture_recv_data) {
|
||||
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;
|
||||
bool is_acquisition_off = true;
|
||||
uint32_t last_read_frame_index = 0;
|
||||
CaptureScreensType curr_capture_type = capture_data->status.capture_type;
|
||||
CaptureSpeedsType curr_capture_speed = capture_data->status.capture_speed;
|
||||
bool audio_enabled = true;
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> clock_last_frame = std::chrono::high_resolution_clock::now();
|
||||
float last_frame_length = 0.0;
|
||||
int ret = 0;
|
||||
uint32_t video_address = 0;
|
||||
uint32_t video_length = 0;
|
||||
uint32_t audio_address = 0;
|
||||
uint32_t audio_length = 0;
|
||||
ret = StartUsbCaptureDma(handlers, usb_device_desc);
|
||||
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");
|
||||
return;
|
||||
}
|
||||
ret = SetLastFrameInfo(handlers, video_address, video_length, audio_address, audio_length, usb_device_desc);
|
||||
if(ret < 0) {
|
||||
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) {
|
||||
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");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
if(last_frame_length > 0)
|
||||
default_sleep((last_frame_length * 1000) / SLEEP_FRAME_DIVIDER);
|
||||
else
|
||||
default_sleep(DEFAULT_FRAME_TIME_MS / SLEEP_FRAME_DIVIDER);
|
||||
}
|
||||
if(!is_acquisition_off)
|
||||
EndAcquisition(capture_data, is_device_capture_recv_data, true, 0, curr_capture_type);
|
||||
}
|
||||
Reference in New Issue
Block a user