summaryrefslogtreecommitdiff
path: root/src/input_common/gcadapter/gc_adapter.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/input_common/gcadapter/gc_adapter.h')
-rw-r--r--src/input_common/gcadapter/gc_adapter.h161
1 files changed, 161 insertions, 0 deletions
diff --git a/src/input_common/gcadapter/gc_adapter.h b/src/input_common/gcadapter/gc_adapter.h
new file mode 100644
index 000000000..b1c2a1958
--- /dev/null
+++ b/src/input_common/gcadapter/gc_adapter.h
@@ -0,0 +1,161 @@
1// Copyright 2014 Dolphin Emulator Project
2// Licensed under GPLv2+
3// Refer to the license.txt file included.
4
5#pragma once
6#include <algorithm>
7#include <functional>
8#include <mutex>
9#include <thread>
10#include <unordered_map>
11#include <libusb.h>
12#include "common/common_types.h"
13#include "common/threadsafe_queue.h"
14
15namespace GCAdapter {
16
17enum {
18 PAD_USE_ORIGIN = 0x0080,
19 PAD_GET_ORIGIN = 0x2000,
20 PAD_ERR_STATUS = 0x8000,
21};
22
23enum class PadButton {
24 PAD_BUTTON_LEFT = 0x0001,
25 PAD_BUTTON_RIGHT = 0x0002,
26 PAD_BUTTON_DOWN = 0x0004,
27 PAD_BUTTON_UP = 0x0008,
28 PAD_TRIGGER_Z = 0x0010,
29 PAD_TRIGGER_R = 0x0020,
30 PAD_TRIGGER_L = 0x0040,
31 PAD_BUTTON_A = 0x0100,
32 PAD_BUTTON_B = 0x0200,
33 PAD_BUTTON_X = 0x0400,
34 PAD_BUTTON_Y = 0x0800,
35 PAD_BUTTON_START = 0x1000,
36 // Below is for compatibility with "AxisButton" type
37 PAD_STICK = 0x2000,
38};
39
40extern const std::array<PadButton, 12> PadButtonArray;
41
42enum class PadAxes : u8 {
43 StickX,
44 StickY,
45 SubstickX,
46 SubstickY,
47 TriggerLeft,
48 TriggerRight,
49 Undefined,
50};
51
52struct GCPadStatus {
53 u16 button{}; // Or-ed PAD_BUTTON_* and PAD_TRIGGER_* bits
54 u8 stick_x{}; // 0 <= stick_x <= 255
55 u8 stick_y{}; // 0 <= stick_y <= 255
56 u8 substick_x{}; // 0 <= substick_x <= 255
57 u8 substick_y{}; // 0 <= substick_y <= 255
58 u8 trigger_left{}; // 0 <= trigger_left <= 255
59 u8 trigger_right{}; // 0 <= trigger_right <= 255
60
61 static constexpr u8 MAIN_STICK_CENTER_X = 0x80;
62 static constexpr u8 MAIN_STICK_CENTER_Y = 0x80;
63 static constexpr u8 MAIN_STICK_RADIUS = 0x7f;
64 static constexpr u8 C_STICK_CENTER_X = 0x80;
65 static constexpr u8 C_STICK_CENTER_Y = 0x80;
66 static constexpr u8 C_STICK_RADIUS = 0x7f;
67 static constexpr u8 THRESHOLD = 10;
68
69 // 256/4, at least a quarter press to count as a press. For polling mostly
70 static constexpr u8 TRIGGER_THRESHOLD = 64;
71
72 u8 port{};
73 PadAxes axis{PadAxes::Undefined};
74 u8 axis_value{255};
75};
76
77struct GCState {
78 std::unordered_map<int, bool> buttons;
79 std::unordered_map<int, u16> axes;
80};
81
82enum class ControllerTypes { None, Wired, Wireless };
83
84enum {
85 NO_ADAPTER_DETECTED = 0,
86 ADAPTER_DETECTED = 1,
87};
88
89class Adapter {
90public:
91 /// Initialize the GC Adapter capture and read sequence
92 Adapter();
93
94 /// Close the adapter read thread and release the adapter
95 ~Adapter();
96 /// Used for polling
97 void BeginConfiguration();
98 void EndConfiguration();
99
100 std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue();
101 const std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue() const;
102
103 std::array<GCState, 4>& GetPadState();
104 const std::array<GCState, 4>& GetPadState() const;
105
106private:
107 GCPadStatus GetPadStatus(int port, const std::array<u8, 37>& adapter_payload);
108
109 void PadToState(const GCPadStatus& pad, GCState& state);
110
111 void Read();
112 void ScanThreadFunc();
113 /// Begin scanning for the GC Adapter.
114 void StartScanThread();
115
116 /// Stop scanning for the adapter
117 void StopScanThread();
118
119 /// Returns true if there is a device connected to port
120 bool DeviceConnected(int port);
121
122 /// Resets status of device connected to port
123 void ResetDeviceType(int port);
124
125 /// Returns true if we successfully gain access to GC Adapter
126 bool CheckDeviceAccess(libusb_device* device);
127
128 /// Captures GC Adapter endpoint address,
129 void GetGCEndpoint(libusb_device* device);
130
131 /// For shutting down, clear all data, join all threads, release usb
132 void Reset();
133
134 /// For use in initialization, querying devices to find the adapter
135 void Setup();
136
137 int current_status = NO_ADAPTER_DETECTED;
138 libusb_device_handle* usb_adapter_handle = nullptr;
139 std::array<ControllerTypes, 4> adapter_controllers_status{};
140
141 std::mutex s_mutex;
142
143 std::thread adapter_input_thread;
144 bool adapter_thread_running;
145
146 std::mutex initialization_mutex;
147 std::thread detect_thread;
148 bool detect_thread_running = false;
149
150 libusb_context* libusb_ctx;
151
152 u8 input_endpoint = 0;
153 u8 output_endpoint = 0;
154
155 bool configuring = false;
156
157 std::array<Common::SPSCQueue<GCPadStatus>, 4> pad_queue;
158 std::array<GCState, 4> state;
159};
160
161} // namespace GCAdapter