From 32cbb1bc7767b77dc05764afedb4867b8e58e15a Mon Sep 17 00:00:00 2001 From: Tobias Date: Fri, 17 Apr 2020 02:50:28 +0200 Subject: [PATCH] input_common/udp: Port various changes from yuzu (#5133) --- src/common/thread.h | 2 +- src/input_common/udp/client.cpp | 49 +++++++++------ src/input_common/udp/client.h | 12 ++-- src/input_common/udp/protocol.cpp | 17 +++-- src/input_common/udp/protocol.h | 101 ++++++++++++++++-------------- src/input_common/udp/udp.cpp | 3 +- 6 files changed, 102 insertions(+), 82 deletions(-) diff --git a/src/common/thread.h b/src/common/thread.h index 70dcf4601..618236b59 100644 --- a/src/common/thread.h +++ b/src/common/thread.h @@ -30,7 +30,7 @@ public: template bool WaitFor(const std::chrono::duration& time) { - std::unique_lock lk(mutex); + std::unique_lock lk{mutex}; if (!condvar.wait_for(lk, time, [this] { return is_set; })) return false; is_set = false; diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp index c9ffe899c..287a064c6 100644 --- a/src/input_common/udp/client.cpp +++ b/src/input_common/udp/client.cpp @@ -32,8 +32,16 @@ public: SocketCallback callback) : callback(std::move(callback)), timer(io_service), socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(client_id), - pad_index(pad_index), - send_endpoint(udp::endpoint(boost::asio::ip::make_address_v4(host), port)) {} + pad_index(pad_index) { + boost::system::error_code ec{}; + auto ipv4 = boost::asio::ip::make_address_v4(host, ec); + if (ec.value() != boost::system::errc::success) { + LOG_ERROR(Input, "Invalid IPv4 address \"{}\" provided to socket", host); + ipv4 = boost::asio::ip::address_v4{}; + } + + send_endpoint = {udp::endpoint(ipv4, port)}; + } void Stop() { io_service.stop(); @@ -85,17 +93,18 @@ private: } void HandleSend(const boost::system::error_code& error) { + boost::system::error_code _ignored{}; // Send a request for getting port info for the pad Request::PortInfo port_info{1, {pad_index, 0, 0, 0}}; - auto port_message = Request::Create(port_info, client_id); + const auto port_message = Request::Create(port_info, client_id); std::memcpy(&send_buffer1, &port_message, PORT_INFO_SIZE); - std::size_t len = socket.send_to(boost::asio::buffer(send_buffer1), send_endpoint); + socket.send_to(boost::asio::buffer(send_buffer1), send_endpoint, {}, _ignored); // Send a request for getting pad data for the pad Request::PadData pad_data{Request::PadData::Flags::Id, pad_index, EMPTY_MAC_ADDRESS}; - auto pad_message = Request::Create(pad_data, client_id); + const auto pad_message = Request::Create(pad_data, client_id); std::memcpy(send_buffer2.data(), &pad_message, PAD_DATA_SIZE); - std::size_t len2 = socket.send_to(boost::asio::buffer(send_buffer2), send_endpoint); + socket.send_to(boost::asio::buffer(send_buffer2), send_endpoint, {}, _ignored); StartSend(timer.expiry()); } @@ -104,8 +113,8 @@ private: boost::asio::basic_waitable_timer timer; udp::socket socket; - u32 client_id; - u8 pad_index; + u32 client_id{}; + u8 pad_index{}; static constexpr std::size_t PORT_INFO_SIZE = sizeof(Message); static constexpr std::size_t PAD_DATA_SIZE = sizeof(Message); @@ -170,16 +179,16 @@ void Client::OnPadData(Response::PadData data) { // TODO: add a setting for "click" touch. Click touch refers to a device that differentiates // between a simple "tap" and a hard press that causes the touch screen to click. - bool is_active = data.touch_1.is_active != 0; + const bool is_active = data.touch_1.is_active != 0; float x = 0; float y = 0; if (is_active && status->touch_calibration) { - u16 min_x = status->touch_calibration->min_x; - u16 max_x = status->touch_calibration->max_x; - u16 min_y = status->touch_calibration->min_y; - u16 max_y = status->touch_calibration->max_y; + const u16 min_x = status->touch_calibration->min_x; + const u16 max_x = status->touch_calibration->max_x; + const u16 min_y = status->touch_calibration->min_y; + const u16 max_y = status->touch_calibration->max_y; x = (std::clamp(static_cast(data.touch_1.x), min_x, max_x) - min_x) / static_cast(max_x - min_x); @@ -212,10 +221,11 @@ void TestCommunication(const std::string& host, u16 port, u8 pad_index, u32 clie bool result = success_event.WaitFor(std::chrono::seconds(8)); socket.Stop(); worker_thread.join(); - if (result) + if (result) { success_callback(); - else + } else { failure_callback(); + } }) .detach(); } @@ -228,8 +238,10 @@ CalibrationConfigurationJob::CalibrationConfigurationJob( std::thread([=] { constexpr u16 CALIBRATION_THRESHOLD = 100; - u16 min_x{UINT16_MAX}, min_y{UINT16_MAX}; - u16 max_x, max_y; + u16 min_x{UINT16_MAX}; + u16 min_y{UINT16_MAX}; + u16 max_x{}; + u16 max_y{}; Status current_status{Status::Initialized}; SocketCallback callback{[](Response::Version version) {}, [](Response::PortInfo info) {}, @@ -239,8 +251,9 @@ CalibrationConfigurationJob::CalibrationConfigurationJob( current_status = Status::Ready; status_callback(current_status); } - if (!data.touch_1.is_active) + if (!data.touch_1.is_active) { return; + } LOG_DEBUG(Input, "Current touch: {} {}", data.touch_1.x, data.touch_1.y); min_x = std::min(min_x, static_cast(data.touch_1.x)); diff --git a/src/input_common/udp/client.h b/src/input_common/udp/client.h index 82bdb68d9..b8c654755 100644 --- a/src/input_common/udp/client.h +++ b/src/input_common/udp/client.h @@ -17,8 +17,8 @@ namespace InputCommon::CemuhookUDP { -static constexpr u16 DEFAULT_PORT = 26760; -static constexpr const char* DEFAULT_ADDR = "127.0.0.1"; +constexpr u16 DEFAULT_PORT = 26760; +constexpr char DEFAULT_ADDR[] = "127.0.0.1"; class Socket; @@ -35,10 +35,10 @@ struct DeviceStatus { // calibration data for scaling the device's touch area to 3ds struct CalibrationData { - u16 min_x; - u16 min_y; - u16 max_x; - u16 max_y; + u16 min_x{}; + u16 min_y{}; + u16 max_x{}; + u16 max_y{}; }; std::optional touch_calibration; }; diff --git a/src/input_common/udp/protocol.cpp b/src/input_common/udp/protocol.cpp index d65069207..5e50bd612 100644 --- a/src/input_common/udp/protocol.cpp +++ b/src/input_common/udp/protocol.cpp @@ -9,7 +9,7 @@ namespace InputCommon::CemuhookUDP { -static const std::size_t GetSizeOfResponseType(Type t) { +static constexpr std::size_t GetSizeOfResponseType(Type t) { switch (t) { case Type::Version: return sizeof(Response::Version); @@ -31,22 +31,21 @@ namespace Response { */ std::optional Validate(u8* data, std::size_t size) { if (size < sizeof(Header)) { - LOG_DEBUG(Input, "Invalid UDP packet received"); - return {}; + return std::nullopt; } - Header header; + Header header{}; std::memcpy(&header, data, sizeof(Header)); if (header.magic != SERVER_MAGIC) { LOG_ERROR(Input, "UDP Packet has an unexpected magic value"); - return {}; + return std::nullopt; } if (header.protocol_version != PROTOCOL_VERSION) { LOG_ERROR(Input, "UDP Packet protocol mismatch"); - return {}; + return std::nullopt; } if (header.type < Type::Version || header.type > Type::PadData) { LOG_ERROR(Input, "UDP Packet is an unknown type"); - return {}; + return std::nullopt; } // Packet size must equal sizeof(Header) + sizeof(Data) @@ -59,7 +58,7 @@ std::optional Validate(u8* data, std::size_t size) { Input, "UDP Packet payload length doesn't match. Received: {} PayloadLength: {} Expected: {}", size, header.payload_length, data_len + sizeof(Type)); - return {}; + return std::nullopt; } const u32 crc32 = header.crc; @@ -70,7 +69,7 @@ std::optional Validate(u8* data, std::size_t size) { result.process_bytes(data, data_len + sizeof(Header)); if (crc32 != result.checksum()) { LOG_ERROR(Input, "UDP Packet CRC check failed. Offset: {}", offsetof(Header, crc)); - return {}; + return std::nullopt; } return header.type; } diff --git a/src/input_common/udp/protocol.h b/src/input_common/udp/protocol.h index 5b1852d55..3ba4d1fc8 100644 --- a/src/input_common/udp/protocol.h +++ b/src/input_common/udp/protocol.h @@ -25,15 +25,15 @@ enum class Type : u32 { }; struct Header { - u32_le magic; - u16_le protocol_version; - u16_le payload_length; - u32_le crc; - u32_le id; + u32_le magic{}; + u16_le protocol_version{}; + u16_le payload_length{}; + u32_le crc{}; + u32_le id{}; ///> In the protocol, the type of the packet is not part of the header, but its convenient to ///> include in the header so the callee doesn't have to duplicate the type twice when building ///> the data - Type type; + Type type{}; }; static_assert(sizeof(Header) == 20, "UDP Message Header struct has wrong size"); static_assert(std::is_trivially_copyable_v
, "UDP Message Header is not trivially copyable"); @@ -44,7 +44,7 @@ constexpr MacAddress EMPTY_MAC_ADDRESS = {0, 0, 0, 0, 0, 0}; #pragma pack(push, 1) template struct Message { - Header header; + Header header{}; T data; }; #pragma pack(pop) @@ -63,7 +63,7 @@ struct Version {}; */ constexpr u32 MAX_PORTS = 4; struct PortInfo { - u32_le pad_count; ///> Number of ports to request data for + u32_le pad_count{}; ///> Number of ports to request data for std::array port; }; static_assert(std::is_trivially_copyable_v, @@ -81,9 +81,9 @@ struct PadData { Mac, }; /// Determines which method will be used as a look up for the controller - Flags flags; + Flags flags{}; /// Index of the port of the controller to retrieve data about - u8 port_id; + u8 port_id{}; /// Mac address of the controller to retrieve data about MacAddress mac; }; @@ -112,20 +112,20 @@ Message Create(const T data, const u32 client_id = 0) { namespace Response { struct Version { - u16_le version; + u16_le version{}; }; static_assert(sizeof(Version) == 2, "UDP Response Version struct has wrong size"); static_assert(std::is_trivially_copyable_v, "UDP Response Version is not trivially copyable"); struct PortInfo { - u8 id; - u8 state; - u8 model; - u8 connection_type; + u8 id{}; + u8 state{}; + u8 model{}; + u8 connection_type{}; MacAddress mac; - u8 battery; - u8 is_pad_active; + u8 battery{}; + u8 is_pad_active{}; }; static_assert(sizeof(PortInfo) == 12, "UDP Response PortInfo struct has wrong size"); static_assert(std::is_trivially_copyable_v, @@ -133,10 +133,10 @@ static_assert(std::is_trivially_copyable_v, #pragma pack(push, 1) struct PadData { - PortInfo info; - u32_le packet_counter; + PortInfo info{}; + u32_le packet_counter{}; - u16_le digital_button; + u16_le digital_button{}; // The following union isn't trivially copyable but we don't use this input anyway. // union DigitalButton { // u16_le button; @@ -160,46 +160,46 @@ struct PadData { u8 home; /// If the device supports a "click" on the touchpad, this will change to 1 when a click happens - u8 touch_hard_press; - u8 left_stick_x; - u8 left_stick_y; - u8 right_stick_x; - u8 right_stick_y; + u8 touch_hard_press{}; + u8 left_stick_x{}; + u8 left_stick_y{}; + u8 right_stick_x{}; + u8 right_stick_y{}; struct AnalogButton { - u8 button_8; - u8 button_7; - u8 button_6; - u8 button_5; - u8 button_12; - u8 button_11; - u8 button_10; - u8 button_9; - u8 button_16; - u8 button_15; - u8 button_14; - u8 button_13; + u8 button_8{}; + u8 button_7{}; + u8 button_6{}; + u8 button_5{}; + u8 button_12{}; + u8 button_11{}; + u8 button_10{}; + u8 button_9{}; + u8 button_16{}; + u8 button_15{}; + u8 button_14{}; + u8 button_13{}; } analog_button; struct TouchPad { - u8 is_active; - u8 id; - u16_le x; - u16_le y; + u8 is_active{}; + u8 id{}; + u16_le x{}; + u16_le y{}; } touch_1, touch_2; u64_le motion_timestamp; struct Accelerometer { - float x; - float y; - float z; + float x{}; + float y{}; + float z{}; } accel; struct Gyroscope { - float pitch; - float yaw; - float roll; + float pitch{}; + float yaw{}; + float roll{}; } gyro; }; #pragma pack(pop) @@ -211,6 +211,13 @@ static_assert(std::is_trivially_copyable_v, static_assert(sizeof(Message) == MAX_PACKET_SIZE, "UDP MAX_PACKET_SIZE is no longer larger than Message"); +static_assert(sizeof(PadData::AnalogButton) == 12, + "UDP Response AnalogButton struct has wrong size "); +static_assert(sizeof(PadData::TouchPad) == 6, "UDP Response TouchPad struct has wrong size "); +static_assert(sizeof(PadData::Accelerometer) == 12, + "UDP Response Accelerometer struct has wrong size "); +static_assert(sizeof(PadData::Gyroscope) == 12, "UDP Response Gyroscope struct has wrong size "); + /** * Create a Response Message from the data * @param data array of bytes sent from the server diff --git a/src/input_common/udp/udp.cpp b/src/input_common/udp/udp.cpp index c4d5121b9..c1d417abb 100644 --- a/src/input_common/udp/udp.cpp +++ b/src/input_common/udp/udp.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include #include #include "common/param_package.h" #include "core/frontend/input.h" @@ -43,7 +44,7 @@ public: std::unique_ptr Create(const Common::ParamPackage& params) override { { std::lock_guard guard(status->update_mutex); - status->touch_calibration.emplace(); + status->touch_calibration = DeviceStatus::CalibrationData{}; // These default values work well for DS4 but probably not other touch inputs status->touch_calibration->min_x = params.Get("min_x", 100); status->touch_calibration->min_y = params.Get("min_y", 50);