| |
| |
| |
|
|
| #pragma once |
|
|
| #include <array> |
| #include <optional> |
| #include <type_traits> |
| #include <boost/crc.hpp> |
| #include "common/bit_field.h" |
| #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(); |
|
|
| namespace Request { |
|
|
| 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 { |
| enum class Flags : u8 { |
| AllPorts, |
| Id, |
| Mac, |
| }; |
| |
| Flags 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) { |
| boost::crc_32_type crc; |
| Header header{ |
| CLIENT_MAGIC, PROTOCOL_VERSION, sizeof(T) + sizeof(Type), 0, client_id, GetMessageType<T>(), |
| }; |
| Message<T> message{header, data}; |
| crc.process_bytes(&message, sizeof(Message<T>)); |
| message.header.crc = crc.checksum(); |
| return message; |
| } |
| } |
|
|
| namespace Response { |
|
|
| 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{}; |
| u8 state{}; |
| u8 model{}; |
| u8 connection_type{}; |
| MacAddress mac; |
| 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<PortInfo>, |
| "UDP Response PortInfo is not trivially copyable"); |
|
|
| #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_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{}; |
| } touch_1, touch_2; |
|
|
| 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::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 "); |
|
|
| |
| |
| |
| |
| |
| |
| 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; |
| } |
| } |
|
|