From a4b98139ee9b73c16aaf2fbbfc64b9dfb60d51bb Mon Sep 17 00:00:00 2001 From: Denis Date: Thu, 21 Dec 2023 02:04:54 +0100 Subject: [PATCH] Use bluetooth dualshock --- CMakeLists.txt | 4 +- dev_out.c | 2 +- rog_ally.c | 8 + rogue_enemy.h | 2 + virt_ds5.c | 992 +++++++++++++++++++++++++++++++++++++++++++++---- virt_ds5.h | 4 +- 6 files changed, 937 insertions(+), 75 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d662d5f..54aa180 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,7 +64,7 @@ add_executable(${ALLINONE_EXECUTABLE_NAME} set_property(TARGET ${ALLINONE_EXECUTABLE_NAME} PROPERTY C_STANDARD 17) -target_link_libraries(${ALLINONE_EXECUTABLE_NAME} PRIVATE Threads::Threads -levdev -ludev -lconfig -lm) +target_link_libraries(${ALLINONE_EXECUTABLE_NAME} PRIVATE Threads::Threads -levdev -ludev -lconfig -lm -lz) set_target_properties(${ALLINONE_EXECUTABLE_NAME} PROPERTIES LINKER_LANGUAGE C) @@ -80,7 +80,7 @@ install(TARGETS ${ROGUE_EXECUTABLE_NAME} DESTINATION bin) set_property(TARGET ${STRAY_EXECUTABLE_NAME} PROPERTY C_STANDARD 17) -target_link_libraries(${STRAY_EXECUTABLE_NAME} PRIVATE Threads::Threads -levdev -ludev -lconfig -lm) +target_link_libraries(${STRAY_EXECUTABLE_NAME} PRIVATE Threads::Threads -levdev -ludev -lconfig -lm -lz) set_target_properties(${STRAY_EXECUTABLE_NAME} PROPERTIES LINKER_LANGUAGE C) diff --git a/dev_out.c b/dev_out.c index 1fb944e..707efe0 100644 --- a/dev_out.c +++ b/dev_out.c @@ -427,7 +427,7 @@ void *dev_out_thread_func(void *ptr) { const int64_t gamepad_report_timing_us = 1250; if (current_gamepad == GAMEPAD_DUALSENSE) { - const int ds5_init_res = virt_dualsense_init(&controller_data.ds5); + const int ds5_init_res = virt_dualsense_init(&controller_data.ds5, true); if (ds5_init_res != 0) { fprintf(stderr, "Unable to initialize the DualSense device: %d\n", ds5_init_res); } else { diff --git a/rog_ally.c b/rog_ally.c index 5f2c0f8..3259efd 100644 --- a/rog_ally.c +++ b/rog_ally.c @@ -1141,7 +1141,15 @@ static void rc71l_platform_deinit(const dev_in_settings_t *const conf, void** pl *platform_data = NULL; } +/** + * This function should use the following: + * pub static DBUS_NAME: &str = "org.asuslinux.Daemon"; + * pub static DBUS_PATH: &str = "/org/asuslinux/Daemon"; + * pub static DBUS_IFACE: &str = "org.asuslinux.Daemon"; + */ static int rc71l_platform_leds(const dev_in_settings_t *const conf, uint8_t r, uint8_t g, uint8_t b, void* platform_data) { + + return 0; } diff --git a/rogue_enemy.h b/rogue_enemy.h index 00197be..a01f1f1 100644 --- a/rogue_enemy.h +++ b/rogue_enemy.h @@ -44,6 +44,8 @@ #include +#include + #define LSB_PER_RAD_S_2000_DEG_S ((double)0.001064724) #define LSB_PER_RAD_S_2000_DEG_S_STR "0.001064724" diff --git a/virt_ds5.c b/virt_ds5.c index e9b70e2..23dadc6 100644 --- a/virt_ds5.c +++ b/virt_ds5.c @@ -3,10 +3,6 @@ #include #include -#include -#include -#include -#include #define DS_FEATURE_REPORT_PAIRING_INFO 0x09 #define DS_FEATURE_REPORT_PAIRING_INFO_SIZE 20 @@ -19,6 +15,8 @@ #define DS_INPUT_REPORT_USB 0x01 #define DS_INPUT_REPORT_USB_SIZE 64 +#define DS_INPUT_REPORT_BT 0x31 +#define DS_INPUT_REPORT_BT_SIZE 78 #define DS_OUTPUT_VALID_FLAG0_HAPTICS_SELECT 0x02 @@ -29,37 +27,855 @@ #define DS5_SPEC_DELTA_TIME 4096.0f +static uint32_t le(uint32_t num) { + const uint32_t b0 = (num & 0x000000ff) << 24u; + const uint32_t b1 = (num & 0x0000ff00) << 8u; + const uint32_t b2 = (num & 0x00ff0000) >> 8u; + const uint32_t b3 = (num & 0xff000000) >> 24u; + + return b0 | b1 | b2 | b3; +} + +static uint32_t crc32_le(uint32_t crc_initial, const uint8_t *const buf, size_t len) { + return crc32(crc_initial ^ 0xffffffff, buf, len) ^ 0xffffffff; +} + +/* Seed values for DualShock4 / DualSense CRC32 for different report types. */ +static uint8_t PS_INPUT_CRC32_SEED = 0xA1; +static uint8_t PS_OUTPUT_CRC32_SEED = 0xA2; +static uint8_t PS_FEATURE_CRC32_SEED = 0xA3; + +#define DS5_EDGE_VERSION 256 +#define DS5_EDGE_VENDOR 0x054C +#define DS5_EDGE_PRODUCT 0x0DF2 + static const char* path = "/dev/uhid"; //static const char* const MAC_ADDR_STR = "e8:47:3a:d6:e7:74"; static const uint8_t MAC_ADDR[] = { 0x74, 0xe7, 0xd6, 0x3a, 0x47, 0xe8 }; static unsigned char rdesc[] = { - 0x05, 0x01, 0x09, 0x05, 0xA1, 0x01, 0x85, 0x01, 0x09, 0x30, 0x09, 0x31, 0x09, 0x32, 0x09, 0x35, - 0x09, 0x33, 0x09, 0x34, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x75, 0x08, 0x95, 0x06, 0x81, 0x02, 0x06, - 0x00, 0xFF, 0x09, 0x20, 0x95, 0x01, 0x81, 0x02, 0x05, 0x01, 0x09, 0x39, 0x15, 0x00, 0x25, 0x07, - 0x35, 0x00, 0x46, 0x3B, 0x01, 0x65, 0x14, 0x75, 0x04, 0x95, 0x01, 0x81, 0x42, 0x65, 0x00, 0x05, - 0x09, 0x19, 0x01, 0x29, 0x0F, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x0F, 0x81, 0x02, 0x06, - 0x00, 0xFF, 0x09, 0x21, 0x95, 0x0D, 0x81, 0x02, 0x06, 0x00, 0xFF, 0x09, 0x22, 0x15, 0x00, 0x26, - 0xFF, 0x00, 0x75, 0x08, 0x95, 0x34, 0x81, 0x02, 0x85, 0x02, 0x09, 0x23, 0x95, 0x3F, 0x91, 0x02, - 0x85, 0x05, 0x09, 0x33, 0x95, 0x28, 0xB1, 0x02, 0x85, 0x08, 0x09, 0x34, 0x95, 0x2F, 0xB1, 0x02, - 0x85, 0x09, 0x09, 0x24, 0x95, 0x13, 0xB1, 0x02, 0x85, 0x0A, 0x09, 0x25, 0x95, 0x1A, 0xB1, 0x02, - 0x85, 0x20, 0x09, 0x26, 0x95, 0x3F, 0xB1, 0x02, 0x85, 0x21, 0x09, 0x27, 0x95, 0x04, 0xB1, 0x02, - 0x85, 0x22, 0x09, 0x40, 0x95, 0x3F, 0xB1, 0x02, 0x85, 0x80, 0x09, 0x28, 0x95, 0x3F, 0xB1, 0x02, - 0x85, 0x81, 0x09, 0x29, 0x95, 0x3F, 0xB1, 0x02, 0x85, 0x82, 0x09, 0x2A, 0x95, 0x09, 0xB1, 0x02, - 0x85, 0x83, 0x09, 0x2B, 0x95, 0x3F, 0xB1, 0x02, 0x85, 0x84, 0x09, 0x2C, 0x95, 0x3F, 0xB1, 0x02, - 0x85, 0x85, 0x09, 0x2D, 0x95, 0x02, 0xB1, 0x02, 0x85, 0xA0, 0x09, 0x2E, 0x95, 0x01, 0xB1, 0x02, - 0x85, 0xE0, 0x09, 0x2F, 0x95, 0x3F, 0xB1, 0x02, 0x85, 0xF0, 0x09, 0x30, 0x95, 0x3F, 0xB1, 0x02, - 0x85, 0xF1, 0x09, 0x31, 0x95, 0x3F, 0xB1, 0x02, 0x85, 0xF2, 0x09, 0x32, 0x95, 0x34, 0xB1, 0x02, - 0x85, 0xF4, 0x09, 0x35, 0x95, 0x3F, 0xB1, 0x02, 0x85, 0xF5, 0x09, 0x36, 0x95, 0x03, 0xB1, 0x02, - 0x85, 0x60, 0x09, 0x41, 0x95, 0x3F, 0xB1, 0x02, 0x85, 0x61, 0x09, 0x42, 0xB1, 0x02, 0x85, 0x62, - 0x09, 0x43, 0xB1, 0x02, 0x85, 0x63, 0x09, 0x44, 0xB1, 0x02, 0x85, 0x64, 0x09, 0x45, 0xB1, 0x02, - 0x85, 0x65, 0x09, 0x46, 0xB1, 0x02, 0x85, 0x68, 0x09, 0x47, 0xB1, 0x02, 0x85, 0x70, 0x09, 0x48, - 0xB1, 0x02, 0x85, 0x71, 0x09, 0x49, 0xB1, 0x02, 0x85, 0x72, 0x09, 0x4A, 0xB1, 0x02, 0x85, 0x73, - 0x09, 0x4B, 0xB1, 0x02, 0x85, 0x74, 0x09, 0x4C, 0xB1, 0x02, 0x85, 0x75, 0x09, 0x4D, 0xB1, 0x02, - 0x85, 0x76, 0x09, 0x4E, 0xB1, 0x02, 0x85, 0x77, 0x09, 0x4F, 0xB1, 0x02, 0x85, 0x78, 0x09, 0x50, - 0xB1, 0x02, 0x85, 0x79, 0x09, 0x51, 0xB1, 0x02, 0x85, 0x7A, 0x09, 0x52, 0xB1, 0x02, 0x85, 0x7B, - 0x09, 0x53, 0xB1, 0x02, 0xC0 + 0x05, + 0x01, // Usage Page (Generic Desktop) 0 + 0x09, + 0x05, // Usage (Game Pad) 2 + 0xA1, + 0x01, // Collection (Application) 4 + 0x85, + 0x01, // Report ID (1) 6 + 0x09, + 0x30, // Usage (X) 8 + 0x09, + 0x31, // Usage (Y) 10 + 0x09, + 0x32, // Usage (Z) 12 + 0x09, + 0x35, // Usage (Rz) 14 + 0x09, + 0x33, // Usage (Rx) 16 + 0x09, + 0x34, // Usage (Ry) 18 + 0x15, + 0x00, // Logical Minimum (0) 20 + 0x26, + 0xFF, + 0x00, // Logical Maximum (255) 22 + 0x75, + 0x08, // Report Size (8) 25 + 0x95, + 0x06, // Report Count (6) 27 + 0x81, + 0x02, // Input (Data,Var,Abs) 29 + 0x06, + 0x00, + 0xFF, // Usage Page (Vendor Defined Page 1) 31 + 0x09, + 0x20, // Usage (Vendor Usage 0x20) 34 + 0x95, + 0x01, // Report Count (1) 36 + 0x81, + 0x02, // Input (Data,Var,Abs) 38 + 0x05, + 0x01, // Usage Page (Generic Desktop) 40 + 0x09, + 0x39, // Usage (Hat switch) 42 + 0x15, + 0x00, // Logical Minimum (0) 44 + 0x25, + 0x07, // Logical Maximum (7) 46 + 0x35, + 0x00, // Physical Minimum (0) 48 + 0x46, + 0x3B, + 0x01, // Physical Maximum (315) 50 + 0x65, + 0x14, // Unit (EnglishRotation: deg) 53 + 0x75, + 0x04, // Report Size (4) 55 + 0x95, + 0x01, // Report Count (1) 57 + 0x81, + 0x42, // Input (Data,Var,Abs,Null) 59 + 0x65, + 0x00, // Unit (None) 61 + 0x05, + 0x09, // Usage Page (Button) 63 + 0x19, + 0x01, // Usage Minimum (1) 65 + 0x29, + 0x0F, // Usage Maximum (15) 67 + 0x15, + 0x00, // Logical Minimum (0) 69 + 0x25, + 0x01, // Logical Maximum (1) 71 + 0x75, + 0x01, // Report Size (1) 73 + 0x95, + 0x0F, // Report Count (15) 75 + 0x81, + 0x02, // Input (Data,Var,Abs) 77 + 0x06, + 0x00, + 0xFF, // Usage Page (Vendor Defined Page 1) 79 + 0x09, + 0x21, // Usage (Vendor Usage 0x21) 82 + 0x95, + 0x0D, // Report Count (13) 84 + 0x81, + 0x02, // Input (Data,Var,Abs) 86 + 0x06, + 0x00, + 0xFF, // Usage Page (Vendor Defined Page 1) 88 + 0x09, + 0x22, // Usage (Vendor Usage 0x22) 91 + 0x15, + 0x00, // Logical Minimum (0) 93 + 0x26, + 0xFF, + 0x00, // Logical Maximum (255) 95 + 0x75, + 0x08, // Report Size (8) 98 + 0x95, + 0x34, // Report Count (52) 100 + 0x81, + 0x02, // Input (Data,Var,Abs) 102 + 0x85, + 0x02, // Report ID (2) 104 + 0x09, + 0x23, // Usage (Vendor Usage 0x23) 106 + 0x95, + 0x3F, // Report Count (63) 108 + 0x91, + 0x02, // Output (Data,Var,Abs) 110 + 0x85, + 0x05, // Report ID (5) 112 + 0x09, + 0x33, // Usage (Vendor Usage 0x33) 114 + 0x95, + 0x28, // Report Count (40) 116 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 118 + 0x85, + 0x08, // Report ID (8) 120 + 0x09, + 0x34, // Usage (Vendor Usage 0x34) 122 + 0x95, + 0x2F, // Report Count (47) 124 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 126 + 0x85, + 0x09, // Report ID (9) 128 + 0x09, + 0x24, // Usage (Vendor Usage 0x24) 130 + 0x95, + 0x13, // Report Count (19) 132 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 134 + 0x85, + 0x0A, // Report ID (10) 136 + 0x09, + 0x25, // Usage (Vendor Usage 0x25) 138 + 0x95, + 0x1A, // Report Count (26) 140 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 142 + 0x85, + 0x20, // Report ID (32) 144 + 0x09, + 0x26, // Usage (Vendor Usage 0x26) 146 + 0x95, + 0x3F, // Report Count (63) 148 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 150 + 0x85, + 0x21, // Report ID (33) 152 + 0x09, + 0x27, // Usage (Vendor Usage 0x27) 154 + 0x95, + 0x04, // Report Count (4) 156 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 158 + 0x85, + 0x22, // Report ID (34) 160 + 0x09, + 0x40, // Usage (Vendor Usage 0x40) 162 + 0x95, + 0x3F, // Report Count (63) 164 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 166 + 0x85, + 0x80, // Report ID (128) 168 + 0x09, + 0x28, // Usage (Vendor Usage 0x28) 170 + 0x95, + 0x3F, // Report Count (63) 172 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 174 + 0x85, + 0x81, // Report ID (129) 176 + 0x09, + 0x29, // Usage (Vendor Usage 0x29) 178 + 0x95, + 0x3F, // Report Count (63) 180 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 182 + 0x85, + 0x82, // Report ID (130) 184 + 0x09, + 0x2A, // Usage (Vendor Usage 0x2a) 186 + 0x95, + 0x09, // Report Count (9) 188 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 190 + 0x85, + 0x83, // Report ID (131) 192 + 0x09, + 0x2B, // Usage (Vendor Usage 0x2b) 194 + 0x95, + 0x3F, // Report Count (63) 196 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 198 + 0x85, + 0x84, // Report ID (132) 200 + 0x09, + 0x2C, // Usage (Vendor Usage 0x2c) 202 + 0x95, + 0x3F, // Report Count (63) 204 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 206 + 0x85, + 0x85, // Report ID (133) 208 + 0x09, + 0x2D, // Usage (Vendor Usage 0x2d) 210 + 0x95, + 0x02, // Report Count (2) 212 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 214 + 0x85, + 0xA0, // Report ID (160) 216 + 0x09, + 0x2E, // Usage (Vendor Usage 0x2e) 218 + 0x95, + 0x01, // Report Count (1) 220 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 222 + 0x85, + 0xE0, // Report ID (224) 224 + 0x09, + 0x2F, // Usage (Vendor Usage 0x2f) 226 + 0x95, + 0x3F, // Report Count (63) 228 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 230 + 0x85, + 0xF0, // Report ID (240) 232 + 0x09, + 0x30, // Usage (Vendor Usage 0x30) 234 + 0x95, + 0x3F, // Report Count (63) 236 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 238 + 0x85, + 0xF1, // Report ID (241) 240 + 0x09, + 0x31, // Usage (Vendor Usage 0x31) 242 + 0x95, + 0x3F, // Report Count (63) 244 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 246 + 0x85, + 0xF2, // Report ID (242) 248 + 0x09, + 0x32, // Usage (Vendor Usage 0x32) 250 + 0x95, + 0x34, // Report Count (52) 252 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 254 + 0x85, + 0xF4, // Report ID (244) 256 + 0x09, + 0x35, // Usage (Vendor Usage 0x35) 258 + 0x95, + 0x3F, // Report Count (63) 260 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 262 + 0x85, + 0xF5, // Report ID (245) 264 + 0x09, + 0x36, // Usage (Vendor Usage 0x36) 266 + 0x95, + 0x03, // Report Count (3) 268 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 270 + 0x85, + 0x60, // Report ID (96) 272 + 0x09, + 0x41, // Usage (Vendor Usage 0x41) 274 + 0x95, + 0x3F, // Report Count (63) 276 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 278 + 0x85, + 0x61, // Report ID (97) 280 + 0x09, + 0x42, // Usage (Vendor Usage 0x42) 282 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 284 + 0x85, + 0x62, // Report ID (98) 286 + 0x09, + 0x43, // Usage (Vendor Usage 0x43) 288 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 290 + 0x85, + 0x63, // Report ID (99) 292 + 0x09, + 0x44, // Usage (Vendor Usage 0x44) 294 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 296 + 0x85, + 0x64, // Report ID (100) 298 + 0x09, + 0x45, // Usage (Vendor Usage 0x45) 300 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 302 + 0x85, + 0x65, // Report ID (101) 304 + 0x09, + 0x46, // Usage (Vendor Usage 0x46) 306 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 308 + 0x85, + 0x68, // Report ID (104) 310 + 0x09, + 0x47, // Usage (Vendor Usage 0x47) 312 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 314 + 0x85, + 0x70, // Report ID (112) 316 + 0x09, + 0x48, // Usage (Vendor Usage 0x48) 318 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 320 + 0x85, + 0x71, // Report ID (113) 322 + 0x09, + 0x49, // Usage (Vendor Usage 0x49) 324 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 326 + 0x85, + 0x72, // Report ID (114) 328 + 0x09, + 0x4A, // Usage (Vendor Usage 0x4a) 330 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 332 + 0x85, + 0x73, // Report ID (115) 334 + 0x09, + 0x4B, // Usage (Vendor Usage 0x4b) 336 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 338 + 0x85, + 0x74, // Report ID (116) 340 + 0x09, + 0x4C, // Usage (Vendor Usage 0x4c) 342 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 344 + 0x85, + 0x75, // Report ID (117) 346 + 0x09, + 0x4D, // Usage (Vendor Usage 0x4d) 348 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 350 + 0x85, + 0x76, // Report ID (118) 352 + 0x09, + 0x4E, // Usage (Vendor Usage 0x4e) 354 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 356 + 0x85, + 0x77, // Report ID (119) 358 + 0x09, + 0x4F, // Usage (Vendor Usage 0x4f) 360 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 362 + 0x85, + 0x78, // Report ID (120) 364 + 0x09, + 0x50, // Usage (Vendor Usage 0x50) 366 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 368 + 0x85, + 0x79, // Report ID (121) 370 + 0x09, + 0x51, // Usage (Vendor Usage 0x51) 372 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 374 + 0x85, + 0x7A, // Report ID (122) 376 + 0x09, + 0x52, // Usage (Vendor Usage 0x52) 378 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 380 + 0x85, + 0x7B, // Report ID (123) 382 + 0x09, + 0x53, // Usage (Vendor Usage 0x53) 384 + 0xB1, + 0x02, // Feature (Data,Var,Abs) 386 + 0xC0, // End Collection 388 +}; + +static unsigned char rdesc_bt[] = { + 0x05, + 0x01, + 0x09, + 0x05, + 0xA1, + 0x01, + 0x85, + 0x01, + 0x09, + 0x30, + 0x09, + 0x31, + 0x09, + 0x32, + 0x09, + 0x35, + 0x15, + 0x00, + 0x26, + 0xFF, + 0x00, + 0x75, + 0x08, + 0x95, + 0x04, + 0x81, + 0x02, + 0x09, + 0x39, + 0x15, + 0x00, + 0x25, + 0x07, + 0x35, + 0x00, + 0x46, + 0x3B, + 0x01, + 0x65, + 0x14, + 0x75, + 0x04, + 0x95, + 0x01, + 0x81, + 0x42, + 0x65, + 0x00, + 0x05, + 0x09, + 0x19, + 0x01, + 0x29, + 0x0E, + 0x15, + 0x00, + 0x25, + 0x01, + 0x75, + 0x01, + 0x95, + 0x0E, + 0x81, + 0x02, + 0x75, + 0x06, + 0x95, + 0x01, + 0x81, + 0x01, + 0x05, + 0x01, + 0x09, + 0x33, + 0x09, + 0x34, + 0x15, + 0x00, + 0x26, + 0xFF, + 0x00, + 0x75, + 0x08, + 0x95, + 0x02, + 0x81, + 0x02, + 0x06, + 0x00, + 0xFF, + 0x15, + 0x00, + 0x26, + 0xFF, + 0x00, + 0x75, + 0x08, + 0x95, + 0x4D, + 0x85, + 0x31, + 0x09, + 0x31, + 0x91, + 0x02, + 0x09, + 0x3B, + 0x81, + 0x02, + 0x85, + 0x32, + 0x09, + 0x32, + 0x95, + 0x8D, + 0x91, + 0x02, + 0x85, + 0x33, + 0x09, + 0x33, + 0x95, + 0xCD, + 0x91, + 0x02, + 0x85, + 0x34, + 0x09, + 0x34, + 0x96, + 0x0D, + 0x01, + 0x91, + 0x02, + 0x85, + 0x35, + 0x09, + 0x35, + 0x96, + 0x4D, + 0x01, + 0x91, + 0x02, + 0x85, + 0x36, + 0x09, + 0x36, + 0x96, + 0x8D, + 0x01, + 0x91, + 0x02, + 0x85, + 0x37, + 0x09, + 0x37, + 0x96, + 0xCD, + 0x01, + 0x91, + 0x02, + 0x85, + 0x38, + 0x09, + 0x38, + 0x96, + 0x0D, + 0x02, + 0x91, + 0x02, + 0x85, + 0x39, + 0x09, + 0x39, + 0x96, + 0x22, + 0x02, + 0x91, + 0x02, + 0x06, + 0x80, + 0xFF, + 0x85, + 0x05, + 0x09, + 0x33, + 0x95, + 0x28, + 0xB1, + 0x02, + 0x85, + 0x08, + 0x09, + 0x34, + 0x95, + 0x2F, + 0xB1, + 0x02, + 0x85, + 0x09, + 0x09, + 0x24, + 0x95, + 0x13, + 0xB1, + 0x02, + 0x85, + 0x20, + 0x09, + 0x26, + 0x95, + 0x3F, + 0xB1, + 0x02, + 0x85, + 0x22, + 0x09, + 0x40, + 0x95, + 0x3F, + 0xB1, + 0x02, + 0x85, + 0x80, + 0x09, + 0x28, + 0x95, + 0x3F, + 0xB1, + 0x02, + 0x85, + 0x81, + 0x09, + 0x29, + 0x95, + 0x3F, + 0xB1, + 0x02, + 0x85, + 0x82, + 0x09, + 0x2A, + 0x95, + 0x09, + 0xB1, + 0x02, + 0x85, + 0x83, + 0x09, + 0x2B, + 0x95, + 0x3F, + 0xB1, + 0x02, + 0x85, + 0xF1, + 0x09, + 0x31, + 0x95, + 0x3F, + 0xB1, + 0x02, + 0x85, + 0xF2, + 0x09, + 0x32, + 0x95, + 0x34, + 0xB1, + 0x02, + 0x85, + 0xF0, + 0x09, + 0x30, + 0x95, + 0x3F, + 0xB1, + 0x02, + 0x85, + 0x60, + 0x09, + 0x41, + 0x95, + 0x3F, + 0xB1, + 0x02, + 0x85, + 0x61, + 0x09, + 0x42, + 0xB1, + 0x02, + 0x85, + 0x62, + 0x09, + 0x43, + 0xB1, + 0x02, + 0x85, + 0x63, + 0x09, + 0x44, + 0xB1, + 0x02, + 0x85, + 0x64, + 0x09, + 0x45, + 0xB1, + 0x02, + 0x85, + 0x65, + 0x09, + 0x46, + 0xB1, + 0x02, + 0x85, + 0x68, + 0x09, + 0x47, + 0xB1, + 0x02, + 0x85, + 0x70, + 0x09, + 0x48, + 0xB1, + 0x02, + 0x85, + 0x71, + 0x09, + 0x49, + 0xB1, + 0x02, + 0x85, + 0x72, + 0x09, + 0x4A, + 0xB1, + 0x02, + 0x85, + 0x73, + 0x09, + 0x4B, + 0xB1, + 0x02, + 0x85, + 0x74, + 0x09, + 0x4C, + 0xB1, + 0x02, + 0x85, + 0x75, + 0x09, + 0x4D, + 0xB1, + 0x02, + 0x85, + 0x76, + 0x09, + 0x4E, + 0xB1, + 0x02, + 0x85, + 0x77, + 0x09, + 0x4F, + 0xB1, + 0x02, + 0x85, + 0x78, + 0x09, + 0x50, + 0xB1, + 0x02, + 0x85, + 0x79, + 0x09, + 0x51, + 0xB1, + 0x02, + 0x85, + 0x7A, + 0x09, + 0x52, + 0xB1, + 0x02, + 0x85, + 0x7B, + 0x09, + 0x53, + 0xB1, + 0x02, + 0x85, + 0xF4, + 0x09, + 0x2C, + 0x95, + 0x3F, + 0xB1, + 0x02, + 0x85, + 0xF5, + 0x09, + 0x2D, + 0x95, + 0x07, + 0xB1, + 0x02, + 0x85, + 0xF6, + 0x09, + 0x2E, + 0x96, + 0x22, + 0x02, + 0xB1, + 0x02, + 0x85, + 0xF7, + 0x09, + 0x2F, + 0x95, + 0x07, + 0xB1, + 0x02, + 0xC0, + 0x00, }; static int uhid_write(int fd, const struct uhid_event *ev) @@ -79,19 +895,19 @@ static int uhid_write(int fd, const struct uhid_event *ev) } } -static int create(int fd) +static int create(int fd, bool bluetooth) { struct uhid_event ev; memset(&ev, 0, sizeof(ev)); ev.type = UHID_CREATE; strcpy((char*)ev.u.create.name, "Sony Corp. DualSense Edge wireless controller (PS5)"); - ev.u.create.rd_data = rdesc; - ev.u.create.rd_size = sizeof(rdesc); - ev.u.create.bus = BUS_USB; - ev.u.create.vendor = 0x054C; - ev.u.create.product = 0x0df2; - ev.u.create.version = 0; + ev.u.create.rd_data = bluetooth ? rdesc_bt : rdesc; + ev.u.create.rd_size = bluetooth ? sizeof(rdesc_bt) : sizeof(rdesc); + ev.u.create.bus = bluetooth ? BUS_BLUETOOTH : BUS_USB; + ev.u.create.vendor = DS5_EDGE_VENDOR; + ev.u.create.product = DS5_EDGE_PRODUCT; + ev.u.create.version = DS5_EDGE_VERSION; ev.u.create.country = 0; memset(&ev.u.create.uniq, 0, sizeof(ev.u.create.uniq)); memcpy(&ev.u.create.uniq, (void*)MAC_ADDR, sizeof(MAC_ADDR)); @@ -109,9 +925,10 @@ static void destroy(int fd) uhid_write(fd, &ev); } -int virt_dualsense_init(virt_dualsense_t *const out_gamepad) { +int virt_dualsense_init(virt_dualsense_t *const out_gamepad, bool bluetooth) { int ret = 0; + out_gamepad->bluetooth = bluetooth; out_gamepad->dt_sum = 0; out_gamepad->dt_buffer_current = 0; memset(out_gamepad->dt_buffer, 0, sizeof(out_gamepad->dt_buffer)); @@ -127,7 +944,7 @@ int virt_dualsense_init(virt_dualsense_t *const out_gamepad) { goto virt_dualshock_init_err; } - ret = create(out_gamepad->fd); + ret = create(out_gamepad->fd, bluetooth); if (ret) { fprintf(stderr, "Error creating uhid device: %d\n", ret); close(out_gamepad->fd); @@ -263,7 +1080,7 @@ int virt_dualsense_event(virt_dualsense_t *const gamepad, gamepad_status_t *cons case UHID_GET_REPORT: //fprintf(stderr, "UHID_GET_REPORT from uhid-dev, report=%d\n", ev.u.get_report.rnum); if (ev.u.get_report.rnum == DS_FEATURE_REPORT_PAIRING_INFO) { - const struct uhid_event mac_addr_response = { + struct uhid_event mac_addr_response = { .type = UHID_GET_REPORT_REPLY, .u = { .get_report_reply = { @@ -281,9 +1098,15 @@ int virt_dualsense_event(virt_dualsense_t *const gamepad, gamepad_status_t *cons } }; + if (gamepad->bluetooth) { + uint32_t crc = crc32_le(0xFFFFFFFFU, (const uint8_t*)&PS_FEATURE_CRC32_SEED, sizeof(PS_FEATURE_CRC32_SEED)); + crc = ~crc32_le(crc, (const Bytef *)&mac_addr_response.u.get_report_reply.data[0], mac_addr_response.u.get_report_reply.size - 4); + memcpy(&mac_addr_response.u.get_report_reply.data[mac_addr_response.u.get_report_reply.size - sizeof(crc)], &crc, sizeof(crc)); + } + uhid_write(fd, &mac_addr_response); } else if (ev.u.get_report.rnum == DS_FEATURE_REPORT_FIRMWARE_INFO) { - const struct uhid_event firmware_info_response = { + struct uhid_event firmware_info_response = { .type = UHID_GET_REPORT_REPLY, .u = { .get_report_reply = { @@ -301,9 +1124,15 @@ int virt_dualsense_event(virt_dualsense_t *const gamepad, gamepad_status_t *cons } }; + if (gamepad->bluetooth) { + uint32_t crc = crc32_le(0xFFFFFFFFU, (const uint8_t*)&PS_FEATURE_CRC32_SEED, sizeof(PS_FEATURE_CRC32_SEED)); + crc = ~crc32_le(crc, (const Bytef *)&firmware_info_response.u.get_report_reply.data[0], firmware_info_response.u.get_report_reply.size - 4); + memcpy(&firmware_info_response.u.get_report_reply.data[firmware_info_response.u.get_report_reply.size - sizeof(crc)], &crc, sizeof(crc)); + } + uhid_write(fd, &firmware_info_response); } else if (ev.u.get_report.rnum == DS_FEATURE_REPORT_CALIBRATION) { - struct uhid_event firmware_info_response = { + struct uhid_event calibration_response = { .type = UHID_GET_REPORT_REPLY, .u = { .get_report_reply = { @@ -320,7 +1149,13 @@ int virt_dualsense_event(virt_dualsense_t *const gamepad, gamepad_status_t *cons } }; - uhid_write(fd, &firmware_info_response); + if (gamepad->bluetooth) { + uint32_t crc = crc32_le(0xFFFFFFFFU, (const uint8_t*)&PS_FEATURE_CRC32_SEED, sizeof(PS_FEATURE_CRC32_SEED)); + crc = ~crc32_le(crc, (const Bytef *)&calibration_response.u.get_report_reply.data[0], calibration_response.u.get_report_reply.size - 4); + memcpy(&calibration_response.u.get_report_reply.data[calibration_response.u.get_report_reply.size - sizeof(crc)], &crc, sizeof(crc)); + } + + uhid_write(fd, &calibration_response); } break; @@ -407,20 +1242,22 @@ void virt_dualsense_compose(virt_dualsense_t *const gamepad, gamepad_status_t *c const int16_t a_z = (int16_t)(-1) * in_device_status->raw_accel[2]; // Swap Y and Z - out_buf[0] = DS_INPUT_REPORT_USB; // [00] report ID (0x01) - out_buf[1] = ((uint64_t)((int64_t)in_device_status->joystick_positions[0][0] + (int64_t)32768) >> (uint64_t)8); // L stick, X axis - out_buf[2] = ((uint64_t)((int64_t)in_device_status->joystick_positions[0][1] + (int64_t)32768) >> (uint64_t)8); // L stick, Y axis - out_buf[3] = ((uint64_t)((int64_t)in_device_status->joystick_positions[1][0] + (int64_t)32768) >> (uint64_t)8); // R stick, X axis - out_buf[4] = ((uint64_t)((int64_t)in_device_status->joystick_positions[1][1] + (int64_t)32768) >> (uint64_t)8); // R stick, Y axis - out_buf[5] = in_device_status->l2_trigger; // Z - out_buf[6] = in_device_status->r2_trigger; // RZ - out_buf[7] = gamepad->seq_num++; // seq_number - out_buf[8] = (in_device_status->square ? 0x10 : 0x00) | + out_buf[0] = gamepad->bluetooth ? DS_INPUT_REPORT_BT : DS_INPUT_REPORT_USB; // [00] report ID (0x01) + + uint8_t *const out_shifted_buf = gamepad->bluetooth ? &out_buf[1] : &out_buf[0]; + out_shifted_buf[1] = ((uint64_t)((int64_t)in_device_status->joystick_positions[0][0] + (int64_t)32768) >> (uint64_t)8); // L stick, X axis + out_shifted_buf[2] = ((uint64_t)((int64_t)in_device_status->joystick_positions[0][1] + (int64_t)32768) >> (uint64_t)8); // L stick, Y axis + out_shifted_buf[3] = ((uint64_t)((int64_t)in_device_status->joystick_positions[1][0] + (int64_t)32768) >> (uint64_t)8); // R stick, X axis + out_shifted_buf[4] = ((uint64_t)((int64_t)in_device_status->joystick_positions[1][1] + (int64_t)32768) >> (uint64_t)8); // R stick, Y axis + out_shifted_buf[5] = in_device_status->l2_trigger; // Z + out_shifted_buf[6] = in_device_status->r2_trigger; // RZ + out_shifted_buf[7] = gamepad->seq_num++; // seq_number + out_shifted_buf[8] = (in_device_status->square ? 0x10 : 0x00) | (in_device_status->cross ? 0x20 : 0x00) | (in_device_status->circle ? 0x40 : 0x00) | (in_device_status->triangle ? 0x80 : 0x00) | (uint8_t)ds5_dpad_from_gamepad(in_device_status->dpad); - out_buf[9] = (in_device_status->l1 ? 0x01 : 0x00) | + out_shifted_buf[9] = (in_device_status->l1 ? 0x01 : 0x00) | (in_device_status->r1 ? 0x02 : 0x00) | (in_device_status->l2_trigger >= 225 ? 0x04 : 0x00) | (in_device_status->r2_trigger >= 225 ? 0x08 : 0x00) | @@ -430,7 +1267,7 @@ void virt_dualsense_compose(virt_dualsense_t *const gamepad, gamepad_status_t *c (in_device_status->r3 ? 0x80 : 0x00); // mic button press is 0x04, touchpad press is 0x02 - out_buf[10] = (in_device_status->l5 ? 0x40 : 0x00) | + out_shifted_buf[10] = (in_device_status->l5 ? 0x40 : 0x00) | (in_device_status->r5 ? 0x80 : 0x00) | (in_device_status->l4 ? 0x10 : 0x00) | (in_device_status->r4 ? 0x20 : 0x00) | @@ -439,40 +1276,53 @@ void virt_dualsense_compose(virt_dualsense_t *const gamepad, gamepad_status_t *c //buf[11] = ; //buf[12] = 0x20; // [12] battery level | this is called sensor_temparature in the kernel driver but is never used... - memcpy(&out_buf[16], &g_x, sizeof(int16_t)); - memcpy(&out_buf[18], &g_y, sizeof(int16_t)); - memcpy(&out_buf[20], &g_z, sizeof(int16_t)); - memcpy(&out_buf[22], &a_x, sizeof(int16_t)); - memcpy(&out_buf[24], &a_y, sizeof(int16_t)); - memcpy(&out_buf[26], &a_z, sizeof(int16_t)); - memcpy(&out_buf[28], ×tamp, sizeof(timestamp)); + memcpy(&out_shifted_buf[16], &g_x, sizeof(int16_t)); + memcpy(&out_shifted_buf[18], &g_y, sizeof(int16_t)); + memcpy(&out_shifted_buf[20], &g_z, sizeof(int16_t)); + memcpy(&out_shifted_buf[22], &a_x, sizeof(int16_t)); + memcpy(&out_shifted_buf[24], &a_y, sizeof(int16_t)); + memcpy(&out_shifted_buf[26], &a_z, sizeof(int16_t)); + memcpy(&out_shifted_buf[28], ×tamp, sizeof(timestamp)); // TODO: when touch is detected send 0x7F, when not 0x80 - out_buf[33] = 0x80; //touch0 active? - out_buf[37] = 0x80; //touch1 active? + out_shifted_buf[33] = 0x80; //touch0 active? + out_shifted_buf[37] = 0x80; //touch1 active? /* buf[30] = 0x1b; // no headset attached */ - out_buf[62] = 0x80; // IDK... it seems constant... - out_buf[57] = 0x80; // IDK... it seems constant... - out_buf[53] = 0x80; // IDK... it seems constant... - out_buf[48] = 0x80; // IDK... it seems constant... - out_buf[35] = 0x80; // IDK... it seems constant... - out_buf[44] = 0x80; // IDK... it seems constant... + out_shifted_buf[62] = 0x80; // IDK... it seems constant... + out_shifted_buf[57] = 0x80; // IDK... it seems constant... + out_shifted_buf[53] = 0x80; // IDK... it seems constant... + out_shifted_buf[48] = 0x80; // IDK... it seems constant... + out_shifted_buf[35] = 0x80; // IDK... it seems constant... + out_shifted_buf[44] = 0x80; // IDK... it seems constant... + + if (gamepad->bluetooth) { + uint32_t crc = crc32_le(0xFFFFFFFFU, (const uint8_t*)&PS_FEATURE_CRC32_SEED, sizeof(PS_FEATURE_CRC32_SEED)); + crc = ~crc32_le(crc, (const Bytef *)&out_shifted_buf[0], DS_INPUT_REPORT_BT_SIZE - 4); + memcpy(&out_shifted_buf[DS_INPUT_REPORT_BT_SIZE - sizeof(crc)], &crc, sizeof(crc)); + } } -int virt_dualsense_send(virt_dualsense_t *const gamepad, uint8_t *const out_buf) { +int virt_dualsense_send(virt_dualsense_t *const gamepad, uint8_t *const out_shifted_buf) { struct uhid_event l = { .type = UHID_INPUT2, .u = { .input2 = { - .size = 64, + .size = gamepad->bluetooth ? DS_INPUT_REPORT_BT_SIZE : DS_INPUT_REPORT_USB_SIZE, } } }; + - memcpy(&l.u.input2.data[0], &out_buf[0], l.u.input2.size); + memcpy(&l.u.input2.data[0], &out_shifted_buf[0], l.u.input2.size); + + if (gamepad->bluetooth) { + uint32_t crc = crc32_le(0xFFFFFFFFU, (const uint8_t*)&PS_INPUT_CRC32_SEED, sizeof(PS_INPUT_CRC32_SEED)); + crc = ~crc32_le(crc, (const uint8_t *)&l.u.input2.data[0], l.u.input2.size - 4); + memcpy(&l.u.input2.data[l.u.input2.size - sizeof(crc)], &crc, sizeof(crc)); + } return uhid_write(gamepad->fd, &l); } diff --git a/virt_ds5.h b/virt_ds5.h index 61a4c5d..6f9d63d 100644 --- a/virt_ds5.h +++ b/virt_ds5.h @@ -13,6 +13,8 @@ typedef struct virt_dualsense { bool debug; + bool bluetooth; + uint8_t seq_num; uint32_t dt_sum; @@ -23,7 +25,7 @@ typedef struct virt_dualsense { uint64_t last_time; } virt_dualsense_t; -int virt_dualsense_init(virt_dualsense_t *const gamepad); +int virt_dualsense_init(virt_dualsense_t *const gamepad, bool bluetooth); int virt_dualsense_get_fd(virt_dualsense_t *const gamepad);