cc3dsfs/source/CaptureDeviceSpecific/3DSCapture_FTD3/3dscapture_ftd3_libusb_acquisition.cpp
Lorenzooone 8e87c7afd1
Some checks failed
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) Has been cancelled
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) Has been cancelled
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) Has been cancelled
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) Has been cancelled
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) Has been cancelled
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) Has been cancelled
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) Has been cancelled
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) Has been cancelled
CD / Create Pi Mono Setup (push) Has been cancelled
CD / Publishing (push) Has been cancelled
Add Wall to compilation flags
2025-04-08 04:20:02 +02:00

227 lines
10 KiB
C++

#include "3dscapture_ftd3_libusb_acquisition.hpp"
#include "3dscapture_ftd3_libusb_comms.hpp"
#include "3dscapture_ftd3_compatibility.hpp"
#include "3dscapture_ftd3_shared_general.hpp"
#include "devicecapture.hpp"
#include <libusb.h>
#include "usb_generic.hpp"
#define MAX_TIME_WAIT 0.5
// This was created to remove the dependency from the FTD3XX library
// under Linux and MacOS (as well as WinUSB).
// There were issues with said library which forced the use of an
// older release (double free when a device is disconnected, for example).
// There were problems with automatic downloads being blocked as well.
// This is something which could not go on indefinitively.
// Optimize data capturing for libusb with async transfers and callbacks,
// instead of waiting for the usb transfer to be done...
struct FTD3LibusbCaptureReceivedData {
bool in_use;
bool* pause_output;
uint32_t index;
int internal_index;
CaptureData* capture_data;
uint32_t* last_index;
bool is_3d;
std::chrono::time_point<std::chrono::high_resolution_clock> *clock_start;
SharedConsumerMutex *is_buffer_free_shared_mutex;
int* status;
ftd3_async_callback_data cb_data;
};
static void ftd3_libusb_read_frame_cb(void* user_data, int transfer_length, int transfer_status);
static int get_ftd3_libusb_status(FTD3LibusbCaptureReceivedData* ftd3_libusb_capture_recv_data) {
return *ftd3_libusb_capture_recv_data[0].status;
}
static void error_ftd3_libusb_status(FTD3LibusbCaptureReceivedData* ftd3_libusb_capture_recv_data, int error_val) {
if((error_val == 0) || (get_ftd3_libusb_status(ftd3_libusb_capture_recv_data) == 0))
*ftd3_libusb_capture_recv_data[0].status = error_val;
}
static void ftd3_libusb_read_frame_request(CaptureData* capture_data, FTD3LibusbCaptureReceivedData* ftd3_libusb_capture_recv_data, uint32_t index, int pipe, bool is_3d) {
if(ftd3_libusb_capture_recv_data == NULL)
return;
if((*ftd3_libusb_capture_recv_data->status) < 0)
return;
ftd3_libusb_capture_recv_data->index = index;
ftd3_libusb_capture_recv_data->cb_data.function = ftd3_libusb_read_frame_cb;
CaptureDataSingleBuffer* data_buf = capture_data->data_buffers.GetWriterBuffer(ftd3_libusb_capture_recv_data->internal_index);
uint8_t* buffer = (uint8_t*)&data_buf->capture_buf;
ftd3_libusb_capture_recv_data->is_3d = is_3d;
ftd3_libusb_async_in_start((ftd3_device_device_handlers*)capture_data->handle, pipe, (uint32_t)(MAX_TIME_WAIT * 1000), buffer, (int)ftd3_get_capture_size(is_3d), &ftd3_libusb_capture_recv_data->cb_data);
}
static void end_ftd3_libusb_read_frame_cb(FTD3LibusbCaptureReceivedData* ftd3_libusb_capture_recv_data, bool early_release) {
if(early_release)
ftd3_libusb_capture_recv_data->capture_data->data_buffers.ReleaseWriterBuffer(ftd3_libusb_capture_recv_data->internal_index, false);
ftd3_libusb_capture_recv_data->in_use = false;
ftd3_libusb_capture_recv_data->is_buffer_free_shared_mutex->specific_unlock(ftd3_libusb_capture_recv_data->internal_index);
}
static void ftd3_libusb_read_frame_cb(void* user_data, int transfer_length, int transfer_status) {
FTD3LibusbCaptureReceivedData* ftd3_libusb_capture_recv_data = (FTD3LibusbCaptureReceivedData*)user_data;
if((*ftd3_libusb_capture_recv_data->status) < 0)
return end_ftd3_libusb_read_frame_cb(ftd3_libusb_capture_recv_data, true);
if(transfer_status != LIBUSB_TRANSFER_COMPLETED) {
*ftd3_libusb_capture_recv_data->status = LIBUSB_ERROR_OTHER;
return end_ftd3_libusb_read_frame_cb(ftd3_libusb_capture_recv_data, true);
}
if(((int32_t)(ftd3_libusb_capture_recv_data->index - (*ftd3_libusb_capture_recv_data->last_index))) <= 0) {
//*ftd3_libusb_capture_recv_data->status = LIBUSB_ERROR_INTERRUPTED;
return end_ftd3_libusb_read_frame_cb(ftd3_libusb_capture_recv_data, true);
}
*ftd3_libusb_capture_recv_data->last_index = ftd3_libusb_capture_recv_data->index;
if(*ftd3_libusb_capture_recv_data->pause_output)
return end_ftd3_libusb_read_frame_cb(ftd3_libusb_capture_recv_data, true);
data_output_update(ftd3_libusb_capture_recv_data->internal_index, transfer_length, ftd3_libusb_capture_recv_data->capture_data, *ftd3_libusb_capture_recv_data->clock_start, ftd3_libusb_capture_recv_data->is_3d);
end_ftd3_libusb_read_frame_cb(ftd3_libusb_capture_recv_data, false);
}
static void close_all_reads_error(FTD3LibusbCaptureReceivedData* ftd3_libusb_capture_recv_data, bool &async_read_closed) {
if(get_ftd3_libusb_status(ftd3_libusb_capture_recv_data) >= 0)
return;
if(!async_read_closed) {
for (int i = 0; i < FTD3_CONCURRENT_BUFFERS; i++)
ftd3_libusb_cancell_callback(&ftd3_libusb_capture_recv_data[i].cb_data);
async_read_closed = true;
}
}
static bool has_too_much_time_passed(const std::chrono::time_point<std::chrono::high_resolution_clock> &start_time) {
const auto curr_time = std::chrono::high_resolution_clock::now();
const std::chrono::duration<double> diff = curr_time - start_time;
return diff.count() > MAX_TIME_WAIT;
}
static void error_too_much_time_passed(FTD3LibusbCaptureReceivedData* ftd3_libusb_capture_recv_data, bool &async_read_closed, const std::chrono::time_point<std::chrono::high_resolution_clock> &start_time) {
if(has_too_much_time_passed(start_time)) {
error_ftd3_libusb_status(ftd3_libusb_capture_recv_data, -1);
close_all_reads_error(ftd3_libusb_capture_recv_data, async_read_closed);
}
}
static void wait_all_ftd3_libusb_buffers_free(FTD3LibusbCaptureReceivedData* ftd3_libusb_capture_recv_data) {
if(ftd3_libusb_capture_recv_data == NULL)
return;
bool async_read_closed = false;
close_all_reads_error(ftd3_libusb_capture_recv_data, async_read_closed);
const auto start_time = std::chrono::high_resolution_clock::now();
for(int i = 0; i < FTD3_CONCURRENT_BUFFERS; i++)
while(ftd3_libusb_capture_recv_data[i].in_use) {
error_too_much_time_passed(ftd3_libusb_capture_recv_data, async_read_closed, start_time);
ftd3_libusb_capture_recv_data[i].is_buffer_free_shared_mutex->specific_timed_lock(i);
}
}
static void wait_one_ftd3_libusb_buffer_free(FTD3LibusbCaptureReceivedData* ftd3_libusb_capture_recv_data) {
bool done = false;
const auto start_time = std::chrono::high_resolution_clock::now();
while(!done) {
for(int i = 0; i < FTD3_CONCURRENT_BUFFERS; i++) {
if(!ftd3_libusb_capture_recv_data[i].in_use)
done = true;
}
if(!done) {
if(has_too_much_time_passed(start_time))
return;
if(get_ftd3_libusb_status(ftd3_libusb_capture_recv_data) < 0)
return;
int dummy = 0;
ftd3_libusb_capture_recv_data[0].is_buffer_free_shared_mutex->general_timed_lock(&dummy);
}
}
}
static FTD3LibusbCaptureReceivedData* ftd3_libusb_get_free_buffer(FTD3LibusbCaptureReceivedData* ftd3_libusb_capture_recv_data) {
wait_one_ftd3_libusb_buffer_free(ftd3_libusb_capture_recv_data);
if(get_ftd3_libusb_status(ftd3_libusb_capture_recv_data) < 0)
return NULL;
for(int i = 0; i < FTD3_CONCURRENT_BUFFERS; i++)
if(!ftd3_libusb_capture_recv_data[i].in_use) {
ftd3_libusb_capture_recv_data[i].is_buffer_free_shared_mutex->specific_try_lock(i);
ftd3_libusb_capture_recv_data[i].in_use = true;
return &ftd3_libusb_capture_recv_data[i];
}
return NULL;
}
static void ftd3_libusb_capture_main_loop_processing(FTD3LibusbCaptureReceivedData* ftd3_libusb_capture_recv_data, int pipe) {
int index = 0;
CaptureData* capture_data = ftd3_libusb_capture_recv_data[0].capture_data;
bool could_use_3d = get_3d_enabled(&capture_data->status, true);
bool stored_3d_status = true;
bool result_3d_setup = ftd3_capture_3d_setup(capture_data, true, stored_3d_status, false);
if(!result_3d_setup)
return;
for(int i = 0; i < FTD3_CONCURRENT_BUFFERS; i++)
ftd3_libusb_read_frame_request(capture_data, ftd3_libusb_get_free_buffer(ftd3_libusb_capture_recv_data), index++, pipe, could_use_3d && stored_3d_status);
while(capture_data->status.connected && capture_data->status.running) {
if(could_use_3d && (stored_3d_status != capture_data->status.requested_3d)) {
*ftd3_libusb_capture_recv_data->pause_output = true;
wait_all_ftd3_libusb_buffers_free(ftd3_libusb_capture_recv_data);
if(get_ftd3_libusb_status(ftd3_libusb_capture_recv_data) < 0) {
capture_error_print(true, capture_data, "Disconnected: Read failed");
return;
}
result_3d_setup = ftd3_capture_3d_setup(capture_data, false, stored_3d_status, false);
if(!result_3d_setup)
return;
*ftd3_libusb_capture_recv_data->pause_output = false;
for(int i = 0; i < FTD3_CONCURRENT_BUFFERS; i++)
ftd3_libusb_read_frame_request(capture_data, ftd3_libusb_get_free_buffer(ftd3_libusb_capture_recv_data), index++, pipe, could_use_3d && stored_3d_status);
*ftd3_libusb_capture_recv_data[0].clock_start = std::chrono::high_resolution_clock::now();
}
if(get_ftd3_libusb_status(ftd3_libusb_capture_recv_data) < 0) {
capture_error_print(true, capture_data, "Disconnected: Read failed");
return;
}
FTD3LibusbCaptureReceivedData* free_buffer = ftd3_libusb_get_free_buffer(ftd3_libusb_capture_recv_data);
ftd3_libusb_read_frame_request(capture_data, free_buffer, index++, pipe, could_use_3d && stored_3d_status);
}
}
void ftd3_libusb_capture_main_loop(CaptureData* capture_data, int pipe) {
if(!usb_is_initialized())
return;
uint32_t last_index = -1;
int status = 0;
bool pause_output = false;
SharedConsumerMutex is_buffer_free_shared_mutex(FTD3_CONCURRENT_BUFFERS);
std::chrono::time_point<std::chrono::high_resolution_clock> clock_start = std::chrono::high_resolution_clock::now();
FTD3LibusbCaptureReceivedData* ftd3_libusb_capture_recv_data = new FTD3LibusbCaptureReceivedData[FTD3_CONCURRENT_BUFFERS];
for(int i = 0; i < FTD3_CONCURRENT_BUFFERS; i++) {
ftd3_libusb_capture_recv_data[i].in_use = false;
ftd3_libusb_capture_recv_data[i].index = i;
ftd3_libusb_capture_recv_data[i].pause_output = &pause_output;
ftd3_libusb_capture_recv_data[i].internal_index = i;
ftd3_libusb_capture_recv_data[i].capture_data = capture_data;
ftd3_libusb_capture_recv_data[i].last_index = &last_index;
ftd3_libusb_capture_recv_data[i].clock_start = &clock_start;
ftd3_libusb_capture_recv_data[i].is_buffer_free_shared_mutex = &is_buffer_free_shared_mutex;
ftd3_libusb_capture_recv_data[i].status = &status;
ftd3_libusb_capture_recv_data[i].cb_data.actual_user_data = &ftd3_libusb_capture_recv_data[i];
ftd3_libusb_capture_recv_data[i].cb_data.transfer_data = NULL;
}
libusb_register_to_event_thread();
ftd3_libusb_capture_main_loop_processing(ftd3_libusb_capture_recv_data, pipe);
wait_all_ftd3_libusb_buffers_free(ftd3_libusb_capture_recv_data);
libusb_unregister_from_event_thread();
delete []ftd3_libusb_capture_recv_data;
}