1 // Copyright 2018 Citra Emulator Project 2 // Licensed under GPLv2 or any later version 3 // Refer to the license.txt file included. 4 5 #pragma once 6 7 #include <functional> 8 #include <memory> 9 #include <mutex> 10 #include <optional> 11 #include <string> 12 #include <thread> 13 #include <tuple> 14 #include "common/common_types.h" 15 #include "common/param_package.h" 16 #include "common/thread.h" 17 #include "common/threadsafe_queue.h" 18 #include "common/vector_math.h" 19 #include "core/frontend/input.h" 20 #include "input_common/motion_input.h" 21 22 namespace InputCommon::CemuhookUDP { 23 24 constexpr char DEFAULT_SRV[] = "127.0.0.1:26760"; 25 26 class Socket; 27 28 namespace Response { 29 struct PadData; 30 struct PortInfo; 31 struct Version; 32 } // namespace Response 33 34 enum class PadMotion { 35 GyroX, 36 GyroY, 37 GyroZ, 38 AccX, 39 AccY, 40 AccZ, 41 Undefined, 42 }; 43 44 enum class PadTouch { 45 Click, 46 Undefined, 47 }; 48 49 struct UDPPadStatus { 50 std::string host{"127.0.0.1"}; 51 u16 port{26760}; 52 std::size_t pad_index{}; 53 PadTouch touch{PadTouch::Undefined}; 54 PadMotion motion{PadMotion::Undefined}; 55 f32 motion_value{0.0f}; 56 }; 57 58 struct DeviceStatus { 59 std::mutex update_mutex; 60 Input::MotionStatus motion_status; 61 std::tuple<float, float, bool> touch_status; 62 63 // calibration data for scaling the device's touch area to 3ds 64 struct CalibrationData { 65 u16 min_x{}; 66 u16 min_y{}; 67 u16 max_x{}; 68 u16 max_y{}; 69 }; 70 std::optional<CalibrationData> touch_calibration; 71 }; 72 73 class Client { 74 public: 75 // Initialize the UDP client capture and read sequence 76 Client(); 77 78 // Close and release the client 79 ~Client(); 80 81 // Used for polling 82 void BeginConfiguration(); 83 void EndConfiguration(); 84 85 std::vector<Common::ParamPackage> GetInputDevices() const; 86 87 bool DeviceConnected(std::size_t client) const; 88 void ReloadSockets(); 89 90 Common::SPSCQueue<UDPPadStatus>& GetPadQueue(); 91 const Common::SPSCQueue<UDPPadStatus>& GetPadQueue() const; 92 93 DeviceStatus& GetPadState(const std::string& host, u16 port, std::size_t pad); 94 const DeviceStatus& GetPadState(const std::string& host, u16 port, std::size_t pad) const; 95 96 private: 97 struct ClientData { 98 std::string host{"127.0.0.1"}; 99 u16 port{26760}; 100 std::size_t pad_index{}; 101 std::unique_ptr<Socket> socket; 102 DeviceStatus status; 103 std::thread thread; 104 u64 packet_sequence{}; 105 s8 active{-1}; 106 107 // Realtime values 108 // motion is initalized with PID values for drift correction on joycons 109 InputCommon::MotionInput motion{0.3f, 0.005f, 0.0f}; 110 std::chrono::time_point<std::chrono::steady_clock> last_motion_update; 111 }; 112 113 // For shutting down, clear all data, join all threads, release usb 114 void Reset(); 115 116 // Translates configuration to client number 117 std::size_t GetClientNumber(std::string_view host, u16 port, std::size_t pad) const; 118 119 void OnVersion(Response::Version); 120 void OnPortInfo(Response::PortInfo); 121 void OnPadData(Response::PadData, std::size_t client); 122 void StartCommunication(std::size_t client, const std::string& host, u16 port, 123 std::size_t pad_index, u32 client_id); 124 void UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc, 125 const Common::Vec3<float>& gyro, bool touch); 126 127 bool configuring = false; 128 129 // Allocate clients for 8 udp servers 130 const std::size_t max_udp_clients = 32; 131 std::array<ClientData, 4 * 8> clients; 132 Common::SPSCQueue<UDPPadStatus> pad_queue; 133 }; 134 135 /// An async job allowing configuration of the touchpad calibration. 136 class CalibrationConfigurationJob { 137 public: 138 enum class Status { 139 Initialized, 140 Ready, 141 Stage1Completed, 142 Completed, 143 }; 144 /** 145 * Constructs and starts the job with the specified parameter. 146 * 147 * @param status_callback Callback for job status updates 148 * @param data_callback Called when calibration data is ready 149 */ 150 explicit CalibrationConfigurationJob(const std::string& host, u16 port, std::size_t pad_index, 151 u32 client_id, std::function<void(Status)> status_callback, 152 std::function<void(u16, u16, u16, u16)> data_callback); 153 ~CalibrationConfigurationJob(); 154 void Stop(); 155 156 private: 157 Common::Event complete_event; 158 }; 159 160 void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, u32 client_id, 161 const std::function<void()>& success_callback, 162 const std::function<void()>& failure_callback); 163 164 } // namespace InputCommon::CemuhookUDP 165