1 // Copyright 2014 Dolphin Emulator Project 2 // Licensed under GPLv2+ 3 // Refer to the license.txt file included. 4 5 #pragma once 6 7 #include <algorithm> 8 #include <array> 9 #include <functional> 10 #include <mutex> 11 #include <thread> 12 #include <unordered_map> 13 #include "common/common_types.h" 14 #include "common/threadsafe_queue.h" 15 16 struct libusb_context; 17 struct libusb_device; 18 struct libusb_device_handle; 19 20 namespace Common { 21 class ParamPackage; 22 } 23 24 namespace GCAdapter { 25 26 enum class PadButton { 27 Undefined = 0x0000, 28 ButtonLeft = 0x0001, 29 ButtonRight = 0x0002, 30 ButtonDown = 0x0004, 31 ButtonUp = 0x0008, 32 TriggerZ = 0x0010, 33 TriggerR = 0x0020, 34 TriggerL = 0x0040, 35 ButtonA = 0x0100, 36 ButtonB = 0x0200, 37 ButtonX = 0x0400, 38 ButtonY = 0x0800, 39 ButtonStart = 0x1000, 40 // Below is for compatibility with "AxisButton" type 41 Stick = 0x2000, 42 }; 43 44 enum class PadAxes : u8 { 45 StickX, 46 StickY, 47 SubstickX, 48 SubstickY, 49 TriggerLeft, 50 TriggerRight, 51 Undefined, 52 }; 53 54 enum class ControllerTypes { 55 None, 56 Wired, 57 Wireless, 58 }; 59 60 struct GCPadStatus { 61 std::size_t port{}; 62 63 PadButton button{PadButton::Undefined}; // Or-ed PAD_BUTTON_* and PAD_TRIGGER_* bits 64 65 PadAxes axis{PadAxes::Undefined}; 66 s16 axis_value{}; 67 u8 axis_threshold{50}; 68 }; 69 70 struct GCController { 71 ControllerTypes type{}; 72 u16 buttons{}; 73 PadButton last_button{}; 74 std::array<s16, 6> axis_values{}; 75 std::array<u8, 6> axis_origin{}; 76 }; 77 78 class Adapter { 79 public: 80 Adapter(); 81 ~Adapter(); 82 83 /// Used for polling 84 void BeginConfiguration(); 85 void EndConfiguration(); 86 87 Common::SPSCQueue<GCPadStatus>& GetPadQueue(); 88 const Common::SPSCQueue<GCPadStatus>& GetPadQueue() const; 89 90 GCController& GetPadState(std::size_t port); 91 const GCController& GetPadState(std::size_t port) const; 92 93 /// Returns true if there is a device connected to port 94 bool DeviceConnected(std::size_t port) const; 95 96 std::vector<Common::ParamPackage> GetInputDevices() const; 97 98 private: 99 using AdapterPayload = std::array<u8, 37>; 100 101 void UpdatePadType(std::size_t port, ControllerTypes pad_type); 102 void UpdateControllers(const AdapterPayload& adapter_payload); 103 void UpdateSettings(std::size_t port); 104 void UpdateStateButtons(std::size_t port, u8 b1, u8 b2); 105 void UpdateStateAxes(std::size_t port, const AdapterPayload& adapter_payload); 106 107 void AdapterInputThread(); 108 109 void AdapterScanThread(); 110 111 bool IsPayloadCorrect(const AdapterPayload& adapter_payload, s32 payload_size); 112 113 /// For use in initialization, querying devices to find the adapter 114 void Setup(); 115 116 /// Resets status of all GC controller devices to a disconnected state 117 void ResetDevices(); 118 119 /// Resets status of device connected to a disconnected state 120 void ResetDevice(std::size_t port); 121 122 /// Returns true if we successfully gain access to GC Adapter 123 bool CheckDeviceAccess(); 124 125 /// Captures GC Adapter endpoint address 126 /// Returns true if the endpoint was set correctly 127 bool GetGCEndpoint(libusb_device* device); 128 129 // Join all threads 130 void JoinThreads(); 131 132 // Release usb handles 133 void ClearLibusbHandle(); 134 135 libusb_device_handle* usb_adapter_handle = nullptr; 136 std::array<GCController, 4> pads; 137 Common::SPSCQueue<GCPadStatus> pad_queue; 138 139 std::thread adapter_input_thread; 140 std::thread adapter_scan_thread; 141 bool adapter_input_thread_running; 142 bool adapter_scan_thread_running; 143 bool restart_scan_thread; 144 145 libusb_context* libusb_ctx; 146 147 u8 input_endpoint{0}; 148 u8 output_endpoint{0}; 149 u8 input_error_counter{0}; 150 151 bool configuring{false}; 152 }; 153 } // namespace GCAdapter 154