mirror of
https://github.com/Lorenzooone/cc3dsfs.git
synced 2026-04-24 23:17:43 -05:00
Implement IS Nitro Async USB accesses
This commit is contained in:
parent
3b18026c74
commit
dccc50036c
|
|
@ -5,7 +5,8 @@
|
|||
#include "capture_structs.hpp"
|
||||
|
||||
int initial_cleanup_capture(const is_nitro_usb_device* usb_device_desc, is_nitro_device_handlers* handlers);
|
||||
int EndAcquisitionCapture(is_nitro_device_handlers* handlers, const is_nitro_usb_device* usb_device_desc);
|
||||
void is_nitro_acquisition_capture_main_loop(CaptureData* capture_data, CaptureReceived* capture_buf);
|
||||
int EndAcquisitionCapture(CaptureData* capture_data, ISNitroCaptureReceivedData* is_nitro_capture_recv_data);
|
||||
int EndAcquisitionCapture(const is_nitro_usb_device* usb_device_desc, is_nitro_device_handlers* handlers);
|
||||
void is_nitro_acquisition_capture_main_loop(CaptureData* capture_data, ISNitroCaptureReceivedData* is_nitro_capture_recv_data);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@
|
|||
#include "capture_structs.hpp"
|
||||
|
||||
int initial_cleanup_emulator(const is_nitro_usb_device* usb_device_desc, is_nitro_device_handlers* handlers);
|
||||
int EndAcquisitionEmulator(is_nitro_device_handlers* handlers, bool do_drain_frames, int start_frames, CaptureScreensType capture_type, const is_nitro_usb_device* usb_device_desc);
|
||||
void is_nitro_acquisition_emulator_main_loop(CaptureData* capture_data, CaptureReceived* capture_buf);
|
||||
int EndAcquisitionEmulator(CaptureData* capture_data, ISNitroCaptureReceivedData* is_nitro_capture_recv_data, bool do_drain_frames, int start_frames, CaptureScreensType capture_type);
|
||||
int EndAcquisitionEmulator(const is_nitro_usb_device* usb_device_desc, is_nitro_device_handlers* handlers, bool do_drain_frames, int start_frames, CaptureScreensType capture_type);
|
||||
void is_nitro_acquisition_emulator_main_loop(CaptureData* capture_data, ISNitroCaptureReceivedData* is_nitro_capture_recv_data);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -2,12 +2,39 @@
|
|||
#define __USB_IS_NITRO_ACQUISITION_GENERAL_HPP
|
||||
|
||||
#include "usb_is_nitro_communications.hpp"
|
||||
#include "utils.hpp"
|
||||
#include "capture_structs.hpp"
|
||||
#include "display_structs.hpp"
|
||||
|
||||
#define NUM_CAPTURE_RECEIVED_DATA_BUFFERS 4
|
||||
|
||||
struct ISNitroCaptureReceivedData {
|
||||
volatile bool in_use;
|
||||
uint32_t index;
|
||||
CaptureReceived buffer;
|
||||
SharedConsumerMutex* is_buffer_free_shared_mutex;
|
||||
int* status;
|
||||
uint32_t* last_index;
|
||||
CaptureData* capture_data;
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock>* clock_start;
|
||||
CaptureScreensType curr_capture_type;
|
||||
isn_async_callback_data cb_data;
|
||||
};
|
||||
|
||||
uint64_t _is_nitro_get_video_in_size(CaptureScreensType capture_type);
|
||||
int set_acquisition_mode(is_nitro_device_handlers* handlers, CaptureScreensType capture_type, CaptureSpeedsType capture_speed, const is_nitro_usb_device* usb_device_desc);
|
||||
int EndAcquisition(is_nitro_device_handlers* handlers, bool do_drain_frames, int start_frames, CaptureScreensType capture_type, const is_nitro_usb_device* usb_device_desc);
|
||||
int EndAcquisition(CaptureData* capture_data, ISNitroCaptureReceivedData* is_nitro_capture_recv_data, bool do_drain_frames, int start_frames, CaptureScreensType capture_type);
|
||||
int EndAcquisition(const is_nitro_usb_device* usb_device_desc, is_nitro_device_handlers* handlers, bool do_drain_frames, int start_frames, CaptureScreensType capture_type);
|
||||
int is_nitro_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);
|
||||
void is_nitro_read_frame_request(CaptureData* capture_data, ISNitroCaptureReceivedData* is_nitro_capture_recv_data, CaptureScreensType curr_capture_type, uint32_t index);
|
||||
|
||||
ISNitroCaptureReceivedData* is_nitro_get_free_buffer(CaptureData* capture_data, ISNitroCaptureReceivedData* is_nitro_capture_recv_data);
|
||||
bool is_nitro_are_buffers_all_free(ISNitroCaptureReceivedData* is_nitro_capture_recv_data);
|
||||
int is_nitro_get_num_free_buffers(ISNitroCaptureReceivedData* is_nitro_capture_recv_data);
|
||||
void wait_all_is_nitro_transfers_done(CaptureData* capture_data, ISNitroCaptureReceivedData* is_nitro_capture_recv_data);
|
||||
void wait_all_is_nitro_buffers_free(CaptureData* capture_data, ISNitroCaptureReceivedData* is_nitro_capture_recv_data);
|
||||
void wait_one_is_nitro_buffer_free(CaptureData* capture_data, ISNitroCaptureReceivedData* is_nitro_capture_recv_data);
|
||||
int get_is_nitro_status(ISNitroCaptureReceivedData* is_nitro_capture_recv_data);
|
||||
void reset_is_nitro_status(ISNitroCaptureReceivedData* is_nitro_capture_recv_data);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -25,6 +25,29 @@ enum is_nitro_forward_config_values_rate {
|
|||
IS_NITRO_FORWARD_CONFIG_RATE_QUARTER = 3,
|
||||
};
|
||||
|
||||
typedef void (*isn_async_callback_function)(void* user_data, int transfer_length, int transfer_status);
|
||||
|
||||
struct isn_async_callback_data {
|
||||
isn_async_callback_function function;
|
||||
void* actual_user_data;
|
||||
void* transfer_data;
|
||||
void* handle;
|
||||
void* base_transfer_data;
|
||||
std::mutex transfer_data_access;
|
||||
SharedConsumerMutex* is_transfer_done_mutex;
|
||||
SharedConsumerMutex* is_transfer_data_ready_mutex;
|
||||
size_t requested_length;
|
||||
uint8_t* buffer;
|
||||
size_t actual_length;
|
||||
int status_value;
|
||||
bool is_data_ready;
|
||||
int internal_index;
|
||||
isn_async_callback_data** cb_queue;
|
||||
int* queue_elems;
|
||||
bool* one_transfer_active;
|
||||
isn_async_callback_data* cb_active_transfer;
|
||||
};
|
||||
|
||||
struct is_nitro_usb_device {
|
||||
std::string name;
|
||||
int vid;
|
||||
|
|
@ -64,5 +87,13 @@ int ResetCPUStart(is_nitro_device_handlers* handlers, const is_nitro_usb_device*
|
|||
int ResetCPUEnd(is_nitro_device_handlers* handlers, const is_nitro_usb_device* device_desc);
|
||||
int ResetFullHardware(is_nitro_device_handlers* handlers, const is_nitro_usb_device* device_desc);
|
||||
int ReadFrame(is_nitro_device_handlers* handlers, uint8_t* buf, int length, const is_nitro_usb_device* device_desc);
|
||||
void ReadFrameAsync(is_nitro_device_handlers* handlers, uint8_t* buf, int length, const is_nitro_usb_device* device_desc, isn_async_callback_data* cb_data);
|
||||
void CloseAsyncRead(is_nitro_device_handlers* handlers, isn_async_callback_data* cb_data);
|
||||
|
||||
void SetupISNitroAsyncThread(is_nitro_device_handlers* handlers, void* user_data, std::thread* thread_ptr, bool* keep_going, ConsumerMutex* is_data_ready);
|
||||
void EndISNitroAsyncThread(is_nitro_device_handlers* handlers, void* user_data, std::thread* thread_ptr, bool* keep_going, ConsumerMutex* is_data_ready);
|
||||
void SleepBetweenTransfers(is_nitro_device_handlers* handlers, float ms);
|
||||
void SleepUntilOneFree(is_nitro_device_handlers* handlers, SharedConsumerMutex* mutex);
|
||||
void SleepUntilFree(is_nitro_device_handlers* handlers, SharedConsumerMutex* mutex, int index);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -3,12 +3,22 @@
|
|||
|
||||
#include <vector>
|
||||
#include "capture_structs.hpp"
|
||||
#include "utils.hpp"
|
||||
#include "usb_is_nitro_communications.hpp"
|
||||
#include "usb_is_nitro_acquisition_general.hpp"
|
||||
|
||||
void is_driver_list_devices(std::vector<CaptureDevice>& devices_list, bool* not_supported_elems, int* curr_serial_extra_id_is_nitro, const size_t num_is_nitro_desc);
|
||||
is_nitro_device_handlers* is_driver_serial_reconnection(const is_nitro_usb_device* usb_device_desc, CaptureDevice* device);
|
||||
is_nitro_device_handlers* is_driver_serial_reconnection(CaptureDevice* device);
|
||||
void is_driver_end_connection(is_nitro_device_handlers* handlers);
|
||||
int is_driver_bulk_out(is_nitro_device_handlers* handlers, uint8_t* buf, int length, int* transferred);
|
||||
int is_driver_bulk_in(is_nitro_device_handlers* handlers, uint8_t* buf, int length, int* transferred);
|
||||
int is_driver_bulk_out(is_nitro_device_handlers* handlers, const is_nitro_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred);
|
||||
int is_driver_bulk_in(is_nitro_device_handlers* handlers, const is_nitro_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred);
|
||||
int is_drive_async_in_start(is_nitro_device_handlers* handlers, const is_nitro_usb_device* usb_device_desc, uint8_t* buf, int length, isn_async_callback_data* cb_data);
|
||||
void is_nitro_is_driver_cancel_callback(isn_async_callback_data* cb_data);
|
||||
|
||||
#endif
|
||||
void is_nitro_is_driver_start_thread(std::thread* thread_ptr, bool* usb_thread_run, ISNitroCaptureReceivedData* is_nitro_capture_recv_data, is_nitro_device_handlers* handlers, ConsumerMutex* AsyncMutexPtr);
|
||||
void is_nitro_is_driver_close_thread(std::thread* thread_ptr, bool* usb_thread_run, ISNitroCaptureReceivedData* is_nitro_capture_recv_data);
|
||||
void is_nitro_is_driver_sleep_between_transfers(float ms);
|
||||
void is_nitro_is_driver_sleep_until_one_free(SharedConsumerMutex* mutex);
|
||||
void is_nitro_is_driver_sleep_until_free(SharedConsumerMutex* mutex, int index);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -5,10 +5,18 @@
|
|||
#include "capture_structs.hpp"
|
||||
#include "usb_is_nitro_communications.hpp"
|
||||
|
||||
void is_nitro_libusb_start_thread(std::thread* thread_ptr, bool* usb_thread_run);
|
||||
void is_nitro_libusb_close_thread(std::thread* thread_ptr, bool* usb_thread_run);
|
||||
void is_nitro_libusb_sleep_between_transfers(float ms);
|
||||
void is_nitro_libusb_sleep_until_one_free(SharedConsumerMutex* mutex);
|
||||
void is_nitro_libusb_sleep_until_free(SharedConsumerMutex* mutex, int index);
|
||||
|
||||
void is_nitro_libusb_list_devices(std::vector<CaptureDevice>& devices_list, bool* no_access_elems, bool* not_supported_elems, int* curr_serial_extra_id_is_nitro, const size_t num_is_nitro_desc);
|
||||
is_nitro_device_handlers* is_nitro_libusb_serial_reconnection(const is_nitro_usb_device* usb_device_desc, CaptureDevice* device, int& curr_serial_extra_id);
|
||||
void is_nitro_libusb_end_connection(is_nitro_device_handlers* handlers, const is_nitro_usb_device* device_desc, bool interface_claimed);
|
||||
int is_nitro_libusb_bulk_out(is_nitro_device_handlers* handlers, const is_nitro_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred);
|
||||
int is_nitro_libusb_bulk_in(is_nitro_device_handlers* handlers, const is_nitro_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred);
|
||||
void is_nitro_libusb_async_in_start(is_nitro_device_handlers* handlers, const is_nitro_usb_device* usb_device_desc, uint8_t* buf, int length, isn_async_callback_data* cb_data);
|
||||
void is_nitro_libusb_cancell_callback(isn_async_callback_data* cb_data);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ public:
|
|||
bool try_lock();
|
||||
void unlock();
|
||||
void update_time_multiplier(float time_multiplier);
|
||||
double get_time_s();
|
||||
|
||||
private:
|
||||
std::mutex access_mutex;
|
||||
|
|
@ -60,4 +61,27 @@ private:
|
|||
float time_multiplier = 1.0;
|
||||
};
|
||||
|
||||
class SharedConsumerMutex {
|
||||
public:
|
||||
SharedConsumerMutex(int num_elements);
|
||||
~SharedConsumerMutex();
|
||||
void general_lock(int* index);
|
||||
bool general_timed_lock(int* index);
|
||||
bool general_try_lock(int* index);
|
||||
void specific_lock(int index);
|
||||
bool specific_timed_lock(int index);
|
||||
bool specific_try_lock(int index);
|
||||
void specific_unlock(int index);
|
||||
void update_time_multiplier(float time_multiplier);
|
||||
double get_time_s();
|
||||
|
||||
private:
|
||||
std::mutex access_mutex;
|
||||
std::condition_variable_any condition;
|
||||
const float base_time_fps = 30;
|
||||
int* counts;
|
||||
int num_elements;
|
||||
float time_multiplier = 1.0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@
|
|||
|
||||
#define FRAME_BUFFER_SIZE 32
|
||||
|
||||
static void is_nitro_read_frame_cb(void* user_data, int transfer_length, int transfer_status);
|
||||
|
||||
static bool initial_cleanup(const is_nitro_usb_device* usb_device_desc, is_nitro_device_handlers* handlers) {
|
||||
if(!usb_device_desc->is_capture)
|
||||
return initial_cleanup_emulator(usb_device_desc, handlers) != LIBUSB_SUCCESS;
|
||||
|
|
@ -73,7 +75,7 @@ static is_nitro_device_handlers* usb_find_by_serial_number(const is_nitro_usb_de
|
|||
final_handlers = is_nitro_libusb_serial_reconnection(usb_device_desc, device, curr_serial_extra_id);
|
||||
|
||||
if (final_handlers == NULL)
|
||||
final_handlers = is_driver_serial_reconnection(usb_device_desc, device);
|
||||
final_handlers = is_driver_serial_reconnection(device);
|
||||
return final_handlers;
|
||||
}
|
||||
|
||||
|
|
@ -166,39 +168,195 @@ int set_acquisition_mode(is_nitro_device_handlers* handlers, CaptureScreensType
|
|||
return UpdateFrameForwardConfig(handlers, IS_NITRO_FORWARD_CONFIG_COLOR_RGB24, capture_mode_flag, capture_rate_flag, usb_device_desc);
|
||||
}
|
||||
|
||||
int EndAcquisition(is_nitro_device_handlers* handlers, bool do_drain_frames, int start_frames, CaptureScreensType capture_type, const is_nitro_usb_device* usb_device_desc) {
|
||||
if(usb_device_desc->is_capture)
|
||||
return EndAcquisitionCapture(handlers, usb_device_desc);
|
||||
return EndAcquisitionEmulator(handlers, do_drain_frames, start_frames, capture_type, usb_device_desc);
|
||||
int EndAcquisition(CaptureData* capture_data, ISNitroCaptureReceivedData* is_nitro_capture_recv_data, bool do_drain_frames, int start_frames, CaptureScreensType capture_type) {
|
||||
if(((const is_nitro_usb_device*)(capture_data->status.device.descriptor))->is_capture)
|
||||
return EndAcquisitionCapture(capture_data, is_nitro_capture_recv_data);
|
||||
return EndAcquisitionEmulator(capture_data, is_nitro_capture_recv_data, do_drain_frames, start_frames, capture_type);
|
||||
}
|
||||
|
||||
int is_nitro_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) {
|
||||
int ret = ReadFrame((is_nitro_device_handlers*)capture_data->handle, (uint8_t*)capture_buf, _is_nitro_get_video_in_size(curr_capture_type), (const is_nitro_usb_device*)capture_data->status.device.descriptor);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
int EndAcquisition(const is_nitro_usb_device* usb_device_desc, is_nitro_device_handlers* handlers, bool do_drain_frames, int start_frames, CaptureScreensType capture_type) {
|
||||
if(usb_device_desc->is_capture)
|
||||
return EndAcquisitionCapture(usb_device_desc, handlers);
|
||||
return EndAcquisitionEmulator(usb_device_desc, handlers, do_drain_frames, start_frames, capture_type);
|
||||
}
|
||||
|
||||
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) {
|
||||
// Output to the other threads...
|
||||
const auto curr_time = std::chrono::high_resolution_clock::now();
|
||||
const std::chrono::duration<double> diff = curr_time - clock_start;
|
||||
clock_start = curr_time;
|
||||
const std::chrono::duration<double> diff = curr_time - (*clock_start);
|
||||
*clock_start = curr_time;
|
||||
capture_data->data_buffers.WriteToBuffer(capture_buf, _is_nitro_get_video_in_size(curr_capture_type), 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;
|
||||
capture_data->status.video_wait.unlock();
|
||||
capture_data->status.audio_wait.unlock();
|
||||
}
|
||||
|
||||
int is_nitro_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) {
|
||||
int ret = ReadFrame((is_nitro_device_handlers*)capture_data->handle, (uint8_t*)capture_buf, _is_nitro_get_video_in_size(curr_capture_type), (const is_nitro_usb_device*)capture_data->status.device.descriptor);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
output_to_thread(capture_data, capture_buf, curr_capture_type, &clock_start);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void is_nitro_read_frame_request(CaptureData* capture_data, ISNitroCaptureReceivedData* is_nitro_capture_recv_data, CaptureScreensType curr_capture_type, uint32_t index) {
|
||||
if(is_nitro_capture_recv_data == NULL)
|
||||
return;
|
||||
is_nitro_capture_recv_data->index = index;
|
||||
is_nitro_capture_recv_data->curr_capture_type = curr_capture_type;
|
||||
is_nitro_capture_recv_data->cb_data.function = is_nitro_read_frame_cb;
|
||||
ReadFrameAsync((is_nitro_device_handlers*)capture_data->handle, (uint8_t*)&is_nitro_capture_recv_data->buffer, _is_nitro_get_video_in_size(curr_capture_type), (const is_nitro_usb_device*)capture_data->status.device.descriptor, &is_nitro_capture_recv_data->cb_data);
|
||||
}
|
||||
|
||||
static void end_is_nitro_read_frame_cb(ISNitroCaptureReceivedData* is_nitro_capture_recv_data) {
|
||||
is_nitro_capture_recv_data->in_use = false;
|
||||
is_nitro_capture_recv_data->is_buffer_free_shared_mutex->specific_unlock(is_nitro_capture_recv_data->cb_data.internal_index);
|
||||
}
|
||||
|
||||
static void is_nitro_read_frame_cb(void* user_data, int transfer_length, int transfer_status) {
|
||||
ISNitroCaptureReceivedData* is_nitro_capture_recv_data = (ISNitroCaptureReceivedData*)user_data;
|
||||
if((*is_nitro_capture_recv_data->status) < 0)
|
||||
return end_is_nitro_read_frame_cb(is_nitro_capture_recv_data);
|
||||
if(transfer_status != LIBUSB_TRANSFER_COMPLETED) {
|
||||
*is_nitro_capture_recv_data->status = LIBUSB_ERROR_OTHER;
|
||||
return end_is_nitro_read_frame_cb(is_nitro_capture_recv_data);
|
||||
}
|
||||
|
||||
if(((int32_t)(is_nitro_capture_recv_data->index - (*is_nitro_capture_recv_data->last_index))) <= 0) {
|
||||
//*is_nitro_capture_recv_data->status = LIBUSB_ERROR_INTERRUPTED;
|
||||
return end_is_nitro_read_frame_cb(is_nitro_capture_recv_data);
|
||||
}
|
||||
*is_nitro_capture_recv_data->last_index = is_nitro_capture_recv_data->index;
|
||||
|
||||
output_to_thread(is_nitro_capture_recv_data->capture_data, &is_nitro_capture_recv_data->buffer, is_nitro_capture_recv_data->curr_capture_type, is_nitro_capture_recv_data->clock_start);
|
||||
end_is_nitro_read_frame_cb(is_nitro_capture_recv_data);
|
||||
}
|
||||
|
||||
int is_nitro_get_num_free_buffers(ISNitroCaptureReceivedData* is_nitro_capture_recv_data) {
|
||||
int num_free = 0;
|
||||
for(int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++)
|
||||
if(!is_nitro_capture_recv_data[i].in_use)
|
||||
num_free += 1;
|
||||
return num_free;
|
||||
}
|
||||
|
||||
void wait_all_is_nitro_transfers_done(CaptureData* capture_data, ISNitroCaptureReceivedData* is_nitro_capture_recv_data) {
|
||||
if (is_nitro_capture_recv_data == NULL)
|
||||
return;
|
||||
if (*is_nitro_capture_recv_data[0].status < 0) {
|
||||
for (int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++)
|
||||
CloseAsyncRead((is_nitro_device_handlers*)capture_data->handle, &is_nitro_capture_recv_data[i].cb_data);
|
||||
}
|
||||
for (int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) {
|
||||
void* transfer_data;
|
||||
do {
|
||||
is_nitro_capture_recv_data[i].cb_data.transfer_data_access.lock();
|
||||
transfer_data = is_nitro_capture_recv_data[i].cb_data.transfer_data;
|
||||
is_nitro_capture_recv_data[i].cb_data.transfer_data_access.unlock();
|
||||
if(transfer_data)
|
||||
SleepUntilFree((is_nitro_device_handlers*)capture_data->handle, is_nitro_capture_recv_data[i].cb_data.is_transfer_done_mutex, i);
|
||||
} while(transfer_data);
|
||||
}
|
||||
}
|
||||
|
||||
void wait_all_is_nitro_buffers_free(CaptureData* capture_data, ISNitroCaptureReceivedData* is_nitro_capture_recv_data) {
|
||||
if (is_nitro_capture_recv_data == NULL)
|
||||
return;
|
||||
if (*is_nitro_capture_recv_data[0].status < 0) {
|
||||
for (int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++)
|
||||
CloseAsyncRead((is_nitro_device_handlers*)capture_data->handle, &is_nitro_capture_recv_data[i].cb_data);
|
||||
}
|
||||
for (int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++)
|
||||
while (is_nitro_capture_recv_data[i].in_use)
|
||||
SleepUntilFree((is_nitro_device_handlers*)capture_data->handle, is_nitro_capture_recv_data[i].is_buffer_free_shared_mutex, i);
|
||||
}
|
||||
|
||||
void wait_one_is_nitro_buffer_free(CaptureData* capture_data, ISNitroCaptureReceivedData* is_nitro_capture_recv_data) {
|
||||
bool done = false;
|
||||
while(!done) {
|
||||
for(int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) {
|
||||
if(!is_nitro_capture_recv_data[i].in_use)
|
||||
done = true;
|
||||
}
|
||||
if(!done) {
|
||||
if(*is_nitro_capture_recv_data[0].status < 0)
|
||||
return;
|
||||
SleepUntilOneFree((is_nitro_device_handlers*)capture_data->handle, is_nitro_capture_recv_data[0].is_buffer_free_shared_mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool is_nitro_are_buffers_all_free(ISNitroCaptureReceivedData* is_nitro_capture_recv_data) {
|
||||
return is_nitro_get_num_free_buffers(is_nitro_capture_recv_data) == NUM_CAPTURE_RECEIVED_DATA_BUFFERS;
|
||||
}
|
||||
|
||||
ISNitroCaptureReceivedData* is_nitro_get_free_buffer(CaptureData* capture_data, ISNitroCaptureReceivedData* is_nitro_capture_recv_data) {
|
||||
wait_one_is_nitro_buffer_free(capture_data, is_nitro_capture_recv_data);
|
||||
if(*is_nitro_capture_recv_data[0].status < 0)
|
||||
return NULL;
|
||||
for(int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++)
|
||||
if(!is_nitro_capture_recv_data[i].in_use) {
|
||||
is_nitro_capture_recv_data[i].is_buffer_free_shared_mutex->specific_try_lock(i);
|
||||
is_nitro_capture_recv_data[i].in_use = true;
|
||||
return &is_nitro_capture_recv_data[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int get_is_nitro_status(ISNitroCaptureReceivedData* is_nitro_capture_recv_data) {
|
||||
return *is_nitro_capture_recv_data[0].status;
|
||||
}
|
||||
|
||||
void reset_is_nitro_status(ISNitroCaptureReceivedData* is_nitro_capture_recv_data) {
|
||||
*is_nitro_capture_recv_data[0].status = 0;
|
||||
}
|
||||
|
||||
void is_nitro_acquisition_main_loop(CaptureData* capture_data) {
|
||||
if(!usb_is_initialized())
|
||||
return;
|
||||
CaptureReceived* capture_buf = new CaptureReceived;
|
||||
bool is_done_thread;
|
||||
ConsumerMutex has_data_been_processed;
|
||||
std::thread async_processing_thread;
|
||||
|
||||
uint32_t last_index = -1;
|
||||
int status = 0;
|
||||
isn_async_callback_data* cb_queue[NUM_CAPTURE_RECEIVED_DATA_BUFFERS];
|
||||
int queue_elems = 0;
|
||||
bool one_transfer_active = false;
|
||||
SharedConsumerMutex is_buffer_free_shared_mutex(NUM_CAPTURE_RECEIVED_DATA_BUFFERS);
|
||||
SharedConsumerMutex is_transfer_done_shared_mutex(NUM_CAPTURE_RECEIVED_DATA_BUFFERS);
|
||||
SharedConsumerMutex is_transfer_data_ready_shared_mutex(NUM_CAPTURE_RECEIVED_DATA_BUFFERS);
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> clock_start = std::chrono::high_resolution_clock::now();
|
||||
ISNitroCaptureReceivedData* is_nitro_capture_recv_data = new ISNitroCaptureReceivedData[NUM_CAPTURE_RECEIVED_DATA_BUFFERS];
|
||||
for(int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) {
|
||||
is_nitro_capture_recv_data[i].in_use = false;
|
||||
is_nitro_capture_recv_data[i].index = i;
|
||||
is_nitro_capture_recv_data[i].capture_data = capture_data;
|
||||
is_nitro_capture_recv_data[i].last_index = &last_index;
|
||||
is_nitro_capture_recv_data[i].clock_start = &clock_start;
|
||||
is_nitro_capture_recv_data[i].is_buffer_free_shared_mutex = &is_buffer_free_shared_mutex;
|
||||
is_nitro_capture_recv_data[i].status = &status;
|
||||
is_nitro_capture_recv_data[i].cb_data.actual_user_data = &is_nitro_capture_recv_data[i];
|
||||
is_nitro_capture_recv_data[i].cb_data.transfer_data = NULL;
|
||||
is_nitro_capture_recv_data[i].cb_data.is_transfer_done_mutex = &is_transfer_done_shared_mutex;
|
||||
is_nitro_capture_recv_data[i].cb_data.internal_index = i;
|
||||
is_nitro_capture_recv_data[i].cb_data.is_transfer_data_ready_mutex = &is_transfer_data_ready_shared_mutex;
|
||||
is_nitro_capture_recv_data[i].cb_data.is_data_ready = false;
|
||||
is_nitro_capture_recv_data[i].cb_data.cb_queue = cb_queue;
|
||||
is_nitro_capture_recv_data[i].cb_data.queue_elems = &queue_elems;
|
||||
is_nitro_capture_recv_data[i].cb_data.one_transfer_active = &one_transfer_active;
|
||||
}
|
||||
SetupISNitroAsyncThread((is_nitro_device_handlers*)capture_data->handle, is_nitro_capture_recv_data, &async_processing_thread, &is_done_thread, &has_data_been_processed);
|
||||
capture_data->status.reset_hardware = false;
|
||||
if(((const is_nitro_usb_device*)(capture_data->status.device.descriptor))->is_capture)
|
||||
is_nitro_acquisition_capture_main_loop(capture_data, capture_buf);
|
||||
is_nitro_acquisition_capture_main_loop(capture_data, is_nitro_capture_recv_data);
|
||||
else
|
||||
is_nitro_acquisition_emulator_main_loop(capture_data, capture_buf);
|
||||
delete capture_buf;
|
||||
is_nitro_acquisition_emulator_main_loop(capture_data, is_nitro_capture_recv_data);
|
||||
wait_all_is_nitro_buffers_free(capture_data, is_nitro_capture_recv_data);
|
||||
EndISNitroAsyncThread((is_nitro_device_handlers*)capture_data->handle, is_nitro_capture_recv_data, &async_processing_thread, &is_done_thread, &has_data_been_processed);
|
||||
delete []is_nitro_capture_recv_data;
|
||||
}
|
||||
|
||||
void usb_is_nitro_acquisition_cleanup(CaptureData* capture_data) {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,9 @@
|
|||
#define RESET_TIMEOUT 4.0
|
||||
#define SLEEP_CHECKS_TIME_MS 20
|
||||
|
||||
static int StartAcquisitionCapture(is_nitro_device_handlers* handlers, CaptureScreensType capture_type, CaptureSpeedsType capture_speed, bool* is_acquisition_off, const is_nitro_usb_device* usb_device_desc) {
|
||||
static int StartAcquisitionCapture(CaptureData* capture_data, ISNitroCaptureReceivedData* is_nitro_capture_recv_data, CaptureScreensType capture_type, CaptureSpeedsType capture_speed, bool* is_acquisition_off, uint32_t &index) {
|
||||
is_nitro_device_handlers* handlers = (is_nitro_device_handlers*)capture_data->handle;
|
||||
const is_nitro_usb_device* usb_device_desc = (const is_nitro_usb_device*)capture_data->status.device.descriptor;
|
||||
int ret = 0;
|
||||
ret = ReadLidState(handlers, is_acquisition_off, usb_device_desc);
|
||||
if(ret < 0)
|
||||
|
|
@ -28,15 +30,19 @@ static int StartAcquisitionCapture(is_nitro_device_handlers* handlers, CaptureSc
|
|||
ret = UpdateFrameForwardEnable(handlers, true, true, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
return StartUsbCaptureDma(handlers, usb_device_desc);
|
||||
ret = StartUsbCaptureDma(handlers, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
reset_is_nitro_status(is_nitro_capture_recv_data);
|
||||
for(int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++)
|
||||
is_nitro_read_frame_request(capture_data, is_nitro_get_free_buffer(capture_data, is_nitro_capture_recv_data), capture_type, index++);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int LidReopenCaptureCheck(CaptureData* capture_data, CaptureScreensType &curr_capture_type, CaptureSpeedsType &curr_capture_speed, bool* is_acquisition_off) {
|
||||
is_nitro_device_handlers* handlers = (is_nitro_device_handlers*)capture_data->handle;
|
||||
const is_nitro_usb_device* usb_device_desc = (const is_nitro_usb_device*)capture_data->status.device.descriptor;
|
||||
static int LidReopenCaptureCheck(CaptureData* capture_data, ISNitroCaptureReceivedData* is_nitro_capture_recv_data, CaptureScreensType &curr_capture_type, CaptureSpeedsType &curr_capture_speed, bool* is_acquisition_off, uint32_t &index) {
|
||||
curr_capture_type = capture_data->status.capture_type;
|
||||
curr_capture_speed = capture_data->status.capture_speed;
|
||||
int ret = StartAcquisitionCapture(handlers, curr_capture_type, curr_capture_speed, is_acquisition_off, usb_device_desc);
|
||||
int ret = StartAcquisitionCapture(capture_data, is_nitro_capture_recv_data, curr_capture_type, curr_capture_speed, is_acquisition_off, index);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
if(!(*is_acquisition_off))
|
||||
|
|
@ -44,7 +50,7 @@ static int LidReopenCaptureCheck(CaptureData* capture_data, CaptureScreensType &
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int CaptureResetHardware(CaptureData* capture_data, CaptureScreensType &curr_capture_type, CaptureSpeedsType &curr_capture_speed, bool *is_acquisition_off, std::chrono::time_point<std::chrono::high_resolution_clock> &clock_last_reset) {
|
||||
static int CaptureResetHardware(CaptureData* capture_data, ISNitroCaptureReceivedData* is_nitro_capture_recv_data, CaptureScreensType &curr_capture_type, CaptureSpeedsType &curr_capture_speed, bool *is_acquisition_off, std::chrono::time_point<std::chrono::high_resolution_clock> &clock_last_reset, uint32_t &index) {
|
||||
is_nitro_device_handlers* handlers = (is_nitro_device_handlers*)capture_data->handle;
|
||||
const is_nitro_usb_device* usb_device_desc = (const is_nitro_usb_device*)capture_data->status.device.descriptor;
|
||||
bool reset_hardware = capture_data->status.reset_hardware;
|
||||
|
|
@ -60,7 +66,7 @@ static int CaptureResetHardware(CaptureData* capture_data, CaptureScreensType &c
|
|||
clock_last_reset = curr_time;
|
||||
|
||||
if(!(*is_acquisition_off))
|
||||
ret = EndAcquisitionCapture(handlers, usb_device_desc);
|
||||
ret = EndAcquisitionCapture(capture_data, is_nitro_capture_recv_data);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
ret = ResetCPUStart(handlers, usb_device_desc);
|
||||
|
|
@ -72,7 +78,7 @@ static int CaptureResetHardware(CaptureData* capture_data, CaptureScreensType &c
|
|||
if(!(*is_acquisition_off)) {
|
||||
curr_capture_type = capture_data->status.capture_type;
|
||||
curr_capture_speed = capture_data->status.capture_speed;
|
||||
ret = StartAcquisitionCapture(handlers, curr_capture_type, curr_capture_speed, is_acquisition_off, usb_device_desc);
|
||||
ret = StartAcquisitionCapture(capture_data, is_nitro_capture_recv_data, curr_capture_type, curr_capture_speed, is_acquisition_off, index);
|
||||
}
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
|
|
@ -80,38 +86,42 @@ static int CaptureResetHardware(CaptureData* capture_data, CaptureScreensType &c
|
|||
}
|
||||
|
||||
int initial_cleanup_capture(const is_nitro_usb_device* usb_device_desc, is_nitro_device_handlers* handlers) {
|
||||
//EndAcquisition(handlers, false, 0, CAPTURE_SCREENS_BOTH, usb_device_desc);
|
||||
//EndAcquisition(handlers, usb_device_desc, false, 0, CAPTURE_SCREENS_BOTH);
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
int EndAcquisitionCapture(is_nitro_device_handlers* handlers, const is_nitro_usb_device* usb_device_desc) {
|
||||
int EndAcquisitionCapture(CaptureData* capture_data, ISNitroCaptureReceivedData* is_nitro_capture_recv_data) {
|
||||
wait_all_is_nitro_buffers_free(capture_data, is_nitro_capture_recv_data);
|
||||
return EndAcquisitionCapture((const is_nitro_usb_device*)capture_data->status.device.descriptor, (is_nitro_device_handlers*)capture_data->handle);
|
||||
}
|
||||
|
||||
int EndAcquisitionCapture(const is_nitro_usb_device* usb_device_desc, is_nitro_device_handlers* handlers) {
|
||||
return StopUsbCaptureDma(handlers, usb_device_desc);
|
||||
}
|
||||
|
||||
void is_nitro_acquisition_capture_main_loop(CaptureData* capture_data, CaptureReceived* capture_buf) {
|
||||
void is_nitro_acquisition_capture_main_loop(CaptureData* capture_data, ISNitroCaptureReceivedData* is_nitro_capture_recv_data) {
|
||||
is_nitro_device_handlers* handlers = (is_nitro_device_handlers*)capture_data->handle;
|
||||
const is_nitro_usb_device* usb_device_desc = (const is_nitro_usb_device*)capture_data->status.device.descriptor;
|
||||
bool is_acquisition_off = true;
|
||||
uint32_t index = 0;
|
||||
CaptureScreensType curr_capture_type = capture_data->status.capture_type;
|
||||
CaptureSpeedsType curr_capture_speed = capture_data->status.capture_speed;
|
||||
int ret = StartAcquisitionCapture(handlers, curr_capture_type, curr_capture_speed, &is_acquisition_off, usb_device_desc);
|
||||
int ret = StartAcquisitionCapture(capture_data, is_nitro_capture_recv_data, curr_capture_type, curr_capture_speed, &is_acquisition_off, index);
|
||||
if(ret < 0) {
|
||||
capture_error_print(true, capture_data, "Capture Start: Failed");
|
||||
return;
|
||||
}
|
||||
int inner_curr_in = 0;
|
||||
auto clock_start = std::chrono::high_resolution_clock::now();
|
||||
auto clock_last_reset = std::chrono::high_resolution_clock::now();
|
||||
|
||||
while(capture_data->status.connected && capture_data->status.running) {
|
||||
ret = CaptureResetHardware(capture_data, curr_capture_type, curr_capture_speed, &is_acquisition_off, clock_last_reset);
|
||||
ret = CaptureResetHardware(capture_data, is_nitro_capture_recv_data, curr_capture_type, curr_capture_speed, &is_acquisition_off, clock_last_reset, index);
|
||||
if(ret < 0) {
|
||||
capture_error_print(true, capture_data, "Hardware reset: Failed");
|
||||
return;
|
||||
}
|
||||
if(is_acquisition_off) {
|
||||
default_sleep(SLEEP_CHECKS_TIME_MS);
|
||||
ret = LidReopenCaptureCheck(capture_data, curr_capture_type, curr_capture_speed, &is_acquisition_off);
|
||||
SleepBetweenTransfers(handlers, SLEEP_CHECKS_TIME_MS);
|
||||
ret = LidReopenCaptureCheck(capture_data, is_nitro_capture_recv_data, curr_capture_type, curr_capture_speed, &is_acquisition_off, index);
|
||||
if(ret < 0) {
|
||||
capture_error_print(true, capture_data, "Lid Reopen: Failed");
|
||||
return;
|
||||
|
|
@ -119,9 +129,10 @@ void is_nitro_acquisition_capture_main_loop(CaptureData* capture_data, CaptureRe
|
|||
}
|
||||
if(is_acquisition_off)
|
||||
continue;
|
||||
ret = is_nitro_read_frame_and_output(capture_data, capture_buf, curr_capture_type, clock_start);
|
||||
wait_one_is_nitro_buffer_free(capture_data, is_nitro_capture_recv_data);
|
||||
ret = get_is_nitro_status(is_nitro_capture_recv_data);
|
||||
if(ret < 0) {
|
||||
ret = EndAcquisition(handlers, true, 0, curr_capture_type, usb_device_desc);
|
||||
ret = EndAcquisition(capture_data, is_nitro_capture_recv_data, true, 0, curr_capture_type);
|
||||
if(ret < 0) {
|
||||
capture_error_print(true, capture_data, "Disconnected: Read error");
|
||||
return;
|
||||
|
|
@ -129,16 +140,17 @@ void is_nitro_acquisition_capture_main_loop(CaptureData* capture_data, CaptureRe
|
|||
is_acquisition_off = true;
|
||||
continue;
|
||||
}
|
||||
is_nitro_read_frame_request(capture_data, is_nitro_get_free_buffer(capture_data, is_nitro_capture_recv_data), curr_capture_type, index++);
|
||||
|
||||
if((curr_capture_type != capture_data->status.capture_type) || (curr_capture_speed != capture_data->status.capture_speed)) {
|
||||
ret = EndAcquisition(handlers, true, 0, curr_capture_type, usb_device_desc);
|
||||
ret = EndAcquisition(capture_data, is_nitro_capture_recv_data, true, 0, curr_capture_type);
|
||||
if(ret < 0) {
|
||||
capture_error_print(true, capture_data, "Capture End: Failed");
|
||||
return;
|
||||
}
|
||||
curr_capture_type = capture_data->status.capture_type;
|
||||
curr_capture_speed = capture_data->status.capture_speed;
|
||||
ret = StartAcquisitionCapture(handlers, curr_capture_type, curr_capture_speed, &is_acquisition_off, usb_device_desc);
|
||||
ret = StartAcquisitionCapture(capture_data, is_nitro_capture_recv_data, curr_capture_type, curr_capture_speed, &is_acquisition_off, index);
|
||||
if(ret < 0) {
|
||||
capture_error_print(true, capture_data, "Capture Restart: Failed");
|
||||
return;
|
||||
|
|
@ -146,5 +158,5 @@ void is_nitro_acquisition_capture_main_loop(CaptureData* capture_data, CaptureRe
|
|||
}
|
||||
}
|
||||
if(!is_acquisition_off)
|
||||
EndAcquisition(handlers, true, 0, curr_capture_type, usb_device_desc);
|
||||
EndAcquisition(capture_data, is_nitro_capture_recv_data, true, 0, curr_capture_type);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -166,21 +166,30 @@ static bool do_sleep(float single_frame_time, std::chrono::time_point<std::chron
|
|||
return result;
|
||||
}
|
||||
|
||||
static void frame_wait(float single_frame_time, std::chrono::time_point<std::chrono::high_resolution_clock> clock_last_reset, CaptureScreensType capture_type, CaptureSpeedsType capture_speed, int curr_frame_counter, int last_frame_counter) {
|
||||
static void frame_wait(is_nitro_device_handlers* handlers, float single_frame_time, std::chrono::time_point<std::chrono::high_resolution_clock> clock_last_reset, CaptureScreensType capture_type, CaptureSpeedsType capture_speed, int curr_frame_counter, int last_frame_counter) {
|
||||
if(curr_frame_counter == FRAME_BUFFER_SIZE)
|
||||
return;
|
||||
float sleep_time = 0;
|
||||
int sleep_counter = 0;
|
||||
while(do_sleep(single_frame_time, clock_last_reset, capture_type, capture_speed, curr_frame_counter, last_frame_counter, &sleep_time)) {
|
||||
default_sleep(sleep_time * 1000.0 / SLEEP_TIME_DIVISOR);
|
||||
SleepBetweenTransfers(handlers, sleep_time * 1000.0 / SLEEP_TIME_DIVISOR);
|
||||
sleep_counter++;
|
||||
}
|
||||
}
|
||||
|
||||
static int reset_acquisition_frames(is_nitro_device_handlers* handlers, uint16_t &curr_frame_counter, uint16_t &last_frame_counter, float &single_frame_time, std::chrono::time_point<std::chrono::high_resolution_clock> &clock_last_reset, CaptureScreensType &curr_capture_type, CaptureScreensType wanted_capture_type, CaptureSpeedsType &curr_capture_speed, CaptureSpeedsType wanted_capture_speed, const is_nitro_usb_device* usb_device_desc) {
|
||||
static int reset_acquisition_frames(CaptureData* capture_data, uint16_t &curr_frame_counter, uint16_t &last_frame_counter, float &single_frame_time, std::chrono::time_point<std::chrono::high_resolution_clock> &clock_last_reset, CaptureScreensType &curr_capture_type, CaptureScreensType wanted_capture_type, CaptureSpeedsType &curr_capture_speed, CaptureSpeedsType wanted_capture_speed, ISNitroCaptureReceivedData* is_nitro_capture_recv_data) {
|
||||
curr_frame_counter += 1;
|
||||
|
||||
if(curr_frame_counter < FRAME_BUFFER_SIZE)
|
||||
return LIBUSB_SUCCESS;
|
||||
|
||||
is_nitro_device_handlers* handlers = (is_nitro_device_handlers*)capture_data->handle;
|
||||
const is_nitro_usb_device* usb_device_desc = (const is_nitro_usb_device*)capture_data->status.device.descriptor;
|
||||
wait_all_is_nitro_buffers_free(capture_data, is_nitro_capture_recv_data);
|
||||
int ret = get_is_nitro_status(is_nitro_capture_recv_data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
int multiplier = 1;
|
||||
switch(curr_capture_speed) {
|
||||
case CAPTURE_SPEEDS_HALF:
|
||||
|
|
@ -194,7 +203,7 @@ static int reset_acquisition_frames(is_nitro_device_handlers* handlers, uint16_t
|
|||
break;
|
||||
}
|
||||
|
||||
int ret = StopUsbCaptureDma(handlers, usb_device_desc);
|
||||
ret = StopUsbCaptureDma(handlers, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
|
||||
|
|
@ -216,10 +225,10 @@ static int reset_acquisition_frames(is_nitro_device_handlers* handlers, uint16_t
|
|||
std::chrono::duration<double> diff;
|
||||
do {
|
||||
// Is this not the first loop? Also, do not sleep too much...
|
||||
if((frame_diff > 0) && ((internalFrameCount & (FRAME_BUFFER_SIZE - 1) < (FRAME_BUFFER_SIZE - 1)))) {
|
||||
if((frame_diff > 0) && (((internalFrameCount & (FRAME_BUFFER_SIZE - 1)) < (FRAME_BUFFER_SIZE - 1)))) {
|
||||
float expected_time = single_frame_time * FRAME_BUFFER_SIZE;
|
||||
if(diff.count() < expected_time)
|
||||
default_sleep(single_frame_time * 1000.0 / SLEEP_TIME_DIVISOR);
|
||||
SleepBetweenTransfers(handlers, single_frame_time * 1000.0 / SLEEP_TIME_DIVISOR);
|
||||
}
|
||||
// Check how many frames have passed...
|
||||
ret = GetFrameCounter(handlers, &internalFrameCount, usb_device_desc);
|
||||
|
|
@ -243,10 +252,18 @@ static int reset_acquisition_frames(is_nitro_device_handlers* handlers, uint16_t
|
|||
}
|
||||
// Exit if enough frames have passed, or if there currently is some delay.
|
||||
// Exiting early makes it possible to catch up to the DMA, if we're behind.
|
||||
} while(((frame_diff < diff_target) && (!(last_frame_counter & (FRAME_BUFFER_SIZE - 1)))) || ((internalFrameCount & (FRAME_BUFFER_SIZE - 1)) >= (FRAME_BUFFER_SIZE - (1 + multiplier))));
|
||||
} while(((frame_diff < diff_target) && (!(last_frame_counter & (FRAME_BUFFER_SIZE - 1)))) || ((internalFrameCount & (FRAME_BUFFER_SIZE - 1)) >= (FRAME_BUFFER_SIZE - ( 1 + multiplier))));
|
||||
// Determine how much time a single frame takes. We'll use it for sleeps
|
||||
curr_time = std::chrono::high_resolution_clock::now();
|
||||
diff = curr_time - clock_last_reset;
|
||||
if((frame_diff > 0) && (frame_diff < (diff_target - (1 + multiplier)))) {
|
||||
bool is_lid_closed = false;
|
||||
ret = ReadLidState(handlers, &is_lid_closed, usb_device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
if(is_lid_closed)
|
||||
frame_diff = 0;
|
||||
}
|
||||
if(frame_diff == 0)
|
||||
single_frame_time = 0;
|
||||
else
|
||||
|
|
@ -279,10 +296,15 @@ static int reset_acquisition_frames(is_nitro_device_handlers* handlers, uint16_t
|
|||
}
|
||||
|
||||
int initial_cleanup_emulator(const is_nitro_usb_device* usb_device_desc, is_nitro_device_handlers* handlers) {
|
||||
return EndAcquisition(handlers, false, 0, CAPTURE_SCREENS_BOTH, usb_device_desc);
|
||||
return EndAcquisition(usb_device_desc, handlers, false, 0, CAPTURE_SCREENS_BOTH);
|
||||
}
|
||||
|
||||
int EndAcquisitionEmulator(is_nitro_device_handlers* handlers, bool do_drain_frames, int start_frames, CaptureScreensType capture_type, const is_nitro_usb_device* usb_device_desc) {
|
||||
int EndAcquisitionEmulator(CaptureData* capture_data, ISNitroCaptureReceivedData* is_nitro_capture_recv_data, bool do_drain_frames, int start_frames, CaptureScreensType capture_type) {
|
||||
wait_all_is_nitro_buffers_free(capture_data, is_nitro_capture_recv_data);
|
||||
return EndAcquisitionEmulator((const is_nitro_usb_device*)capture_data->status.device.descriptor, (is_nitro_device_handlers*)capture_data->handle, do_drain_frames, start_frames, capture_type);
|
||||
}
|
||||
|
||||
int EndAcquisitionEmulator(const is_nitro_usb_device* usb_device_desc, is_nitro_device_handlers* handlers, bool do_drain_frames, int start_frames, CaptureScreensType capture_type) {
|
||||
int ret = 0;
|
||||
if (do_drain_frames)
|
||||
ret = drain_frames(handlers, FRAME_BUFFER_SIZE, start_frames, capture_type, usb_device_desc);
|
||||
|
|
@ -294,9 +316,10 @@ int EndAcquisitionEmulator(is_nitro_device_handlers* handlers, bool do_drain_fra
|
|||
return UpdateFrameForwardEnable(handlers, false, false, usb_device_desc);
|
||||
}
|
||||
|
||||
void is_nitro_acquisition_emulator_main_loop(CaptureData* capture_data, CaptureReceived* capture_buf) {
|
||||
void is_nitro_acquisition_emulator_main_loop(CaptureData* capture_data, ISNitroCaptureReceivedData* is_nitro_capture_recv_data) {
|
||||
is_nitro_device_handlers* handlers = (is_nitro_device_handlers*)capture_data->handle;
|
||||
const is_nitro_usb_device* usb_device_desc = (const is_nitro_usb_device*)capture_data->status.device.descriptor;
|
||||
uint32_t index = 0;
|
||||
uint16_t last_frame_counter = 0;
|
||||
float single_frame_time = 0;
|
||||
uint16_t curr_frame_counter = 0;
|
||||
|
|
@ -307,29 +330,29 @@ void is_nitro_acquisition_emulator_main_loop(CaptureData* capture_data, CaptureR
|
|||
capture_error_print(true, capture_data, "Capture Start: Failed");
|
||||
return;
|
||||
}
|
||||
auto clock_start = std::chrono::high_resolution_clock::now();
|
||||
auto clock_last_reset = std::chrono::high_resolution_clock::now();
|
||||
|
||||
while (capture_data->status.connected && capture_data->status.running) {
|
||||
frame_wait(single_frame_time, clock_last_reset, curr_capture_type, curr_capture_speed, curr_frame_counter, last_frame_counter);
|
||||
|
||||
if (single_frame_time > 0) {
|
||||
ret = is_nitro_read_frame_and_output(capture_data, capture_buf, curr_capture_type, clock_start);
|
||||
if (ret < 0) {
|
||||
capture_error_print(true, capture_data, "Disconnected: Read error");
|
||||
return;
|
||||
}
|
||||
ret = get_is_nitro_status(is_nitro_capture_recv_data);
|
||||
if(ret < 0) {
|
||||
capture_error_print(true, capture_data, "Disconnected: Read error");
|
||||
return;
|
||||
}
|
||||
if(single_frame_time > 0) {
|
||||
is_nitro_read_frame_request(capture_data, is_nitro_get_free_buffer(capture_data, is_nitro_capture_recv_data), curr_capture_type, index++);
|
||||
frame_wait(handlers, single_frame_time, clock_last_reset, curr_capture_type, curr_capture_speed, curr_frame_counter + 1, last_frame_counter);
|
||||
}
|
||||
else {
|
||||
capture_data->status.cooldown_curr_in = FIX_PARTIAL_FIRST_FRAME_NUM;
|
||||
default_sleep(SLEEP_CHECKS_TIME_MS);
|
||||
clock_last_reset = std::chrono::high_resolution_clock::now();
|
||||
SleepBetweenTransfers(handlers, SLEEP_CHECKS_TIME_MS);
|
||||
}
|
||||
capture_data->status.curr_delay = last_frame_counter % FRAME_BUFFER_SIZE;
|
||||
ret = reset_acquisition_frames(handlers, curr_frame_counter, last_frame_counter, single_frame_time, clock_last_reset, curr_capture_type, capture_data->status.capture_type, curr_capture_speed, capture_data->status.capture_speed, usb_device_desc);
|
||||
if (ret < 0) {
|
||||
ret = reset_acquisition_frames(capture_data, curr_frame_counter, last_frame_counter, single_frame_time, clock_last_reset, curr_capture_type, capture_data->status.capture_type, curr_capture_speed, capture_data->status.capture_speed, is_nitro_capture_recv_data);
|
||||
if(ret < 0) {
|
||||
capture_error_print(true, capture_data, "Disconnected: Frame counter reset error");
|
||||
break;
|
||||
}
|
||||
}
|
||||
EndAcquisition(handlers, true, curr_frame_counter, curr_capture_type, usb_device_desc);
|
||||
EndAcquisition(capture_data, is_nitro_capture_recv_data, true, curr_frame_counter, curr_capture_type);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -163,14 +163,21 @@ static void fix_endianness_header(is_nitro_nec_packet_header* header) {
|
|||
static int bulk_out(is_nitro_device_handlers* handlers, const is_nitro_usb_device* usb_device_desc, uint8_t *buf, int length, int *transferred) {
|
||||
if(handlers->usb_handle)
|
||||
return is_nitro_libusb_bulk_out(handlers, usb_device_desc, buf, length, transferred);
|
||||
return is_driver_bulk_out(handlers, buf, length, transferred);
|
||||
return is_driver_bulk_out(handlers, usb_device_desc, buf, length, transferred);
|
||||
}
|
||||
|
||||
// Read from bulk endpoint. Returns libusb error code
|
||||
static int bulk_in(is_nitro_device_handlers* handlers, const is_nitro_usb_device* usb_device_desc, uint8_t *buf, int length, int *transferred) {
|
||||
if(handlers->usb_handle)
|
||||
return is_nitro_libusb_bulk_in(handlers, usb_device_desc, buf, length, transferred);
|
||||
return is_driver_bulk_in(handlers, buf, length, transferred);
|
||||
return is_driver_bulk_in(handlers, usb_device_desc, buf, length, transferred);
|
||||
}
|
||||
|
||||
// Read from bulk endpoint. Returns libusb error code
|
||||
static void bulk_in_async(is_nitro_device_handlers* handlers, const is_nitro_usb_device* usb_device_desc, uint8_t *buf, int length, isn_async_callback_data* cb_data) {
|
||||
if(handlers->usb_handle)
|
||||
return is_nitro_libusb_async_in_start(handlers, usb_device_desc, buf, length, cb_data);
|
||||
is_drive_async_in_start(handlers, usb_device_desc, buf, length, cb_data);
|
||||
}
|
||||
|
||||
static int SendWritePacket(is_nitro_device_handlers* handlers, uint16_t command, is_nitro_packet_type type, uint32_t address, uint8_t* buf, int length, const is_nitro_usb_device* device_desc, bool expect_result = true) {
|
||||
|
|
@ -385,7 +392,7 @@ int DisableLca2(is_nitro_device_handlers* handlers, const is_nitro_usb_device* d
|
|||
ret = WriteNecMemU16(handlers, 0x0F84000A, 1, device_desc);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
//default_sleep(2000);
|
||||
//SleepBetweenTransfers(handlers, 2000);
|
||||
return WriteNecMemU16(handlers, 0x0F84000A, 0, device_desc);
|
||||
}
|
||||
|
||||
|
|
@ -526,3 +533,42 @@ int ReadFrame(is_nitro_device_handlers* handlers, uint8_t* buf, int length, cons
|
|||
return ret;
|
||||
}
|
||||
|
||||
void ReadFrameAsync(is_nitro_device_handlers* handlers, uint8_t* buf, int length, const is_nitro_usb_device* device_desc, isn_async_callback_data* cb_data) {
|
||||
return bulk_in_async(handlers, device_desc, buf, length, cb_data);
|
||||
}
|
||||
|
||||
void CloseAsyncRead(is_nitro_device_handlers* handlers, isn_async_callback_data* cb_data) {
|
||||
if(handlers->usb_handle)
|
||||
return is_nitro_libusb_cancell_callback(cb_data);
|
||||
return is_nitro_is_driver_cancel_callback(cb_data);
|
||||
}
|
||||
|
||||
void SetupISNitroAsyncThread(is_nitro_device_handlers* handlers, void* user_data, std::thread* thread_ptr, bool* keep_going, ConsumerMutex* is_data_ready) {
|
||||
if(handlers->usb_handle)
|
||||
return is_nitro_libusb_start_thread(thread_ptr, keep_going);
|
||||
return is_nitro_is_driver_start_thread(thread_ptr, keep_going, (ISNitroCaptureReceivedData*)user_data, handlers, is_data_ready);
|
||||
}
|
||||
|
||||
void EndISNitroAsyncThread(is_nitro_device_handlers* handlers, void* user_data, std::thread* thread_ptr, bool* keep_going, ConsumerMutex* is_data_ready) {
|
||||
if(handlers->usb_handle)
|
||||
return is_nitro_libusb_close_thread(thread_ptr, keep_going);
|
||||
return is_nitro_is_driver_close_thread(thread_ptr, keep_going, (ISNitroCaptureReceivedData*)user_data);
|
||||
}
|
||||
|
||||
void SleepBetweenTransfers(is_nitro_device_handlers* handlers, float ms) {
|
||||
if (handlers->usb_handle)
|
||||
return is_nitro_libusb_sleep_between_transfers(ms);
|
||||
return is_nitro_is_driver_sleep_between_transfers(ms);
|
||||
}
|
||||
|
||||
void SleepUntilOneFree(is_nitro_device_handlers* handlers, SharedConsumerMutex* mutex) {
|
||||
if (handlers->usb_handle)
|
||||
return is_nitro_libusb_sleep_until_one_free(mutex);
|
||||
return is_nitro_is_driver_sleep_until_one_free(mutex);
|
||||
}
|
||||
|
||||
void SleepUntilFree(is_nitro_device_handlers* handlers, SharedConsumerMutex* mutex, int index) {
|
||||
if (handlers->usb_handle)
|
||||
return is_nitro_libusb_sleep_until_free(mutex, index);
|
||||
return is_nitro_is_driver_sleep_until_free(mutex, index);
|
||||
}
|
||||
|
|
@ -1,6 +1,9 @@
|
|||
#include "usb_is_nitro_communications.hpp"
|
||||
#include "usb_is_nitro_setup_general.hpp"
|
||||
#include "usb_is_nitro_is_driver.hpp"
|
||||
#include "usb_is_nitro_acquisition_general.hpp"
|
||||
#include "frontend.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
|
|
@ -26,8 +29,29 @@
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
|
||||
//#define USE_QUEUED_TRANSFERS
|
||||
|
||||
static int SubmitRead(isn_async_callback_data* cb_data);
|
||||
|
||||
const GUID is_nitro_driver_guid = { .Data1 = 0xB78D7ADA, .Data2 = 0xDDF4, .Data3 = 0x418F, .Data4 = {0x8C, 0x7C, 0x4A, 0xC8, 0x80, 0x30, 0xF5, 0x42} };
|
||||
|
||||
static void is_nitro_is_driver_function(bool* usb_thread_run, ISNitroCaptureReceivedData* is_nitro_capture_recv_data, is_nitro_device_handlers* handlers) {
|
||||
while(*usb_thread_run) {
|
||||
for (int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) {
|
||||
isn_async_callback_data* cb_data = (isn_async_callback_data*)&is_nitro_capture_recv_data[i].cb_data;
|
||||
bool read_data_ready = false;
|
||||
cb_data->transfer_data_access.lock();
|
||||
read_data_ready = cb_data->is_data_ready;
|
||||
cb_data->is_data_ready = false;
|
||||
cb_data->transfer_data_access.unlock();
|
||||
if(is_nitro_capture_recv_data[i].in_use && read_data_ready)
|
||||
cb_data->function(&is_nitro_capture_recv_data[i], cb_data->actual_length, cb_data->status_value);
|
||||
}
|
||||
int dummy = 0;
|
||||
is_nitro_capture_recv_data[0].cb_data.is_transfer_data_ready_mutex->general_timed_lock(&dummy);
|
||||
}
|
||||
}
|
||||
|
||||
static bool read_is_driver_device_info(HANDLE handle, uint8_t* buffer, size_t size, DWORD* num_read) {
|
||||
return DeviceIoControl(handle, 0x22000C, buffer, size, buffer, size, num_read, NULL);
|
||||
}
|
||||
|
|
@ -80,16 +104,7 @@ static bool is_driver_get_device_pid_vid(std::string path, uint16_t& out_vid, ui
|
|||
return true;
|
||||
}
|
||||
|
||||
static void set_handle_timeout(HANDLE handle, int timeout) {
|
||||
COMMTIMEOUTS timeouts;
|
||||
if (GetCommTimeouts(handle, &timeouts)) {
|
||||
timeouts.ReadTotalTimeoutConstant = timeout;
|
||||
timeouts.ReadTotalTimeoutMultiplier = 0;
|
||||
SetCommTimeouts(handle, &timeouts);
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_driver_setup_connection(is_nitro_device_handlers* handlers, const is_nitro_usb_device* usb_device_desc, std::string path) {
|
||||
static bool is_driver_setup_connection(is_nitro_device_handlers* handlers, std::string path) {
|
||||
handlers->usb_handle = NULL;
|
||||
handlers->mutex = NULL;
|
||||
handlers->write_handle = INVALID_HANDLE_VALUE;
|
||||
|
|
@ -103,8 +118,8 @@ static bool is_driver_setup_connection(is_nitro_device_handlers* handlers, const
|
|||
}
|
||||
if (handlers->mutex == NULL)
|
||||
return false;
|
||||
handlers->write_handle = CreateFile((path + (char)(std::filesystem::path::preferred_separator)+"Pipe00").c_str(), (GENERIC_READ | GENERIC_WRITE), (FILE_SHARE_READ | FILE_SHARE_WRITE), NULL, OPEN_EXISTING, 0, NULL);
|
||||
handlers->read_handle = CreateFile((path + (char)(std::filesystem::path::preferred_separator)+"Pipe01").c_str(), (GENERIC_READ | GENERIC_WRITE), (FILE_SHARE_READ | FILE_SHARE_WRITE), NULL, OPEN_EXISTING, 0, NULL);
|
||||
handlers->write_handle = CreateFile((path + (char)(std::filesystem::path::preferred_separator)+"Pipe00").c_str(), (GENERIC_READ | GENERIC_WRITE), (FILE_SHARE_READ | FILE_SHARE_WRITE), NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
|
||||
handlers->read_handle = CreateFile((path + (char)(std::filesystem::path::preferred_separator)+"Pipe01").c_str(), (GENERIC_READ | GENERIC_WRITE), (FILE_SHARE_READ | FILE_SHARE_WRITE), NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
|
||||
if ((handlers->write_handle == INVALID_HANDLE_VALUE) || (handlers->read_handle == INVALID_HANDLE_VALUE))
|
||||
return false;
|
||||
if (!is_driver_device_reset(handlers->write_handle))
|
||||
|
|
@ -113,18 +128,101 @@ static bool is_driver_setup_connection(is_nitro_device_handlers* handlers, const
|
|||
return false;
|
||||
if (!is_driver_pipe_reset(handlers->read_handle))
|
||||
return false;
|
||||
set_handle_timeout(handlers->read_handle, usb_device_desc->bulk_timeout);
|
||||
set_handle_timeout(handlers->write_handle, usb_device_desc->bulk_timeout);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int wait_result_io_operation(HANDLE handle, OVERLAPPED* overlapped_var, int* transferred, const is_nitro_usb_device* usb_device_desc) {
|
||||
DWORD num_bytes = 0;
|
||||
int retval = 0;
|
||||
int error = 0;
|
||||
do {
|
||||
retval = GetOverlappedResultEx(handle, overlapped_var, &num_bytes, usb_device_desc->bulk_timeout, true);
|
||||
error = GetLastError();
|
||||
} while((retval == 0) && (error == WAIT_IO_COMPLETION));
|
||||
*transferred = num_bytes;
|
||||
if (retval == 0) {
|
||||
if (error == WAIT_TIMEOUT) {
|
||||
CancelIoEx(handle, overlapped_var);
|
||||
return LIBUSB_ERROR_TIMEOUT;
|
||||
}
|
||||
return LIBUSB_ERROR_OTHER;
|
||||
}
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
static void ClearAllQueueElements(isn_async_callback_data* cb_data) {
|
||||
int queue_elems_curr = *cb_data->queue_elems;
|
||||
for (int i = 0; i < queue_elems_curr; i++) {
|
||||
cb_data->cb_queue[i]->transfer_data = NULL;
|
||||
ISNitroCaptureReceivedData* user_data = (ISNitroCaptureReceivedData*)cb_data->cb_queue[i]->actual_user_data;
|
||||
user_data->in_use = false;
|
||||
}
|
||||
*cb_data->queue_elems = 0;
|
||||
}
|
||||
|
||||
static void BasicCompletionOutputRoutine(isn_async_callback_data* cb_data, int num_bytes, int error) {
|
||||
cb_data->transfer_data_access.lock();
|
||||
if ((error == LIBUSB_SUCCESS) && (num_bytes != cb_data->requested_length))
|
||||
error = LIBUSB_ERROR_INTERRUPTED;
|
||||
if (error == LIBUSB_SUCCESS) {
|
||||
if (*cb_data->queue_elems) {
|
||||
isn_async_callback_data* cb_data_next = (isn_async_callback_data*)cb_data->cb_queue[--(*cb_data->queue_elems)];
|
||||
int retval = SubmitRead(cb_data_next);
|
||||
if (retval == 0)
|
||||
error = LIBUSB_ERROR_BUSY;
|
||||
}
|
||||
else
|
||||
*cb_data->one_transfer_active = false;
|
||||
}
|
||||
if (error != LIBUSB_SUCCESS) {
|
||||
ClearAllQueueElements(cb_data);
|
||||
*cb_data->one_transfer_active = false;
|
||||
}
|
||||
cb_data->transfer_data = NULL;
|
||||
cb_data->actual_length = num_bytes;
|
||||
cb_data->status_value = error;
|
||||
cb_data->is_data_ready = true;
|
||||
cb_data->is_transfer_data_ready_mutex->specific_unlock(cb_data->internal_index);
|
||||
cb_data->is_transfer_done_mutex->specific_unlock(cb_data->internal_index);
|
||||
cb_data->transfer_data_access.unlock();
|
||||
}
|
||||
|
||||
static void OverlappedCompletionNothingRoutine(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, OVERLAPPED* overlapped_var) {
|
||||
return;
|
||||
}
|
||||
|
||||
static void OverlappedCompletionOutputRoutine(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, OVERLAPPED* overlapped_var) {
|
||||
isn_async_callback_data* cb_data = (isn_async_callback_data*)overlapped_var->hEvent;
|
||||
DWORD num_bytes = 0;
|
||||
bool retval = false;
|
||||
int error = LIBUSB_ERROR_OTHER;
|
||||
if (!dwErrorCode) {
|
||||
retval = GetOverlappedResult(cb_data->handle, overlapped_var, &num_bytes, false);
|
||||
error = GetLastError();
|
||||
}
|
||||
|
||||
error = retval ? LIBUSB_SUCCESS : LIBUSB_ERROR_OTHER;
|
||||
BasicCompletionOutputRoutine(cb_data, num_bytes, error);
|
||||
}
|
||||
|
||||
static int SubmitRead(isn_async_callback_data* cb_data) {
|
||||
#ifdef USE_QUEUED_TRANSFERS
|
||||
int retval = ReadFileEx(cb_data->handle, cb_data->buffer, cb_data->requested_length, (OVERLAPPED*)cb_data->transfer_data, OverlappedCompletionOutputRoutine);
|
||||
#else
|
||||
int retval = ReadFileEx(cb_data->handle, cb_data->buffer, cb_data->requested_length, (OVERLAPPED*)cb_data->transfer_data, OverlappedCompletionNothingRoutine);
|
||||
#endif
|
||||
if (retval)
|
||||
cb_data->cb_active_transfer = cb_data;
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
||||
is_nitro_device_handlers* is_driver_serial_reconnection(const is_nitro_usb_device* usb_device_desc, CaptureDevice* device) {
|
||||
is_nitro_device_handlers* is_driver_serial_reconnection(CaptureDevice* device) {
|
||||
is_nitro_device_handlers* final_handlers = NULL;
|
||||
#ifdef _WIN32
|
||||
if (device->path != "") {
|
||||
is_nitro_device_handlers handlers;
|
||||
if (is_driver_setup_connection(&handlers, usb_device_desc, device->path)) {
|
||||
if (is_driver_setup_connection(&handlers, device->path)) {
|
||||
final_handlers = new is_nitro_device_handlers;
|
||||
final_handlers->usb_handle = NULL;
|
||||
final_handlers->mutex = handlers.mutex;
|
||||
|
|
@ -176,7 +274,7 @@ void is_driver_list_devices(std::vector<CaptureDevice> &devices_list, bool* not_
|
|||
const is_nitro_usb_device* usb_device_desc = GetISNitroDesc(j);
|
||||
if(not_supported_elems[j] && (usb_device_desc->vid == vid) && (usb_device_desc->pid == pid)) {
|
||||
is_nitro_device_handlers handlers;
|
||||
if(is_driver_setup_connection(&handlers, usb_device_desc, path))
|
||||
if(is_driver_setup_connection(&handlers, path))
|
||||
is_nitro_insert_device(devices_list, &handlers, usb_device_desc, curr_serial_extra_id_is_nitro[j], path);
|
||||
is_driver_end_connection(&handlers);
|
||||
break;
|
||||
|
|
@ -191,23 +289,126 @@ void is_driver_list_devices(std::vector<CaptureDevice> &devices_list, bool* not_
|
|||
}
|
||||
|
||||
// Write to bulk
|
||||
int is_driver_bulk_out(is_nitro_device_handlers* handlers, uint8_t* buf, int length, int* transferred) {
|
||||
bool result = true;
|
||||
int is_driver_bulk_out(is_nitro_device_handlers* handlers, const is_nitro_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred) {
|
||||
#ifdef _WIN32
|
||||
OVERLAPPED overlapped_var;
|
||||
memset(&overlapped_var, 0, sizeof(OVERLAPPED));
|
||||
DWORD num_bytes = 0;
|
||||
result = WriteFile(handlers->write_handle, buf, length, &num_bytes, NULL);
|
||||
*transferred = num_bytes;
|
||||
int retval = WriteFileEx(handlers->write_handle, buf, length, &overlapped_var, OverlappedCompletionNothingRoutine);
|
||||
if(retval == 0)
|
||||
return LIBUSB_ERROR_BUSY;
|
||||
return wait_result_io_operation(handlers->write_handle, &overlapped_var, transferred, usb_device_desc);
|
||||
#endif
|
||||
return result ? LIBUSB_SUCCESS : LIBUSB_ERROR_OTHER;
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
// Read from bulk
|
||||
int is_driver_bulk_in(is_nitro_device_handlers* handlers, uint8_t* buf, int length, int* transferred) {
|
||||
bool result = true;
|
||||
int is_driver_bulk_in(is_nitro_device_handlers* handlers, const is_nitro_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred) {
|
||||
#ifdef _WIN32
|
||||
DWORD num_bytes = 0;
|
||||
result = ReadFile(handlers->read_handle, buf, length, &num_bytes, NULL);
|
||||
*transferred = num_bytes;
|
||||
OVERLAPPED overlapped_var;
|
||||
memset(&overlapped_var, 0, sizeof(OVERLAPPED));
|
||||
int retval = ReadFileEx(handlers->read_handle, buf, length, &overlapped_var, OverlappedCompletionNothingRoutine);
|
||||
if (retval == 0)
|
||||
return LIBUSB_ERROR_BUSY;
|
||||
return wait_result_io_operation(handlers->read_handle, &overlapped_var, transferred, usb_device_desc);
|
||||
#endif
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
int is_drive_async_in_start(is_nitro_device_handlers* handlers, const is_nitro_usb_device* usb_device_desc, uint8_t* buf, int length, isn_async_callback_data* cb_data) {
|
||||
#ifdef _WIN32
|
||||
cb_data->transfer_data_access.lock();
|
||||
cb_data->is_data_ready = false;
|
||||
cb_data->transfer_data = cb_data->base_transfer_data;
|
||||
cb_data->handle = handlers->read_handle;
|
||||
cb_data->requested_length = length;
|
||||
cb_data->buffer = buf;
|
||||
OVERLAPPED* overlap_data = (OVERLAPPED*)cb_data->transfer_data;
|
||||
memset(overlap_data, 0, sizeof(OVERLAPPED));
|
||||
#ifdef USE_QUEUED_TRANSFERS
|
||||
overlap_data->hEvent = cb_data;
|
||||
#endif
|
||||
cb_data->is_transfer_done_mutex->specific_try_lock(cb_data->internal_index);
|
||||
cb_data->is_transfer_data_ready_mutex->specific_try_lock(cb_data->internal_index);
|
||||
int retval = 1;
|
||||
if (!(*cb_data->one_transfer_active))
|
||||
retval = SubmitRead(cb_data);
|
||||
else
|
||||
cb_data->cb_queue[(*cb_data->queue_elems)++] = cb_data;
|
||||
if(retval == 1)
|
||||
*cb_data->one_transfer_active = true;
|
||||
cb_data->transfer_data_access.unlock();
|
||||
if (retval == 0)
|
||||
return LIBUSB_ERROR_BUSY;
|
||||
#ifndef USE_QUEUED_TRANSFERS
|
||||
int num_bytes = 0;
|
||||
int error = wait_result_io_operation(handlers->read_handle, (OVERLAPPED*)overlap_data, &num_bytes, usb_device_desc);
|
||||
BasicCompletionOutputRoutine(cb_data, num_bytes, error);
|
||||
#endif
|
||||
#endif
|
||||
return LIBUSB_SUCCESS;
|
||||
}
|
||||
|
||||
void is_nitro_is_driver_start_thread(std::thread* thread_ptr, bool* usb_thread_run, ISNitroCaptureReceivedData* is_nitro_capture_recv_data, is_nitro_device_handlers* handlers, ConsumerMutex* AsyncMutexPtr) {
|
||||
#ifdef _WIN32
|
||||
*usb_thread_run = true;
|
||||
for (int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++)
|
||||
is_nitro_capture_recv_data[i].cb_data.base_transfer_data = new OVERLAPPED;
|
||||
*thread_ptr = std::thread(is_nitro_is_driver_function, usb_thread_run, is_nitro_capture_recv_data, handlers);
|
||||
#endif
|
||||
}
|
||||
|
||||
void is_nitro_is_driver_close_thread(std::thread* thread_ptr, bool* usb_thread_run, ISNitroCaptureReceivedData* is_nitro_capture_recv_data) {
|
||||
#ifdef _WIN32
|
||||
*usb_thread_run = false;
|
||||
is_nitro_capture_recv_data[0].cb_data.is_transfer_data_ready_mutex->specific_unlock(0);
|
||||
thread_ptr->join();
|
||||
for (int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++)
|
||||
delete is_nitro_capture_recv_data[i].cb_data.base_transfer_data;
|
||||
#endif
|
||||
}
|
||||
|
||||
void is_nitro_is_driver_cancel_callback(isn_async_callback_data* cb_data) {
|
||||
#ifdef _WIN32
|
||||
cb_data->transfer_data_access.lock();
|
||||
ClearAllQueueElements(cb_data);
|
||||
if(*cb_data->one_transfer_active) {
|
||||
CancelIoEx(cb_data->cb_active_transfer->handle, (OVERLAPPED*)cb_data->cb_active_transfer->transfer_data);
|
||||
*cb_data->one_transfer_active = false;
|
||||
}
|
||||
cb_data->transfer_data_access.unlock();
|
||||
#endif
|
||||
}
|
||||
|
||||
void is_nitro_is_driver_sleep_between_transfers(float ms) {
|
||||
#ifdef _WIN32
|
||||
#ifdef USE_QUEUED_TRANSFERS
|
||||
SleepEx(ms, true);
|
||||
#else
|
||||
default_sleep(ms);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void is_nitro_is_driver_sleep_until_one_free(SharedConsumerMutex* mutex) {
|
||||
#ifdef _WIN32
|
||||
int dummy = 0;
|
||||
#ifdef USE_QUEUED_TRANSFERS
|
||||
SleepEx(mutex->get_time_s() * 100, true);
|
||||
mutex->general_try_lock(&dummy);
|
||||
#else
|
||||
mutex->general_timed_lock(&dummy);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void is_nitro_is_driver_sleep_until_free(SharedConsumerMutex* mutex, int index) {
|
||||
#ifdef _WIN32
|
||||
#ifdef USE_QUEUED_TRANSFERS
|
||||
while (!(mutex->specific_try_lock(index)))
|
||||
SleepEx(mutex->get_time_s() * 100, true);
|
||||
#else
|
||||
mutex->specific_lock(index);
|
||||
#endif
|
||||
#endif
|
||||
return result ? LIBUSB_SUCCESS : LIBUSB_ERROR_OTHER;
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
#include "usb_generic.hpp"
|
||||
|
||||
#include <libusb.h>
|
||||
#include <frontend.hpp>
|
||||
|
||||
// Code based off of Gericom's sample code. Distributed under the MIT License. Copyright (c) 2024 Gericom
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
|
|
@ -24,6 +25,30 @@
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
|
||||
static void is_nitro_usb_thread_function(bool* usb_thread_run) {
|
||||
if(!usb_is_initialized())
|
||||
return;
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 300000;
|
||||
while(*usb_thread_run)
|
||||
libusb_handle_events_timeout_completed(get_usb_ctx(), &tv, NULL);
|
||||
}
|
||||
|
||||
void is_nitro_libusb_start_thread(std::thread* thread_ptr, bool* usb_thread_run) {
|
||||
if(!usb_is_initialized())
|
||||
return;
|
||||
*usb_thread_run = true;
|
||||
*thread_ptr = std::thread(is_nitro_usb_thread_function, usb_thread_run);
|
||||
}
|
||||
|
||||
void is_nitro_libusb_close_thread(std::thread* thread_ptr, bool* usb_thread_run) {
|
||||
if(!usb_is_initialized())
|
||||
return;
|
||||
*usb_thread_run = false;
|
||||
thread_ptr->join();
|
||||
}
|
||||
|
||||
static bool is_nitro_libusb_setup_connection(libusb_device_handle* handle, const is_nitro_usb_device* usb_device_desc) {
|
||||
if (libusb_set_configuration(handle, usb_device_desc->default_config) != LIBUSB_SUCCESS)
|
||||
return false;
|
||||
|
|
@ -136,3 +161,46 @@ int is_nitro_libusb_bulk_out(is_nitro_device_handlers* handlers, const is_nitro_
|
|||
int is_nitro_libusb_bulk_in(is_nitro_device_handlers* handlers, const is_nitro_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred) {
|
||||
return libusb_bulk_transfer(handlers->usb_handle, usb_device_desc->ep2_in, buf, length, transferred, usb_device_desc->bulk_timeout);
|
||||
}
|
||||
|
||||
void is_nitro_libusb_cancell_callback(isn_async_callback_data* cb_data) {
|
||||
cb_data->transfer_data_access.lock();
|
||||
if(cb_data->transfer_data)
|
||||
libusb_cancel_transfer((libusb_transfer*)cb_data->transfer_data);
|
||||
cb_data->transfer_data_access.unlock();
|
||||
}
|
||||
|
||||
void is_nitro_libusb_async_callback(libusb_transfer* transfer) {
|
||||
isn_async_callback_data* cb_data = (isn_async_callback_data*)transfer->user_data;
|
||||
cb_data->transfer_data_access.lock();
|
||||
cb_data->transfer_data = NULL;
|
||||
cb_data->is_transfer_done_mutex->specific_unlock(cb_data->internal_index);
|
||||
cb_data->transfer_data_access.unlock();
|
||||
cb_data->function(cb_data->actual_user_data, transfer->actual_length, transfer->status);
|
||||
}
|
||||
|
||||
// Read from bulk
|
||||
void is_nitro_libusb_async_in_start(is_nitro_device_handlers* handlers, const is_nitro_usb_device* usb_device_desc, uint8_t* buf, int length, isn_async_callback_data* cb_data) {
|
||||
libusb_transfer *transfer_in = libusb_alloc_transfer(0);
|
||||
if(!transfer_in)
|
||||
return;
|
||||
cb_data->transfer_data_access.lock();
|
||||
cb_data->transfer_data = transfer_in;
|
||||
cb_data->is_transfer_done_mutex->specific_try_lock(cb_data->internal_index);
|
||||
libusb_fill_bulk_transfer(transfer_in, handlers->usb_handle, usb_device_desc->ep2_in, buf, length, is_nitro_libusb_async_callback, cb_data, usb_device_desc->bulk_timeout);
|
||||
transfer_in->flags |= LIBUSB_TRANSFER_FREE_TRANSFER;
|
||||
libusb_submit_transfer(transfer_in);
|
||||
cb_data->transfer_data_access.unlock();
|
||||
}
|
||||
|
||||
void is_nitro_libusb_sleep_between_transfers(float ms) {
|
||||
default_sleep(ms);
|
||||
}
|
||||
|
||||
void is_nitro_libusb_sleep_until_one_free(SharedConsumerMutex* mutex) {
|
||||
int dummy = 0;
|
||||
mutex->general_timed_lock(&dummy);
|
||||
}
|
||||
|
||||
void is_nitro_libusb_sleep_until_free(SharedConsumerMutex* mutex, int index) {
|
||||
mutex->specific_lock(index);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#include "usb_generic.hpp"
|
||||
#include <thread>
|
||||
|
||||
static bool usb_thread_run = false;
|
||||
static bool usb_initialized = false;
|
||||
static libusb_context* usb_ctx = NULL; // libusb session context
|
||||
|
||||
|
|
@ -13,13 +15,11 @@ void usb_init() {
|
|||
return;
|
||||
}
|
||||
usb_initialized = true;
|
||||
return;
|
||||
}
|
||||
|
||||
void usb_close() {
|
||||
if(usb_initialized) {
|
||||
if(usb_initialized)
|
||||
libusb_exit(usb_ctx);
|
||||
}
|
||||
usb_ctx = NULL;
|
||||
usb_initialized = false;
|
||||
}
|
||||
|
|
|
|||
179
source/utils.cpp
179
source/utils.cpp
|
|
@ -214,16 +214,20 @@ ConsumerMutex::ConsumerMutex() {
|
|||
}
|
||||
|
||||
void ConsumerMutex::update_time_multiplier(float time_multiplier) {
|
||||
if(time_multiplier <= 0)
|
||||
if (time_multiplier <= 0)
|
||||
return;
|
||||
this->time_multiplier = time_multiplier;
|
||||
}
|
||||
|
||||
double ConsumerMutex::get_time_s() {
|
||||
return 1.0 / ((base_time_fps) * (1.0 / this->time_multiplier));
|
||||
}
|
||||
|
||||
void ConsumerMutex::lock() {
|
||||
access_mutex.lock();
|
||||
bool success = false;
|
||||
while(!success) {
|
||||
if(count) {
|
||||
while (!success) {
|
||||
if (count) {
|
||||
count--;
|
||||
success = true;
|
||||
}
|
||||
|
|
@ -233,41 +237,192 @@ void ConsumerMutex::lock() {
|
|||
}
|
||||
access_mutex.unlock();
|
||||
}
|
||||
|
||||
|
||||
bool ConsumerMutex::timed_lock() {
|
||||
std::chrono::duration<double>max_timed_wait = std::chrono::duration<double>(1.0 / ((base_time_fps) * (1.0 / this->time_multiplier)));
|
||||
std::chrono::duration<double>max_timed_wait = std::chrono::duration<double>(this->get_time_s());
|
||||
access_mutex.lock();
|
||||
bool success = false;
|
||||
while(!success) {
|
||||
if(count) {
|
||||
while (!success) {
|
||||
if (count) {
|
||||
count--;
|
||||
success = true;
|
||||
}
|
||||
else {
|
||||
auto result = condition.wait_for(access_mutex, max_timed_wait);
|
||||
if((result == std::cv_status::timeout) && (!count))
|
||||
if ((result == std::cv_status::timeout) && (!count))
|
||||
break;
|
||||
}
|
||||
}
|
||||
access_mutex.unlock();
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
bool ConsumerMutex::try_lock() {
|
||||
access_mutex.lock();
|
||||
bool success = false;
|
||||
if(count) {
|
||||
if (count) {
|
||||
count--;
|
||||
success = true;
|
||||
}
|
||||
access_mutex.unlock();
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
void ConsumerMutex::unlock() {
|
||||
access_mutex.lock();
|
||||
// Enforce 1 max
|
||||
count = 1;
|
||||
condition.notify_one();
|
||||
condition.notify_all();
|
||||
access_mutex.unlock();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
||||
SharedConsumerMutex::SharedConsumerMutex(int num_elements) {
|
||||
this->num_elements = num_elements;
|
||||
if(this->num_elements <= 0)
|
||||
this->num_elements = 1;
|
||||
this->counts = new int[this->num_elements];
|
||||
for(int i = 0; i < this->num_elements; i++)
|
||||
this->counts[i] = 0;
|
||||
}
|
||||
|
||||
SharedConsumerMutex::~SharedConsumerMutex() {
|
||||
delete []this->counts;
|
||||
}
|
||||
|
||||
void SharedConsumerMutex::update_time_multiplier(float time_multiplier) {
|
||||
if (time_multiplier <= 0)
|
||||
return;
|
||||
this->time_multiplier = time_multiplier;
|
||||
}
|
||||
|
||||
double SharedConsumerMutex::get_time_s() {
|
||||
return 1.0 / ((base_time_fps) * (1.0 / this->time_multiplier));
|
||||
}
|
||||
|
||||
void SharedConsumerMutex::general_lock(int* index) {
|
||||
access_mutex.lock();
|
||||
bool success = false;
|
||||
while (!success) {
|
||||
for (int i = 0; i < num_elements; i++)
|
||||
if (counts[i]) {
|
||||
counts[i]--;
|
||||
success = true;
|
||||
*index = i;
|
||||
break;
|
||||
}
|
||||
if (!success)
|
||||
condition.wait(access_mutex);
|
||||
}
|
||||
access_mutex.unlock();
|
||||
}
|
||||
|
||||
bool SharedConsumerMutex::general_timed_lock(int* index) {
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> clock_start = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> clock_end = clock_start + std::chrono::nanoseconds((int)(this->get_time_s() * 1000 * 1000));
|
||||
access_mutex.lock();
|
||||
bool success = false;
|
||||
auto result = std::cv_status::no_timeout;
|
||||
while (!success) {
|
||||
for (int i = 0; i < num_elements; i++)
|
||||
if (counts[i]) {
|
||||
counts[i]--;
|
||||
success = true;
|
||||
*index = i;
|
||||
break;
|
||||
}
|
||||
if(!success) {
|
||||
const auto curr_time = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double>timed_wait = clock_end - curr_time;
|
||||
if (curr_time >= clock_end)
|
||||
result = std::cv_status::timeout;
|
||||
if (result == std::cv_status::timeout)
|
||||
break;
|
||||
result = condition.wait_for(access_mutex, timed_wait);
|
||||
}
|
||||
}
|
||||
access_mutex.unlock();
|
||||
return success;
|
||||
}
|
||||
|
||||
bool SharedConsumerMutex::general_try_lock(int* index) {
|
||||
access_mutex.lock();
|
||||
bool success = false;
|
||||
for (int i = 0; i < num_elements; i++)
|
||||
if (counts[i]) {
|
||||
counts[i]--;
|
||||
success = true;
|
||||
*index = i;
|
||||
break;
|
||||
}
|
||||
access_mutex.unlock();
|
||||
return success;
|
||||
}
|
||||
|
||||
void SharedConsumerMutex::specific_unlock(int index) {
|
||||
if ((index < 0) || (index >= num_elements))
|
||||
return;
|
||||
access_mutex.lock();
|
||||
// Enforce 1 max
|
||||
counts[index] = 1;
|
||||
condition.notify_all();
|
||||
access_mutex.unlock();
|
||||
}
|
||||
|
||||
void SharedConsumerMutex::specific_lock(int index) {
|
||||
if ((index < 0) || (index >= num_elements))
|
||||
return;
|
||||
access_mutex.lock();
|
||||
bool success = false;
|
||||
while (!success) {
|
||||
if(counts[index]) {
|
||||
counts[index]--;
|
||||
success = true;
|
||||
}
|
||||
else
|
||||
condition.wait(access_mutex);
|
||||
}
|
||||
access_mutex.unlock();
|
||||
}
|
||||
|
||||
bool SharedConsumerMutex::specific_timed_lock(int index) {
|
||||
if ((index < 0) || (index >= num_elements))
|
||||
return false;
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> clock_start = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> clock_end = clock_start + std::chrono::nanoseconds((int)(this->get_time_s() * 1000 * 1000));
|
||||
access_mutex.lock();
|
||||
bool success = false;
|
||||
auto result = std::cv_status::no_timeout;
|
||||
while (!success) {
|
||||
if (counts[index]) {
|
||||
counts[index]--;
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
if (!success) {
|
||||
const auto curr_time = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double>timed_wait = clock_end - curr_time;
|
||||
if (curr_time >= clock_end)
|
||||
result = std::cv_status::timeout;
|
||||
if (result == std::cv_status::timeout)
|
||||
break;
|
||||
result = condition.wait_for(access_mutex, timed_wait);
|
||||
}
|
||||
}
|
||||
access_mutex.unlock();
|
||||
return success;
|
||||
}
|
||||
|
||||
bool SharedConsumerMutex::specific_try_lock(int index) {
|
||||
if((index < 0) || (index >= num_elements))
|
||||
return false;
|
||||
access_mutex.lock();
|
||||
bool success = false;
|
||||
if (counts[index]) {
|
||||
counts[index]--;
|
||||
success = true;
|
||||
}
|
||||
access_mutex.unlock();
|
||||
return success;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user