diff --git a/CMakeLists.txt b/CMakeLists.txt index 67b88fa..29e7b04 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,10 +10,11 @@ set(N3DSXL_LOOPY_SUPPORT 1) set(NEW_DS_LOOPY_SUPPORT 1) set(IS_DEVICES_SUPPORT 1) set(OLD_DS_3DS_LOOPY_SUPPORT 1) +set(CYPRESS_NISETRO_SUPPORT 1) set(USE_FTD2XX_FOR_NEW_DS_LOOPY ${NEW_DS_LOOPY_SUPPORT}) set(USE_LIBFTDI_FOR_NEW_DS_LOOPY ${NEW_DS_LOOPY_SUPPORT}) -set(USE_LIBUSB_SUPPORT ${IS_DEVICES_SUPPORT} OR ${OLD_DS_3DS_LOOPY_SUPPORT} OR ${USE_LIBFTDI_FOR_NEW_DS_LOOPY}) +set(USE_LIBUSB_SUPPORT ${IS_DEVICES_SUPPORT} OR ${OLD_DS_3DS_LOOPY_SUPPORT} OR ${USE_LIBFTDI_FOR_NEW_DS_LOOPY} OR ${CYPRESS_NISETRO_SUPPORT}) if(NOT (${CMAKE_SYSTEM_NAME} STREQUAL "Windows")) #Performance outside of Windows is very bad for the official drivers... set(USE_FTD2XX_FOR_NEW_DS_LOOPY 0) @@ -293,6 +294,7 @@ set(EXTRA_DEPENDENCIES "") set(SOURCE_CPP_DEVICE_FILES_BASE_PATH "source/CaptureDeviceSpecific") set(SOURCE_CPP_IS_DEVICES_FILES_BASE_PATH "${SOURCE_CPP_DEVICE_FILES_BASE_PATH}/ISDevices") set(SOURCE_CPP_FTD2_FILES_BASE_PATH "${SOURCE_CPP_DEVICE_FILES_BASE_PATH}/DSCapture_FTD2") +set(SOURCE_CPP_CYPRESS_NISETRO_DEVICES_FILES_BASE_PATH "${SOURCE_CPP_DEVICE_FILES_BASE_PATH}/Nisetro") if(N3DSXL_LOOPY_SUPPORT) list(APPEND FETCH_CONTENT_MAKE_AVAILABLE_LIBRARIES FTD3XX) list(APPEND SOURCE_CPP_EXTRA_FILES ${SOURCE_CPP_DEVICE_FILES_BASE_PATH}/3dscapture_ftd3.cpp) @@ -328,6 +330,14 @@ if(OLD_DS_3DS_LOOPY_SUPPORT) list(APPEND EXTRA_CXX_FLAGS "-DUSE_DS_3DS_USB") endif() endif() +if(CYPRESS_NISETRO_SUPPORT) + list(APPEND SOURCE_CPP_EXTRA_FILES ${SOURCE_CPP_CYPRESS_NISETRO_DEVICES_FILES_BASE_PATH}/cypress_nisetro_driver_comms.cpp ${SOURCE_CPP_CYPRESS_NISETRO_DEVICES_FILES_BASE_PATH}/cypress_nisetro_libusb_comms.cpp ${SOURCE_CPP_CYPRESS_NISETRO_DEVICES_FILES_BASE_PATH}/cypress_nisetro_communications.cpp ${SOURCE_CPP_CYPRESS_NISETRO_DEVICES_FILES_BASE_PATH}/cypress_nisetro_acquisition.cpp ${TOOLS_DATA_DIR}/nisetro_ds_fw.cpp) + if(MSVC) + list(APPEND EXTRA_CXX_FLAGS "/DUSE_CYNI_USB") + else() + list(APPEND EXTRA_CXX_FLAGS "-DUSE_CYNI_USB") + endif() +endif() if(NEW_DS_LOOPY_SUPPORT) list(APPEND SOURCE_CPP_EXTRA_FILES ${SOURCE_CPP_FTD2_FILES_BASE_PATH}/dscapture_ftd2_shared.cpp ${SOURCE_CPP_FTD2_FILES_BASE_PATH}/dscapture_ftd2_compatibility.cpp ${TOOLS_DATA_DIR}/ftd2_ds2_fw_1.cpp ${TOOLS_DATA_DIR}/ftd2_ds2_fw_2.cpp) if(MSVC) @@ -475,9 +485,9 @@ execute_process(COMMAND ${CMAKE_COMMAND} --build ${TOOLS_DATA_DIR}) set(OUTPUT_NAME cc3dsfs) if(MSVC) - set_source_files_properties(source/conversions.cpp PROPERTIES COMPILE_OPTIONS "/O2") + set_source_files_properties(source/conversions.cpp PROPERTIES COMPILE_OPTIONS "$<$:/O2>") else() - set_source_files_properties(source/conversions.cpp PROPERTIES COMPILE_OPTIONS "-O3") + set_source_files_properties(source/conversions.cpp PROPERTIES COMPILE_OPTIONS "$<$:-O3>") endif() add_executable(${OUTPUT_NAME} source/cc3dsfs.cpp source/utils.cpp source/audio_data.cpp source/audio.cpp source/frontend.cpp source/TextRectangle.cpp source/WindowScreen.cpp source/WindowScreen_Menu.cpp source/devicecapture.cpp source/conversions.cpp source/ExtraButtons.cpp source/Menus/ConnectionMenu.cpp source/Menus/OptionSelectionMenu.cpp source/Menus/MainMenu.cpp source/Menus/VideoMenu.cpp source/Menus/CropMenu.cpp source/Menus/PARMenu.cpp source/Menus/RotationMenu.cpp source/Menus/OffsetMenu.cpp source/Menus/AudioMenu.cpp source/Menus/BFIMenu.cpp source/Menus/RelativePositionMenu.cpp source/Menus/ResolutionMenu.cpp source/Menus/FileConfigMenu.cpp source/Menus/ExtraSettingsMenu.cpp source/Menus/StatusMenu.cpp source/Menus/LicenseMenu.cpp source/WindowCommands.cpp source/Menus/ShortcutMenu.cpp source/Menus/ActionSelectionMenu.cpp source/Menus/ScalingRatioMenu.cpp source/Menus/ISNitroMenu.cpp source/Menus/VideoEffectsMenu.cpp source/CaptureDataBuffers.cpp source/Menus/InputMenu.cpp ${TOOLS_DATA_DIR}/font_ttf.cpp ${TOOLS_DATA_DIR}/shaders_list.cpp ${SOURCE_CPP_EXTRA_FILES}) @@ -498,7 +508,7 @@ endif() if(USE_FTD2XX_FOR_NEW_DS_LOOPY) target_link_libraries(${OUTPUT_NAME} PRIVATE ${ftd2xx_BINARY_DIR}/${FTD2XX_SUBFOLDER}/${FTD2XX_LIB}) endif() -target_include_directories(${OUTPUT_NAME} PRIVATE ${EXTRA_INCLUDE_DIRECTORIES} ${TOOLS_DATA_DIR} ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/include/Menus ${CMAKE_SOURCE_DIR}/include/CaptureDeviceSpecific ${CMAKE_SOURCE_DIR}/include/CaptureDeviceSpecific/ISDevices ${CMAKE_SOURCE_DIR}/include/CaptureDeviceSpecific/DSCapture_FTD2 ${libftdi1_SOURCE_DIR}/src) +target_include_directories(${OUTPUT_NAME} PRIVATE ${EXTRA_INCLUDE_DIRECTORIES} ${TOOLS_DATA_DIR} ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/include/Menus ${CMAKE_SOURCE_DIR}/include/CaptureDeviceSpecific ${CMAKE_SOURCE_DIR}/include/CaptureDeviceSpecific/ISDevices ${CMAKE_SOURCE_DIR}/include/CaptureDeviceSpecific/Nisetro ${CMAKE_SOURCE_DIR}/include/CaptureDeviceSpecific/DSCapture_FTD2 ${libftdi1_SOURCE_DIR}/src) target_compile_features(${OUTPUT_NAME} PRIVATE cxx_std_20) target_compile_options(${OUTPUT_NAME} PRIVATE ${EXTRA_CXX_FLAGS}) @@ -537,6 +547,13 @@ add_custom_command( DEPENDS ${CMAKE_SOURCE_DIR}/bin/ftd2_ds2_fw_2.bin ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION} ) +add_custom_command( + OUTPUT ${TOOLS_DATA_DIR}/nisetro_ds_fw.cpp + COMMENT "Convert fw binary to C - Nisetro DS" + COMMAND ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION} ${CMAKE_SOURCE_DIR}/bin/nisetro_ds_fw.bin ${TOOLS_DATA_DIR} nisetro_ds_fw nisetro_ds_fw + DEPENDS ${CMAKE_SOURCE_DIR}/bin/nisetro_ds_fw.bin ${TOOLS_DATA_DIR}/CMakeBin2C${HOST_FINAL_EXTENSION} +) + set(SHADERS_LIST "") list(APPEND SHADERS_LIST ${CMAKE_SOURCE_DIR}/shaders/bit_crusher_fragment_shader.2_to_x_1_7.frag ${CMAKE_SOURCE_DIR}/shaders/bit_merger_crusher_fragment_shader.2_to_x_1_6.frag ${CMAKE_SOURCE_DIR}/shaders/bit_merger_crusher_fragment_shader_7.frag ${CMAKE_SOURCE_DIR}/shaders/bit_merger_fragment_shader.2_to_x_0_6.frag ${CMAKE_SOURCE_DIR}/shaders/bit_merger_fragment_shader_7.frag ${CMAKE_SOURCE_DIR}/shaders/frame_blending_bit_crusher_fragment_shader.2_to_x_1_7.frag ${CMAKE_SOURCE_DIR}/shaders/frame_blending_fragment_shader.frag ${CMAKE_SOURCE_DIR}/shaders/no_effect_fragment_shader.frag) @@ -606,6 +623,7 @@ else() install(FILES ${USB_RULES_DIR}/51-istwl.rules DESTINATION .) install(FILES ${USB_RULES_DIR}/50-ftd2xx.rules DESTINATION .) install(FILES ${USB_RULES_DIR}/51-ftd2xx.rules DESTINATION .) + install(FILES ${USB_RULES_DIR}/51-nisetro.rules DESTINATION .) install(FILES ${SETUP_SCRIPTS_DIR}/install_usb_rules${SCRIPT_EXTENSION} DESTINATION .) endif() diff --git a/bin/nisetro_ds_fw.bin b/bin/nisetro_ds_fw.bin new file mode 100644 index 0000000..70fc0e6 Binary files /dev/null and b/bin/nisetro_ds_fw.bin differ diff --git a/include/CaptureDeviceSpecific/Nisetro/cypress_nisetro_acquisition.hpp b/include/CaptureDeviceSpecific/Nisetro/cypress_nisetro_acquisition.hpp new file mode 100644 index 0000000..39c0671 --- /dev/null +++ b/include/CaptureDeviceSpecific/Nisetro/cypress_nisetro_acquisition.hpp @@ -0,0 +1,20 @@ +#ifndef __CYPRESS_NISETRO_ACQUISITION_HPP +#define __CYPRESS_NISETRO_ACQUISITION_HPP + +#include +#include "utils.hpp" +#include "hw_defs.hpp" +#include "capture_structs.hpp" +#include "display_structs.hpp" +#include "devicecapture.hpp" + +void list_devices_cyni_device(std::vector &devices_list, std::vector &no_access_list); +bool cyni_device_connect_usb(bool print_failed, CaptureData* capture_data, CaptureDevice* device); +uint64_t cyni_device_get_video_in_size(CaptureStatus* status); +uint64_t cyni_device_get_video_in_size(CaptureData* capture_data); +void cyni_device_acquisition_main_loop(CaptureData* capture_data); +void usb_cyni_device_acquisition_cleanup(CaptureData* capture_data); +void usb_cyni_device_init(); +void usb_cyni_device_close(); + +#endif diff --git a/include/CaptureDeviceSpecific/Nisetro/cypress_nisetro_acquisition_general.hpp b/include/CaptureDeviceSpecific/Nisetro/cypress_nisetro_acquisition_general.hpp new file mode 100644 index 0000000..8c7384b --- /dev/null +++ b/include/CaptureDeviceSpecific/Nisetro/cypress_nisetro_acquisition_general.hpp @@ -0,0 +1,44 @@ +#ifndef __CYPRESS_NISETRO_ACQUISITION_GENERAL_HPP +#define __CYPRESS_NISETRO_ACQUISITION_GENERAL_HPP + +#include "cypress_nisetro_communications.hpp" + +#define NUM_CAPTURE_RECEIVED_DATA_BUFFERS 4 + +struct CypressDeviceCaptureReceivedData { + volatile bool in_use; + uint32_t index; + CaptureReceived buffer; + SharedConsumerMutex* is_buffer_free_shared_mutex; + size_t* scheduled_special_read; + uint32_t* active_special_read_index; + bool* is_active_special_read; + bool* recalibration_request; + int* status; + uint32_t* last_index; + int* errors_since_last_output; + int* consecutive_output_to_thread; + CaptureData* capture_data; + std::chrono::time_point* clock_start; + CaptureScreensType curr_capture_type; + cyni_async_callback_data cb_data; +}; + +std::string get_serial(const cyni_device_usb_device* usb_device_desc, std::string serial, uint16_t bcd_device, int& curr_serial_extra_id); +CaptureDevice cypress_create_device(const cyni_device_usb_device* usb_device_desc, std::string serial, std::string path); +CaptureDevice cypress_create_device(const cyni_device_usb_device* usb_device_desc, std::string serial); +void cypress_insert_device(std::vector& devices_list, const cyni_device_usb_device* usb_device_desc, std::string serial, uint16_t bcd_device, int& curr_serial_extra_id, std::string path); +void cypress_insert_device(std::vector& devices_list, const cyni_device_usb_device* usb_device_desc, std::string serial, uint16_t bcd_device, int& curr_serial_extra_id); +void cypress_output_to_thread(CaptureData* capture_data, CaptureReceived* capture_buf, CaptureScreensType curr_capture_type, std::chrono::time_point* clock_start, size_t read_size); +int cypress_device_read_frame_and_output(CaptureData* capture_data, CaptureReceived* capture_buf, CaptureScreensType curr_capture_type, std::chrono::time_point &clock_start); +int cypress_device_read_frame_request(CaptureData* capture_data, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data, CaptureScreensType curr_capture_type, uint32_t index); +int cypress_device_get_num_free_buffers(CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data); +void wait_all_cypress_device_buffers_free(CaptureData* capture_data, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data); +void wait_one_cypress_device_buffer_free(CaptureData* capture_data, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data); +bool cypress_device_are_buffers_all_free(CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data); +CypressDeviceCaptureReceivedData* cypress_device_get_free_buffer(CaptureData* capture_data, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data); +int get_cypress_device_status(CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data); +void error_cypress_device_status(CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data, int error_val); +void reset_cypress_device_status(CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data); + +#endif diff --git a/include/CaptureDeviceSpecific/Nisetro/cypress_nisetro_communications.hpp b/include/CaptureDeviceSpecific/Nisetro/cypress_nisetro_communications.hpp new file mode 100644 index 0000000..cfc0b20 --- /dev/null +++ b/include/CaptureDeviceSpecific/Nisetro/cypress_nisetro_communications.hpp @@ -0,0 +1,84 @@ +#ifndef __CYPRESS_NISETRO_DEVICE_COMMUNICATIONS_HPP +#define __CYPRESS_NISETRO_DEVICE_COMMUNICATIONS_HPP + +#include +#include +#include +#include +#include "utils.hpp" +#include "capture_structs.hpp" + +enum cypress_nisetro_device_type { + CYPRESS_NISETRO_BLANK_DEVICE, + CYPRESS_NISETRO_DS_DEVICE, +}; + +typedef void (*cyni_async_callback_function)(void* user_data, int transfer_length, int transfer_status); + +struct cyni_async_callback_data { + cyni_async_callback_function function; + void* actual_user_data; + void* transfer_data; + void* handle; + void* extra_transfer_data; + void* base_transfer_data; + std::mutex transfer_data_access; + SharedConsumerMutex* is_transfer_done_mutex; + SharedConsumerMutex* is_transfer_data_ready_mutex; + std::chrono::time_point start_request; + float timeout_s; + size_t requested_length; + uint8_t* buffer; + size_t actual_length; + int status_value; + int internal_index; + bool is_data_ready; +}; + +struct cyni_device_usb_device { + std::string name; + std::string long_name; + int vid; + int pid; + int default_config; + int default_interface; + int bulk_timeout; + int ep_ctrl_bulk_in; + int ep_ctrl_bulk_out; + int ep_bulk_in; + cypress_nisetro_device_type device_type; + InputVideoDataType video_data_type; + size_t max_usb_packet_size; + bool do_pipe_clear_reset; + uint8_t* firmware_to_load; + size_t firmware_size; + cypress_nisetro_device_type next_device; + bool has_bcd_device_serial; + int alt_interface; +}; + +struct cyni_device_device_handlers { + libusb_device_handle* usb_handle; + void* read_handle; + void* write_handle; + void* mutex; + std::string path; +}; + +int GetNumCyNiDeviceDesc(void); +const cyni_device_usb_device* GetCyNiDeviceDesc(int index);const cyni_device_usb_device* GetNextDeviceDesc(const cyni_device_usb_device* device); +const cyni_device_usb_device* GetNextDeviceDesc(const cyni_device_usb_device* device); +bool has_to_load_firmware(const cyni_device_usb_device* device); +bool load_firmware(cyni_device_device_handlers* handlers, const cyni_device_usb_device* device, uint8_t patch_id); +int capture_start(cyni_device_device_handlers* handlers, const cyni_device_usb_device* device); +int StartCaptureDma(cyni_device_device_handlers* handlers, const cyni_device_usb_device* device); +int capture_end(cyni_device_device_handlers* handlers, const cyni_device_usb_device* device); +int ReadFrame(cyni_device_device_handlers* handlers, uint8_t* buf, int length, const cyni_device_usb_device* device_desc); +int ReadFrameAsync(cyni_device_device_handlers* handlers, uint8_t* buf, int length, const cyni_device_usb_device* device_desc, cyni_async_callback_data* cb_data); +void CloseAsyncRead(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, cyni_async_callback_data* cb_data); +void SetupCypressDeviceAsyncThread(cyni_device_device_handlers* handlers, void* user_data, std::thread* thread_ptr, bool* keep_going, ConsumerMutex* is_data_ready); +void EndCypressDeviceAsyncThread(cyni_device_device_handlers* handlers, void* user_data, std::thread* thread_ptr, bool* keep_going, ConsumerMutex* is_data_ready); +void SetMaxTransferSize(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, size_t new_max_transfer_size); +void pipe_reset_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc); + +#endif diff --git a/include/CaptureDeviceSpecific/Nisetro/cypress_nisetro_driver_comms.hpp b/include/CaptureDeviceSpecific/Nisetro/cypress_nisetro_driver_comms.hpp new file mode 100644 index 0000000..f99e194 --- /dev/null +++ b/include/CaptureDeviceSpecific/Nisetro/cypress_nisetro_driver_comms.hpp @@ -0,0 +1,29 @@ +#ifndef __CYPRESS_NISETRO_DRIVER_COMMS_HPP +#define __CYPRESS_NISETRO_DRIVER_COMMS_HPP + +#include +#include "capture_structs.hpp" +#include "utils.hpp" +#include "cypress_nisetro_communications.hpp" +#include "cypress_nisetro_acquisition_general.hpp" + +void cypress_driver_list_devices(std::vector& devices_list, bool* not_supported_elems, int* curr_serial_extra_id_cypress, const size_t num_cypress_desc); +void cypress_driver_find_used_serial(const cyni_device_usb_device* usb_device_desc, bool* found, size_t num_free_fw_ids, int &curr_serial_extra_id); +void cypress_nisetro_driver_end_connection(cyni_device_device_handlers* handlers); +int cypress_driver_ctrl_transfer_in(cyni_device_device_handlers* handlers, uint8_t* buffer, size_t inner_size, uint16_t value, uint16_t index, uint16_t request_code, int* num_read); +int cypress_driver_ctrl_transfer_out(cyni_device_device_handlers* handlers, uint8_t* buffer, size_t inner_size, uint16_t value, uint16_t index, uint16_t request_code, int* num_read); +int cypress_driver_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred); +int cypress_driver_ctrl_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred); +int cypress_driver_ctrl_bulk_out(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred); +void cypress_driver_pipe_reset_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc); +void cypress_driver_pipe_reset_ctrl_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc); +void cypress_driver_pipe_reset_ctrl_bulk_out(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc); +cyni_device_device_handlers* cypress_driver_serial_reconnection(CaptureDevice* device); +cyni_device_device_handlers* cypress_driver_find_by_serial_number(const cyni_device_usb_device* usb_device_desc, std::string wanted_serial_number, int &curr_serial_extra_id, CaptureDevice* new_device); +int cypress_driver_async_in_start(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, cyni_async_callback_data* cb_data); +void cypress_driver_start_thread(std::thread* thread_ptr, bool* usb_thread_run, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data, cyni_device_device_handlers* handlers, ConsumerMutex* AsyncMutexPtr); +void cypress_driver_close_thread(std::thread* thread_ptr, bool* usb_thread_run, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data); +void cypress_driver_cancel_callback(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, cyni_async_callback_data* cb_data); +void cypress_driver_set_transfer_size_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, size_t new_transfer_size); + +#endif diff --git a/include/CaptureDeviceSpecific/Nisetro/cypress_nisetro_libusb_comms.hpp b/include/CaptureDeviceSpecific/Nisetro/cypress_nisetro_libusb_comms.hpp new file mode 100644 index 0000000..cf3b0bb --- /dev/null +++ b/include/CaptureDeviceSpecific/Nisetro/cypress_nisetro_libusb_comms.hpp @@ -0,0 +1,25 @@ +#ifndef __CYPRESS_NISETRO_DEVICE_LIBUSB_HPP +#define __CYPRESS_NISETRO_DEVICE_LIBUSB_HPP + +#include +#include "capture_structs.hpp" +#include "cypress_nisetro_communications.hpp" + +void cypress_libusb_start_thread(std::thread* thread_ptr, bool* usb_thread_run); +void cypress_libusb_close_thread(std::thread* thread_ptr, bool* usb_thread_run); +void cypress_libusb_list_devices(std::vector &devices_list, bool* no_access_elems, bool* not_supported_elems, int *curr_serial_extra_id_cypress, const size_t num_cypress_desc); +cyni_device_device_handlers* cypress_libusb_serial_reconnection(const cyni_device_usb_device* usb_device_desc, std::string wanted_serial_number, int &curr_serial_extra_id, CaptureDevice* new_device); +void cypress_libusb_find_used_serial(const cyni_device_usb_device* usb_device_desc, bool* found, size_t num_free_fw_ids, int &curr_serial_extra_id); +void cypress_libusb_end_connection(cyni_device_device_handlers* handlers, const cyni_device_usb_device* device_desc, bool interface_claimed); +int cypress_libusb_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred); +int cypress_libusb_ctrl_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred); +int cypress_libusb_ctrl_bulk_out(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred); +void cypress_libusb_pipe_reset_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc); +void cypress_libusb_pipe_reset_ctrl_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc); +void cypress_libusb_pipe_reset_ctrl_bulk_out(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc); +int cypress_libusb_ctrl_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, uint8_t request, uint16_t value, uint16_t index, int* transferred); +int cypress_libusb_ctrl_out(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, uint8_t request, uint16_t value, uint16_t index, int* transferred); +int cypress_libusb_async_in_start(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, cyni_async_callback_data* cb_data); +void cypress_libusb_cancell_callback(cyni_async_callback_data* cb_data); + +#endif diff --git a/include/capture_structs.hpp b/include/capture_structs.hpp index 10eef79..f649b89 100755 --- a/include/capture_structs.hpp +++ b/include/capture_structs.hpp @@ -20,7 +20,7 @@ #define FTD2_INTRA_PACKET_HEADER_SIZE 2 #define MAX_PACKET_SIZE_FTD2 (MAX_PACKET_SIZE_USB2 - FTD2_INTRA_PACKET_HEADER_SIZE) -enum CaptureConnectionType { CAPTURE_CONN_FTD3, CAPTURE_CONN_USB, CAPTURE_CONN_FTD2, CAPTURE_CONN_IS_NITRO }; +enum CaptureConnectionType { CAPTURE_CONN_FTD3, CAPTURE_CONN_USB, CAPTURE_CONN_FTD2, CAPTURE_CONN_IS_NITRO, CAPTURE_CONN_CYPRESS_NISETRO }; enum InputVideoDataType { VIDEO_DATA_RGB, VIDEO_DATA_BGR, VIDEO_DATA_RGB16, VIDEO_DATA_BGR16 }; enum CaptureScreensType { CAPTURE_SCREENS_BOTH, CAPTURE_SCREENS_TOP, CAPTURE_SCREENS_BOTTOM, CAPTURE_SCREENS_ENUM_END }; enum CaptureSpeedsType { CAPTURE_SPEEDS_FULL, CAPTURE_SPEEDS_HALF, CAPTURE_SPEEDS_THIRD, CAPTURE_SPEEDS_QUARTER, CAPTURE_SPEEDS_ENUM_END }; @@ -118,6 +118,10 @@ struct ALIGNED(16) PACKED ISNitroCaptureReceived { ISNitroEmulatorVideoInputData video_in; }; +struct ALIGNED(16) PACKED CypressNisetroDSCaptureReceived { + ISNitroEmulatorVideoInputData video_in; +}; + struct ALIGNED(16) PACKED ISTWLCaptureVideoReceived { ISTWLCaptureVideoInputData video_in; uint32_t time; @@ -155,6 +159,7 @@ union CaptureReceived { FTD2OldDSCaptureReceivedRaw ftd2_received_old_ds_raw; ISNitroCaptureReceived is_nitro_capture_received; ISTWLCaptureReceived is_twl_capture_received; + CypressNisetroDSCaptureReceived cypress_nisetro_capture_received; }; struct CaptureDevice { diff --git a/source/CaptureDeviceSpecific/ISDevices/usb_is_device_is_driver.cpp b/source/CaptureDeviceSpecific/ISDevices/usb_is_device_is_driver.cpp index 66129b0..49bd813 100644 --- a/source/CaptureDeviceSpecific/ISDevices/usb_is_device_is_driver.cpp +++ b/source/CaptureDeviceSpecific/ISDevices/usb_is_device_is_driver.cpp @@ -176,12 +176,10 @@ static void STDCALL OverlappedCompletionNothingRoutine(DWORD dwErrorCode, DWORD } 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 diff --git a/source/CaptureDeviceSpecific/Nisetro/cypress_nisetro_acquisition.cpp b/source/CaptureDeviceSpecific/Nisetro/cypress_nisetro_acquisition.cpp new file mode 100644 index 0000000..b27ed2b --- /dev/null +++ b/source/CaptureDeviceSpecific/Nisetro/cypress_nisetro_acquisition.cpp @@ -0,0 +1,554 @@ +#include "devicecapture.hpp" +#include "cypress_nisetro_driver_comms.hpp" +#include "cypress_nisetro_libusb_comms.hpp" +#include "cypress_nisetro_communications.hpp" +#include "cypress_nisetro_acquisition.hpp" +#include "cypress_nisetro_acquisition_general.hpp" +#include "usb_generic.hpp" + +#include +#include +#include + +#define SERIAL_NUMBER_SIZE (0x100 + 1) +#define MAX_TIME_WAIT 1.0 +#define MAX_ERRORS_ALLOWED 100 +#define NUM_CONSECUTIVE_NEEDED_OUTPUT 6 + +static void cypress_device_read_frame_cb(void* user_data, int transfer_length, int transfer_status); + +static cyni_device_device_handlers* usb_find_by_serial_number(const cyni_device_usb_device* usb_device_desc, std::string wanted_serial_number, CaptureDevice* new_device) { + cyni_device_device_handlers* final_handlers = NULL; + int curr_serial_extra_id = 0; + final_handlers = cypress_libusb_serial_reconnection(usb_device_desc, wanted_serial_number, curr_serial_extra_id, new_device); + + if (final_handlers == NULL) + final_handlers = cypress_driver_find_by_serial_number(usb_device_desc, wanted_serial_number, curr_serial_extra_id, new_device); + return final_handlers; +} + +static int usb_find_free_fw_id(const cyni_device_usb_device* usb_device_desc) { + int curr_serial_extra_id = 0; + const int num_free_fw_ids = 0x100; + bool found[num_free_fw_ids]; + for(int i = 0; i < num_free_fw_ids; i++) + found[i] = false; + cypress_libusb_find_used_serial(usb_device_desc, found, num_free_fw_ids, curr_serial_extra_id); + cypress_driver_find_used_serial(usb_device_desc, found, num_free_fw_ids, curr_serial_extra_id); + + for(int i = 0; i < num_free_fw_ids; i++) + if(!found[i]) + return i; + return 0; +} + +static cyni_device_device_handlers* usb_reconnect(const cyni_device_usb_device* usb_device_desc, CaptureDevice* device) { + cyni_device_device_handlers* final_handlers = NULL; + int curr_serial_extra_id = 0; + final_handlers = cypress_libusb_serial_reconnection(usb_device_desc, device->serial_number, curr_serial_extra_id, NULL); + + if (final_handlers == NULL) + final_handlers = cypress_driver_serial_reconnection(device); + return final_handlers; +} + +std::string get_serial(const cyni_device_usb_device* usb_device_desc, std::string serial, uint16_t bcd_device, int& curr_serial_extra_id) { + if(serial != "") + return serial; + if(usb_device_desc->has_bcd_device_serial) + return std::to_string(bcd_device & 0xFF); + return std::to_string((curr_serial_extra_id++) + 1); +} + +static void cypress_nisetro_connection_end(cyni_device_device_handlers* handlers, const cyni_device_usb_device *device_desc, bool interface_claimed = true) { + if (handlers == NULL) + return; + if (handlers->usb_handle) + cypress_libusb_end_connection(handlers, device_desc, interface_claimed); + else + cypress_nisetro_driver_end_connection(handlers); + delete handlers; +} + +CaptureDevice cypress_create_device(const cyni_device_usb_device* usb_device_desc, std::string serial, std::string path) { + return CaptureDevice(serial, usb_device_desc->name, usb_device_desc->long_name, path, CAPTURE_CONN_CYPRESS_NISETRO, (void*)usb_device_desc, false, false, false, WIDTH_DS, HEIGHT_DS + HEIGHT_DS, 0, 0, 0, 0, 0, HEIGHT_DS, usb_device_desc->video_data_type); +} + +CaptureDevice cypress_create_device(const cyni_device_usb_device* usb_device_desc, std::string serial) { + return CaptureDevice(serial, usb_device_desc->name, usb_device_desc->long_name, CAPTURE_CONN_CYPRESS_NISETRO, (void*)usb_device_desc, false, false, false, WIDTH_DS, HEIGHT_DS + HEIGHT_DS, 0, 0, 0, 0, 0, HEIGHT_DS, usb_device_desc->video_data_type);; +} + +void cypress_insert_device(std::vector& devices_list, const cyni_device_usb_device* usb_device_desc, std::string serial, uint16_t bcd_device, int& curr_serial_extra_id, std::string path) { + devices_list.push_back(cypress_create_device(usb_device_desc, get_serial(usb_device_desc, serial, bcd_device, curr_serial_extra_id), path)); +} + +void cypress_insert_device(std::vector& devices_list, const cyni_device_usb_device* usb_device_desc, std::string serial, uint16_t bcd_device, int& curr_serial_extra_id) { + devices_list.push_back(cypress_create_device(usb_device_desc, get_serial(usb_device_desc, serial, bcd_device, curr_serial_extra_id))); +} + +void list_devices_cyni_device(std::vector &devices_list, std::vector &no_access_list) { + const size_t num_cyni_device_desc = GetNumCyNiDeviceDesc(); + int* curr_serial_extra_id_cyni_device = new int[num_cyni_device_desc]; + bool* no_access_elems = new bool[num_cyni_device_desc]; + bool* not_supported_elems = new bool[num_cyni_device_desc]; + for (int i = 0; i < num_cyni_device_desc; i++) { + no_access_elems[i] = false; + not_supported_elems[i] = false; + curr_serial_extra_id_cyni_device[i] = 0; + } + cypress_libusb_list_devices(devices_list, no_access_elems, not_supported_elems, curr_serial_extra_id_cyni_device, num_cyni_device_desc); + + bool any_not_supported = false; + for(int i = 0; i < num_cyni_device_desc; i++) + any_not_supported |= not_supported_elems[i]; + for(int i = 0; i < num_cyni_device_desc; i++) + if(no_access_elems[i]) { + const cyni_device_usb_device* usb_device = GetCyNiDeviceDesc(i); + no_access_list.emplace_back(usb_device->vid, usb_device->pid); + } + if(any_not_supported) + cypress_driver_list_devices(devices_list, not_supported_elems, curr_serial_extra_id_cyni_device, num_cyni_device_desc); + + delete[] curr_serial_extra_id_cyni_device; + delete[] no_access_elems; + delete[] not_supported_elems; +} + +bool cyni_device_connect_usb(bool print_failed, CaptureData* capture_data, CaptureDevice* device) { + const cyni_device_usb_device* usb_device_info = (const cyni_device_usb_device*)device->descriptor; + cyni_device_device_handlers* handlers = usb_reconnect(usb_device_info, device); + if(handlers == NULL) { + capture_error_print(true, capture_data, "Device not found"); + return false; + } + if(has_to_load_firmware(usb_device_info)) { + const cyni_device_usb_device* next_usb_device_info = GetNextDeviceDesc(usb_device_info); + int free_fw_id = usb_find_free_fw_id(next_usb_device_info); + int ret = load_firmware(handlers, usb_device_info, free_fw_id); + if(!ret) { + capture_error_print(true, capture_data, "Firmware load error"); + return false; + } + cypress_nisetro_connection_end(handlers, usb_device_info); + std::string new_serial_number = std::to_string(free_fw_id); + CaptureDevice new_device; + for(int i = 0; i < 20; i++) { + default_sleep(500); + handlers = usb_find_by_serial_number(next_usb_device_info, new_serial_number, &new_device); + if(handlers != NULL) + break; + } + if(handlers == NULL) { + capture_error_print(true, capture_data, "Device reconnection error"); + return false; + } + *device = new_device; + } + capture_data->handle = (void*)handlers; + + return true; +} + +uint64_t cyni_device_get_video_in_size(cypress_nisetro_device_type device_type) { + return sizeof(CypressNisetroDSCaptureReceived); +} + + +uint64_t cyni_device_get_video_in_size(CaptureStatus* status) { + return cyni_device_get_video_in_size(((const cyni_device_usb_device*)(status->device.descriptor))->device_type); +} + + +uint64_t cyni_device_get_video_in_size(CaptureData* capture_data) { + return cyni_device_get_video_in_size(&capture_data->status); +} + +static int find_first_vsync_byte(CaptureReceived* capture_buf, size_t read_size) { + uint8_t* data_in = (uint8_t*)capture_buf->cypress_nisetro_capture_received.video_in.screen_data; + if((data_in[0] & 0x80) && (!(data_in[read_size - 1] & 0x80))) + return 0; + int pos = 0; + while((pos < read_size) && (data_in[pos] & 0x80)) + pos++; + while((pos < read_size) && (!(data_in[pos] & 0x80))) + pos++; + return pos; +} + +void cypress_output_to_thread(CaptureData* capture_data, CaptureReceived* capture_buf, CaptureScreensType curr_capture_type, std::chrono::time_point* clock_start, size_t read_size, size_t* scheduled_special_read, bool* recalibration_request) { + // Output to the other threads... + int offset = find_first_vsync_byte(capture_buf, read_size); + const cyni_device_usb_device* usb_device_info = (const cyni_device_usb_device*)capture_data->status.device.descriptor; + if(offset) { + if(offset % usb_device_info->max_usb_packet_size) + *recalibration_request = true; + else + *scheduled_special_read = offset; + return; + } + const auto curr_time = std::chrono::high_resolution_clock::now(); + const std::chrono::duration diff = curr_time - (*clock_start); + *clock_start = curr_time; + capture_data->data_buffers.WriteToBuffer(capture_buf, read_size, diff.count(), &capture_data->status.device, curr_capture_type); + if (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 cypress_device_read_frame_and_output(CaptureData* capture_data, CaptureReceived* capture_buf, CaptureScreensType curr_capture_type, std::chrono::time_point &clock_start, size_t* scheduled_special_read, bool* recalibration_request) { + const cyni_device_usb_device* usb_device_info = (const cyni_device_usb_device*)capture_data->status.device.descriptor; + size_t read_size = cyni_device_get_video_in_size(usb_device_info->device_type); + if(*scheduled_special_read) + read_size = *scheduled_special_read; + int ret = ReadFrame((cyni_device_device_handlers*)capture_data->handle, (uint8_t*)capture_buf, read_size, usb_device_info); + if (ret < 0) + return ret; + if(*scheduled_special_read) { + *scheduled_special_read = 0; + return ret; + } + cypress_output_to_thread(capture_data, capture_buf, curr_capture_type, &clock_start, read_size, scheduled_special_read, recalibration_request); + return ret; +} + +int cypress_device_read_frame_request(CaptureData* capture_data, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data, CaptureScreensType curr_capture_type, uint32_t index) { + if(cypress_device_capture_recv_data == NULL) + return LIBUSB_SUCCESS; + if((*cypress_device_capture_recv_data->status) < 0) { + cypress_device_capture_recv_data->in_use = false; + return LIBUSB_SUCCESS; + } + const cyni_device_usb_device* usb_device_info = (const cyni_device_usb_device*)capture_data->status.device.descriptor; + cypress_device_capture_recv_data->index = index; + cypress_device_capture_recv_data->curr_capture_type = curr_capture_type; + cypress_device_capture_recv_data->cb_data.function = cypress_device_read_frame_cb; + size_t read_size = cyni_device_get_video_in_size(usb_device_info->device_type); + if(*cypress_device_capture_recv_data->scheduled_special_read) { + read_size = *cypress_device_capture_recv_data->scheduled_special_read; + *cypress_device_capture_recv_data->active_special_read_index = index; + *cypress_device_capture_recv_data->is_active_special_read = true; + *cypress_device_capture_recv_data->scheduled_special_read = 0; + } + return ReadFrameAsync((cyni_device_device_handlers*)capture_data->handle, (uint8_t*)&cypress_device_capture_recv_data->buffer, read_size, usb_device_info, &cypress_device_capture_recv_data->cb_data); +} + +static void end_cypress_device_read_frame_cb(CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data) { + cypress_device_capture_recv_data->in_use = false; + cypress_device_capture_recv_data->is_buffer_free_shared_mutex->specific_unlock(cypress_device_capture_recv_data->cb_data.internal_index); +} + +static void cypress_device_read_frame_cb(void* user_data, int transfer_length, int transfer_status) { + CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data = (CypressDeviceCaptureReceivedData*)user_data; + if((*cypress_device_capture_recv_data->status) < 0) + return end_cypress_device_read_frame_cb(cypress_device_capture_recv_data); + if(transfer_status != LIBUSB_TRANSFER_COMPLETED) { + int error = LIBUSB_ERROR_OTHER; + if(transfer_status == LIBUSB_TRANSFER_TIMED_OUT) + error = LIBUSB_ERROR_TIMEOUT; + else { + *cypress_device_capture_recv_data->errors_since_last_output += 1; + *cypress_device_capture_recv_data->consecutive_output_to_thread = 0; + } + *cypress_device_capture_recv_data->status = error; + return end_cypress_device_read_frame_cb(cypress_device_capture_recv_data); + } + + if(((int32_t)(cypress_device_capture_recv_data->index - (*cypress_device_capture_recv_data->last_index))) <= 0) { + //*cypress_device_capture_recv_data->status = LIBUSB_ERROR_INTERRUPTED; + return end_cypress_device_read_frame_cb(cypress_device_capture_recv_data); + } + *cypress_device_capture_recv_data->consecutive_output_to_thread += 1; + if((*cypress_device_capture_recv_data->consecutive_output_to_thread) > NUM_CONSECUTIVE_NEEDED_OUTPUT) + *cypress_device_capture_recv_data->errors_since_last_output = 0; + *cypress_device_capture_recv_data->last_index = cypress_device_capture_recv_data->index; + if((*cypress_device_capture_recv_data->is_active_special_read) && (((int32_t)(cypress_device_capture_recv_data->index - (*cypress_device_capture_recv_data->active_special_read_index))) >= 0)) { + *cypress_device_capture_recv_data->is_active_special_read = false; + return end_cypress_device_read_frame_cb(cypress_device_capture_recv_data); + } + + if((*cypress_device_capture_recv_data->scheduled_special_read) || (*cypress_device_capture_recv_data->is_active_special_read) || (*cypress_device_capture_recv_data->recalibration_request)) + return end_cypress_device_read_frame_cb(cypress_device_capture_recv_data); + + cypress_output_to_thread(cypress_device_capture_recv_data->capture_data, &cypress_device_capture_recv_data->buffer, cypress_device_capture_recv_data->curr_capture_type, cypress_device_capture_recv_data->clock_start, transfer_length, cypress_device_capture_recv_data->scheduled_special_read, cypress_device_capture_recv_data->recalibration_request); + end_cypress_device_read_frame_cb(cypress_device_capture_recv_data); +} + +int cypress_device_get_num_free_buffers(CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data) { + int num_free = 0; + for(int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) + if(!cypress_device_capture_recv_data[i].in_use) + num_free += 1; + return num_free; +} + +static void close_all_reads_error(CaptureData* capture_data, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data, bool &async_read_closed) { + cyni_device_device_handlers* handlers = (cyni_device_device_handlers*)capture_data->handle; + const cyni_device_usb_device* usb_device_desc = (const cyni_device_usb_device*)capture_data->status.device.descriptor; + if(get_cypress_device_status(cypress_device_capture_recv_data) < 0) { + if(!async_read_closed) { + if(handlers->usb_handle) { + for (int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) + CloseAsyncRead(handlers, usb_device_desc, &cypress_device_capture_recv_data[i].cb_data); + } + else + CloseAsyncRead(handlers, usb_device_desc, &cypress_device_capture_recv_data[0].cb_data); + async_read_closed = true; + } + } +} + +static bool has_too_much_time_passed(const std::chrono::time_point &start_time) { + const auto curr_time = std::chrono::high_resolution_clock::now(); + const std::chrono::duration diff = curr_time - start_time; + return diff.count() > MAX_TIME_WAIT; +} + +static void error_too_much_time_passed(CaptureData* capture_data, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data, bool &async_read_closed, const std::chrono::time_point &start_time) { + if(has_too_much_time_passed(start_time)) { + error_cypress_device_status(cypress_device_capture_recv_data, -1); + close_all_reads_error(capture_data, cypress_device_capture_recv_data, async_read_closed); + } +} + +void wait_all_cypress_device_buffers_free(CaptureData* capture_data, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data) { + if(cypress_device_capture_recv_data == NULL) + return; + cyni_device_device_handlers* handlers = (cyni_device_device_handlers*)capture_data->handle; + bool async_read_closed = false; + close_all_reads_error(capture_data, cypress_device_capture_recv_data, async_read_closed); + const auto start_time = std::chrono::high_resolution_clock::now(); + for(int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) + while(cypress_device_capture_recv_data[i].in_use) { + error_too_much_time_passed(capture_data, cypress_device_capture_recv_data, async_read_closed, start_time); + cypress_device_capture_recv_data[i].is_buffer_free_shared_mutex->specific_timed_lock(i); + } +} + +void wait_one_cypress_device_buffer_free(CaptureData* capture_data, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data) { + cyni_device_device_handlers* handlers = (cyni_device_device_handlers*)capture_data->handle; + bool done = false; + const auto start_time = std::chrono::high_resolution_clock::now(); + while(!done) { + for(int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) { + if(!cypress_device_capture_recv_data[i].in_use) + done = true; + } + if(!done) { + if(has_too_much_time_passed(start_time)) + return; + if(get_cypress_device_status(cypress_device_capture_recv_data) < 0) + return; + int dummy = 0; + cypress_device_capture_recv_data[0].is_buffer_free_shared_mutex->general_timed_lock(&dummy); + } + } +} + +void wait_specific_cypress_device_buffer_free(CaptureData* capture_data, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data) { + cyni_device_device_handlers* handlers = (cyni_device_device_handlers*)capture_data->handle; + bool done = false; + const auto start_time = std::chrono::high_resolution_clock::now(); + while(!done) { + if(!cypress_device_capture_recv_data->in_use) + done = true; + if(!done) { + if(has_too_much_time_passed(start_time)) + return; + if(get_cypress_device_status(cypress_device_capture_recv_data) < 0) + return; + int dummy = 0; + cypress_device_capture_recv_data->is_buffer_free_shared_mutex->general_timed_lock(&dummy); + } + } +} + +bool cypress_device_are_buffers_all_free(CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data) { + return cypress_device_get_num_free_buffers(cypress_device_capture_recv_data) == NUM_CAPTURE_RECEIVED_DATA_BUFFERS; +} + +CypressDeviceCaptureReceivedData* cypress_device_get_free_buffer(CaptureData* capture_data, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data) { + wait_one_cypress_device_buffer_free(capture_data, cypress_device_capture_recv_data); + if(get_cypress_device_status(cypress_device_capture_recv_data) < 0) + return NULL; + for(int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) + if(!cypress_device_capture_recv_data[i].in_use) { + cypress_device_capture_recv_data[i].is_buffer_free_shared_mutex->specific_try_lock(i); + cypress_device_capture_recv_data[i].in_use = true; + return &cypress_device_capture_recv_data[i]; + } + return NULL; +} + +int get_cypress_device_status(CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data) { + return *cypress_device_capture_recv_data[0].status; +} + +void error_cypress_device_status(CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data, int error_val) { + if((error_val == 0) || (get_cypress_device_status(cypress_device_capture_recv_data) == 0)) + *cypress_device_capture_recv_data[0].status = error_val; +} + +void reset_cypress_device_status(CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data) { + error_cypress_device_status(cypress_device_capture_recv_data, 0); +} + +void recalibration_reads(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data, CypressDeviceCaptureReceivedData* chosen_buffer, uint32_t &index, CaptureScreensType curr_capture_type) { + CaptureData* capture_data = cypress_device_capture_recv_data[0].capture_data; + do { + if(get_cypress_device_status(cypress_device_capture_recv_data) < 0) + return; + chosen_buffer->in_use = false; + wait_all_cypress_device_buffers_free(capture_data, cypress_device_capture_recv_data); + chosen_buffer->in_use = true; + if(get_cypress_device_status(cypress_device_capture_recv_data) < 0) + return; + CypressDeviceCaptureReceivedData* next_buffer = cypress_device_get_free_buffer(capture_data, cypress_device_capture_recv_data); + default_sleep(); + *chosen_buffer->recalibration_request = false; + chosen_buffer->in_use = true; + int ret = cypress_device_read_frame_request(capture_data, chosen_buffer, curr_capture_type, index++); + if(ret < 0) { + error_cypress_device_status(cypress_device_capture_recv_data, ret); + return; + } + ret = cypress_device_read_frame_request(capture_data, next_buffer, curr_capture_type, index++); + if(ret < 0) { + next_buffer->in_use = false; + error_cypress_device_status(cypress_device_capture_recv_data, ret); + wait_specific_cypress_device_buffer_free(capture_data, chosen_buffer); + chosen_buffer->in_use = true; + return; + } + wait_specific_cypress_device_buffer_free(capture_data, chosen_buffer); + } while((*chosen_buffer->recalibration_request) && capture_data->status.connected && capture_data->status.running); + chosen_buffer->in_use = true; +} + +static bool cyni_device_acquisition_loop(CaptureData* capture_data, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data) { + cyni_device_device_handlers* handlers = (cyni_device_device_handlers*)capture_data->handle; + const cyni_device_usb_device* usb_device_desc = (const cyni_device_usb_device*)capture_data->status.device.descriptor; + uint32_t index = 0; + CaptureScreensType curr_capture_type = capture_data->status.capture_type; + CaptureSpeedsType curr_capture_speed = capture_data->status.capture_speed; + int ret = capture_start(handlers, usb_device_desc); + if (ret < 0) { + capture_error_print(true, capture_data, "Capture Start: Failed"); + return false; + } + SetMaxTransferSize(handlers, usb_device_desc, cyni_device_get_video_in_size(usb_device_desc->device_type)); + auto clock_last_reset = std::chrono::high_resolution_clock::now(); + for(int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) { + CypressDeviceCaptureReceivedData* chosen_buffer = cypress_device_get_free_buffer(capture_data, cypress_device_capture_recv_data); + ret = cypress_device_read_frame_request(capture_data, chosen_buffer, curr_capture_type, index++); + if(ret < 0) { + chosen_buffer->in_use = false; + error_cypress_device_status(cypress_device_capture_recv_data, ret); + capture_error_print(true, capture_data, "Initial Reads: Failed"); + return false; + } + } + + StartCaptureDma(handlers, usb_device_desc); + while (capture_data->status.connected && capture_data->status.running) { + ret = get_cypress_device_status(cypress_device_capture_recv_data); + if(ret < 0) { + wait_all_cypress_device_buffers_free(capture_data, cypress_device_capture_recv_data); + if((*cypress_device_capture_recv_data[0].errors_since_last_output) > MAX_ERRORS_ALLOWED) { + capture_error_print(true, capture_data, "Disconnected: Read error"); + return false; + } + *cypress_device_capture_recv_data[0].recalibration_request = false; + *cypress_device_capture_recv_data[0].scheduled_special_read = 0; + *cypress_device_capture_recv_data[0].is_active_special_read = false; + pipe_reset_bulk_in(handlers, usb_device_desc); + reset_cypress_device_status(cypress_device_capture_recv_data); + default_sleep(100); + } + CypressDeviceCaptureReceivedData* chosen_buffer = cypress_device_get_free_buffer(capture_data, cypress_device_capture_recv_data); + if(chosen_buffer == NULL) + error_cypress_device_status(cypress_device_capture_recv_data, LIBUSB_ERROR_TIMEOUT); + if(chosen_buffer && (*chosen_buffer->recalibration_request)) { + *chosen_buffer->recalibration_request = false; + recalibration_reads(handlers, usb_device_desc, cypress_device_capture_recv_data, chosen_buffer, index, curr_capture_type); + } + ret = cypress_device_read_frame_request(capture_data, chosen_buffer, curr_capture_type, index++); + if(ret < 0) { + chosen_buffer->in_use = false; + error_cypress_device_status(cypress_device_capture_recv_data, ret); + capture_error_print(true, capture_data, "Setup Read: Failed"); + return false; + } + } + return true; +} + +void cyni_device_acquisition_main_loop(CaptureData* capture_data) { + if(!usb_is_initialized()) + return; + bool is_done_thread; + ConsumerMutex has_data_been_processed; + std::thread async_processing_thread; + cyni_device_device_handlers* handlers = (cyni_device_device_handlers*)capture_data->handle; + const cyni_device_usb_device* usb_device_desc = (const cyni_device_usb_device*)capture_data->status.device.descriptor; + + uint32_t last_index = -1; + int status = 0; + cyni_async_callback_data* cb_queue[NUM_CAPTURE_RECEIVED_DATA_BUFFERS]; + int queue_elems = 0; + size_t scheduled_special_read = 0; + uint32_t active_special_read_index = 0; + bool is_active_special_read = false; + bool one_transfer_active = false; + bool recalibration_request = false; + int errors_since_last_output = 0; + int consecutive_output_to_thread = 0; + 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 clock_start = std::chrono::high_resolution_clock::now(); + CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data = new CypressDeviceCaptureReceivedData[NUM_CAPTURE_RECEIVED_DATA_BUFFERS]; + for(int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) { + cypress_device_capture_recv_data[i].in_use = false; + cypress_device_capture_recv_data[i].index = i; + cypress_device_capture_recv_data[i].capture_data = capture_data; + cypress_device_capture_recv_data[i].scheduled_special_read = &scheduled_special_read; + cypress_device_capture_recv_data[i].active_special_read_index = &active_special_read_index; + cypress_device_capture_recv_data[i].is_active_special_read = &is_active_special_read; + cypress_device_capture_recv_data[i].last_index = &last_index; + cypress_device_capture_recv_data[i].errors_since_last_output = &errors_since_last_output; + cypress_device_capture_recv_data[i].recalibration_request = &recalibration_request; + cypress_device_capture_recv_data[i].consecutive_output_to_thread = &consecutive_output_to_thread; + cypress_device_capture_recv_data[i].clock_start = &clock_start; + cypress_device_capture_recv_data[i].is_buffer_free_shared_mutex = &is_buffer_free_shared_mutex; + cypress_device_capture_recv_data[i].status = &status; + cypress_device_capture_recv_data[i].cb_data.actual_user_data = &cypress_device_capture_recv_data[i]; + cypress_device_capture_recv_data[i].cb_data.transfer_data = NULL; + cypress_device_capture_recv_data[i].cb_data.is_transfer_done_mutex = &is_transfer_done_shared_mutex; + cypress_device_capture_recv_data[i].cb_data.internal_index = i; + cypress_device_capture_recv_data[i].cb_data.is_transfer_data_ready_mutex = &is_transfer_data_ready_shared_mutex; + } + SetupCypressDeviceAsyncThread(handlers, cypress_device_capture_recv_data, &async_processing_thread, &is_done_thread, &has_data_been_processed); + bool proper_return = cyni_device_acquisition_loop(capture_data, cypress_device_capture_recv_data); + wait_all_cypress_device_buffers_free(capture_data, cypress_device_capture_recv_data); + EndCypressDeviceAsyncThread(handlers, cypress_device_capture_recv_data, &async_processing_thread, &is_done_thread, &has_data_been_processed); + delete []cypress_device_capture_recv_data; + + if(proper_return) + capture_end(handlers, usb_device_desc); +} + +void usb_cyni_device_acquisition_cleanup(CaptureData* capture_data) { + if(!usb_is_initialized()) + return; + cypress_nisetro_connection_end((cyni_device_device_handlers*)capture_data->handle, (const cyni_device_usb_device*)capture_data->status.device.descriptor); + capture_data->handle = NULL; +} +void usb_cyni_device_init() { + return usb_init(); +} + +void usb_cyni_device_close() { + usb_close(); +} + diff --git a/source/CaptureDeviceSpecific/Nisetro/cypress_nisetro_communications.cpp b/source/CaptureDeviceSpecific/Nisetro/cypress_nisetro_communications.cpp new file mode 100644 index 0000000..a827496 --- /dev/null +++ b/source/CaptureDeviceSpecific/Nisetro/cypress_nisetro_communications.cpp @@ -0,0 +1,256 @@ +#include "frontend.hpp" +#include "cypress_nisetro_communications.hpp" +#include "cypress_nisetro_libusb_comms.hpp" +#include "cypress_nisetro_driver_comms.hpp" +#include "cypress_nisetro_acquisition_general.hpp" +#include "nisetro_ds_fw.h" + +#include +#include +#include +#include +#include + +#define CYPRESS_BASE_USB_PACKET_LIMIT 64 +#define CYPRESS_NISETRO_USB_PACKET_LIMIT 512 + +#define CMD_EP6IN_START 0x50 +#define CMD_EP6IN_STOP 0x51 +#define CMD_EP2OUT_START 0x52 +#define CMD_EP2OUT_STOP 0x53 +#define CMD_PORT_CFG 0x54 +#define CMD_REG_READ 0x55 +#define CMD_REG_WRITE 0x56 +#define CMD_PORT_READ 0x57 +#define CMD_PORT_WRITE 0x58 +#define CMD_IFCONFIG 0x59 +#define CMD_MODE_IDLE 0x5a + +#define PIO_DROP 0x20 +#define PIO_RESET 0x10 +#define PIO_DIR 0x08 + +static const cyni_device_usb_device cypress_fx2_generic_device = { +.name = "EZ-USB FX2", .long_name = "EZ-USB FX2", +.vid = 0x04B4, .pid = 0x8613, +.default_config = 1, .default_interface = 0, +.bulk_timeout = 500, +.ep_ctrl_bulk_in = 0, .ep_ctrl_bulk_out = 0, +.ep_bulk_in = 0, +.device_type = CYPRESS_NISETRO_BLANK_DEVICE, +.video_data_type = VIDEO_DATA_RGB, .max_usb_packet_size = CYPRESS_BASE_USB_PACKET_LIMIT, +.do_pipe_clear_reset = false, +.firmware_to_load = nisetro_ds_fw, .firmware_size = nisetro_ds_fw_len, +.next_device = CYPRESS_NISETRO_DS_DEVICE, +.has_bcd_device_serial = false, .alt_interface = 1 +}; + +static const cyni_device_usb_device cypress_fx2_nisetro_ds_device = { +.name = "Nisetro DS", .long_name = "Nisetro DS", +.vid = 0x04B4, .pid = 0x1004, +.default_config = 1, .default_interface = 0, +.bulk_timeout = 500, +.ep_ctrl_bulk_in = 1 | LIBUSB_ENDPOINT_IN, .ep_ctrl_bulk_out = 1 | LIBUSB_ENDPOINT_OUT, +.ep_bulk_in = 6 | LIBUSB_ENDPOINT_IN, +.device_type = CYPRESS_NISETRO_DS_DEVICE, +.video_data_type = VIDEO_DATA_RGB, .max_usb_packet_size = CYPRESS_NISETRO_USB_PACKET_LIMIT, +.do_pipe_clear_reset = true, +.firmware_to_load = NULL, .firmware_size = 0, +.next_device = CYPRESS_NISETRO_DS_DEVICE, +.has_bcd_device_serial = true, .alt_interface = 0 +}; + +static const cyni_device_usb_device* all_usb_cyni_device_devices_desc[] = { + &cypress_fx2_generic_device, + &cypress_fx2_nisetro_ds_device, +}; + +static int ctrl_in_transfer(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, uint8_t request, uint16_t value, uint16_t index, int* transferred) { + if(handlers->usb_handle) + return cypress_libusb_ctrl_in(handlers, usb_device_desc, buf, length, request, value, index, transferred); + return cypress_driver_ctrl_transfer_in(handlers, buf, length, value, index, request, transferred); +} + +static int ctrl_out_transfer(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, uint8_t request, uint16_t value, uint16_t index, int* transferred) { + if(handlers->usb_handle) + return cypress_libusb_ctrl_out(handlers, usb_device_desc, buf, length, request, value, index, transferred); + return cypress_driver_ctrl_transfer_out(handlers, buf, length, value, index, request, transferred); +} + +static int bulk_in_transfer(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred) { + if(handlers->usb_handle) + return cypress_libusb_bulk_in(handlers, usb_device_desc, buf, length, transferred); + return cypress_driver_bulk_in(handlers, usb_device_desc, buf, length, transferred); +} + +static int bulk_in_async(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t *buf, int length, cyni_async_callback_data* cb_data) { + if(handlers->usb_handle) + return cypress_libusb_async_in_start(handlers, usb_device_desc, buf, length, cb_data); + return cypress_driver_async_in_start(handlers, usb_device_desc, buf, length, cb_data); +} + +static int ctrl_bulk_in_transfer(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred) { + if(handlers->usb_handle) + return cypress_libusb_ctrl_bulk_in(handlers, usb_device_desc, buf, length, transferred); + return cypress_driver_ctrl_bulk_in(handlers, usb_device_desc, buf, length, transferred); +} + +static int ctrl_bulk_out_transfer(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred) { + if(handlers->usb_handle) + return cypress_libusb_ctrl_bulk_out(handlers, usb_device_desc, buf, length, transferred); + return cypress_driver_ctrl_bulk_out(handlers, usb_device_desc, buf, length, transferred); +} + +void pipe_reset_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc) { + if(handlers->usb_handle) + return cypress_libusb_pipe_reset_bulk_in(handlers, usb_device_desc); + return cypress_driver_pipe_reset_bulk_in(handlers, usb_device_desc); +} + +static void pipe_reset_ctrl_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc) { + if(handlers->usb_handle) + return cypress_libusb_pipe_reset_ctrl_bulk_in(handlers, usb_device_desc); + return cypress_driver_pipe_reset_ctrl_bulk_in(handlers, usb_device_desc); +} + +static void pipe_reset_ctrl_bulk_out(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc) { + if(handlers->usb_handle) + return cypress_libusb_pipe_reset_ctrl_bulk_out(handlers, usb_device_desc); + return cypress_driver_pipe_reset_ctrl_bulk_out(handlers, usb_device_desc); +} + +int GetNumCyNiDeviceDesc() { + return sizeof(all_usb_cyni_device_devices_desc) / sizeof(all_usb_cyni_device_devices_desc[0]); +} + +const cyni_device_usb_device* GetCyNiDeviceDesc(int index) { + if((index < 0) || (index >= GetNumCyNiDeviceDesc())) + index = 0; + return all_usb_cyni_device_devices_desc[index]; +} + +const cyni_device_usb_device* GetNextDeviceDesc(const cyni_device_usb_device* device) { + for(int i = 0; i < GetNumCyNiDeviceDesc(); i++) { + const cyni_device_usb_device* examined_device = GetCyNiDeviceDesc(i); + if(examined_device->device_type == device->next_device) + return examined_device; + } + return NULL; +} + +bool has_to_load_firmware(const cyni_device_usb_device* device) { + return !((device->firmware_to_load == NULL) || (device->firmware_size == 0)); +} + +bool load_firmware(cyni_device_device_handlers* handlers, const cyni_device_usb_device* device, uint8_t patch_id) { + if(!has_to_load_firmware(device)) + return true; + int transferred = 0; + uint8_t* fw_data = new uint8_t[device->firmware_size]; + memcpy(fw_data, device->firmware_to_load, device->firmware_size); + int num_patches = read_le16(fw_data, 1); + for(int i = 0; i < num_patches; i++) { + int pos_patch = read_le16(fw_data, 2 + i); + write_le16(fw_data + pos_patch, patch_id | 0xFF00); + } + uint8_t buffer[0x8000]; + buffer[0] = 1; + int ret = ctrl_out_transfer(handlers, device, buffer, 1, 0xA0, 0xE600, 0, &transferred); + if(ret < 0) { + delete []fw_data; + return false; + } + bool done = false; + int fw_pos = read_le16(fw_data); + while(!done) { + int inside_len = read_be16(fw_data + fw_pos); + int offset = read_be16(fw_data + fw_pos, 1); + done = (inside_len & 0x8000) != 0; + inside_len &= 0x7FFF; + fw_pos += 4; + if((inside_len + fw_pos) > device->firmware_size) { + delete []fw_data; + return false; + } + memcpy(buffer, fw_data + fw_pos, inside_len); + fw_pos += inside_len; + ret = ctrl_out_transfer(handlers, device, buffer, inside_len, 0xA0, offset, 0, &transferred); + if(ret < 0) { + delete []fw_data; + return false; + } + } + delete []fw_data; + return true; +} + +int capture_start(cyni_device_device_handlers* handlers, const cyni_device_usb_device* device) { + uint8_t buffer[] = { CMD_PORT_CFG, 0x07, PIO_RESET | PIO_DIR, CMD_MODE_IDLE, CMD_IFCONFIG, 0xE3, CMD_REG_WRITE, 0, 0x08, CMD_MODE_IDLE}; + int transferred = 0; + pipe_reset_ctrl_bulk_in(handlers, device); + pipe_reset_ctrl_bulk_out(handlers, device); + int ret = ctrl_bulk_out_transfer(handlers, device, buffer, sizeof(buffer), &transferred); + if(ret < 0) + return ret; + pipe_reset_bulk_in(handlers, device); + return ret; +} + +int StartCaptureDma(cyni_device_device_handlers* handlers, const cyni_device_usb_device* device) { + uint8_t buffer[] = { CMD_PORT_WRITE, PIO_RESET, CMD_EP6IN_START, CMD_PORT_WRITE, 0}; + int transferred = 0; + return ctrl_bulk_out_transfer(handlers, device, buffer, sizeof(buffer), &transferred); +} + +int capture_end(cyni_device_device_handlers* handlers, const cyni_device_usb_device* device) { + int transferred = 0; + uint8_t buffer[] = { CMD_PORT_WRITE, 0, CMD_EP6IN_STOP, CMD_MODE_IDLE}; + int ret = ctrl_bulk_out_transfer(handlers, device, buffer, sizeof(buffer), &transferred); + if(ret < 0) + return ret; + + uint8_t buffer2[] = { CMD_REG_READ, 0, CMD_REG_READ, 1, CMD_REG_READ, 2, CMD_REG_READ, 3, CMD_REG_READ, 4, CMD_REG_READ, 5, CMD_REG_READ, 6, CMD_REG_READ, 7}; + ret = ctrl_bulk_out_transfer(handlers, device, buffer2, sizeof(buffer2), &transferred); + if(ret < 0) + return ret; + + pipe_reset_ctrl_bulk_in(handlers, device); + return ctrl_bulk_in_transfer(handlers, device, buffer2, 8, &transferred); +} + +void SetMaxTransferSize(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, size_t new_max_transfer_size) { + if(handlers->usb_handle) + return; + cypress_driver_set_transfer_size_bulk_in(handlers, usb_device_desc, new_max_transfer_size); +} + +int ReadFrame(cyni_device_device_handlers* handlers, uint8_t* buf, int length, const cyni_device_usb_device* device_desc) { + // Maybe making this async would be better for lower end hardware... + int num_bytes = 0; + int ret = bulk_in_transfer(handlers, device_desc, buf, length, &num_bytes); + if(num_bytes != length) + return LIBUSB_ERROR_INTERRUPTED; + return ret; +} + +int ReadFrameAsync(cyni_device_device_handlers* handlers, uint8_t* buf, int length, const cyni_device_usb_device* device_desc, cyni_async_callback_data* cb_data) { + return bulk_in_async(handlers, device_desc, buf, length, cb_data); +} + +void CloseAsyncRead(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, cyni_async_callback_data* cb_data) { + if(handlers->usb_handle) + return cypress_libusb_cancell_callback(cb_data); + return cypress_driver_cancel_callback(handlers, usb_device_desc, cb_data); +} + +void SetupCypressDeviceAsyncThread(cyni_device_device_handlers* handlers, void* user_data, std::thread* thread_ptr, bool* keep_going, ConsumerMutex* is_data_ready) { + if(handlers->usb_handle) + return cypress_libusb_start_thread(thread_ptr, keep_going); + return cypress_driver_start_thread(thread_ptr, keep_going, (CypressDeviceCaptureReceivedData*)user_data, handlers, is_data_ready); +} + +void EndCypressDeviceAsyncThread(cyni_device_device_handlers* handlers, void* user_data, std::thread* thread_ptr, bool* keep_going, ConsumerMutex* is_data_ready) { + if(handlers->usb_handle) + return cypress_libusb_close_thread(thread_ptr, keep_going); + return cypress_driver_close_thread(thread_ptr, keep_going, (CypressDeviceCaptureReceivedData*)user_data); +} diff --git a/source/CaptureDeviceSpecific/Nisetro/cypress_nisetro_driver_comms.cpp b/source/CaptureDeviceSpecific/Nisetro/cypress_nisetro_driver_comms.cpp new file mode 100644 index 0000000..c4871ed --- /dev/null +++ b/source/CaptureDeviceSpecific/Nisetro/cypress_nisetro_driver_comms.cpp @@ -0,0 +1,716 @@ +#include "cypress_nisetro_driver_comms.hpp" +#include "cypress_nisetro_acquisition_general.hpp" + +#include +#include +#ifdef _WIN32 +#include +#include + +#define BASE_IOCTL_INDEX 0 + +#define DIR_HOST_TO_DEVICE 0 +#define DIR_DEVICE_TO_HOST 1 + +#define IOCTL_ADAPT_SEND_EP0_CONTROL_TRANSFER CTL_CODE(FILE_DEVICE_UNKNOWN, BASE_IOCTL_INDEX + 8, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_ADAPT_SEND_NON_EP0_DIRECT CTL_CODE(FILE_DEVICE_UNKNOWN, BASE_IOCTL_INDEX + 18, METHOD_NEITHER, FILE_ANY_ACCESS) +#define IOCTL_ADAPT_RESET_PIPE CTL_CODE(FILE_DEVICE_UNKNOWN, BASE_IOCTL_INDEX + 11, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_ADAPT_SET_TRANSFER_SIZE CTL_CODE(FILE_DEVICE_UNKNOWN, BASE_IOCTL_INDEX + 14, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_ADAPT_ABORT_PIPE CTL_CODE(FILE_DEVICE_UNKNOWN, BASE_IOCTL_INDEX + 17, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define USB_REQUEST_GET_STATUS 0x00 +#define USB_REQUEST_CLEAR_FEATURE 0x01 + +#define USB_REQUEST_SET_FEATURE 0x03 + +#define USB_REQUEST_SET_ADDRESS 0x05 +#define USB_REQUEST_GET_DESCRIPTOR 0x06 +#define USB_REQUEST_SET_DESCRIPTOR 0x07 +#define USB_REQUEST_GET_CONFIGURATION 0x08 +#define USB_REQUEST_SET_CONFIGURATION 0x09 +#define USB_REQUEST_GET_INTERFACE 0x0A +#define USB_REQUEST_SET_INTERFACE 0x0B +#define USB_REQUEST_SYNC_FRAME 0x0C + +#define USB_DEVICE_DESCRIPTOR_TYPE 0x01 +#define USB_CONFIGURATION_DESCRIPTOR_TYPE 0x02 +#define USB_STRING_DESCRIPTOR_TYPE 0x03 +#define USB_INTERFACE_DESCRIPTOR_TYPE 0x04 +#define USB_ENDPOINT_DESCRIPTOR_TYPE 0x05 + +#define TARGET_DEVICE 0 +#define REQUEST_STANDARD 0 +#define REQUEST_VENDOR 2 + +#pragma pack(push, 1) + +struct PACKED USB_COMMON_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; +}; + +struct PACKED USB_STRING_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + WCHAR bString[1]; +}; + +struct PACKED USB_DEVICE_DESCRIPTOR { + UCHAR bLength; + UCHAR bDescriptorType; + USHORT bcdUSB; + UCHAR bDeviceClass; + UCHAR bDeviceSubClass; + UCHAR bDeviceProtocol; + UCHAR bMaxPacketSize0; + USHORT idVendor; + USHORT idProduct; + USHORT bcdDevice; + UCHAR iManufacturer; + UCHAR iProduct; + UCHAR iSerialNumber; + UCHAR bNumConfigurations; +}; + +// Is this fine? Without any check for endianness? +// Shouldn't all of this be packed?! +struct PACKED CYPRESS_WORD_SPLIT { + UCHAR lowByte; + UCHAR hiByte; +}; + +struct PACKED CYPRESS_BM_REQ_TYPE { + UCHAR Recipient:2; + UCHAR Reserved:3; + UCHAR Type:2; + UCHAR Direction:1; +}; + +struct PACKED CYPRESS_SETUP_PACKET { + union { + CYPRESS_BM_REQ_TYPE bmReqType; + UCHAR bmRequest; + }; + UCHAR bRequest; + union { + CYPRESS_WORD_SPLIT wVal; + USHORT wValue; + }; + union { + CYPRESS_WORD_SPLIT wIndx; + USHORT wIndex; + }; + union { + CYPRESS_WORD_SPLIT wLen; + USHORT wLength; + }; + ULONG ulTimeOut; +}; + +struct PACKED CYPRESS_ISO_ADV_PARAMS { + USHORT isoId; + USHORT isoCmd; + ULONG ulParam1; + ULONG ulParam2; +}; + +struct PACKED CYPRESS_SINGLE_TRANSFER { + union { + CYPRESS_SETUP_PACKET SetupPacket; + CYPRESS_ISO_ADV_PARAMS IsoParams; + }; + + UCHAR reserved; + + UCHAR ucEndpointAddress; + ULONG NtStatus; + ULONG UsbdStatus; + ULONG IsoPacketOffset; + ULONG IsoPacketLength; + ULONG BufferOffset; + ULONG BufferLength; +}; + +struct PACKED CYPRESS_SET_TRANSFER_SIZE_INFO { + UCHAR EndpointAddress; + ULONG TransferSize; +}; + +#pragma pack(pop) + +static GUID cypress_driver_guid = {.Data1 = 0xae18aa60, .Data2 = 0x7f6a, .Data3 = 0x11d4, .Data4 = {0x97, 0xdd, 0x0, 0x1, 0x2, 0x29, 0xb9, 0x59}}; + +static void cypress_driver_wait_async_transfers(CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data) { + HANDLE to_wait_array[NUM_CAPTURE_RECEIVED_DATA_BUFFERS]; + for(int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) + to_wait_array[i] = ((OVERLAPPED*)cypress_device_capture_recv_data[i].cb_data.base_transfer_data)->hEvent; + WaitForMultipleObjects(NUM_CAPTURE_RECEIVED_DATA_BUFFERS, to_wait_array, false, 300); +} + +static bool cypress_driver_process_async_transfers(CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data, cyni_device_device_handlers* handlers) { + bool found = false; + for (int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) { + cyni_async_callback_data* cb_data = (cyni_async_callback_data*)&cypress_device_capture_recv_data[i].cb_data; + bool possible_result = false; + bool is_data_ready = false; + cb_data->transfer_data_access.lock(); + possible_result = cb_data->transfer_data != NULL; + is_data_ready = cb_data->is_data_ready; + cb_data->transfer_data_access.unlock(); + if(cypress_device_capture_recv_data[i].in_use && is_data_ready) + found = true; + if(cypress_device_capture_recv_data[i].in_use && possible_result) { + DWORD bytes_transferred = 0; + int error = 0; + if(!GetOverlappedResult(handlers->read_handle, (OVERLAPPED*)cb_data->transfer_data, &bytes_transferred, false)) + error = GetLastError(); + if(error == ERROR_IO_INCOMPLETE) { + const auto curr_time = std::chrono::high_resolution_clock::now(); + const std::chrono::duration diff = curr_time - cb_data->start_request; + if(diff.count() > cb_data->timeout_s) + error_cypress_device_status(cypress_device_capture_recv_data, LIBUSB_ERROR_TIMEOUT); + } + if(error != ERROR_IO_INCOMPLETE) { + CYPRESS_SINGLE_TRANSFER* transfer_info = (CYPRESS_SINGLE_TRANSFER*)cb_data->extra_transfer_data; + if(!error) { + error = transfer_info->UsbdStatus; + if(!error) + error = transfer_info->NtStatus; + } + cb_data->actual_length = bytes_transferred; + cb_data->status_value = error; + cb_data->transfer_data = NULL; + cb_data->is_data_ready = true; + found = true; + } + } + } + return found; +} + +static void cypress_driver_function(bool* usb_thread_run, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data, cyni_device_device_handlers* handlers) { + int ret = 0; + while(*usb_thread_run) { + if(cypress_driver_process_async_transfers(cypress_device_capture_recv_data, handlers)) { + for (int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) { + cyni_async_callback_data* cb_data = (cyni_async_callback_data*)&cypress_device_capture_recv_data[i].cb_data; + bool is_data_ready = false; + cb_data->transfer_data_access.lock(); + is_data_ready = cb_data->is_data_ready; + cb_data->transfer_data_access.unlock(); + if(cypress_device_capture_recv_data[i].in_use && is_data_ready) { + cb_data->is_data_ready = false; + cb_data->function(&cypress_device_capture_recv_data[i], cb_data->actual_length, cb_data->status_value); + } + } + } + else + cypress_driver_wait_async_transfers(cypress_device_capture_recv_data); + } +} + +static bool cypress_driver_bulk_async_start(HANDLE handle, uint8_t* buffer, size_t size, DWORD* num_read, uint8_t ep_num, OVERLAPPED* overlap, CYPRESS_SINGLE_TRANSFER* single_transfer) { + memset(single_transfer, 0, sizeof(CYPRESS_SINGLE_TRANSFER)); + single_transfer->ucEndpointAddress = ep_num; + bool retval = DeviceIoControl(handle, IOCTL_ADAPT_SEND_NON_EP0_DIRECT, single_transfer, sizeof(CYPRESS_SINGLE_TRANSFER), buffer, size, num_read, overlap); + return retval; +} + +static bool cypress_driver_bulk_sync_start(HANDLE handle, uint8_t* buffer, size_t size, DWORD* num_read, uint8_t ep_num) { + CYPRESS_SINGLE_TRANSFER single_transfer; + return cypress_driver_bulk_async_start(handle, buffer, size, num_read, ep_num, NULL, &single_transfer); +} + +static bool cypress_driver_generic_ctrl_transfer(HANDLE handle, uint8_t* buffer, size_t inner_size, uint8_t val_hi, uint8_t val_low, uint16_t index, uint16_t timeout_s, uint8_t recipient, uint8_t type, uint8_t direction, uint16_t request_code, DWORD* num_read) { + size_t full_size = inner_size + sizeof(CYPRESS_SINGLE_TRANSFER); + uint8_t* full_buffer = new uint8_t[full_size]; + memset(full_buffer, 0, full_size); + CYPRESS_SINGLE_TRANSFER* single_transfer = (CYPRESS_SINGLE_TRANSFER*)full_buffer; + single_transfer->SetupPacket.bmReqType.Direction = direction; + single_transfer->SetupPacket.bmReqType.Type = type; + single_transfer->SetupPacket.bmReqType.Recipient = recipient; + single_transfer->SetupPacket.bRequest = request_code; + single_transfer->SetupPacket.wVal.hiByte = val_hi; + single_transfer->SetupPacket.wVal.lowByte = val_low; + single_transfer->SetupPacket.wIndex = index; + single_transfer->SetupPacket.wLength = inner_size; + single_transfer->SetupPacket.ulTimeOut = timeout_s; + single_transfer->BufferLength = single_transfer->SetupPacket.wLength; + single_transfer->BufferOffset = sizeof(CYPRESS_SINGLE_TRANSFER); + if(direction == DIR_HOST_TO_DEVICE) + memcpy(full_buffer + single_transfer->BufferOffset, buffer, inner_size); + bool retval = DeviceIoControl(handle, IOCTL_ADAPT_SEND_EP0_CONTROL_TRANSFER, full_buffer, full_size, full_buffer, full_size, num_read, NULL); + if((*num_read) >= sizeof(CYPRESS_SINGLE_TRANSFER)) + *num_read -= sizeof(CYPRESS_SINGLE_TRANSFER); + else + *num_read = 0; + if(direction == DIR_DEVICE_TO_HOST) + memcpy(buffer, full_buffer + single_transfer->BufferOffset, inner_size); + delete []full_buffer; + if((*num_read) != inner_size) + return false; + return retval; +} + +static bool read_cypress_driver_generic_info(HANDLE handle, uint8_t* buffer, size_t inner_size, uint8_t val_hi, uint8_t val_low, uint16_t index, DWORD* num_read) { + return cypress_driver_generic_ctrl_transfer(handle, buffer, inner_size, val_hi, val_low, index, 5, TARGET_DEVICE, REQUEST_STANDARD, DIR_DEVICE_TO_HOST, USB_REQUEST_GET_DESCRIPTOR, num_read); +} + +static bool read_cypress_driver_device_info(HANDLE handle, uint8_t* buffer, size_t inner_size, DWORD* num_read) { + return read_cypress_driver_generic_info(handle, buffer, inner_size, USB_DEVICE_DESCRIPTOR_TYPE, 0, 0, num_read); +} + +static bool cypress_driver_get_string_language_info(HANDLE handle, USHORT &language_id, USHORT preferred_language = 0x0409) { + USB_COMMON_DESCRIPTOR cmnDescriptor; + DWORD num_read = 0; + language_id = 0; + bool retval = read_cypress_driver_generic_info(handle, (uint8_t*)&cmnDescriptor, sizeof(cmnDescriptor), USB_STRING_DESCRIPTOR_TYPE, 0, 0, &num_read); + if(!retval) + return false; + if(cmnDescriptor.bLength == 2) + return true; + uint8_t* buffer = new uint8_t[cmnDescriptor.bLength]; + retval = read_cypress_driver_generic_info(handle, buffer, cmnDescriptor.bLength, USB_STRING_DESCRIPTOR_TYPE, 0, 0, &num_read); + if(retval) { + USB_STRING_DESCRIPTOR* IDs = (USB_STRING_DESCRIPTOR*)buffer; + int num_langs = (cmnDescriptor.bLength - 2) / 2; + language_id = IDs[0].bString[0]; + for(int i = 0; i < num_langs; i++) + if(IDs[i].bString[0] == preferred_language) + language_id = preferred_language; + } + delete []buffer; + return retval; +} + +static bool cypress_driver_get_string_info(HANDLE handle, UCHAR string_index, USHORT language_id, std::string &out_str) { + USB_COMMON_DESCRIPTOR cmnDescriptor; + DWORD num_read = 0; + out_str = ""; + bool retval = read_cypress_driver_generic_info(handle, (uint8_t*)&cmnDescriptor, sizeof(cmnDescriptor), USB_STRING_DESCRIPTOR_TYPE, string_index, language_id, &num_read); + if(!retval) + return false; + uint8_t* buffer = new uint8_t[cmnDescriptor.bLength]; + retval = read_cypress_driver_generic_info(handle, buffer, cmnDescriptor.bLength, USB_STRING_DESCRIPTOR_TYPE, string_index, language_id, &num_read); + if(retval && num_read >= 2) { + uint8_t bytes = buffer[0]; + if(bytes > num_read) + bytes = num_read; + uint8_t signature = buffer[1]; + if((signature == 3) && (bytes > 2)) + out_str = read_string(buffer, bytes - 2); + } + delete []buffer; + return retval; +} + +static std::string cypress_driver_get_device_path(HDEVINFO DeviceInfoSet, SP_DEVICE_INTERFACE_DATA* DeviceInterfaceData) { + std::string result = ""; + // Call this with an empty buffer to the required size of the structure. + ULONG requiredSize; + SetupDiGetDeviceInterfaceDetail(DeviceInfoSet, DeviceInterfaceData, NULL, 0, &requiredSize, NULL); + if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) + return result; + + PSP_DEVICE_INTERFACE_DETAIL_DATA devInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)(new uint8_t[requiredSize]); + if(!devInterfaceDetailData) + return result; + + devInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + if(SetupDiGetDeviceInterfaceDetail(DeviceInfoSet, DeviceInterfaceData, devInterfaceDetailData, requiredSize, &requiredSize, NULL)) + result = (std::string)(devInterfaceDetailData->DevicePath); + + delete []((uint8_t*)devInterfaceDetailData); + return result; +} + +static bool cypress_driver_get_device_pid_vid_ids(HANDLE handle, uint16_t& out_vid, uint16_t& out_pid, UCHAR &imanufacturer, UCHAR &iserial, USHORT &bcdDevice) { + if (handle == INVALID_HANDLE_VALUE) + return false; + USB_DEVICE_DESCRIPTOR out_descriptor; + memset(&out_descriptor, 0, sizeof(out_descriptor)); + DWORD num_read = 0; + bool result = read_cypress_driver_device_info(handle, (uint8_t*)&out_descriptor, sizeof(USB_DEVICE_DESCRIPTOR), &num_read); + if(!result) + return false; + out_vid = out_descriptor.idVendor; + out_pid = out_descriptor.idProduct; + imanufacturer = out_descriptor.iManufacturer; + iserial = out_descriptor.iSerialNumber; + bcdDevice = out_descriptor.bcdDevice; + return true; +} + +static bool cypress_driver_get_device_pid_vid_manufacturer_serial_number(std::string path, uint16_t& out_vid, uint16_t& out_pid, std::string &manufacturer, std::string &serial, uint16_t& bcd_device) { + HANDLE handle = CreateFile(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; + UCHAR imanufacturer; + UCHAR iserial; + if(!cypress_driver_get_device_pid_vid_ids(handle, out_vid, out_pid, imanufacturer, iserial, bcd_device)) { + CloseHandle(handle); + return false; + } + USHORT language = 0; + cypress_driver_get_string_language_info(handle, language); + cypress_driver_get_string_info(handle, imanufacturer, language, manufacturer); + cypress_driver_get_string_info(handle, iserial, language, serial); + CloseHandle(handle); + return true; +} + +static bool cypress_nisetro_driver_setup_connection(cyni_device_device_handlers* handlers, std::string path, bool do_pipe_clear_reset) { + handlers->usb_handle = NULL; + 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()); + if((handlers->mutex != NULL) && (GetLastError() == ERROR_ALREADY_EXISTS)) { + CloseHandle(handlers->mutex); + handlers->mutex = NULL; + } + if(handlers->mutex == NULL) + return false; + handlers->write_handle = CreateFile(path.c_str(), (GENERIC_READ | GENERIC_WRITE), (FILE_SHARE_READ | FILE_SHARE_WRITE), NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + handlers->read_handle = handlers->write_handle; + if((handlers->write_handle == INVALID_HANDLE_VALUE) || (handlers->read_handle == INVALID_HANDLE_VALUE)) + return false; + if(do_pipe_clear_reset) { + /* + if(!is_driver_device_reset(handlers->write_handle)) + return false; + if(!is_driver_pipe_reset(handlers->write_handle)) + return false; + if(!is_driver_pipe_reset(handlers->read_handle)) + return false; + */ + } + return true; +} + +static void cypress_nisetro_driver_close_handle(void** handle, void* default_value = INVALID_HANDLE_VALUE) { + #ifdef _WIN32 + if ((*handle) == default_value) + return; + CloseHandle(*handle); + *handle = default_value; + #endif +} + +static void cypress_driver_pipe_reset(HANDLE handle, uint8_t endpoint) { + DWORD dwBytes = 0; + DeviceIoControl(handle, IOCTL_ADAPT_RESET_PIPE, &endpoint, sizeof(uint8_t), NULL, 0, &dwBytes, 0); +} + +#endif + +cyni_device_device_handlers* cypress_driver_serial_reconnection(CaptureDevice* device) { + cyni_device_device_handlers* final_handlers = NULL; + #ifdef _WIN32 + if(device->path != "") { + cyni_device_device_handlers handlers; + const cyni_device_usb_device* usb_device_info = (const cyni_device_usb_device*)device->descriptor; + if(cypress_nisetro_driver_setup_connection(&handlers, device->path, usb_device_info->do_pipe_clear_reset)) { + final_handlers = new cyni_device_device_handlers; + final_handlers->usb_handle = NULL; + 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 + cypress_nisetro_driver_end_connection(&handlers); + } + #endif + return final_handlers; +} + +void cypress_driver_list_devices(std::vector &devices_list, bool* not_supported_elems, int *curr_serial_extra_id_cypress, const size_t num_cypress_desc) { + #ifdef _WIN32 + HDEVINFO DeviceInfoSet = SetupDiGetClassDevs( + &cypress_driver_guid, + NULL, + NULL, + DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + + SP_DEVICE_INTERFACE_DATA DeviceInterfaceData; + ZeroMemory(&DeviceInterfaceData, sizeof(SP_DEVICE_INTERFACE_DATA)); + DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + uint32_t i = 0; + while(SetupDiEnumDeviceInterfaces(DeviceInfoSet, NULL, &cypress_driver_guid, i++, &DeviceInterfaceData)) { + std::string path = cypress_driver_get_device_path(DeviceInfoSet, &DeviceInterfaceData); + if (path == "") + continue; + uint16_t vid = 0; + uint16_t pid = 0; + uint16_t bcd_device = 0; + std::string manufacturer; + std::string serial; + if(!cypress_driver_get_device_pid_vid_manufacturer_serial_number(path, vid, pid, manufacturer, serial, bcd_device)) + continue; + for (int j = 0; j < num_cypress_desc; j++) { + const cyni_device_usb_device* usb_device_desc = GetCyNiDeviceDesc(j); + if(not_supported_elems[j] && (usb_device_desc->vid == vid) && (usb_device_desc->pid == pid)) { + cyni_device_device_handlers handlers; + bool result_conn_check = cypress_nisetro_driver_setup_connection(&handlers, path, usb_device_desc->do_pipe_clear_reset); + cypress_nisetro_driver_end_connection(&handlers); + if(result_conn_check) + cypress_insert_device(devices_list, usb_device_desc, serial, bcd_device, curr_serial_extra_id_cypress[j], path); + break; + } + } + } + + if(DeviceInfoSet) + SetupDiDestroyDeviceInfoList(DeviceInfoSet); + #endif +} + +cyni_device_device_handlers* cypress_driver_find_by_serial_number(const cyni_device_usb_device* usb_device_desc, std::string wanted_serial_number, int &curr_serial_extra_id, CaptureDevice* new_device) { + cyni_device_device_handlers* final_handlers = NULL; + #ifdef _WIN32 + HDEVINFO DeviceInfoSet = SetupDiGetClassDevs( + &cypress_driver_guid, + NULL, + NULL, + DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + + SP_DEVICE_INTERFACE_DATA DeviceInterfaceData; + ZeroMemory(&DeviceInterfaceData, sizeof(SP_DEVICE_INTERFACE_DATA)); + DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + uint32_t i = 0; + while(SetupDiEnumDeviceInterfaces(DeviceInfoSet, NULL, &cypress_driver_guid, i++, &DeviceInterfaceData)) { + std::string path = cypress_driver_get_device_path(DeviceInfoSet, &DeviceInterfaceData); + if (path == "") + continue; + uint16_t vid = 0; + uint16_t pid = 0; + uint16_t bcd_device = 0; + std::string manufacturer; + std::string serial; + if(!cypress_driver_get_device_pid_vid_manufacturer_serial_number(path, vid, pid, manufacturer, serial, bcd_device)) + continue; + std::string read_serial = get_serial(usb_device_desc, serial, bcd_device, curr_serial_extra_id); + if((usb_device_desc->vid == vid) && (usb_device_desc->pid == pid) && (wanted_serial_number == read_serial)) { + cyni_device_device_handlers handlers; + if(cypress_nisetro_driver_setup_connection(&handlers, path, usb_device_desc->do_pipe_clear_reset)) { + final_handlers = new cyni_device_device_handlers; + final_handlers->usb_handle = NULL; + final_handlers->mutex = handlers.mutex; + final_handlers->read_handle = handlers.read_handle; + final_handlers->write_handle = handlers.write_handle; + final_handlers->path = path; + if(new_device != NULL) + *new_device = cypress_create_device(usb_device_desc, wanted_serial_number, path); + } + else + cypress_nisetro_driver_end_connection(&handlers); + break; + } + } + + if(DeviceInfoSet) + SetupDiDestroyDeviceInfoList(DeviceInfoSet); + #endif + return final_handlers; +} + +int cypress_driver_ctrl_transfer_in(cyni_device_device_handlers* handlers, uint8_t* buffer, size_t inner_size, uint16_t value, uint16_t index, uint16_t request_code, int* num_read) { + #ifdef _WIN32 + DWORD dummy = 0; + bool retval = cypress_driver_generic_ctrl_transfer(handlers->read_handle, buffer, inner_size, (value >> 8) & 0xFF, value & 0xFF, index, 1, TARGET_DEVICE, REQUEST_VENDOR, DIR_DEVICE_TO_HOST, request_code, &dummy); + *num_read = dummy; + return retval ? 0 : -1; + #else + return 0; + #endif +} + +int cypress_driver_ctrl_transfer_out(cyni_device_device_handlers* handlers, uint8_t* buffer, size_t inner_size, uint16_t value, uint16_t index, uint16_t request_code, int* num_read) { + #ifdef _WIN32 + DWORD dummy = 0; + bool retval = cypress_driver_generic_ctrl_transfer(handlers->write_handle, buffer, inner_size, (value >> 8) & 0xFF, value & 0xFF, index, 1, TARGET_DEVICE, REQUEST_VENDOR, DIR_HOST_TO_DEVICE, request_code, &dummy); + *num_read = dummy; + return retval ? 0 : -1; + #else + return 0; + #endif +} + +void cypress_nisetro_driver_end_connection(cyni_device_device_handlers* handlers) { + #ifdef _WIN32 + cypress_nisetro_driver_close_handle(&handlers->write_handle); + handlers->read_handle = handlers->write_handle; + cypress_nisetro_driver_close_handle(&handlers->mutex, NULL); + #endif +} + +int cypress_driver_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred) { + int result = LIBUSB_SUCCESS; + #ifdef _WIN32 + DWORD inner_transfered = 0; + if(!cypress_driver_bulk_sync_start(handlers->read_handle, buf, length, &inner_transfered, usb_device_desc->ep_bulk_in)) + result = -1; + *transferred = inner_transfered; + #endif + return result; +} + +int cypress_driver_ctrl_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred) { + int result = LIBUSB_SUCCESS; + #ifdef _WIN32 + DWORD inner_transfered = 0; + if(!cypress_driver_bulk_sync_start(handlers->read_handle, buf, length, &inner_transfered, usb_device_desc->ep_ctrl_bulk_in)) + result = -1; + *transferred = inner_transfered; + #endif + return result; +} + +int cypress_driver_ctrl_bulk_out(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred) { + int result = LIBUSB_SUCCESS; + #ifdef _WIN32 + DWORD inner_transfered = 0; + if(!cypress_driver_bulk_sync_start(handlers->write_handle, buf, length, &inner_transfered, usb_device_desc->ep_ctrl_bulk_out)) + result = -1; + *transferred = inner_transfered; + #endif + return result; +} + +void cypress_driver_pipe_reset_ctrl_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc) { + #ifdef _WIN32 + cypress_driver_pipe_reset(handlers->read_handle, usb_device_desc->ep_ctrl_bulk_in); + #endif +} + +void cypress_driver_pipe_reset_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc) { + #ifdef _WIN32 + cypress_driver_pipe_reset(handlers->read_handle, usb_device_desc->ep_bulk_in); + #endif +} + +void cypress_driver_pipe_reset_ctrl_bulk_out(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc) { + #ifdef _WIN32 + cypress_driver_pipe_reset(handlers->read_handle, usb_device_desc->ep_ctrl_bulk_out); + #endif +} + +void cypress_driver_find_used_serial(const cyni_device_usb_device* usb_device_desc, bool* found, size_t num_free_fw_ids, int &curr_serial_extra_id) { + #ifdef _WIN32 + HDEVINFO DeviceInfoSet = SetupDiGetClassDevs( + &cypress_driver_guid, + NULL, + NULL, + DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + + SP_DEVICE_INTERFACE_DATA DeviceInterfaceData; + ZeroMemory(&DeviceInterfaceData, sizeof(SP_DEVICE_INTERFACE_DATA)); + DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + uint32_t i = 0; + while(SetupDiEnumDeviceInterfaces(DeviceInfoSet, NULL, &cypress_driver_guid, i++, &DeviceInterfaceData)) { + std::string path = cypress_driver_get_device_path(DeviceInfoSet, &DeviceInterfaceData); + if (path == "") + continue; + uint16_t vid = 0; + uint16_t pid = 0; + uint16_t bcd_device = 0; + std::string manufacturer; + std::string serial; + if(!cypress_driver_get_device_pid_vid_manufacturer_serial_number(path, vid, pid, manufacturer, serial, bcd_device)) + continue; + std::string read_serial = get_serial(usb_device_desc, serial, bcd_device, curr_serial_extra_id); + if((usb_device_desc->vid == vid) && (usb_device_desc->pid == pid)) { + try { + int pos = std::stoi(read_serial); + if((pos < 0) || (pos >= num_free_fw_ids)) + continue; + found[pos] = true; + } + catch(...) { + continue; + } + } + } + + if(DeviceInfoSet) + SetupDiDestroyDeviceInfoList(DeviceInfoSet); + #endif +} + +int cypress_driver_async_in_start(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, cyni_async_callback_data* cb_data) { + #ifdef _WIN32 + cb_data->transfer_data_access.lock(); + cb_data->transfer_data = cb_data->base_transfer_data; + cb_data->handle = handlers->read_handle; + cb_data->requested_length = length; + cb_data->buffer = buf; + cb_data->start_request = std::chrono::high_resolution_clock::now(); + cb_data->timeout_s = usb_device_desc->bulk_timeout / 1000.0; + OVERLAPPED* overlap_data = (OVERLAPPED*)cb_data->transfer_data; + cb_data->is_transfer_done_mutex->specific_try_lock(cb_data->internal_index); + int retval = cypress_driver_bulk_async_start(cb_data->handle, cb_data->buffer, cb_data->requested_length, NULL, usb_device_desc->ep_bulk_in, overlap_data, (CYPRESS_SINGLE_TRANSFER*)cb_data->extra_transfer_data); + cb_data->transfer_data_access.unlock(); + if(!retval) { + int error = GetLastError(); + if(error != ERROR_IO_PENDING) + return LIBUSB_ERROR_BUSY; + } + #endif + return LIBUSB_SUCCESS; +} + +void cypress_driver_start_thread(std::thread* thread_ptr, bool* usb_thread_run, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data, cyni_device_device_handlers* handlers, ConsumerMutex* AsyncMutexPtr) { + #ifdef _WIN32 + *usb_thread_run = true; + for (int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) { + cypress_device_capture_recv_data[i].cb_data.extra_transfer_data = new CYPRESS_SINGLE_TRANSFER; + cypress_device_capture_recv_data[i].cb_data.base_transfer_data = new OVERLAPPED; + ((OVERLAPPED*)cypress_device_capture_recv_data[i].cb_data.base_transfer_data)->hEvent = CreateEvent(NULL, false, false, NULL); + } + *thread_ptr = std::thread(cypress_driver_function, usb_thread_run, cypress_device_capture_recv_data, handlers); + #endif +} + +void cypress_driver_close_thread(std::thread* thread_ptr, bool* usb_thread_run, CypressDeviceCaptureReceivedData* cypress_device_capture_recv_data) { + #ifdef _WIN32 + *usb_thread_run = false; + thread_ptr->join(); + for (int i = 0; i < NUM_CAPTURE_RECEIVED_DATA_BUFFERS; i++) { + CloseHandle(((OVERLAPPED*)cypress_device_capture_recv_data[i].cb_data.base_transfer_data)->hEvent); + delete ((OVERLAPPED*)cypress_device_capture_recv_data[i].cb_data.base_transfer_data); + delete ((CYPRESS_SINGLE_TRANSFER*)cypress_device_capture_recv_data[i].cb_data.extra_transfer_data); + } + #endif +} + +void cypress_driver_cancel_callback(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, cyni_async_callback_data* cb_data) { + #ifdef _WIN32 + DWORD transferred = 0; + OVERLAPPED ov; + memset(&ov, 0, sizeof(OVERLAPPED)); + ov.hEvent = CreateEvent(NULL, false, false, NULL); + uint8_t pipe = usb_device_desc->ep_bulk_in; + bool ret = DeviceIoControl(handlers->read_handle, IOCTL_ADAPT_ABORT_PIPE, &pipe, sizeof(uint8_t), NULL, 0, &transferred, &ov); + if((!ret) && (GetLastError() == ERROR_IO_PENDING)) + WaitForSingleObject(ov.hEvent, INFINITE); + CloseHandle(ov.hEvent); + #endif +} + +void cypress_driver_set_transfer_size_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, size_t new_transfer_size) { + #ifdef _WIN32 + DWORD transferred; + CYPRESS_SET_TRANSFER_SIZE_INFO SetTransferInfo; + + new_transfer_size = ((new_transfer_size + usb_device_desc->max_usb_packet_size - 1) / usb_device_desc->max_usb_packet_size) * usb_device_desc->max_usb_packet_size; + + SetTransferInfo.EndpointAddress = usb_device_desc->ep_bulk_in; + SetTransferInfo.TransferSize = new_transfer_size; + + DeviceIoControl(handlers->read_handle, IOCTL_ADAPT_SET_TRANSFER_SIZE, &SetTransferInfo, sizeof(CYPRESS_SET_TRANSFER_SIZE_INFO), &SetTransferInfo, sizeof(CYPRESS_SET_TRANSFER_SIZE_INFO), &transferred, NULL); + #endif +} diff --git a/source/CaptureDeviceSpecific/Nisetro/cypress_nisetro_libusb_comms.cpp b/source/CaptureDeviceSpecific/Nisetro/cypress_nisetro_libusb_comms.cpp new file mode 100644 index 0000000..479262c --- /dev/null +++ b/source/CaptureDeviceSpecific/Nisetro/cypress_nisetro_libusb_comms.cpp @@ -0,0 +1,264 @@ +#include "cypress_nisetro_libusb_comms.hpp" +#include "cypress_nisetro_acquisition_general.hpp" + +#include +#include +#include "usb_generic.hpp" + +static void cypress_device_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 cypress_libusb_start_thread(std::thread* thread_ptr, bool* usb_thread_run) { + if(!usb_is_initialized()) + return; + *usb_thread_run = true; + *thread_ptr = std::thread(cypress_device_usb_thread_function, usb_thread_run); +} + +void cypress_libusb_close_thread(std::thread* thread_ptr, bool* usb_thread_run) { + if(!usb_is_initialized()) + return; + *usb_thread_run = false; + thread_ptr->join(); +} + +// Read from ctrl_in +int cypress_libusb_ctrl_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, uint8_t request, uint16_t value, uint16_t index, int* transferred) { + int ret = libusb_control_transfer(handlers->usb_handle, 0xC0, request, value, index, buf, length, usb_device_desc->bulk_timeout); + if(ret >= 0) + *transferred = ret; + return ret; +} + +// Write to ctrl_out +int cypress_libusb_ctrl_out(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, uint8_t request, uint16_t value, uint16_t index, int* transferred) { + int ret = libusb_control_transfer(handlers->usb_handle, 0x40, request, value, index, buf, length, usb_device_desc->bulk_timeout); + if(ret >= 0) + *transferred = ret; + return ret; +} + +// Read from bulk +int cypress_libusb_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred) { + return libusb_bulk_transfer(handlers->usb_handle, usb_device_desc->ep_bulk_in, buf, length, transferred, usb_device_desc->bulk_timeout); +} + +// Read from ctrl bulk +int cypress_libusb_ctrl_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred) { + return libusb_bulk_transfer(handlers->usb_handle, usb_device_desc->ep_ctrl_bulk_in, buf, length, transferred, usb_device_desc->bulk_timeout); +} + +// Write to ctrl bulk +int cypress_libusb_ctrl_bulk_out(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, int* transferred) { + return libusb_bulk_transfer(handlers->usb_handle, usb_device_desc->ep_ctrl_bulk_out, buf, length, transferred, usb_device_desc->bulk_timeout); +} + +void cypress_libusb_pipe_reset_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc) { + libusb_clear_halt(handlers->usb_handle, usb_device_desc->ep_bulk_in); +} + +void cypress_libusb_pipe_reset_ctrl_bulk_in(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc) { + libusb_clear_halt(handlers->usb_handle, usb_device_desc->ep_ctrl_bulk_in); +} + +void cypress_libusb_pipe_reset_ctrl_bulk_out(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc) { + libusb_clear_halt(handlers->usb_handle, usb_device_desc->ep_ctrl_bulk_out); +} + +void cypress_libusb_cancell_callback(cyni_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 STDCALL cypress_libusb_async_callback(libusb_transfer* transfer) { + cyni_async_callback_data* cb_data = (cyni_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 +int cypress_libusb_async_in_start(cyni_device_device_handlers* handlers, const cyni_device_usb_device* usb_device_desc, uint8_t* buf, int length, cyni_async_callback_data* cb_data) { + libusb_transfer *transfer_in = libusb_alloc_transfer(0); + if(!transfer_in) + return LIBUSB_ERROR_OTHER; + 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->ep_bulk_in, buf, length, cypress_libusb_async_callback, cb_data, usb_device_desc->bulk_timeout); + transfer_in->flags |= LIBUSB_TRANSFER_FREE_TRANSFER; + int retval = libusb_submit_transfer(transfer_in); + cb_data->transfer_data_access.unlock(); + return retval; +} + +static bool cypress_libusb_setup_connection(libusb_device_handle* handle, const cyni_device_usb_device* usb_device_desc) { + int result = libusb_kernel_driver_active(handle, usb_device_desc->default_interface); + if(result == 1) + libusb_detach_kernel_driver(handle, usb_device_desc->default_interface); + result = libusb_set_configuration(handle, usb_device_desc->default_config); + if(result != LIBUSB_SUCCESS) + return false; + result = libusb_kernel_driver_active(handle, usb_device_desc->default_interface); + if(result == 1) + libusb_detach_kernel_driver(handle, usb_device_desc->default_interface); + result = libusb_claim_interface(handle, usb_device_desc->default_interface); + if(result != LIBUSB_SUCCESS) + return false; + if(usb_device_desc->alt_interface != 0) { + result = libusb_set_interface_alt_setting(handle, usb_device_desc->default_interface, usb_device_desc->alt_interface); + if(result != LIBUSB_SUCCESS) + return false; + } + return true; +} + +static void read_strings(libusb_device_handle *handle, libusb_device_descriptor *usb_descriptor, char* manufacturer, char* serial) { + manufacturer[0] = 0; + serial[0] = 0; + libusb_get_string_descriptor_ascii(handle, usb_descriptor->iManufacturer, (uint8_t*)manufacturer, 0x100); + libusb_get_string_descriptor_ascii(handle, usb_descriptor->iSerialNumber, (uint8_t*)serial, 0x100); + manufacturer[0xFF] = 0; + serial[0xFF] = 0; +} + +static int cypress_libusb_insert_device(std::vector &devices_list, const cyni_device_usb_device* usb_device_desc, libusb_device *usb_device, libusb_device_descriptor *usb_descriptor, int &curr_serial_extra_id) { + libusb_device_handle *handle = NULL; + if((usb_descriptor->idVendor != usb_device_desc->vid) || (usb_descriptor->idProduct != usb_device_desc->pid)) + return LIBUSB_ERROR_NOT_FOUND; + int result = libusb_open(usb_device, &handle); + if((result < 0) || (handle == NULL)) + return result; + char manufacturer[0x100]; + char serial[0x100]; + read_strings(handle, usb_descriptor, manufacturer, serial); + bool result_setup = cypress_libusb_setup_connection(handle, usb_device_desc); + if(result_setup) + cypress_insert_device(devices_list, usb_device_desc, (std::string)(serial), usb_descriptor->bcdDevice, curr_serial_extra_id); + libusb_release_interface(handle, usb_device_desc->default_interface); + libusb_close(handle); + return result; +} + +cyni_device_device_handlers* cypress_libusb_serial_reconnection(const cyni_device_usb_device* usb_device_desc, std::string wanted_serial_number, int &curr_serial_extra_id, CaptureDevice* new_device) { + if(!usb_is_initialized()) + return NULL; + libusb_device **usb_devices; + int num_devices = libusb_get_device_list(get_usb_ctx(), &usb_devices); + libusb_device_descriptor usb_descriptor{}; + cyni_device_device_handlers* final_handlers = NULL; + + for(int i = 0; i < num_devices; i++) { + cyni_device_device_handlers handlers; + int result = libusb_get_device_descriptor(usb_devices[i], &usb_descriptor); + if(result < 0) + continue; + if((usb_descriptor.idVendor != usb_device_desc->vid) || (usb_descriptor.idProduct != usb_device_desc->pid)) + continue; + result = libusb_open(usb_devices[i], &handlers.usb_handle); + if(result || (handlers.usb_handle == NULL)) + continue; + char manufacturer[0x100]; + char serial[0x100]; + read_strings(handlers.usb_handle, &usb_descriptor, manufacturer, serial); + std::string device_serial_number = get_serial(usb_device_desc, (std::string)(serial), usb_descriptor.bcdDevice, curr_serial_extra_id); + if((wanted_serial_number == device_serial_number) && (cypress_libusb_setup_connection(handlers.usb_handle, usb_device_desc))) { + final_handlers = new cyni_device_device_handlers; + final_handlers->usb_handle = handlers.usb_handle; + if(new_device != NULL) + *new_device = cypress_create_device(usb_device_desc, wanted_serial_number); + break; + } + libusb_close(handlers.usb_handle); + } + + if(num_devices >= 0) + libusb_free_device_list(usb_devices, 1); + + return final_handlers; +} + +void cypress_libusb_end_connection(cyni_device_device_handlers* handlers, const cyni_device_usb_device* device_desc, bool interface_claimed) { + if (interface_claimed) + libusb_release_interface(handlers->usb_handle, device_desc->default_interface); + libusb_close(handlers->usb_handle); + handlers->usb_handle = NULL; +} + +void cypress_libusb_find_used_serial(const cyni_device_usb_device* usb_device_desc, bool* found, size_t num_free_fw_ids, int &curr_serial_extra_id) { + if(!usb_is_initialized()) + return; + libusb_device **usb_devices; + int num_devices = libusb_get_device_list(get_usb_ctx(), &usb_devices); + libusb_device_descriptor usb_descriptor{}; + cyni_device_device_handlers* final_handlers = NULL; + + for(int i = 0; i < num_devices; i++) { + cyni_device_device_handlers handlers; + int result = libusb_get_device_descriptor(usb_devices[i], &usb_descriptor); + if(result < 0) + continue; + if((usb_descriptor.idVendor != usb_device_desc->vid) || (usb_descriptor.idProduct != usb_device_desc->pid)) + continue; + result = libusb_open(usb_devices[i], &handlers.usb_handle); + if(result || (handlers.usb_handle == NULL)) + continue; + char manufacturer[0x100]; + char serial[0x100]; + read_strings(handlers.usb_handle, &usb_descriptor, manufacturer, serial); + libusb_close(handlers.usb_handle); + std::string device_serial_number = get_serial(usb_device_desc, (std::string)(serial), usb_descriptor.bcdDevice, curr_serial_extra_id); + try { + int pos = std::stoi(device_serial_number); + if((pos < 0) || (pos >= num_free_fw_ids)) + continue; + found[pos] = true; + } + catch(...) { + continue; + } + } + + if(num_devices >= 0) + libusb_free_device_list(usb_devices, 1); + + return; +} + +void cypress_libusb_list_devices(std::vector &devices_list, bool* no_access_elems, bool* not_supported_elems, int *curr_serial_extra_id_cypress, const size_t num_cypress_desc) { + if(!usb_is_initialized()) + return; + libusb_device **usb_devices; + int num_devices = libusb_get_device_list(get_usb_ctx(), &usb_devices); + libusb_device_descriptor usb_descriptor{}; + + for(int i = 0; i < num_devices; i++) { + int result = libusb_get_device_descriptor(usb_devices[i], &usb_descriptor); + if(result < 0) + continue; + for (int j = 0; j < num_cypress_desc; j++) { + result = cypress_libusb_insert_device(devices_list, GetCyNiDeviceDesc(j), usb_devices[i], &usb_descriptor, curr_serial_extra_id_cypress[j]); + if (result != LIBUSB_ERROR_NOT_FOUND) { + if (result == LIBUSB_ERROR_ACCESS) + no_access_elems[j] = true; + if (result == LIBUSB_ERROR_NOT_SUPPORTED) + not_supported_elems[j] = true; + break; + } + } + } + + if(num_devices >= 0) + libusb_free_device_list(usb_devices, 1); +} diff --git a/source/conversions.cpp b/source/conversions.cpp index 4bc4b5d..ee31e32 100755 --- a/source/conversions.cpp +++ b/source/conversions.cpp @@ -207,6 +207,20 @@ inline static void to_8_bit_6(uint8_t* out, uint8_t* in) { out[2] = to_8_bit_6(in[2]); } +static void usb_cypress_nisetro_ds_convertVideoToOutput(CaptureReceived *p_in, VideoOutputData *p_out) { + int pos_top = 0; + int pos_bottom = WIDTH_DS * HEIGHT_DS * 3; + uint8_t* data_in = (uint8_t*)p_in->cypress_nisetro_capture_received.video_in.screen_data; + uint8_t* data_out = (uint8_t*)p_out->screen_data; + for(int i = 0; i < sizeof(CypressNisetroDSCaptureReceived); i++) { + uint8_t conv = to_8_bit_6(data_in[i]); + if(data_in[i] & 0x40) + data_out[pos_bottom++] = conv; + else + data_out[pos_top++] = conv; + } +} + static void usb_is_device_convertVideoToOutput(CaptureReceived *p_in, VideoOutputData *p_out, CaptureStatus* status, CaptureScreensType capture_type) { bool is_nitro = true; #ifdef USE_IS_DEVICES_USB @@ -284,6 +298,12 @@ bool convertVideoToOutput(VideoOutputData *p_out, const bool is_big_endian, Capt converted = true; } #endif + #ifdef USE_CYNI_USB + if(chosen_device->cc_type == CAPTURE_CONN_CYPRESS_NISETRO) { + usb_cypress_nisetro_ds_convertVideoToOutput(p_in, p_out); + converted = true; + } + #endif return converted; } diff --git a/source/devicecapture.cpp b/source/devicecapture.cpp index 5366b40..70f69d2 100755 --- a/source/devicecapture.cpp +++ b/source/devicecapture.cpp @@ -3,6 +3,7 @@ #include "dscapture_ftd2_shared.hpp" #include "usb_ds_3ds_capture.hpp" #include "usb_is_device_acquisition.hpp" +#include "cypress_nisetro_acquisition.hpp" #include #include @@ -78,6 +79,9 @@ bool connect(bool print_failed, CaptureData* capture_data, FrontendData* fronten // Device Listing std::vector devices_list; std::vector no_access_list; + #ifdef USE_CYNI_USB + list_devices_cyni_device(devices_list, no_access_list); + #endif #ifdef USE_FTD3 list_devices_ftd3(devices_list, no_access_list); #endif @@ -115,6 +119,10 @@ bool connect(bool print_failed, CaptureData* capture_data, FrontendData* fronten } // Actual connection + #ifdef USE_CYNI_USB + if((devices_list[chosen_device].cc_type == CAPTURE_CONN_CYPRESS_NISETRO) && (!cyni_device_connect_usb(print_failed, capture_data, &devices_list[chosen_device]))) + return false; + #endif #ifdef USE_FTD3 if((devices_list[chosen_device].cc_type == CAPTURE_CONN_FTD3) && (!connect_ftd3(print_failed, capture_data, &devices_list[chosen_device]))) return false; @@ -151,6 +159,10 @@ void captureCall(CaptureData* capture_data) { } // Main capture loop + #ifdef USE_CYNI_USB + if(capture_data->status.device.cc_type == CAPTURE_CONN_CYPRESS_NISETRO) + cyni_device_acquisition_main_loop(capture_data); + #endif #ifdef USE_FTD3 if(capture_data->status.device.cc_type == CAPTURE_CONN_FTD3) ftd3_capture_main_loop(capture_data); @@ -177,6 +189,10 @@ void captureCall(CaptureData* capture_data) { capture_data->status.audio_wait.unlock(); // Capture cleanup + #ifdef USE_CYNI_USB + if(capture_data->status.device.cc_type == CAPTURE_CONN_CYPRESS_NISETRO) + usb_cyni_device_acquisition_cleanup(capture_data); + #endif #ifdef USE_FTD3 if(capture_data->status.device.cc_type == CAPTURE_CONN_FTD3) ftd3_capture_cleanup(capture_data); @@ -214,6 +230,10 @@ uint64_t get_audio_n_samples(CaptureData* capture_data, uint64_t read) { } uint64_t get_video_in_size(CaptureData* capture_data) { + #ifdef USE_CYNI_USB + if(capture_data->status.device.cc_type == CAPTURE_CONN_CYPRESS_NISETRO) + return cyni_device_get_video_in_size(capture_data); + #endif #ifdef USE_FTD3 if(capture_data->status.device.cc_type == CAPTURE_CONN_FTD3) return ftd3_get_video_in_size(capture_data); @@ -251,6 +271,9 @@ void capture_init() { #ifdef USE_FTD2 ftd2_init_shared(); #endif + #ifdef USE_CYNI_USB + usb_cyni_device_init(); + #endif } void capture_close() { @@ -263,4 +286,7 @@ void capture_close() { #ifdef USE_FTD2 ftd2_end_shared(); #endif + #ifdef USE_CYNI_USB + usb_cyni_device_close(); + #endif } diff --git a/usb_rules/51-nisetro.rules b/usb_rules/51-nisetro.rules new file mode 100644 index 0000000..f0d560a --- /dev/null +++ b/usb_rules/51-nisetro.rules @@ -0,0 +1,2 @@ +SUBSYSTEM=="usb", ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="8613", MODE="0666" +SUBSYSTEM=="usb", ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="1004", MODE="0666"