Proper IS TWL Capture initialization

This commit is contained in:
Lorenzooone 2024-12-20 13:21:57 +01:00
parent 4bd8a189fb
commit b9cd5ceca0
18 changed files with 570 additions and 64 deletions

View File

@ -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(

View File

@ -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.

View File

@ -1 +0,0 @@
"R¤ŠÅJV1åiTÁE•ªè<C2AA>$°bÄÌÍÔ.§÷î‡L7mçªf€Ö«rVÄöå&65™'Eö´¥eYºôð@»´BØ<dý<64>>»x?óþ£¼;}Ûº‚àÒ»:sš$ò1¹x<C2B9>Ga÷Ý´¹…]©ðð\˸c @ œ!?H_Oÿï_Œ?mÞ©~À+>žþåѽHѧ}—ÙÂAeYòÓH<O_N ø÷‚

Binary file not shown.

Binary file not shown.

View File

@ -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);

View File

@ -10,8 +10,11 @@
void is_driver_list_devices(std::vector<CaptureDevice>& 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);

View File

@ -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);

View File

@ -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 {

View File

@ -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);

View File

@ -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<double> 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;

View File

@ -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 <libusb.h>
#include <cstring>
@ -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);

View File

@ -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();

View File

@ -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)

View File

@ -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<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)));
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

View File

@ -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

View File

@ -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)

View File

@ -26,6 +26,7 @@
static bool checked_be_once = false;
static bool _is_be = false;
std::chrono::time_point<std::chrono::high_resolution_clock> 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::duration<double>diff = 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];