| | |
| | |
| | |
| |
|
| | #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; |
| | } |
| | } |
| |
|