| | |
| | |
| |
|
| | #pragma once |
| |
|
| | #include <array> |
| | #include <optional> |
| | #include <type_traits> |
| |
|
| | #ifdef _MSC_VER |
| | #pragma warning(push) |
| | #pragma warning(disable : 4701) |
| | #endif |
| |
|
| | #include <boost/crc.hpp> |
| |
|
| | #ifdef _MSC_VER |
| | #pragma warning(pop) |
| | #endif |
| |
|
| | #include "common/swap.h" |
| |
|
| | namespace InputCommon::CemuhookUDP { |
| |
|
| | constexpr std::size_t MAX_PACKET_SIZE = 100; |
| | constexpr u16 PROTOCOL_VERSION = 1001; |
| | constexpr u32 CLIENT_MAGIC = 0x43555344; |
| | constexpr u32 SERVER_MAGIC = 0x53555344; |
| |
|
| | enum class Type : u32 { |
| | Version = 0x00100000, |
| | PortInfo = 0x00100001, |
| | PadData = 0x00100002, |
| | }; |
| |
|
| | struct Header { |
| | u32_le magic{}; |
| | u16_le protocol_version{}; |
| | u16_le payload_length{}; |
| | u32_le crc{}; |
| | u32_le id{}; |
| | |
| | |
| | |
| | Type type{}; |
| | }; |
| | static_assert(sizeof(Header) == 20, "UDP Message Header struct has wrong size"); |
| | static_assert(std::is_trivially_copyable_v<Header>, "UDP Message Header is not trivially copyable"); |
| |
|
| | using MacAddress = std::array<u8, 6>; |
| | constexpr MacAddress EMPTY_MAC_ADDRESS = {0, 0, 0, 0, 0, 0}; |
| |
|
| | #pragma pack(push, 1) |
| | template <typename T> |
| | struct Message { |
| | Header header{}; |
| | T data; |
| | }; |
| | #pragma pack(pop) |
| |
|
| | template <typename T> |
| | constexpr Type GetMessageType(); |
| |
|
| | template <typename T> |
| | Message<T> CreateMessage(const u32 magic, const T data, const u32 sender_id) { |
| | boost::crc_32_type crc; |
| | Header header{ |
| | magic, PROTOCOL_VERSION, sizeof(T) + sizeof(Type), 0, sender_id, GetMessageType<T>(), |
| | }; |
| | Message<T> message{header, data}; |
| | crc.process_bytes(&message, sizeof(Message<T>)); |
| | message.header.crc = crc.checksum(); |
| | return message; |
| | } |
| |
|
| | namespace Request { |
| |
|
| | enum RegisterFlags : u8 { |
| | AllPads, |
| | PadID, |
| | PadMACAddress, |
| | }; |
| |
|
| | struct Version {}; |
| | |
| | |
| | |
| | |
| | |
| | |
| | constexpr u32 MAX_PORTS = 4; |
| | struct PortInfo { |
| | u32_le pad_count{}; |
| | std::array<u8, MAX_PORTS> port; |
| | }; |
| | static_assert(std::is_trivially_copyable_v<PortInfo>, |
| | "UDP Request PortInfo is not trivially copyable"); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | struct PadData { |
| | |
| | RegisterFlags flags{}; |
| | |
| | u8 port_id{}; |
| | |
| | MacAddress mac; |
| | }; |
| | static_assert(sizeof(PadData) == 8, "UDP Request PadData struct has wrong size"); |
| | static_assert(std::is_trivially_copyable_v<PadData>, |
| | "UDP Request PadData is not trivially copyable"); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | template <typename T> |
| | Message<T> Create(const T data, const u32 client_id = 0) { |
| | return CreateMessage(CLIENT_MAGIC, data, client_id); |
| | } |
| | } |
| |
|
| | namespace Response { |
| |
|
| | enum class ConnectionType : u8 { |
| | None, |
| | Usb, |
| | Bluetooth, |
| | }; |
| |
|
| | enum class State : u8 { |
| | Disconnected, |
| | Reserved, |
| | Connected, |
| | }; |
| |
|
| | enum class Model : u8 { |
| | None, |
| | PartialGyro, |
| | FullGyro, |
| | Generic, |
| | }; |
| |
|
| | enum class Battery : u8 { |
| | None = 0x00, |
| | Dying = 0x01, |
| | Low = 0x02, |
| | Medium = 0x03, |
| | High = 0x04, |
| | Full = 0x05, |
| | Charging = 0xEE, |
| | Charged = 0xEF, |
| | }; |
| |
|
| | struct Version { |
| | u16_le version{}; |
| | }; |
| | static_assert(sizeof(Version) == 2, "UDP Response Version struct has wrong size"); |
| | static_assert(std::is_trivially_copyable_v<Version>, |
| | "UDP Response Version is not trivially copyable"); |
| |
|
| | struct PortInfo { |
| | u8 id{}; |
| | State state{}; |
| | Model model{}; |
| | ConnectionType connection_type{}; |
| | MacAddress mac; |
| | Battery battery{}; |
| | u8 is_pad_active{}; |
| | }; |
| | static_assert(sizeof(PortInfo) == 12, "UDP Response PortInfo struct has wrong size"); |
| | static_assert(std::is_trivially_copyable_v<PortInfo>, |
| | "UDP Response PortInfo is not trivially copyable"); |
| |
|
| | struct TouchPad { |
| | u8 is_active{}; |
| | u8 id{}; |
| | u16_le x{}; |
| | u16_le y{}; |
| | }; |
| | static_assert(sizeof(TouchPad) == 6, "UDP Response TouchPad struct has wrong size "); |
| |
|
| | #pragma pack(push, 1) |
| | struct PadData { |
| | PortInfo info{}; |
| | u32_le packet_counter{}; |
| |
|
| | u16_le digital_button{}; |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | u8 home; |
| | |
| | u8 touch_hard_press{}; |
| | u8 left_stick_x{}; |
| | u8 left_stick_y{}; |
| | u8 right_stick_x{}; |
| | u8 right_stick_y{}; |
| |
|
| | struct AnalogButton { |
| | u8 button_dpad_left_analog{}; |
| | u8 button_dpad_down_analog{}; |
| | u8 button_dpad_right_analog{}; |
| | u8 button_dpad_up_analog{}; |
| | u8 button_square_analog{}; |
| | u8 button_cross_analog{}; |
| | u8 button_circle_analog{}; |
| | u8 button_triangle_analog{}; |
| | u8 button_r1_analog{}; |
| | u8 button_l1_analog{}; |
| | u8 trigger_r2{}; |
| | u8 trigger_l2{}; |
| | } analog_button; |
| |
|
| | std::array<TouchPad, 2> touch; |
| |
|
| | u64_le motion_timestamp; |
| |
|
| | struct Accelerometer { |
| | float x{}; |
| | float y{}; |
| | float z{}; |
| | } accel; |
| |
|
| | struct Gyroscope { |
| | float pitch{}; |
| | float yaw{}; |
| | float roll{}; |
| | } gyro; |
| | }; |
| | #pragma pack(pop) |
| |
|
| | static_assert(sizeof(PadData) == 80, "UDP Response PadData struct has wrong size "); |
| | static_assert(std::is_trivially_copyable_v<PadData>, |
| | "UDP Response PadData is not trivially copyable"); |
| |
|
| | static_assert(sizeof(Message<PadData>) == MAX_PACKET_SIZE, |
| | "UDP MAX_PACKET_SIZE is no longer larger than Message<PadData>"); |
| |
|
| | static_assert(sizeof(PadData::AnalogButton) == 12, |
| | "UDP Response AnalogButton 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 "); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | std::optional<Type> Validate(u8* data, std::size_t size); |
| |
|
| | } |
| |
|
| | template <> |
| | constexpr Type GetMessageType<Request::Version>() { |
| | return Type::Version; |
| | } |
| | template <> |
| | constexpr Type GetMessageType<Request::PortInfo>() { |
| | return Type::PortInfo; |
| | } |
| | template <> |
| | constexpr Type GetMessageType<Request::PadData>() { |
| | return Type::PadData; |
| | } |
| | template <> |
| | constexpr Type GetMessageType<Response::Version>() { |
| | return Type::Version; |
| | } |
| | template <> |
| | constexpr Type GetMessageType<Response::PortInfo>() { |
| | return Type::PortInfo; |
| | } |
| | template <> |
| | constexpr Type GetMessageType<Response::PadData>() { |
| | return Type::PadData; |
| | } |
| | } |
| |
|