diff options
Diffstat (limited to 'src/input_common')
-rw-r--r-- | src/input_common/gcadapter/gc_adapter.cpp | 178 | ||||
-rw-r--r-- | src/input_common/gcadapter/gc_adapter.h | 54 | ||||
-rw-r--r-- | src/input_common/gcadapter/gc_poller.cpp | 24 |
3 files changed, 75 insertions, 181 deletions
diff --git a/src/input_common/gcadapter/gc_adapter.cpp b/src/input_common/gcadapter/gc_adapter.cpp index 38210ffcb..02d06876f 100644 --- a/src/input_common/gcadapter/gc_adapter.cpp +++ b/src/input_common/gcadapter/gc_adapter.cpp @@ -24,11 +24,9 @@ Adapter::Adapter() { } LOG_INFO(Input, "GC Adapter Initialization started"); - current_status = NO_ADAPTER_DETECTED; - const int init_res = libusb_init(&libusb_ctx); if (init_res == LIBUSB_SUCCESS) { - StartScanThread(); + Setup(); } else { LOG_ERROR(Input, "libusb could not be initialized. failed with error = {}", init_res); } @@ -36,14 +34,9 @@ Adapter::Adapter() { GCPadStatus Adapter::GetPadStatus(std::size_t port, const std::array<u8, 37>& adapter_payload) { GCPadStatus pad = {}; - bool get_origin = false; - - ControllerTypes type = ControllerTypes(adapter_payload[1 + (9 * port)] >> 4); - if (type != ControllerTypes::None) { - get_origin = true; - } + const std::size_t offset = 1 + (9 * port); - adapter_controllers_status[port] = type; + adapter_controllers_status[port] = static_cast<ControllerTypes>(adapter_payload[offset] >> 4); static constexpr std::array<PadButton, 8> b1_buttons{ PadButton::PAD_BUTTON_A, PadButton::PAD_BUTTON_B, PadButton::PAD_BUTTON_X, @@ -58,9 +51,19 @@ GCPadStatus Adapter::GetPadStatus(std::size_t port, const std::array<u8, 37>& ad PadButton::PAD_TRIGGER_L, }; + static constexpr std::array<PadAxes, 6> axes{ + PadAxes::StickX, PadAxes::StickY, PadAxes::SubstickX, + PadAxes::SubstickY, PadAxes::TriggerLeft, PadAxes::TriggerRight, + }; + + if (adapter_controllers_status[port] == ControllerTypes::None && !get_origin[port]) { + // Controller may have been disconnected, recalibrate if reconnected. + get_origin[port] = true; + } + if (adapter_controllers_status[port] != ControllerTypes::None) { - const u8 b1 = adapter_payload[1 + (9 * port) + 1]; - const u8 b2 = adapter_payload[1 + (9 * port) + 2]; + const u8 b1 = adapter_payload[offset + 1]; + const u8 b2 = adapter_payload[offset + 2]; for (std::size_t i = 0; i < b1_buttons.size(); ++i) { if ((b1 & (1U << i)) != 0) { @@ -73,17 +76,15 @@ GCPadStatus Adapter::GetPadStatus(std::size_t port, const std::array<u8, 37>& ad pad.button |= static_cast<u16>(b2_buttons[j]); } } - - if (get_origin) { - pad.button |= PAD_GET_ORIGIN; + for (PadAxes axis : axes) { + const std::size_t index = static_cast<std::size_t>(axis); + pad.axis_values[index] = adapter_payload[offset + 3 + index]; } - pad.stick_x = adapter_payload[1 + (9 * port) + 3]; - pad.stick_y = adapter_payload[1 + (9 * port) + 4]; - pad.substick_x = adapter_payload[1 + (9 * port) + 5]; - pad.substick_y = adapter_payload[1 + (9 * port) + 6]; - pad.trigger_left = adapter_payload[1 + (9 * port) + 7]; - pad.trigger_right = adapter_payload[1 + (9 * port) + 8]; + if (get_origin[port]) { + origin_status[port].axis_values = pad.axis_values; + get_origin[port] = false; + } } return pad; } @@ -94,82 +95,47 @@ void Adapter::PadToState(const GCPadStatus& pad, GCState& state) { state.buttons.insert_or_assign(button_value, pad.button & button_value); } - state.axes.insert_or_assign(static_cast<u8>(PadAxes::StickX), pad.stick_x); - state.axes.insert_or_assign(static_cast<u8>(PadAxes::StickY), pad.stick_y); - state.axes.insert_or_assign(static_cast<u8>(PadAxes::SubstickX), pad.substick_x); - state.axes.insert_or_assign(static_cast<u8>(PadAxes::SubstickY), pad.substick_y); - state.axes.insert_or_assign(static_cast<u8>(PadAxes::TriggerLeft), pad.trigger_left); - state.axes.insert_or_assign(static_cast<u8>(PadAxes::TriggerRight), pad.trigger_right); + for (size_t i = 0; i < pad.axis_values.size(); ++i) { + state.axes.insert_or_assign(static_cast<u8>(i), pad.axis_values[i]); + } } void Adapter::Read() { LOG_DEBUG(Input, "GC Adapter Read() thread started"); - int payload_size_in, payload_size_copy; + int payload_size; std::array<u8, 37> adapter_payload; - std::array<u8, 37> adapter_payload_copy; std::array<GCPadStatus, 4> pads; while (adapter_thread_running) { libusb_interrupt_transfer(usb_adapter_handle, input_endpoint, adapter_payload.data(), - sizeof(adapter_payload), &payload_size_in, 16); - payload_size_copy = 0; - // this mutex might be redundant? - { - std::lock_guard<std::mutex> lk(s_mutex); - std::copy(std::begin(adapter_payload), std::end(adapter_payload), - std::begin(adapter_payload_copy)); - payload_size_copy = payload_size_in; - } + sizeof(adapter_payload), &payload_size, 16); - if (payload_size_copy != sizeof(adapter_payload_copy) || - adapter_payload_copy[0] != LIBUSB_DT_HID) { - LOG_ERROR(Input, "error reading payload (size: {}, type: {:02x})", payload_size_copy, - adapter_payload_copy[0]); + if (payload_size != sizeof(adapter_payload) || adapter_payload[0] != LIBUSB_DT_HID) { + LOG_ERROR(Input, + "Error reading payload (size: {}, type: {:02x}) Is the adapter connected?", + payload_size, adapter_payload[0]); adapter_thread_running = false; // error reading from adapter, stop reading. break; } for (std::size_t port = 0; port < pads.size(); ++port) { - pads[port] = GetPadStatus(port, adapter_payload_copy); + pads[port] = GetPadStatus(port, adapter_payload); if (DeviceConnected(port) && configuring) { - if (pads[port].button != PAD_GET_ORIGIN) { + if (pads[port].button != 0) { pad_queue[port].Push(pads[port]); } - // Accounting for a threshold here because of some controller variance - if (pads[port].stick_x > pads[port].MAIN_STICK_CENTER_X + pads[port].THRESHOLD || - pads[port].stick_x < pads[port].MAIN_STICK_CENTER_X - pads[port].THRESHOLD) { - pads[port].axis = GCAdapter::PadAxes::StickX; - pads[port].axis_value = pads[port].stick_x; - pad_queue[port].Push(pads[port]); - } - if (pads[port].stick_y > pads[port].MAIN_STICK_CENTER_Y + pads[port].THRESHOLD || - pads[port].stick_y < pads[port].MAIN_STICK_CENTER_Y - pads[port].THRESHOLD) { - pads[port].axis = GCAdapter::PadAxes::StickY; - pads[port].axis_value = pads[port].stick_y; - pad_queue[port].Push(pads[port]); - } - if (pads[port].substick_x > pads[port].C_STICK_CENTER_X + pads[port].THRESHOLD || - pads[port].substick_x < pads[port].C_STICK_CENTER_X - pads[port].THRESHOLD) { - pads[port].axis = GCAdapter::PadAxes::SubstickX; - pads[port].axis_value = pads[port].substick_x; - pad_queue[port].Push(pads[port]); - } - if (pads[port].substick_y > pads[port].C_STICK_CENTER_Y + pads[port].THRESHOLD || - pads[port].substick_y < pads[port].C_STICK_CENTER_Y - pads[port].THRESHOLD) { - pads[port].axis = GCAdapter::PadAxes::SubstickY; - pads[port].axis_value = pads[port].substick_y; - pad_queue[port].Push(pads[port]); - } - if (pads[port].trigger_left > pads[port].TRIGGER_THRESHOLD) { - pads[port].axis = GCAdapter::PadAxes::TriggerLeft; - pads[port].axis_value = pads[port].trigger_left; - pad_queue[port].Push(pads[port]); - } - if (pads[port].trigger_right > pads[port].TRIGGER_THRESHOLD) { - pads[port].axis = GCAdapter::PadAxes::TriggerRight; - pads[port].axis_value = pads[port].trigger_right; - pad_queue[port].Push(pads[port]); + // Accounting for a threshold here to ensure an intentional press + for (size_t i = 0; i < pads[port].axis_values.size(); ++i) { + const u8 value = pads[port].axis_values[i]; + const u8 origin = origin_status[port].axis_values[i]; + + if (value > origin + pads[port].THRESHOLD || + value < origin - pads[port].THRESHOLD) { + pads[port].axis = static_cast<PadAxes>(i); + pads[port].axis_value = pads[port].axis_values[i]; + pad_queue[port].Push(pads[port]); + } } } PadToState(pads[port], state[port]); @@ -178,42 +144,11 @@ void Adapter::Read() { } } -void Adapter::ScanThreadFunc() { - LOG_INFO(Input, "GC Adapter scanning thread started"); - - while (detect_thread_running) { - if (usb_adapter_handle == nullptr) { - std::lock_guard<std::mutex> lk(initialization_mutex); - Setup(); - } - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - } -} - -void Adapter::StartScanThread() { - if (detect_thread_running) { - return; - } - if (!libusb_ctx) { - return; - } - - detect_thread_running = true; - detect_thread = std::thread(&Adapter::ScanThreadFunc, this); -} - -void Adapter::StopScanThread() { - detect_thread_running = false; - detect_thread.join(); -} - void Adapter::Setup() { - // Reset the error status in case the adapter gets unplugged - if (current_status < 0) { - current_status = NO_ADAPTER_DETECTED; - } - + // Initialize all controllers as unplugged adapter_controllers_status.fill(ControllerTypes::None); + // Initialize all ports to store axis origin values + get_origin.fill(true); // pointer to list of connected usb devices libusb_device** devices{}; @@ -222,8 +157,6 @@ void Adapter::Setup() { const ssize_t device_count = libusb_get_device_list(libusb_ctx, &devices); if (device_count < 0) { LOG_ERROR(Input, "libusb_get_device_list failed with error: {}", device_count); - detect_thread_running = false; // Stop the loop constantly checking for gc adapter - // TODO: For hotplug+gc adapter checkbox implementation, revert this. return; } @@ -321,31 +254,21 @@ void Adapter::GetGCEndpoint(libusb_device* device) { sizeof(clear_payload), nullptr, 16); adapter_thread_running = true; - current_status = ADAPTER_DETECTED; adapter_input_thread = std::thread([=] { Read(); }); // Read input } Adapter::~Adapter() { - StopScanThread(); Reset(); } void Adapter::Reset() { - std::unique_lock<std::mutex> lock(initialization_mutex, std::defer_lock); - if (!lock.try_lock()) { - return; - } - if (current_status != ADAPTER_DETECTED) { - return; - } - if (adapter_thread_running) { adapter_thread_running = false; } adapter_input_thread.join(); adapter_controllers_status.fill(ControllerTypes::None); - current_status = NO_ADAPTER_DETECTED; + get_origin.fill(true); if (usb_adapter_handle) { libusb_release_interface(usb_adapter_handle, 1); @@ -367,6 +290,7 @@ void Adapter::ResetDeviceType(std::size_t port) { } void Adapter::BeginConfiguration() { + get_origin.fill(true); for (auto& pq : pad_queue) { pq.Clear(); } @@ -396,4 +320,8 @@ const std::array<GCState, 4>& Adapter::GetPadState() const { return state; } +int Adapter::GetOriginValue(int port, int axis) const { + return origin_status[port].axis_values[axis]; +} + } // namespace GCAdapter diff --git a/src/input_common/gcadapter/gc_adapter.h b/src/input_common/gcadapter/gc_adapter.h index e2cdd6255..bed81915c 100644 --- a/src/input_common/gcadapter/gc_adapter.h +++ b/src/input_common/gcadapter/gc_adapter.h @@ -17,12 +17,6 @@ struct libusb_device_handle; namespace GCAdapter { -enum { - PAD_USE_ORIGIN = 0x0080, - PAD_GET_ORIGIN = 0x2000, - PAD_ERR_STATUS = 0x8000, -}; - enum class PadButton { PAD_BUTTON_LEFT = 0x0001, PAD_BUTTON_RIGHT = 0x0002, @@ -53,24 +47,10 @@ enum class PadAxes : u8 { }; struct GCPadStatus { - u16 button{}; // Or-ed PAD_BUTTON_* and PAD_TRIGGER_* bits - u8 stick_x{}; // 0 <= stick_x <= 255 - u8 stick_y{}; // 0 <= stick_y <= 255 - u8 substick_x{}; // 0 <= substick_x <= 255 - u8 substick_y{}; // 0 <= substick_y <= 255 - u8 trigger_left{}; // 0 <= trigger_left <= 255 - u8 trigger_right{}; // 0 <= trigger_right <= 255 - - static constexpr u8 MAIN_STICK_CENTER_X = 0x80; - static constexpr u8 MAIN_STICK_CENTER_Y = 0x80; - static constexpr u8 MAIN_STICK_RADIUS = 0x7f; - static constexpr u8 C_STICK_CENTER_X = 0x80; - static constexpr u8 C_STICK_CENTER_Y = 0x80; - static constexpr u8 C_STICK_RADIUS = 0x7f; - static constexpr u8 THRESHOLD = 10; - - // 256/4, at least a quarter press to count as a press. For polling mostly - static constexpr u8 TRIGGER_THRESHOLD = 64; + u16 button{}; // Or-ed PAD_BUTTON_* and PAD_TRIGGER_* bits + + std::array<u8, 6> axis_values{}; // Triggers and sticks, following indices defined in PadAxes + static constexpr u8 THRESHOLD = 50; // Threshold for axis press for polling u8 port{}; PadAxes axis{PadAxes::Undefined}; @@ -84,11 +64,6 @@ struct GCState { enum class ControllerTypes { None, Wired, Wireless }; -enum { - NO_ADAPTER_DETECTED = 0, - ADAPTER_DETECTED = 1, -}; - class Adapter { public: /// Initialize the GC Adapter capture and read sequence @@ -109,18 +84,14 @@ public: std::array<GCState, 4>& GetPadState(); const std::array<GCState, 4>& GetPadState() const; + int GetOriginValue(int port, int axis) const; + private: GCPadStatus GetPadStatus(std::size_t port, const std::array<u8, 37>& adapter_payload); void PadToState(const GCPadStatus& pad, GCState& state); void Read(); - void ScanThreadFunc(); - /// Begin scanning for the GC Adapter. - void StartScanThread(); - - /// Stop scanning for the adapter - void StopScanThread(); /// Resets status of device connected to port void ResetDeviceType(std::size_t port); @@ -137,19 +108,11 @@ private: /// For use in initialization, querying devices to find the adapter void Setup(); - int current_status = NO_ADAPTER_DETECTED; libusb_device_handle* usb_adapter_handle = nullptr; - std::array<ControllerTypes, 4> adapter_controllers_status{}; - - std::mutex s_mutex; std::thread adapter_input_thread; bool adapter_thread_running; - std::mutex initialization_mutex; - std::thread detect_thread; - bool detect_thread_running = false; - libusb_context* libusb_ctx; u8 input_endpoint = 0; @@ -157,8 +120,11 @@ private: bool configuring = false; - std::array<Common::SPSCQueue<GCPadStatus>, 4> pad_queue; std::array<GCState, 4> state; + std::array<bool, 4> get_origin; + std::array<GCPadStatus, 4> origin_status; + std::array<Common::SPSCQueue<GCPadStatus>, 4> pad_queue; + std::array<ControllerTypes, 4> adapter_controllers_status{}; }; } // namespace GCAdapter diff --git a/src/input_common/gcadapter/gc_poller.cpp b/src/input_common/gcadapter/gc_poller.cpp index b20419ec3..96e22d3ad 100644 --- a/src/input_common/gcadapter/gc_poller.cpp +++ b/src/input_common/gcadapter/gc_poller.cpp @@ -38,18 +38,12 @@ public: explicit GCAxisButton(int port_, int axis_, float threshold_, bool trigger_if_greater_, GCAdapter::Adapter* adapter) : port(port_), axis(axis_), threshold(threshold_), trigger_if_greater(trigger_if_greater_), - gcadapter(adapter) { - // L/R triggers range is only in positive direction beginning near 0 - // 0.0 threshold equates to near half trigger press, but threshold accounts for variability. - if (axis > 3) { - threshold *= -0.5; - } - } + gcadapter(adapter), origin_value(adapter->GetOriginValue(port_, axis_)) {} bool GetStatus() const override { if (gcadapter->DeviceConnected(port)) { - const float axis_value = - (gcadapter->GetPadState()[port].axes.at(axis) - 128.0f) / 128.0f; + const float current_axis_value = gcadapter->GetPadState()[port].axes.at(axis); + const float axis_value = (current_axis_value - origin_value) / 128.0f; if (trigger_if_greater) { // TODO: Might be worthwile to set a slider for the trigger threshold. It is // currently always set to 0.5 in configure_input_player.cpp ZL/ZR HandleClick @@ -66,6 +60,7 @@ private: float threshold; bool trigger_if_greater; GCAdapter::Adapter* gcadapter; + const float origin_value; }; GCButtonFactory::GCButtonFactory(std::shared_ptr<GCAdapter::Adapter> adapter_) @@ -155,15 +150,18 @@ void GCButtonFactory::EndConfiguration() { class GCAnalog final : public Input::AnalogDevice { public: GCAnalog(int port_, int axis_x_, int axis_y_, float deadzone_, GCAdapter::Adapter* adapter) - : port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter) {} + : port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter), + origin_value_x(adapter->GetOriginValue(port_, axis_x_)), + origin_value_y(adapter->GetOriginValue(port_, axis_y_)) {} float GetAxis(int axis) const { if (gcadapter->DeviceConnected(port)) { std::lock_guard lock{mutex}; + const auto origin_value = axis % 2 == 0 ? origin_value_x : origin_value_y; // division is not by a perfect 128 to account for some variance in center location // e.g. my device idled at 131 in X, 120 in Y, and full range of motion was in range // [20-230] - return (gcadapter->GetPadState()[port].axes.at(axis) - 128.0f) / 95.0f; + return (gcadapter->GetPadState()[port].axes.at(axis) - origin_value) / 95.0f; } return 0.0f; } @@ -215,8 +213,10 @@ private: const int axis_x; const int axis_y; const float deadzone; - mutable std::mutex mutex; GCAdapter::Adapter* gcadapter; + const float origin_value_x; + const float origin_value_y; + mutable std::mutex mutex; }; /// An analog device factory that creates analog devices from GC Adapter |