From 6a57b2ab09b6f246e225e319b021d6a21f59e37d Mon Sep 17 00:00:00 2001 From: wiz <76851476+wizpizz@users.noreply.github.com> Date: Sat, 14 Nov 2026 19:02:09 +0100 Subject: [PATCH 1/2] feat(atk): support the VXE R1 Pro over the 1K dongle The R1 Pro reports CID/MID 2,8 through the 0x3554:0xf58a dongle. The dongle is not in the vendor catalog, so the driver matched the pair to the VXE R1 NK (0x373b, PAW3395SE) and failed to decode a 400-DPI stage, reporting it as a checksum failure. - Accept a CID/MID-only catalog match only within the connected USB vendor; the numbering restarts per vendor. - Register 2,8 under 0x3554 as the VXE R1 Pro (PAW3395, R1 family). - Reuse the F58A receiver write/echo helpers for the settings captured from ATK HUB on the R1 Pro, including configuration banks. - Handle the R1 Pro's DPI lighting Off state, which is carried by the enabled flag alone. - Add ui.dpiLighting.brightnessModes so a UI can lock brightness in modes that ignore it (R1 Pro and R1 Pro Max: steady only). - Report an undecodable DPI row with a valid checksum as a likely misidentified model instead of a checksum failure. --- .../vxe-r1-pro/receiver-atk-hub-profiles.txt | 538 ++++++++++++++++++ captures/vxe-r1-pro/receiver-atk-hub.txt | 287 ++++++++++ docs/vxe-r1-pro-testing.md | 95 ++++ src/drivers/atk/hid.test.ts | 16 +- src/drivers/atk/hid.ts | 52 +- src/drivers/atk/products.ts | 36 +- src/drivers/atk/r1-pro-max-hid.test.ts | 156 ++++- src/drivers/mouse-types.ts | 5 + 8 files changed, 1166 insertions(+), 19 deletions(-) create mode 100644 captures/vxe-r1-pro/receiver-atk-hub-profiles.txt create mode 100644 captures/vxe-r1-pro/receiver-atk-hub.txt create mode 100644 docs/vxe-r1-pro-testing.md diff --git a/captures/vxe-r1-pro/receiver-atk-hub-profiles.txt b/captures/vxe-r1-pro/receiver-atk-hub-profiles.txt new file mode 100644 index 00000000..4a3aca91 --- /dev/null +++ b/captures/vxe-r1-pro/receiver-atk-hub-profiles.txt @@ -0,0 +1,538 @@ +# ATK HUB (v3-hub.atk.store) switching configuration banks on a VXE R1 Pro, +# firmware 1.20, through the 0x3554:0xf58a 1K dongle. Same format and redactions +# as receiver-atk-hub.txt. The last two marks apply a host-stored "computer +# config", which selects bank 4 and rewrites its rows. + +=== changing to config 2 (there seems to be 4 configs on board). (20505 ms) + 22117 out 3554:f58a id=8 0f 00 00 00 01 01 00 00 00 00 00 00 00 00 00 3c + 22219 in 3554:f58a id=8 0f 00 00 00 01 01 00 00 00 00 00 00 00 00 00 3c + 22225 in 3554:f58a id=8 0a 00 00 00 0a 04 00 00 00 00 00 00 00 00 00 35 + 23219 out 3554:f58a id=8 08 00 00 60 08 00 00 00 00 00 00 00 00 00 00 dd + 23223 out 3554:f58a id=8 08 00 00 68 08 00 00 00 00 00 00 00 00 00 00 d5 + 23223 in 3554:f58a id=8 08 00 00 60 08 01 01 00 53 01 02 00 52 00 00 33 + 23227 out 3554:f58a id=8 08 00 00 70 08 00 00 00 00 00 00 00 00 00 00 cd + 23227 in 3554:f58a id=8 08 00 00 68 08 01 04 00 50 01 08 00 4c 00 00 2b + 23231 in 3554:f58a id=8 08 00 00 70 08 01 10 00 44 02 01 00 52 00 00 23 + 23241 out 3554:f58a id=8 0e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3f + 23251 in 3554:f58a id=8 0e 00 00 00 01 01 00 00 00 00 00 00 00 00 00 3d + 23261 out 3554:f58a id=8 12 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3b + 23265 in 3554:f58a id=8 12 00 00 00 02 01 20 00 00 00 00 00 00 00 00 18 + 23276 out 3554:f58a id=8 08 00 00 4c 08 00 00 00 00 00 00 00 00 00 00 f1 + 23279 in 3554:f58a id=8 08 00 00 4c 08 02 53 80 d5 03 52 00 55 00 00 9d + 23291 out 3554:f58a id=8 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 49 + 23295 in 3554:f58a id=8 04 00 00 00 02 14 00 0d f6 00 00 00 00 00 00 30 + 23307 out 3554:f58a id=8 08 00 01 00 0a 00 00 00 00 00 00 00 00 00 00 3a + 23311 out 3554:f58a id=8 08 00 01 0a 0a 00 00 00 00 00 00 00 00 00 00 30 + 23311 in 3554:f58a id=8 08 00 01 00 0a ff ff ff ff ff ff ff ff ff ff 44 + 23314 out 3554:f58a id=8 08 00 01 20 0a 00 00 00 00 00 00 00 00 00 00 1a + 23314 in 3554:f58a id=8 08 00 01 0a 0a ff ff ff ff ff ff ff ff ff ff 3a + 23317 out 3554:f58a id=8 08 00 01 2a 0a 00 00 00 00 00 00 00 00 00 00 10 + 23317 in 3554:f58a id=8 08 00 01 20 0a ff ff ff ff ff ff ff ff ff ff 24 + 23320 out 3554:f58a id=8 08 00 01 40 0a 00 00 00 00 00 00 00 00 00 00 fa + 23320 in 3554:f58a id=8 08 00 01 2a 0a ff ff ff ff ff ff ff ff ff ff 1a + 23323 out 3554:f58a id=8 08 00 01 4a 0a 00 00 00 00 00 00 00 00 00 00 f0 + 23323 in 3554:f58a id=8 08 00 01 40 0a ff ff ff ff ff ff ff ff ff ff 04 + 23326 out 3554:f58a id=8 08 00 01 60 0a 00 00 00 00 00 00 00 00 00 00 da + 23326 in 3554:f58a id=8 08 00 01 4a 0a ff ff ff ff ff ff ff ff ff ff fa + 23329 out 3554:f58a id=8 08 00 01 6a 0a 00 00 00 00 00 00 00 00 00 00 d0 + 23329 in 3554:f58a id=8 08 00 01 60 0a ff ff ff ff ff ff ff ff ff ff e4 + 23332 out 3554:f58a id=8 08 00 01 80 0a 00 00 00 00 00 00 00 00 00 00 ba + 23332 in 3554:f58a id=8 08 00 01 6a 0a ff ff ff ff ff ff ff ff ff ff da + 23335 out 3554:f58a id=8 08 00 01 8a 0a 00 00 00 00 00 00 00 00 00 00 b0 + 23335 in 3554:f58a id=8 08 00 01 80 0a ff ff ff ff ff ff ff ff ff ff c4 + 23338 out 3554:f58a id=8 08 00 01 a0 0a 00 00 00 00 00 00 00 00 00 00 9a + 23338 in 3554:f58a id=8 08 00 01 8a 0a ff ff ff ff ff ff ff ff ff ff ba + 23341 out 3554:f58a id=8 08 00 01 aa 0a 00 00 00 00 00 00 00 00 00 00 90 + 23341 in 3554:f58a id=8 08 00 01 a0 0a ff ff ff ff ff ff ff ff ff ff a4 + 23345 in 3554:f58a id=8 08 00 01 aa 0a ff ff ff ff ff ff ff ff ff ff 9a + 23355 out 3554:f58a id=8 08 00 00 a9 0a 00 00 00 00 00 00 00 00 00 00 92 + 23359 out 3554:f58a id=8 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3d + 23359 in 3554:f58a id=8 08 00 00 a9 0a 08 4d 01 54 06 4f 00 55 00 55 e9 + 23362 out 3554:f58a id=8 17 00 00 00 00 00 00 00 00 00 00 00 00 00 00 36 + 23362 in 3554:f58a id=8 10 00 00 00 03 02 08 4b 00 00 00 00 00 00 00 e5 + 23365 out 3554:f58a id=8 08 00 00 0a 02 00 00 00 00 00 00 00 00 00 00 39 + 23365 in 3554:f58a id=8 17 00 00 00 0a 00 00 00 00 00 00 00 00 00 00 2c + 23368 out 3554:f58a id=8 1d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 30 + 23368 in 3554:f58a id=8 08 00 00 0a 02 01 54 00 00 00 00 00 00 00 00 e4 + 23369 out 3554:f58a id=8 08 00 00 b5 06 00 00 00 00 00 00 00 00 00 00 8a + 23369 in 3554:f58a id=8 1d 01 00 00 00 00 00 00 00 00 00 00 00 00 00 2f + 23372 out 3554:f58a id=8 08 00 00 00 0a 00 00 00 00 00 00 00 00 00 00 3b + 23372 in 3554:f58a id=8 08 00 00 b5 06 00 55 06 4f 00 55 00 00 00 00 8b + 23375 out 3554:f58a id=8 08 00 00 bd 04 00 00 00 00 00 00 00 00 00 00 84 + 23375 in 3554:f58a id=8 08 00 00 00 0a 01 54 04 51 01 54 00 55 00 55 92 + 23378 out 3554:f58a id=8 08 00 00 0c 08 00 00 00 00 00 00 00 00 00 00 31 + 23378 in 3554:f58a id=8 08 00 00 bd 04 ff ff ff ff 00 00 00 00 00 00 88 + 23381 out 3554:f58a id=8 08 00 00 14 08 00 00 00 00 00 00 00 00 00 00 29 + 23381 in 3554:f58a id=8 08 00 00 0c 08 07 07 00 47 0f 0f 00 37 00 00 87 + 23385 out 3554:f58a id=8 08 00 00 1c 08 00 00 00 00 00 00 00 00 00 00 21 + 23385 in 3554:f58a id=8 08 00 00 14 08 1f 1f 00 17 3f 3f 00 d7 00 00 7f + 23387 out 3554:f58a id=8 08 00 00 24 08 00 00 00 00 00 00 00 00 00 00 19 + 23387 in 3554:f58a id=8 08 00 00 1c 08 3f 3f 00 d7 3f 3f 00 d7 00 00 77 + 23390 out 3554:f58a id=8 08 00 00 2c 08 00 00 00 00 00 00 00 00 00 00 11 + 23390 in 3554:f58a id=8 08 00 00 24 08 3f 3f 00 d7 3f 3f 00 d7 00 00 6f + 23393 out 3554:f58a id=8 08 00 00 34 08 00 00 00 00 00 00 00 00 00 00 09 + 23393 in 3554:f58a id=8 08 00 00 2c 08 ff 00 00 56 00 ff 00 56 00 00 67 + 23396 out 3554:f58a id=8 08 00 00 3c 08 00 00 00 00 00 00 00 00 00 00 01 + 23396 in 3554:f58a id=8 08 00 00 34 08 00 00 ff 56 ff 00 ff 57 00 00 5f + 23399 out 3554:f58a id=8 08 00 00 44 08 00 00 00 00 00 00 00 00 00 00 f9 + 23399 in 3554:f58a id=8 08 00 00 3c 08 ff 00 ff 57 ff 00 ff 57 00 00 57 + 23402 out 3554:f58a id=8 08 00 00 e3 02 00 00 00 00 00 00 00 00 00 00 60 + 23402 in 3554:f58a id=8 08 00 00 44 08 ff 00 ff 57 ff 00 ff 57 00 00 4f + 23405 out 3554:f58a id=8 08 00 1b 4c 04 00 00 00 00 00 00 00 00 00 00 da + 23405 in 3554:f58a id=8 08 00 00 e3 02 ff ff 00 00 00 00 00 00 00 00 62 + 23408 in 3554:f58a id=8 08 00 1b 4c 04 ff ff ff ff 00 00 00 00 00 00 de + +=== changing to config 3 (35032 ms) + 36406 out 3554:f58a id=8 0f 00 00 00 01 02 00 00 00 00 00 00 00 00 00 3b + 36502 in 3554:f58a id=8 0f 00 00 00 01 02 00 00 00 00 00 00 00 00 00 3b + 36509 in 3554:f58a id=8 0a 00 00 00 0a 04 00 00 00 00 00 00 00 00 00 35 + 37507 out 3554:f58a id=8 08 00 00 60 08 00 00 00 00 00 00 00 00 00 00 dd + 37511 out 3554:f58a id=8 08 00 00 68 08 00 00 00 00 00 00 00 00 00 00 d5 + 37511 in 3554:f58a id=8 08 00 00 60 08 01 01 00 53 01 02 00 52 00 00 33 + 37514 out 3554:f58a id=8 08 00 00 70 08 00 00 00 00 00 00 00 00 00 00 cd + 37514 in 3554:f58a id=8 08 00 00 68 08 01 04 00 50 01 08 00 4c 00 00 2b + 37517 in 3554:f58a id=8 08 00 00 70 08 01 10 00 44 02 01 00 52 00 00 23 + 37529 out 3554:f58a id=8 0e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3f + 37533 in 3554:f58a id=8 0e 00 00 00 01 02 00 00 00 00 00 00 00 00 00 3c + 37544 out 3554:f58a id=8 12 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3b + 37548 in 3554:f58a id=8 12 00 00 00 02 01 20 00 00 00 00 00 00 00 00 18 + 37559 out 3554:f58a id=8 08 00 00 4c 08 00 00 00 00 00 00 00 00 00 00 f1 + 37563 in 3554:f58a id=8 08 00 00 4c 08 02 53 80 d5 03 52 00 55 00 00 9d + 37575 out 3554:f58a id=8 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 49 + 37579 in 3554:f58a id=8 04 00 00 00 02 14 00 0d f6 00 00 00 00 00 00 30 + 37589 out 3554:f58a id=8 08 00 01 00 0a 00 00 00 00 00 00 00 00 00 00 3a + 37594 out 3554:f58a id=8 08 00 01 0a 0a 00 00 00 00 00 00 00 00 00 00 30 + 37594 in 3554:f58a id=8 08 00 01 00 0a ff ff ff ff ff ff ff ff ff ff 44 + 37597 out 3554:f58a id=8 08 00 01 20 0a 00 00 00 00 00 00 00 00 00 00 1a + 37597 in 3554:f58a id=8 08 00 01 0a 0a ff ff ff ff ff ff ff ff ff ff 3a + 37601 out 3554:f58a id=8 08 00 01 2a 0a 00 00 00 00 00 00 00 00 00 00 10 + 37601 in 3554:f58a id=8 08 00 01 20 0a ff ff ff ff ff ff ff ff ff ff 24 + 37605 out 3554:f58a id=8 08 00 01 40 0a 00 00 00 00 00 00 00 00 00 00 fa + 37605 in 3554:f58a id=8 08 00 01 2a 0a ff ff ff ff ff ff ff ff ff ff 1a + 37608 out 3554:f58a id=8 08 00 01 4a 0a 00 00 00 00 00 00 00 00 00 00 f0 + 37608 in 3554:f58a id=8 08 00 01 40 0a ff ff ff ff ff ff ff ff ff ff 04 + 37612 out 3554:f58a id=8 08 00 01 60 0a 00 00 00 00 00 00 00 00 00 00 da + 37612 in 3554:f58a id=8 08 00 01 4a 0a ff ff ff ff ff ff ff ff ff ff fa + 37615 out 3554:f58a id=8 08 00 01 6a 0a 00 00 00 00 00 00 00 00 00 00 d0 + 37615 in 3554:f58a id=8 08 00 01 60 0a ff ff ff ff ff ff ff ff ff ff e4 + 37618 out 3554:f58a id=8 08 00 01 80 0a 00 00 00 00 00 00 00 00 00 00 ba + 37618 in 3554:f58a id=8 08 00 01 6a 0a ff ff ff ff ff ff ff ff ff ff da + 37621 out 3554:f58a id=8 08 00 01 8a 0a 00 00 00 00 00 00 00 00 00 00 b0 + 37621 in 3554:f58a id=8 08 00 01 80 0a ff ff ff ff ff ff ff ff ff ff c4 + 37624 out 3554:f58a id=8 08 00 01 a0 0a 00 00 00 00 00 00 00 00 00 00 9a + 37624 in 3554:f58a id=8 08 00 01 8a 0a ff ff ff ff ff ff ff ff ff ff ba + 37627 out 3554:f58a id=8 08 00 01 aa 0a 00 00 00 00 00 00 00 00 00 00 90 + 37627 in 3554:f58a id=8 08 00 01 a0 0a ff ff ff ff ff ff ff ff ff ff a4 + 37631 in 3554:f58a id=8 08 00 01 aa 0a ff ff ff ff ff ff ff ff ff ff 9a + 37642 out 3554:f58a id=8 08 00 00 a9 0a 00 00 00 00 00 00 00 00 00 00 92 + 37646 out 3554:f58a id=8 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3d + 37646 in 3554:f58a id=8 08 00 00 a9 0a 08 4d 01 54 06 4f 00 55 00 55 e9 + 37649 out 3554:f58a id=8 17 00 00 00 00 00 00 00 00 00 00 00 00 00 00 36 + 37649 in 3554:f58a id=8 10 00 00 00 03 02 08 4b 00 00 00 00 00 00 00 e5 + 37652 out 3554:f58a id=8 08 00 00 0a 02 00 00 00 00 00 00 00 00 00 00 39 + 37652 in 3554:f58a id=8 17 00 00 00 0a 00 00 00 00 00 00 00 00 00 00 2c + 37655 out 3554:f58a id=8 1d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 30 + 37655 in 3554:f58a id=8 08 00 00 0a 02 01 54 00 00 00 00 00 00 00 00 e4 + 37656 out 3554:f58a id=8 08 00 00 b5 06 00 00 00 00 00 00 00 00 00 00 8a + 37656 in 3554:f58a id=8 1d 01 00 00 00 00 00 00 00 00 00 00 00 00 00 2f + 37660 out 3554:f58a id=8 08 00 00 00 0a 00 00 00 00 00 00 00 00 00 00 3b + 37660 in 3554:f58a id=8 08 00 00 b5 06 00 55 06 4f 00 55 00 00 00 00 8b + 37663 out 3554:f58a id=8 08 00 00 bd 04 00 00 00 00 00 00 00 00 00 00 84 + 37663 in 3554:f58a id=8 08 00 00 00 0a 01 54 04 51 01 54 00 55 00 55 92 + 37666 out 3554:f58a id=8 08 00 00 0c 08 00 00 00 00 00 00 00 00 00 00 31 + 37666 in 3554:f58a id=8 08 00 00 bd 04 ff ff ff ff 00 00 00 00 00 00 88 + 37669 out 3554:f58a id=8 08 00 00 14 08 00 00 00 00 00 00 00 00 00 00 29 + 37669 in 3554:f58a id=8 08 00 00 0c 08 07 07 00 47 0f 0f 00 37 00 00 87 + 37672 out 3554:f58a id=8 08 00 00 1c 08 00 00 00 00 00 00 00 00 00 00 21 + 37672 in 3554:f58a id=8 08 00 00 14 08 1f 1f 00 17 3f 3f 00 d7 00 00 7f + 37675 out 3554:f58a id=8 08 00 00 24 08 00 00 00 00 00 00 00 00 00 00 19 + 37675 in 3554:f58a id=8 08 00 00 1c 08 3f 3f 00 d7 3f 3f 00 d7 00 00 77 + 37678 out 3554:f58a id=8 08 00 00 2c 08 00 00 00 00 00 00 00 00 00 00 11 + 37678 in 3554:f58a id=8 08 00 00 24 08 3f 3f 00 d7 3f 3f 00 d7 00 00 6f + 37681 out 3554:f58a id=8 08 00 00 34 08 00 00 00 00 00 00 00 00 00 00 09 + 37681 in 3554:f58a id=8 08 00 00 2c 08 ff 00 00 56 00 ff 00 56 00 00 67 + 37684 out 3554:f58a id=8 08 00 00 3c 08 00 00 00 00 00 00 00 00 00 00 01 + 37684 in 3554:f58a id=8 08 00 00 34 08 00 00 ff 56 ff 00 ff 57 00 00 5f + 37688 out 3554:f58a id=8 08 00 00 44 08 00 00 00 00 00 00 00 00 00 00 f9 + 37688 in 3554:f58a id=8 08 00 00 3c 08 ff 00 ff 57 ff 00 ff 57 00 00 57 + 37691 out 3554:f58a id=8 08 00 00 e3 02 00 00 00 00 00 00 00 00 00 00 60 + 37691 in 3554:f58a id=8 08 00 00 44 08 ff 00 ff 57 ff 00 ff 57 00 00 4f + 37694 out 3554:f58a id=8 08 00 1b 4c 04 00 00 00 00 00 00 00 00 00 00 da + 37694 in 3554:f58a id=8 08 00 00 e3 02 ff ff 00 00 00 00 00 00 00 00 62 + 37697 in 3554:f58a id=8 08 00 1b 4c 04 ff ff ff ff 00 00 00 00 00 00 de + +=== to 4 (40947 ms) + 42230 out 3554:f58a id=8 0f 00 00 00 01 03 00 00 00 00 00 00 00 00 00 3a + 42327 in 3554:f58a id=8 0f 00 00 00 01 03 00 00 00 00 00 00 00 00 00 3a + 42334 in 3554:f58a id=8 0a 00 00 00 0a 04 00 00 00 00 00 00 00 00 00 35 + 43332 out 3554:f58a id=8 08 00 00 60 08 00 00 00 00 00 00 00 00 00 00 dd + 43336 out 3554:f58a id=8 08 00 00 68 08 00 00 00 00 00 00 00 00 00 00 d5 + 43336 in 3554:f58a id=8 08 00 00 60 08 01 01 00 53 01 02 00 52 00 00 33 + 43340 out 3554:f58a id=8 08 00 00 70 08 00 00 00 00 00 00 00 00 00 00 cd + 43340 in 3554:f58a id=8 08 00 00 68 08 01 04 00 50 01 08 00 4c 00 00 2b + 43344 in 3554:f58a id=8 08 00 00 70 08 01 10 00 44 02 01 00 52 00 00 23 + 43355 out 3554:f58a id=8 0e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3f + 43359 in 3554:f58a id=8 0e 00 00 00 01 03 00 00 00 00 00 00 00 00 00 3b + 43370 out 3554:f58a id=8 12 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3b + 43375 in 3554:f58a id=8 12 00 00 00 02 01 20 00 00 00 00 00 00 00 00 18 + 43386 out 3554:f58a id=8 08 00 00 4c 08 00 00 00 00 00 00 00 00 00 00 f1 + 43391 in 3554:f58a id=8 08 00 00 4c 08 02 53 80 d5 03 52 00 55 00 00 9d + 43403 out 3554:f58a id=8 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 49 + 43407 in 3554:f58a id=8 04 00 00 00 02 14 00 0d f2 00 00 00 00 00 00 34 + 43419 out 3554:f58a id=8 08 00 01 00 0a 00 00 00 00 00 00 00 00 00 00 3a + 43423 out 3554:f58a id=8 08 00 01 0a 0a 00 00 00 00 00 00 00 00 00 00 30 + 43424 in 3554:f58a id=8 08 00 01 00 0a ff ff ff ff ff ff ff ff ff ff 44 + 43429 out 3554:f58a id=8 08 00 01 20 0a 00 00 00 00 00 00 00 00 00 00 1a + 43429 in 3554:f58a id=8 08 00 01 0a 0a ff ff ff ff ff ff ff ff ff ff 3a + 43433 out 3554:f58a id=8 08 00 01 2a 0a 00 00 00 00 00 00 00 00 00 00 10 + 43433 in 3554:f58a id=8 08 00 01 20 0a ff ff ff ff ff ff ff ff ff ff 24 + 43436 out 3554:f58a id=8 08 00 01 40 0a 00 00 00 00 00 00 00 00 00 00 fa + 43436 in 3554:f58a id=8 08 00 01 2a 0a ff ff ff ff ff ff ff ff ff ff 1a + 43440 out 3554:f58a id=8 08 00 01 4a 0a 00 00 00 00 00 00 00 00 00 00 f0 + 43440 in 3554:f58a id=8 08 00 01 40 0a ff ff ff ff ff ff ff ff ff ff 04 + 43444 out 3554:f58a id=8 08 00 01 60 0a 00 00 00 00 00 00 00 00 00 00 da + 43444 in 3554:f58a id=8 08 00 01 4a 0a ff ff ff ff ff ff ff ff ff ff fa + 43448 out 3554:f58a id=8 08 00 01 6a 0a 00 00 00 00 00 00 00 00 00 00 d0 + 43448 in 3554:f58a id=8 08 00 01 60 0a ff ff ff ff ff ff ff ff ff ff e4 + 43452 out 3554:f58a id=8 08 00 01 80 0a 00 00 00 00 00 00 00 00 00 00 ba + 43452 in 3554:f58a id=8 08 00 01 6a 0a ff ff ff ff ff ff ff ff ff ff da + 43456 out 3554:f58a id=8 08 00 01 8a 0a 00 00 00 00 00 00 00 00 00 00 b0 + 43456 in 3554:f58a id=8 08 00 01 80 0a ff ff ff ff ff ff ff ff ff ff c4 + 43459 out 3554:f58a id=8 08 00 01 a0 0a 00 00 00 00 00 00 00 00 00 00 9a + 43459 in 3554:f58a id=8 08 00 01 8a 0a ff ff ff ff ff ff ff ff ff ff ba + 43463 out 3554:f58a id=8 08 00 01 aa 0a 00 00 00 00 00 00 00 00 00 00 90 + 43463 in 3554:f58a id=8 08 00 01 a0 0a ff ff ff ff ff ff ff ff ff ff a4 + 43467 in 3554:f58a id=8 08 00 01 aa 0a ff ff ff ff ff ff ff ff ff ff 9a + 43478 out 3554:f58a id=8 08 00 00 a9 0a 00 00 00 00 00 00 00 00 00 00 92 + 43482 out 3554:f58a id=8 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3d + 43482 in 3554:f58a id=8 08 00 00 a9 0a 08 4d 01 54 06 4f 00 55 00 55 e9 + 43487 out 3554:f58a id=8 17 00 00 00 00 00 00 00 00 00 00 00 00 00 00 36 + 43487 in 3554:f58a id=8 10 00 00 00 03 02 08 4b 00 00 00 00 00 00 00 e5 + 43491 out 3554:f58a id=8 08 00 00 0a 02 00 00 00 00 00 00 00 00 00 00 39 + 43491 in 3554:f58a id=8 17 00 00 00 0a 00 00 00 00 00 00 00 00 00 00 2c + 43495 out 3554:f58a id=8 1d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 30 + 43495 in 3554:f58a id=8 08 00 00 0a 02 01 54 00 00 00 00 00 00 00 00 e4 + 43496 out 3554:f58a id=8 08 00 00 b5 06 00 00 00 00 00 00 00 00 00 00 8a + 43496 in 3554:f58a id=8 1d 01 00 00 00 00 00 00 00 00 00 00 00 00 00 2f + 43500 out 3554:f58a id=8 08 00 00 00 0a 00 00 00 00 00 00 00 00 00 00 3b + 43500 in 3554:f58a id=8 08 00 00 b5 06 00 55 06 4f 00 55 00 00 00 00 8b + 43504 out 3554:f58a id=8 08 00 00 bd 04 00 00 00 00 00 00 00 00 00 00 84 + 43504 in 3554:f58a id=8 08 00 00 00 0a 01 54 04 51 01 54 00 55 00 55 92 + 43508 out 3554:f58a id=8 08 00 00 0c 08 00 00 00 00 00 00 00 00 00 00 31 + 43509 in 3554:f58a id=8 08 00 00 bd 04 ff ff ff ff 00 00 00 00 00 00 88 + 43513 out 3554:f58a id=8 08 00 00 14 08 00 00 00 00 00 00 00 00 00 00 29 + 43513 in 3554:f58a id=8 08 00 00 0c 08 07 07 00 47 0f 0f 00 37 00 00 87 + 43517 out 3554:f58a id=8 08 00 00 1c 08 00 00 00 00 00 00 00 00 00 00 21 + 43517 in 3554:f58a id=8 08 00 00 14 08 1f 1f 00 17 3f 3f 00 d7 00 00 7f + 43521 out 3554:f58a id=8 08 00 00 24 08 00 00 00 00 00 00 00 00 00 00 19 + 43521 in 3554:f58a id=8 08 00 00 1c 08 3f 3f 00 d7 3f 3f 00 d7 00 00 77 + 43525 out 3554:f58a id=8 08 00 00 2c 08 00 00 00 00 00 00 00 00 00 00 11 + 43525 in 3554:f58a id=8 08 00 00 24 08 3f 3f 00 d7 3f 3f 00 d7 00 00 6f + 43529 out 3554:f58a id=8 08 00 00 34 08 00 00 00 00 00 00 00 00 00 00 09 + 43529 in 3554:f58a id=8 08 00 00 2c 08 ff 00 00 56 00 ff 00 56 00 00 67 + 43533 out 3554:f58a id=8 08 00 00 3c 08 00 00 00 00 00 00 00 00 00 00 01 + 43533 in 3554:f58a id=8 08 00 00 34 08 00 00 ff 56 ff 00 ff 57 00 00 5f + 43537 out 3554:f58a id=8 08 00 00 44 08 00 00 00 00 00 00 00 00 00 00 f9 + 43537 in 3554:f58a id=8 08 00 00 3c 08 ff 00 ff 57 ff 00 ff 57 00 00 57 + 43541 out 3554:f58a id=8 08 00 00 e3 02 00 00 00 00 00 00 00 00 00 00 60 + 43541 in 3554:f58a id=8 08 00 00 44 08 ff 00 ff 57 ff 00 ff 57 00 00 4f + 43545 out 3554:f58a id=8 08 00 1b 4c 04 00 00 00 00 00 00 00 00 00 00 da + 43545 in 3554:f58a id=8 08 00 00 e3 02 ff ff 00 00 00 00 00 00 00 00 62 + 43549 in 3554:f58a id=8 08 00 1b 4c 04 ff ff ff ff 00 00 00 00 00 00 de + +=== back to 1 (47410 ms) + 48594 out 3554:f58a id=8 0f 00 00 00 01 00 00 00 00 00 00 00 00 00 00 3d + 48695 in 3554:f58a id=8 0f 00 00 00 01 00 00 00 00 00 00 00 00 00 00 3d + 48698 in 3554:f58a id=8 0a 00 00 00 0a 04 00 00 00 00 00 00 00 00 00 35 + 49699 out 3554:f58a id=8 08 00 00 60 08 00 00 00 00 00 00 00 00 00 00 dd + 49703 out 3554:f58a id=8 08 00 00 68 08 00 00 00 00 00 00 00 00 00 00 d5 + 49703 in 3554:f58a id=8 08 00 00 60 08 01 01 00 53 01 02 00 52 00 00 33 + 49707 out 3554:f58a id=8 08 00 00 70 08 00 00 00 00 00 00 00 00 00 00 cd + 49707 in 3554:f58a id=8 08 00 00 68 08 01 04 00 50 01 08 00 4c 00 00 2b + 49712 in 3554:f58a id=8 08 00 00 70 08 01 10 00 44 02 01 00 52 00 00 23 + 49723 out 3554:f58a id=8 0e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3f + 49727 in 3554:f58a id=8 0e 00 00 00 01 00 00 00 00 00 00 00 00 00 00 3e + 49738 out 3554:f58a id=8 12 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3b + 49742 in 3554:f58a id=8 12 00 00 00 02 01 20 00 00 00 00 00 00 00 00 18 + 49753 out 3554:f58a id=8 08 00 00 4c 08 00 00 00 00 00 00 00 00 00 00 f1 + 49757 in 3554:f58a id=8 08 00 00 4c 08 02 53 ff 56 05 50 00 55 00 00 9d + 49768 out 3554:f58a id=8 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 49 + 49771 in 3554:f58a id=8 04 00 00 00 02 14 00 0d f2 00 00 00 00 00 00 34 + 49782 out 3554:f58a id=8 08 00 01 00 0a 00 00 00 00 00 00 00 00 00 00 3a + 49785 out 3554:f58a id=8 08 00 01 0a 0a 00 00 00 00 00 00 00 00 00 00 30 + 49785 in 3554:f58a id=8 08 00 01 00 0a ff ff ff ff ff ff ff ff ff ff 44 + 49789 out 3554:f58a id=8 08 00 01 20 0a 00 00 00 00 00 00 00 00 00 00 1a + 49789 in 3554:f58a id=8 08 00 01 0a 0a ff ff ff ff ff ff ff ff ff ff 3a + 49792 out 3554:f58a id=8 08 00 01 2a 0a 00 00 00 00 00 00 00 00 00 00 10 + 49792 in 3554:f58a id=8 08 00 01 20 0a ff ff ff ff ff ff ff ff ff ff 24 + 49797 out 3554:f58a id=8 08 00 01 40 0a 00 00 00 00 00 00 00 00 00 00 fa + 49797 in 3554:f58a id=8 08 00 01 2a 0a ff ff ff ff ff ff ff ff ff ff 1a + 49801 out 3554:f58a id=8 08 00 01 4a 0a 00 00 00 00 00 00 00 00 00 00 f0 + 49801 in 3554:f58a id=8 08 00 01 40 0a ff ff ff ff ff ff ff ff ff ff 04 + 49804 out 3554:f58a id=8 08 00 01 60 0a 00 00 00 00 00 00 00 00 00 00 da + 49804 in 3554:f58a id=8 08 00 01 4a 0a ff ff ff ff ff ff ff ff ff ff fa + 49807 out 3554:f58a id=8 08 00 01 6a 0a 00 00 00 00 00 00 00 00 00 00 d0 + 49807 in 3554:f58a id=8 08 00 01 60 0a 02 82 92 01 42 92 01 69 00 00 85 + 49811 out 3554:f58a id=8 08 00 01 80 0a 00 00 00 00 00 00 00 00 00 00 ba + 49811 in 3554:f58a id=8 08 00 01 6a 0a ff ff ff ff ff ff ff ff ff ff da + 49814 out 3554:f58a id=8 08 00 01 8a 0a 00 00 00 00 00 00 00 00 00 00 b0 + 49814 in 3554:f58a id=8 08 00 01 80 0a ff ff ff ff ff ff ff ff ff ff c4 + 49817 out 3554:f58a id=8 08 00 01 a0 0a 00 00 00 00 00 00 00 00 00 00 9a + 49817 in 3554:f58a id=8 08 00 01 8a 0a ff ff ff ff ff ff ff ff ff ff ba + 49820 out 3554:f58a id=8 08 00 01 aa 0a 00 00 00 00 00 00 00 00 00 00 90 + 49820 in 3554:f58a id=8 08 00 01 a0 0a ff ff ff ff ff ff ff ff ff ff a4 + 49824 in 3554:f58a id=8 08 00 01 aa 0a ff ff ff ff ff ff ff ff ff ff 9a + 49835 out 3554:f58a id=8 08 00 00 a9 0a 00 00 00 00 00 00 00 00 00 00 92 + 49839 out 3554:f58a id=8 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3d + 49839 in 3554:f58a id=8 08 00 00 a9 0a 04 51 00 55 06 4f 00 55 00 55 e9 + 49842 out 3554:f58a id=8 17 00 00 00 00 00 00 00 00 00 00 00 00 00 00 36 + 49842 in 3554:f58a id=8 10 00 00 00 03 02 08 4b 00 00 00 00 00 00 00 e5 + 49846 out 3554:f58a id=8 08 00 00 0a 02 00 00 00 00 00 00 00 00 00 00 39 + 49846 in 3554:f58a id=8 17 00 00 00 0a 00 00 00 00 00 00 00 00 00 00 2c + 49850 out 3554:f58a id=8 1d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 30 + 49850 in 3554:f58a id=8 08 00 00 0a 02 01 54 00 00 00 00 00 00 00 00 e4 + 49851 out 3554:f58a id=8 08 00 00 b5 06 00 00 00 00 00 00 00 00 00 00 8a + 49851 in 3554:f58a id=8 1d 01 00 00 00 00 00 00 00 00 00 00 00 00 00 2f + 49854 out 3554:f58a id=8 08 00 00 00 0a 00 00 00 00 00 00 00 00 00 00 3b + 49854 in 3554:f58a id=8 08 00 00 b5 06 01 54 06 4f 01 54 00 00 00 00 8b + 49858 out 3554:f58a id=8 08 00 00 bd 04 00 00 00 00 00 00 00 00 00 00 84 + 49858 in 3554:f58a id=8 08 00 00 00 0a 01 54 04 51 03 52 00 55 00 55 92 + 49862 out 3554:f58a id=8 08 00 00 0c 08 00 00 00 00 00 00 00 00 00 00 31 + 49862 in 3554:f58a id=8 08 00 00 bd 04 ff ff ff ff 00 00 00 00 00 00 88 + 49866 out 3554:f58a id=8 08 00 00 14 08 00 00 00 00 00 00 00 00 00 00 29 + 49866 in 3554:f58a id=8 08 00 00 0c 08 07 07 00 47 0f 0f 00 37 00 00 87 + 49870 out 3554:f58a id=8 08 00 00 1c 08 00 00 00 00 00 00 00 00 00 00 21 + 49870 in 3554:f58a id=8 08 00 00 14 08 3f 3f 00 d7 17 17 00 27 00 00 7f + 49874 out 3554:f58a id=8 08 00 00 24 08 00 00 00 00 00 00 00 00 00 00 19 + 49874 in 3554:f58a id=8 08 00 00 1c 08 17 17 00 27 27 27 00 07 00 00 77 + 49878 out 3554:f58a id=8 08 00 00 2c 08 00 00 00 00 00 00 00 00 00 00 11 + 49878 in 3554:f58a id=8 08 00 00 24 08 3f 3f 00 d7 3f 3f 00 d7 00 00 6f + 49881 out 3554:f58a id=8 08 00 00 34 08 00 00 00 00 00 00 00 00 00 00 09 + 49881 in 3554:f58a id=8 08 00 00 2c 08 ff 00 00 56 00 ff 00 56 00 00 67 + 49884 out 3554:f58a id=8 08 00 00 3c 08 00 00 00 00 00 00 00 00 00 00 01 + 49884 in 3554:f58a id=8 08 00 00 34 08 ff 00 ff 57 df b6 20 a0 00 00 5f + 49888 out 3554:f58a id=8 08 00 00 44 08 00 00 00 00 00 00 00 00 00 00 f9 + 49888 in 3554:f58a id=8 08 00 00 3c 08 ff c3 5c 37 ff ff 00 57 00 00 57 + 49892 out 3554:f58a id=8 08 00 00 e3 02 00 00 00 00 00 00 00 00 00 00 60 + 49892 in 3554:f58a id=8 08 00 00 44 08 ff 00 ff 57 ff 00 ff 57 00 00 4f + 49897 out 3554:f58a id=8 08 00 1b 4c 04 00 00 00 00 00 00 00 00 00 00 da + 49897 in 3554:f58a id=8 08 00 00 e3 02 ff ff 00 00 00 00 00 00 00 00 62 + 49901 in 3554:f58a id=8 08 00 1b 4c 04 ff ff ff ff 00 00 00 00 00 00 de + +=== creating new config , not sure if this is gonna owrk (68488 ms) + 82991 out 3554:f58a id=8 0f 00 00 00 01 03 00 00 00 00 00 00 00 00 00 3a + 83093 in 3554:f58a id=8 0f 00 00 00 01 03 00 00 00 00 00 00 00 00 00 3a + 83100 in 3554:f58a id=8 0a 00 00 00 0a 04 00 00 00 00 00 00 00 00 00 35 + 84403 out 3554:f58a id=8 07 00 00 a9 0a 04 51 00 55 06 4f 00 55 00 55 ea + 84410 in 3554:f58a id=8 07 00 00 a9 0a 04 51 00 55 06 4f 00 55 00 55 ea + 84465 out 3554:f58a id=8 07 00 00 0c 08 07 07 00 47 0f 0f 00 37 00 00 88 + 84470 out 3554:f58a id=8 07 00 00 14 08 3f 3f 00 d7 17 17 00 27 00 00 80 + 84470 in 3554:f58a id=8 07 00 00 0c 08 07 07 00 47 0f 0f 00 37 00 00 88 + 84474 out 3554:f58a id=8 07 00 00 1c 08 17 17 00 27 27 27 00 07 00 00 78 + 84474 in 3554:f58a id=8 07 00 00 14 08 3f 3f 00 d7 17 17 00 27 00 00 80 + 84478 out 3554:f58a id=8 07 00 00 24 08 3f 3f 00 d7 3f 3f 00 d7 00 00 70 + 84478 in 3554:f58a id=8 07 00 00 1c 08 17 17 00 27 27 27 00 07 00 00 78 + 84483 in 3554:f58a id=8 07 00 00 24 08 3f 3f 00 d7 3f 3f 00 d7 00 00 70 + 84534 out 3554:f58a id=8 07 00 00 2c 08 ff 00 00 56 00 ff 00 56 00 00 68 + 84538 out 3554:f58a id=8 07 00 00 34 08 ff 00 ff 57 df b6 20 a0 00 00 60 + 84538 in 3554:f58a id=8 07 00 00 2c 08 ff 00 00 56 00 ff 00 56 00 00 68 + 84542 out 3554:f58a id=8 07 00 00 3c 08 ff c3 5c 37 ff ff 00 57 00 00 58 + 84542 in 3554:f58a id=8 07 00 00 34 08 ff 00 ff 57 df b6 20 a0 00 00 60 + 84546 out 3554:f58a id=8 07 00 00 44 08 ff 00 ff 57 ff 00 ff 57 00 00 50 + 84546 in 3554:f58a id=8 07 00 00 3c 08 ff c3 5c 37 ff ff 00 57 00 00 58 + 84550 in 3554:f58a id=8 07 00 00 44 08 ff 00 ff 57 ff 00 ff 57 00 00 50 + 84602 out 3554:f58a id=8 07 00 00 00 0a 01 54 04 51 03 52 00 00 00 55 e8 + 84607 in 3554:f58a id=8 07 00 00 00 0a 01 54 04 51 03 52 00 00 00 55 e8 + 84658 out 3554:f58a id=8 07 00 00 00 0a 01 54 04 51 03 52 00 00 00 55 e8 + 84663 in 3554:f58a id=8 07 00 00 00 0a 01 54 04 51 03 52 00 00 00 55 e8 + 84717 out 3554:f58a id=8 07 00 00 b5 06 01 54 06 4f 01 54 00 00 00 00 8c + 84723 in 3554:f58a id=8 07 00 00 b5 06 01 54 06 4f 01 54 00 00 00 00 8c + 84774 out 3554:f58a id=8 07 00 00 0a 02 01 54 00 00 00 00 00 00 00 00 e5 + 84781 in 3554:f58a id=8 07 00 00 0a 02 01 54 00 00 00 00 00 00 00 00 e5 + 84831 out 3554:f58a id=8 16 00 00 00 0a 00 00 00 00 00 00 00 00 00 00 2d + 84927 in 3554:f58a id=8 16 00 00 00 0a 00 00 00 00 00 00 00 00 00 00 2d + 84979 out 3554:f58a id=8 07 00 00 a9 0a 04 51 00 55 06 4f 00 55 00 55 ea + 84984 in 3554:f58a id=8 07 00 00 a9 0a 04 51 00 55 06 4f 00 55 00 55 ea + 85037 out 3554:f58a id=8 07 00 00 a9 0a 04 51 00 55 06 4f 00 55 00 55 ea + 85041 in 3554:f58a id=8 07 00 00 a9 0a 04 51 00 55 06 4f 00 55 00 55 ea + 85094 out 3554:f58a id=8 07 00 00 a9 0a 04 51 00 55 06 4f 00 55 00 55 ea + 85098 in 3554:f58a id=8 07 00 00 a9 0a 04 51 00 55 06 4f 00 55 00 55 ea + 85151 out 3554:f58a id=8 07 00 00 a9 0a 04 51 00 55 06 4f 00 55 00 55 ea + 85156 in 3554:f58a id=8 07 00 00 a9 0a 04 51 00 55 06 4f 00 55 00 55 ea + 85208 out 3554:f58a id=8 07 00 00 4c 08 00 00 ff 56 05 50 00 55 00 00 f3 + 85213 in 3554:f58a id=8 07 00 00 4c 08 00 00 ff 56 05 50 00 55 00 00 f3 + 85265 out 3554:f58a id=8 07 00 00 a9 0a 04 51 00 55 06 4f 00 55 00 55 ea + 85270 out 3554:f58a id=8 07 00 00 b5 06 01 54 06 4f 01 54 00 00 00 00 8c + 85270 in 3554:f58a id=8 07 00 00 a9 0a 04 51 00 55 06 4f 00 55 00 55 ea + 85274 in 3554:f58a id=8 07 00 00 b5 06 01 54 06 4f 01 54 00 00 00 00 8c + 85328 out 3554:f58a id=8 07 00 00 bd 04 ff 56 ff 56 00 00 00 00 00 00 db + 85333 in 3554:f58a id=8 07 00 00 bd 04 ff 56 ff 56 00 00 00 00 00 00 db + 85385 out 3554:f58a id=8 07 00 00 60 04 01 01 00 53 00 00 00 00 00 00 8d + 85390 in 3554:f58a id=8 07 00 00 60 04 01 01 00 53 00 00 00 00 00 00 8d + 85442 out 3554:f58a id=8 07 00 00 64 04 01 02 00 52 00 00 00 00 00 00 89 + 85448 in 3554:f58a id=8 07 00 00 64 04 01 02 00 52 00 00 00 00 00 00 89 + 85500 out 3554:f58a id=8 07 00 00 68 04 01 04 00 50 00 00 00 00 00 00 85 + 85504 in 3554:f58a id=8 07 00 00 68 04 01 04 00 50 00 00 00 00 00 00 85 + 85557 out 3554:f58a id=8 07 00 00 6c 04 01 08 00 4c 00 00 00 00 00 00 81 + 85561 in 3554:f58a id=8 07 00 00 6c 04 01 08 00 4c 00 00 00 00 00 00 81 + 85614 out 3554:f58a id=8 07 00 01 60 0a 02 82 92 01 42 92 01 69 00 00 86 + 85619 in 3554:f58a id=8 07 00 01 60 0a 02 82 92 01 42 92 01 69 00 00 86 + 85671 out 3554:f58a id=8 07 00 00 70 04 01 10 00 44 00 00 00 00 00 00 7d + 85676 in 3554:f58a id=8 07 00 00 70 04 01 10 00 44 00 00 00 00 00 00 7d + 85728 out 3554:f58a id=8 07 00 00 74 04 02 01 00 52 00 00 00 00 00 00 79 + 85733 in 3554:f58a id=8 07 00 00 74 04 02 01 00 52 00 00 00 00 00 00 79 + 86785 out 3554:f58a id=8 08 00 00 60 08 00 00 00 00 00 00 00 00 00 00 dd + 86790 out 3554:f58a id=8 08 00 00 68 08 00 00 00 00 00 00 00 00 00 00 d5 + 86790 in 3554:f58a id=8 08 00 00 60 08 01 01 00 53 01 02 00 52 00 00 33 + 86794 out 3554:f58a id=8 08 00 00 70 08 00 00 00 00 00 00 00 00 00 00 cd + 86794 in 3554:f58a id=8 08 00 00 68 08 01 04 00 50 01 08 00 4c 00 00 2b + 86798 in 3554:f58a id=8 08 00 00 70 08 01 10 00 44 02 01 00 52 00 00 23 + 86808 out 3554:f58a id=8 0e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3f + 86813 in 3554:f58a id=8 0e 00 00 00 01 03 00 00 00 00 00 00 00 00 00 3b + 86824 out 3554:f58a id=8 12 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3b + 86829 in 3554:f58a id=8 12 00 00 00 02 01 20 00 00 00 00 00 00 00 00 18 + 86840 out 3554:f58a id=8 08 00 00 4c 08 00 00 00 00 00 00 00 00 00 00 f1 + 86844 in 3554:f58a id=8 08 00 00 4c 08 02 53 ff 56 05 50 00 55 00 00 9d + 86856 out 3554:f58a id=8 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 49 + 86861 in 3554:f58a id=8 04 00 00 00 02 14 00 0d f2 00 00 00 00 00 00 34 + 86872 out 3554:f58a id=8 08 00 01 00 0a 00 00 00 00 00 00 00 00 00 00 3a + 86876 out 3554:f58a id=8 08 00 01 0a 0a 00 00 00 00 00 00 00 00 00 00 30 + 86876 in 3554:f58a id=8 08 00 01 00 0a ff ff ff ff ff ff ff ff ff ff 44 + 86880 out 3554:f58a id=8 08 00 01 20 0a 00 00 00 00 00 00 00 00 00 00 1a + 86880 in 3554:f58a id=8 08 00 01 0a 0a ff ff ff ff ff ff ff ff ff ff 3a + 86884 out 3554:f58a id=8 08 00 01 2a 0a 00 00 00 00 00 00 00 00 00 00 10 + 86884 in 3554:f58a id=8 08 00 01 20 0a ff ff ff ff ff ff ff ff ff ff 24 + 86889 out 3554:f58a id=8 08 00 01 40 0a 00 00 00 00 00 00 00 00 00 00 fa + 86889 in 3554:f58a id=8 08 00 01 2a 0a ff ff ff ff ff ff ff ff ff ff 1a + 86893 out 3554:f58a id=8 08 00 01 4a 0a 00 00 00 00 00 00 00 00 00 00 f0 + 86893 in 3554:f58a id=8 08 00 01 40 0a ff ff ff ff ff ff ff ff ff ff 04 + 86897 out 3554:f58a id=8 08 00 01 60 0a 00 00 00 00 00 00 00 00 00 00 da + 86897 in 3554:f58a id=8 08 00 01 4a 0a ff ff ff ff ff ff ff ff ff ff fa + 86901 out 3554:f58a id=8 08 00 01 6a 0a 00 00 00 00 00 00 00 00 00 00 d0 + 86901 in 3554:f58a id=8 08 00 01 60 0a 02 82 92 01 42 92 01 69 00 00 85 + 86905 out 3554:f58a id=8 08 00 01 80 0a 00 00 00 00 00 00 00 00 00 00 ba + 86905 in 3554:f58a id=8 08 00 01 6a 0a ff ff ff ff ff ff ff ff ff ff da + 86909 out 3554:f58a id=8 08 00 01 8a 0a 00 00 00 00 00 00 00 00 00 00 b0 + 86909 in 3554:f58a id=8 08 00 01 80 0a ff ff ff ff ff ff ff ff ff ff c4 + 86913 out 3554:f58a id=8 08 00 01 a0 0a 00 00 00 00 00 00 00 00 00 00 9a + 86913 in 3554:f58a id=8 08 00 01 8a 0a ff ff ff ff ff ff ff ff ff ff ba + 86917 out 3554:f58a id=8 08 00 01 aa 0a 00 00 00 00 00 00 00 00 00 00 90 + 86917 in 3554:f58a id=8 08 00 01 a0 0a ff ff ff ff ff ff ff ff ff ff a4 + 86922 in 3554:f58a id=8 08 00 01 aa 0a ff ff ff ff ff ff ff ff ff ff 9a + 86933 out 3554:f58a id=8 08 00 00 a9 0a 00 00 00 00 00 00 00 00 00 00 92 + 86937 out 3554:f58a id=8 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3d + 86937 in 3554:f58a id=8 08 00 00 a9 0a 04 51 00 55 06 4f 00 55 00 55 e9 + 86941 out 3554:f58a id=8 17 00 00 00 00 00 00 00 00 00 00 00 00 00 00 36 + 86941 in 3554:f58a id=8 10 00 00 00 03 02 08 4b 00 00 00 00 00 00 00 e5 + 86945 out 3554:f58a id=8 08 00 00 0a 02 00 00 00 00 00 00 00 00 00 00 39 + 86945 in 3554:f58a id=8 17 00 00 00 0a 00 00 00 00 00 00 00 00 00 00 2c + 86949 out 3554:f58a id=8 1d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 30 + 86949 in 3554:f58a id=8 08 00 00 0a 02 01 54 00 00 00 00 00 00 00 00 e4 + 86950 out 3554:f58a id=8 08 00 00 b5 06 00 00 00 00 00 00 00 00 00 00 8a + 86950 in 3554:f58a id=8 1d 01 00 00 00 00 00 00 00 00 00 00 00 00 00 2f + 86954 out 3554:f58a id=8 08 00 00 00 0a 00 00 00 00 00 00 00 00 00 00 3b + 86954 in 3554:f58a id=8 08 00 00 b5 06 01 54 06 4f 01 54 00 00 00 00 8b + 86958 out 3554:f58a id=8 08 00 00 bd 04 00 00 00 00 00 00 00 00 00 00 84 + 86958 in 3554:f58a id=8 08 00 00 00 0a 01 54 04 51 03 52 00 55 00 55 92 + 86962 out 3554:f58a id=8 08 00 00 0c 08 00 00 00 00 00 00 00 00 00 00 31 + 86962 in 3554:f58a id=8 08 00 00 bd 04 ff 56 ff 56 00 00 00 00 00 00 da + 86966 out 3554:f58a id=8 08 00 00 14 08 00 00 00 00 00 00 00 00 00 00 29 + 86966 in 3554:f58a id=8 08 00 00 0c 08 07 07 00 47 0f 0f 00 37 00 00 87 + 86970 out 3554:f58a id=8 08 00 00 1c 08 00 00 00 00 00 00 00 00 00 00 21 + 86970 in 3554:f58a id=8 08 00 00 14 08 3f 3f 00 d7 17 17 00 27 00 00 7f + 86974 out 3554:f58a id=8 08 00 00 24 08 00 00 00 00 00 00 00 00 00 00 19 + 86974 in 3554:f58a id=8 08 00 00 1c 08 17 17 00 27 27 27 00 07 00 00 77 + 86979 out 3554:f58a id=8 08 00 00 2c 08 00 00 00 00 00 00 00 00 00 00 11 + 86979 in 3554:f58a id=8 08 00 00 24 08 3f 3f 00 d7 3f 3f 00 d7 00 00 6f + 86983 out 3554:f58a id=8 08 00 00 34 08 00 00 00 00 00 00 00 00 00 00 09 + 86983 in 3554:f58a id=8 08 00 00 2c 08 ff 00 00 56 00 ff 00 56 00 00 67 + 86987 out 3554:f58a id=8 08 00 00 3c 08 00 00 00 00 00 00 00 00 00 00 01 + 86987 in 3554:f58a id=8 08 00 00 34 08 ff 00 ff 57 df b6 20 a0 00 00 5f + 86991 out 3554:f58a id=8 08 00 00 44 08 00 00 00 00 00 00 00 00 00 00 f9 + 86992 in 3554:f58a id=8 08 00 00 3c 08 ff c3 5c 37 ff ff 00 57 00 00 57 + 86996 out 3554:f58a id=8 08 00 00 e3 02 00 00 00 00 00 00 00 00 00 00 60 + 86996 in 3554:f58a id=8 08 00 00 44 08 ff 00 ff 57 ff 00 ff 57 00 00 4f + 87000 out 3554:f58a id=8 08 00 1b 4c 04 00 00 00 00 00 00 00 00 00 00 da + 87000 in 3554:f58a id=8 08 00 00 e3 02 ff ff 00 00 00 00 00 00 00 00 62 + 87004 in 3554:f58a id=8 08 00 1b 4c 04 ff ff ff ff 00 00 00 00 00 00 de + +=== created and applied. tho seems like it's stored locally o nthe pc, not on the mouse cuz only 4 slots on the mouse maybe? (121418 ms) + +=== switching back to 1 (131058 ms) + 132371 out 3554:f58a id=8 0f 00 00 00 01 00 00 00 00 00 00 00 00 00 00 3d + 132469 in 3554:f58a id=8 0f 00 00 00 01 00 00 00 00 00 00 00 00 00 00 3d + 132478 in 3554:f58a id=8 0a 00 00 00 0a 04 00 00 00 00 00 00 00 00 00 35 + 133470 out 3554:f58a id=8 08 00 00 60 08 00 00 00 00 00 00 00 00 00 00 dd + 133476 out 3554:f58a id=8 08 00 00 68 08 00 00 00 00 00 00 00 00 00 00 d5 + 133476 in 3554:f58a id=8 08 00 00 60 08 01 01 00 53 01 02 00 52 00 00 33 + 133481 out 3554:f58a id=8 08 00 00 70 08 00 00 00 00 00 00 00 00 00 00 cd + 133481 in 3554:f58a id=8 08 00 00 68 08 01 04 00 50 01 08 00 4c 00 00 2b + 133485 in 3554:f58a id=8 08 00 00 70 08 01 10 00 44 02 01 00 52 00 00 23 + 133497 out 3554:f58a id=8 0e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3f + 133501 in 3554:f58a id=8 0e 00 00 00 01 00 00 00 00 00 00 00 00 00 00 3e + 133511 out 3554:f58a id=8 12 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3b + 133516 in 3554:f58a id=8 12 00 00 00 02 01 20 00 00 00 00 00 00 00 00 18 + 133526 out 3554:f58a id=8 08 00 00 4c 08 00 00 00 00 00 00 00 00 00 00 f1 + 133531 in 3554:f58a id=8 08 00 00 4c 08 02 53 ff 56 05 50 00 55 00 00 9d + 133543 out 3554:f58a id=8 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 49 + 133548 in 3554:f58a id=8 04 00 00 00 02 14 00 0d f2 00 00 00 00 00 00 34 + 133559 out 3554:f58a id=8 08 00 01 00 0a 00 00 00 00 00 00 00 00 00 00 3a + 133563 out 3554:f58a id=8 08 00 01 0a 0a 00 00 00 00 00 00 00 00 00 00 30 + 133563 in 3554:f58a id=8 08 00 01 00 0a ff ff ff ff ff ff ff ff ff ff 44 + 133567 out 3554:f58a id=8 08 00 01 20 0a 00 00 00 00 00 00 00 00 00 00 1a + 133567 in 3554:f58a id=8 08 00 01 0a 0a ff ff ff ff ff ff ff ff ff ff 3a + 133571 out 3554:f58a id=8 08 00 01 2a 0a 00 00 00 00 00 00 00 00 00 00 10 + 133571 in 3554:f58a id=8 08 00 01 20 0a ff ff ff ff ff ff ff ff ff ff 24 + 133574 out 3554:f58a id=8 08 00 01 40 0a 00 00 00 00 00 00 00 00 00 00 fa + 133574 in 3554:f58a id=8 08 00 01 2a 0a ff ff ff ff ff ff ff ff ff ff 1a + 133577 out 3554:f58a id=8 08 00 01 4a 0a 00 00 00 00 00 00 00 00 00 00 f0 + 133577 in 3554:f58a id=8 08 00 01 40 0a ff ff ff ff ff ff ff ff ff ff 04 + 133580 out 3554:f58a id=8 08 00 01 60 0a 00 00 00 00 00 00 00 00 00 00 da + 133580 in 3554:f58a id=8 08 00 01 4a 0a ff ff ff ff ff ff ff ff ff ff fa + 133584 out 3554:f58a id=8 08 00 01 6a 0a 00 00 00 00 00 00 00 00 00 00 d0 + 133584 in 3554:f58a id=8 08 00 01 60 0a 02 82 92 01 42 92 01 69 00 00 85 + 133587 out 3554:f58a id=8 08 00 01 80 0a 00 00 00 00 00 00 00 00 00 00 ba + 133587 in 3554:f58a id=8 08 00 01 6a 0a ff ff ff ff ff ff ff ff ff ff da + 133590 out 3554:f58a id=8 08 00 01 8a 0a 00 00 00 00 00 00 00 00 00 00 b0 + 133590 in 3554:f58a id=8 08 00 01 80 0a ff ff ff ff ff ff ff ff ff ff c4 + 133593 out 3554:f58a id=8 08 00 01 a0 0a 00 00 00 00 00 00 00 00 00 00 9a + 133593 in 3554:f58a id=8 08 00 01 8a 0a ff ff ff ff ff ff ff ff ff ff ba + 133596 out 3554:f58a id=8 08 00 01 aa 0a 00 00 00 00 00 00 00 00 00 00 90 + 133596 in 3554:f58a id=8 08 00 01 a0 0a ff ff ff ff ff ff ff ff ff ff a4 + 133599 in 3554:f58a id=8 08 00 01 aa 0a ff ff ff ff ff ff ff ff ff ff 9a + 133610 out 3554:f58a id=8 08 00 00 a9 0a 00 00 00 00 00 00 00 00 00 00 92 + 133614 out 3554:f58a id=8 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3d + 133614 in 3554:f58a id=8 08 00 00 a9 0a 04 51 00 55 06 4f 00 55 00 55 e9 + 133618 out 3554:f58a id=8 17 00 00 00 00 00 00 00 00 00 00 00 00 00 00 36 + 133618 in 3554:f58a id=8 10 00 00 00 03 02 08 4b 00 00 00 00 00 00 00 e5 + 133622 out 3554:f58a id=8 08 00 00 0a 02 00 00 00 00 00 00 00 00 00 00 39 + 133622 in 3554:f58a id=8 17 00 00 00 0a 00 00 00 00 00 00 00 00 00 00 2c + 133625 out 3554:f58a id=8 1d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 30 + 133625 in 3554:f58a id=8 08 00 00 0a 02 01 54 00 00 00 00 00 00 00 00 e4 + 133626 out 3554:f58a id=8 08 00 00 b5 06 00 00 00 00 00 00 00 00 00 00 8a + 133626 in 3554:f58a id=8 1d 01 00 00 00 00 00 00 00 00 00 00 00 00 00 2f + 133630 out 3554:f58a id=8 08 00 00 00 0a 00 00 00 00 00 00 00 00 00 00 3b + 133630 in 3554:f58a id=8 08 00 00 b5 06 01 54 06 4f 01 54 00 00 00 00 8b + 133634 out 3554:f58a id=8 08 00 00 bd 04 00 00 00 00 00 00 00 00 00 00 84 + 133634 in 3554:f58a id=8 08 00 00 00 0a 01 54 04 51 03 52 00 55 00 55 92 + 133637 out 3554:f58a id=8 08 00 00 0c 08 00 00 00 00 00 00 00 00 00 00 31 + 133637 in 3554:f58a id=8 08 00 00 bd 04 ff ff ff ff 00 00 00 00 00 00 88 + 133640 out 3554:f58a id=8 08 00 00 14 08 00 00 00 00 00 00 00 00 00 00 29 + 133640 in 3554:f58a id=8 08 00 00 0c 08 07 07 00 47 0f 0f 00 37 00 00 87 + 133643 out 3554:f58a id=8 08 00 00 1c 08 00 00 00 00 00 00 00 00 00 00 21 + 133643 in 3554:f58a id=8 08 00 00 14 08 3f 3f 00 d7 17 17 00 27 00 00 7f + 133646 out 3554:f58a id=8 08 00 00 24 08 00 00 00 00 00 00 00 00 00 00 19 + 133646 in 3554:f58a id=8 08 00 00 1c 08 17 17 00 27 27 27 00 07 00 00 77 + 133651 out 3554:f58a id=8 08 00 00 2c 08 00 00 00 00 00 00 00 00 00 00 11 + 133651 in 3554:f58a id=8 08 00 00 24 08 3f 3f 00 d7 3f 3f 00 d7 00 00 6f + 133654 out 3554:f58a id=8 08 00 00 34 08 00 00 00 00 00 00 00 00 00 00 09 + 133654 in 3554:f58a id=8 08 00 00 2c 08 ff 00 00 56 00 ff 00 56 00 00 67 + 133657 out 3554:f58a id=8 08 00 00 3c 08 00 00 00 00 00 00 00 00 00 00 01 + 133657 in 3554:f58a id=8 08 00 00 34 08 ff 00 ff 57 df b6 20 a0 00 00 5f + 133660 out 3554:f58a id=8 08 00 00 44 08 00 00 00 00 00 00 00 00 00 00 f9 + 133660 in 3554:f58a id=8 08 00 00 3c 08 ff c3 5c 37 ff ff 00 57 00 00 57 + 133663 out 3554:f58a id=8 08 00 00 e3 02 00 00 00 00 00 00 00 00 00 00 60 + 133663 in 3554:f58a id=8 08 00 00 44 08 ff 00 ff 57 ff 00 ff 57 00 00 4f + 133668 out 3554:f58a id=8 08 00 1b 4c 04 00 00 00 00 00 00 00 00 00 00 da + 133668 in 3554:f58a id=8 08 00 00 e3 02 ff ff 00 00 00 00 00 00 00 00 62 + 133671 in 3554:f58a id=8 08 00 1b 4c 04 ff ff ff ff 00 00 00 00 00 00 de diff --git a/captures/vxe-r1-pro/receiver-atk-hub.txt b/captures/vxe-r1-pro/receiver-atk-hub.txt new file mode 100644 index 00000000..61b15189 --- /dev/null +++ b/captures/vxe-r1-pro/receiver-atk-hub.txt @@ -0,0 +1,287 @@ +# ATK HUB (v3-hub.atk.store) driving a VXE R1 Pro, firmware 1.20, through the +# 0x3554:0xf58a "VXE NordicMouse 1K Dongle". Columns: ms, direction, USB id, +# report id, 16-byte frame. Marks (===) are the owner's notes on what was changed. +# The hub's session handshake (command 0x01) and the receiver RF identity +# (command 0x03 reply) are removed. + 23758 out 3554:f58a id=8 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3d + 23763 out 3554:f58a id=8 12 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3b + 23763 in 3554:f58a id=8 10 00 00 00 03 02 08 4b 00 00 00 00 00 00 00 e5 + 23767 out 3554:f58a id=8 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 4a + 23768 in 3554:f58a id=8 12 00 00 00 02 01 20 00 00 00 00 00 00 00 00 18 + 23771 out 3554:f58a id=8 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 49 + 23775 out 3554:f58a id=8 1d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 30 + 23776 in 3554:f58a id=8 04 00 00 00 02 14 00 0d f6 00 00 00 00 00 00 30 + 23779 in 3554:f58a id=8 1d 01 00 00 00 00 00 00 00 00 00 00 00 00 00 2f + +=== clicking on the device on the device list, after clicking it will open the mouse's overview/dashboard where you can change stuff (58805 ms) + 60176 out 3554:f58a id=8 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3d + 60182 out 3554:f58a id=8 12 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3b + 60183 in 3554:f58a id=8 10 00 00 00 03 02 08 4b 00 00 00 00 00 00 00 e5 + 60187 out 3554:f58a id=8 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 4a + 60187 in 3554:f58a id=8 12 00 00 00 02 01 20 00 00 00 00 00 00 00 00 18 + 60189 out 3554:f58a id=8 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 49 + 60193 out 3554:f58a id=8 1d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 30 + 60194 in 3554:f58a id=8 04 00 00 00 02 14 00 0d fa 00 00 00 00 00 00 2c + 60195 in 3554:f58a id=8 1d 01 00 00 00 00 00 00 00 00 00 00 00 00 00 2f + 60564 out 3554:f58a id=8 08 00 00 60 08 00 00 00 00 00 00 00 00 00 00 dd + 60572 out 3554:f58a id=8 08 00 00 68 08 00 00 00 00 00 00 00 00 00 00 d5 + 60572 in 3554:f58a id=8 08 00 00 60 08 01 01 00 53 01 02 00 52 00 00 33 + 60577 out 3554:f58a id=8 08 00 00 70 08 00 00 00 00 00 00 00 00 00 00 cd + 60577 in 3554:f58a id=8 08 00 00 68 08 01 04 00 50 01 08 00 4c 00 00 2b + 60582 in 3554:f58a id=8 08 00 00 70 08 01 10 00 44 02 01 00 52 00 00 23 + 60593 out 3554:f58a id=8 0e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3f + 60597 in 3554:f58a id=8 0e 00 00 00 01 00 00 00 00 00 00 00 00 00 00 3e + 60607 out 3554:f58a id=8 12 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3b + 60612 in 3554:f58a id=8 12 00 00 00 02 01 20 00 00 00 00 00 00 00 00 18 + 60624 out 3554:f58a id=8 08 00 00 4c 08 00 00 00 00 00 00 00 00 00 00 f1 + 60629 in 3554:f58a id=8 08 00 00 4c 08 02 53 80 d5 05 50 00 55 00 00 9d + 60642 out 3554:f58a id=8 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 49 + 60646 in 3554:f58a id=8 04 00 00 00 02 14 00 0d fa 00 00 00 00 00 00 2c + 60658 out 3554:f58a id=8 08 00 01 00 0a 00 00 00 00 00 00 00 00 00 00 3a + 60663 out 3554:f58a id=8 08 00 01 0a 0a 00 00 00 00 00 00 00 00 00 00 30 + 60663 in 3554:f58a id=8 08 00 01 00 0a ff ff ff ff ff ff ff ff ff ff 44 + 60668 out 3554:f58a id=8 08 00 01 20 0a 00 00 00 00 00 00 00 00 00 00 1a + 60668 in 3554:f58a id=8 08 00 01 0a 0a ff ff ff ff ff ff ff ff ff ff 3a + 60671 out 3554:f58a id=8 08 00 01 2a 0a 00 00 00 00 00 00 00 00 00 00 10 + 60671 in 3554:f58a id=8 08 00 01 20 0a ff ff ff ff ff ff ff ff ff ff 24 + 60675 out 3554:f58a id=8 08 00 01 40 0a 00 00 00 00 00 00 00 00 00 00 fa + 60675 in 3554:f58a id=8 08 00 01 2a 0a ff ff ff ff ff ff ff ff ff ff 1a + 60679 out 3554:f58a id=8 08 00 01 4a 0a 00 00 00 00 00 00 00 00 00 00 f0 + 60679 in 3554:f58a id=8 08 00 01 40 0a ff ff ff ff ff ff ff ff ff ff 04 + 60683 out 3554:f58a id=8 08 00 01 60 0a 00 00 00 00 00 00 00 00 00 00 da + 60683 in 3554:f58a id=8 08 00 01 4a 0a ff ff ff ff ff ff ff ff ff ff fa + 60687 out 3554:f58a id=8 08 00 01 6a 0a 00 00 00 00 00 00 00 00 00 00 d0 + 60687 in 3554:f58a id=8 08 00 01 60 0a 02 82 92 01 42 92 01 69 00 00 85 + 60691 out 3554:f58a id=8 08 00 01 80 0a 00 00 00 00 00 00 00 00 00 00 ba + 60691 in 3554:f58a id=8 08 00 01 6a 0a ff ff ff ff ff ff ff ff ff ff da + 60695 out 3554:f58a id=8 08 00 01 8a 0a 00 00 00 00 00 00 00 00 00 00 b0 + 60695 in 3554:f58a id=8 08 00 01 80 0a ff ff ff ff ff ff ff ff ff ff c4 + 60699 out 3554:f58a id=8 08 00 01 a0 0a 00 00 00 00 00 00 00 00 00 00 9a + 60699 in 3554:f58a id=8 08 00 01 8a 0a ff ff ff ff ff ff ff ff ff ff ba + 60703 out 3554:f58a id=8 08 00 01 aa 0a 00 00 00 00 00 00 00 00 00 00 90 + 60703 in 3554:f58a id=8 08 00 01 a0 0a ff ff ff ff ff ff ff ff ff ff a4 + 60708 in 3554:f58a id=8 08 00 01 aa 0a ff ff ff ff ff ff ff ff ff ff 9a + 60719 out 3554:f58a id=8 08 00 00 a9 0a 00 00 00 00 00 00 00 00 00 00 92 + 60726 out 3554:f58a id=8 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3d + 60726 in 3554:f58a id=8 08 00 00 a9 0a 04 51 00 55 06 4f 00 55 00 55 e9 + 60731 out 3554:f58a id=8 17 00 00 00 00 00 00 00 00 00 00 00 00 00 00 36 + 60731 in 3554:f58a id=8 10 00 00 00 03 02 08 4b 00 00 00 00 00 00 00 e5 + 60735 out 3554:f58a id=8 08 00 00 0a 02 00 00 00 00 00 00 00 00 00 00 39 + 60735 in 3554:f58a id=8 17 00 00 00 0a 00 00 00 00 00 00 00 00 00 00 2c + 60739 out 3554:f58a id=8 1d 00 00 00 00 00 00 00 00 00 00 00 00 00 00 30 + 60739 in 3554:f58a id=8 08 00 00 0a 02 01 54 00 00 00 00 00 00 00 00 e4 + 60740 out 3554:f58a id=8 08 00 00 b5 06 00 00 00 00 00 00 00 00 00 00 8a + 60740 in 3554:f58a id=8 1d 01 00 00 00 00 00 00 00 00 00 00 00 00 00 2f + 60744 out 3554:f58a id=8 08 00 00 00 0a 00 00 00 00 00 00 00 00 00 00 3b + 60744 in 3554:f58a id=8 08 00 00 b5 06 00 55 06 4f 01 54 00 00 00 00 8b + 60748 out 3554:f58a id=8 08 00 00 bd 04 00 00 00 00 00 00 00 00 00 00 84 + 60748 in 3554:f58a id=8 08 00 00 00 0a 01 54 04 51 03 52 00 55 00 55 92 + 60753 out 3554:f58a id=8 08 00 00 0c 08 00 00 00 00 00 00 00 00 00 00 31 + 60754 in 3554:f58a id=8 08 00 00 bd 04 ff ff ff ff 00 00 00 00 00 00 88 + 60758 out 3554:f58a id=8 08 00 00 14 08 00 00 00 00 00 00 00 00 00 00 29 + 60758 in 3554:f58a id=8 08 00 00 0c 08 07 07 00 47 0f 0f 00 37 00 00 87 + 60762 out 3554:f58a id=8 08 00 00 1c 08 00 00 00 00 00 00 00 00 00 00 21 + 60762 in 3554:f58a id=8 08 00 00 14 08 3f 3f 00 d7 17 17 00 27 00 00 7f + 60766 out 3554:f58a id=8 08 00 00 24 08 00 00 00 00 00 00 00 00 00 00 19 + 60766 in 3554:f58a id=8 08 00 00 1c 08 17 17 00 27 27 27 00 07 00 00 77 + 60770 out 3554:f58a id=8 08 00 00 2c 08 00 00 00 00 00 00 00 00 00 00 11 + 60770 in 3554:f58a id=8 08 00 00 24 08 3f 3f 00 d7 3f 3f 00 d7 00 00 6f + 60775 out 3554:f58a id=8 08 00 00 34 08 00 00 00 00 00 00 00 00 00 00 09 + 60775 in 3554:f58a id=8 08 00 00 2c 08 ff 00 00 56 00 ff 00 56 00 00 67 + 60779 out 3554:f58a id=8 08 00 00 3c 08 00 00 00 00 00 00 00 00 00 00 01 + 60779 in 3554:f58a id=8 08 00 00 34 08 ff 00 ff 57 ff c3 5c 37 00 00 5f + 60783 out 3554:f58a id=8 08 00 00 44 08 00 00 00 00 00 00 00 00 00 00 f9 + 60783 in 3554:f58a id=8 08 00 00 3c 08 ff c3 5c 37 ff ff 00 57 00 00 57 + 60788 out 3554:f58a id=8 08 00 00 e3 02 00 00 00 00 00 00 00 00 00 00 60 + 60788 in 3554:f58a id=8 08 00 00 44 08 ff 00 ff 57 ff 00 ff 57 00 00 4f + 60794 out 3554:f58a id=8 08 00 1b 4c 04 00 00 00 00 00 00 00 00 00 00 da + 60794 in 3554:f58a id=8 08 00 00 e3 02 ff ff 00 00 00 00 00 00 00 00 62 + 60798 in 3554:f58a id=8 08 00 1b 4c 04 ff ff ff ff 00 00 00 00 00 00 de + +=== switching dpi to another one already on the mouse (dpi2, 800) (93905 ms) + 96951 out 3554:f58a id=8 07 00 00 00 0a 01 54 04 51 01 54 00 00 00 55 e8 + 96958 in 3554:f58a id=8 07 00 00 00 0a 01 54 04 51 01 54 00 00 00 55 e8 + +=== switching to dpi 1, 400 (105975 ms) + 107458 out 3554:f58a id=8 07 00 00 00 0a 01 54 04 51 00 55 00 00 00 55 e8 + 107463 in 3554:f58a id=8 07 00 00 00 0a 01 54 04 51 00 55 00 00 00 55 e8 + +=== switching to dpi3, 3200 (118816 ms) + 122181 out 3554:f58a id=8 07 00 00 00 0a 01 54 04 51 02 53 00 00 00 55 e8 + 122186 in 3554:f58a id=8 07 00 00 00 0a 01 54 04 51 02 53 00 00 00 55 e8 + +=== switching back to original, dpi4, 1200 (131228 ms) + 133336 out 3554:f58a id=8 07 00 00 00 0a 01 54 04 51 03 52 00 00 00 55 e8 + 133341 in 3554:f58a id=8 07 00 00 00 0a 01 54 04 51 03 52 00 00 00 55 e8 + +=== changing active dpi4 value to 1500 (150582 ms) + 153256 out 3554:f58a id=8 07 00 00 0c 08 07 07 00 47 0f 0f 00 37 00 00 88 + 153261 out 3554:f58a id=8 07 00 00 14 08 3f 3f 00 d7 1d 1d 00 1b 00 00 80 + 153261 in 3554:f58a id=8 07 00 00 0c 08 07 07 00 47 0f 0f 00 37 00 00 88 + 153265 out 3554:f58a id=8 07 00 00 1c 08 17 17 00 27 27 27 00 07 00 00 78 + 153265 in 3554:f58a id=8 07 00 00 14 08 3f 3f 00 d7 1d 1d 00 1b 00 00 80 + 153268 out 3554:f58a id=8 07 00 00 24 08 3f 3f 00 d7 3f 3f 00 d7 00 00 70 + 153268 in 3554:f58a id=8 07 00 00 1c 08 17 17 00 27 27 27 00 07 00 00 78 + 153271 in 3554:f58a id=8 07 00 00 24 08 3f 3f 00 d7 3f 3f 00 d7 00 00 70 + +=== back to 1200 (158796 ms) + 161745 out 3554:f58a id=8 07 00 00 0c 08 07 07 00 47 0f 0f 00 37 00 00 88 + 161751 out 3554:f58a id=8 07 00 00 14 08 3f 3f 00 d7 17 17 00 27 00 00 80 + 161751 in 3554:f58a id=8 07 00 00 0c 08 07 07 00 47 0f 0f 00 37 00 00 88 + 161756 out 3554:f58a id=8 07 00 00 1c 08 17 17 00 27 27 27 00 07 00 00 78 + 161757 in 3554:f58a id=8 07 00 00 14 08 3f 3f 00 d7 17 17 00 27 00 00 80 + 161762 out 3554:f58a id=8 07 00 00 24 08 3f 3f 00 d7 3f 3f 00 d7 00 00 70 + 161762 in 3554:f58a id=8 07 00 00 1c 08 17 17 00 27 27 27 00 07 00 00 78 + 161767 in 3554:f58a id=8 07 00 00 24 08 3f 3f 00 d7 3f 3f 00 d7 00 00 70 + +=== changing polling rate to 500 (181352 ms) + 182267 out 3554:f58a id=8 07 00 00 00 0a 02 53 04 51 03 52 00 00 00 55 e8 + 182272 in 3554:f58a id=8 07 00 00 00 0a 02 53 04 51 03 52 00 00 00 55 e8 + +=== back to 1k (188268 ms) + 189111 out 3554:f58a id=8 07 00 00 00 0a 01 54 04 51 03 52 00 00 00 55 e8 + 189120 in 3554:f58a id=8 07 00 00 00 0a 01 54 04 51 03 52 00 00 00 55 e8 + +=== changing LOD to 2mm (215151 ms) + 216487 out 3554:f58a id=8 07 00 00 0a 02 02 53 00 00 00 00 00 00 00 00 e5 + 216493 in 3554:f58a id=8 07 00 00 0a 02 02 53 00 00 00 00 00 00 00 00 e5 + +=== back to 1mm (220813 ms) + 221928 out 3554:f58a id=8 07 00 00 0a 02 01 54 00 00 00 00 00 00 00 00 e5 + 221934 in 3554:f58a id=8 07 00 00 0a 02 01 54 00 00 00 00 00 00 00 00 e5 + +=== dbeounce to 20ms (232856 ms) + 233852 out 3554:f58a id=8 07 00 00 a9 0a 14 41 00 55 06 4f 00 55 00 55 ea + 233856 in 3554:f58a id=8 07 00 00 a9 0a 14 41 00 55 06 4f 00 55 00 55 ea + +=== back to 4ms (237797 ms) + 239228 out 3554:f58a id=8 07 00 00 a9 0a 04 51 00 55 06 4f 00 55 00 55 ea + 239232 in 3554:f58a id=8 07 00 00 a9 0a 04 51 00 55 06 4f 00 55 00 55 ea + +=== to 0ms (242390 ms) + 245404 out 3554:f58a id=8 07 00 00 a9 0a 00 55 00 55 06 4f 00 55 00 55 ea + 245407 in 3554:f58a id=8 07 00 00 a9 0a 00 55 00 55 06 4f 00 55 00 55 ea + +=== back to 4ms (248662 ms) + 249919 out 3554:f58a id=8 07 00 00 a9 0a 04 51 00 55 06 4f 00 55 00 55 ea + 249923 in 3554:f58a id=8 07 00 00 a9 0a 04 51 00 55 06 4f 00 55 00 55 ea + +=== enablign movement sync (267388 ms) + 268547 out 3554:f58a id=8 07 00 00 a9 0a 04 51 01 54 06 4f 00 55 00 55 ea + 268552 in 3554:f58a id=8 07 00 00 a9 0a 04 51 01 54 06 4f 00 55 00 55 ea + +=== disabling (272721 ms) + 273821 out 3554:f58a id=8 07 00 00 a9 0a 04 51 00 55 06 4f 00 55 00 55 ea + 273826 in 3554:f58a id=8 07 00 00 a9 0a 04 51 00 55 06 4f 00 55 00 55 ea + +=== changing sleep timer to 30min (283260 ms) + 284457 out 3554:f58a id=8 07 00 00 a9 0a 04 51 00 55 b4 a1 00 55 00 55 ea + 284462 out 3554:f58a id=8 07 00 00 b5 06 01 54 b4 a1 01 54 00 00 00 00 8c + 284462 in 3554:f58a id=8 07 00 00 a9 0a 04 51 00 55 b4 a1 00 55 00 55 ea + 284467 in 3554:f58a id=8 07 00 00 b5 06 01 54 b4 a1 01 54 00 00 00 00 8c + +=== back to 1min (287285 ms) + 288400 out 3554:f58a id=8 07 00 00 a9 0a 04 51 00 55 06 4f 00 55 00 55 ea + 288404 out 3554:f58a id=8 07 00 00 b5 06 01 54 06 4f 01 54 00 00 00 00 8c + 288404 in 3554:f58a id=8 07 00 00 a9 0a 04 51 00 55 06 4f 00 55 00 55 ea + 288408 in 3554:f58a id=8 07 00 00 b5 06 01 54 06 4f 01 54 00 00 00 00 8c + +=== enabling ripple contrl (299671 ms) + 300691 out 3554:f58a id=8 07 00 00 a9 0a 04 51 00 55 06 4f 00 55 01 54 ea + 300696 in 3554:f58a id=8 07 00 00 a9 0a 04 51 00 55 06 4f 00 55 01 54 ea + +=== disabling (303150 ms) + 304350 out 3554:f58a id=8 07 00 00 a9 0a 04 51 00 55 06 4f 00 55 00 55 ea + 304355 in 3554:f58a id=8 07 00 00 a9 0a 04 51 00 55 06 4f 00 55 00 55 ea + +=== changing dpi4 color (321693 ms) + 325622 out 3554:f58a id=8 07 00 00 2c 08 ff 00 00 56 00 ff 00 56 00 00 68 + 325626 out 3554:f58a id=8 07 00 00 34 08 ff 00 ff 57 5c ff 7c 7e 00 00 60 + 325626 in 3554:f58a id=8 07 00 00 2c 08 ff 00 00 56 00 ff 00 56 00 00 68 + 325629 out 3554:f58a id=8 07 00 00 3c 08 ff c3 5c 37 ff ff 00 57 00 00 58 + 325629 in 3554:f58a id=8 07 00 00 34 08 ff 00 ff 57 5c ff 7c 7e 00 00 60 + 325635 out 3554:f58a id=8 07 00 00 44 08 ff 00 ff 57 ff 00 ff 57 00 00 50 + 325635 in 3554:f58a id=8 07 00 00 3c 08 ff c3 5c 37 ff ff 00 57 00 00 58 + 325640 in 3554:f58a id=8 07 00 00 44 08 ff 00 ff 57 ff 00 ff 57 00 00 50 + 326633 out 3554:f58a id=8 07 00 00 2c 08 ff 00 00 56 00 ff 00 56 00 00 68 + 326638 out 3554:f58a id=8 07 00 00 34 08 ff 00 ff 57 2b a6 44 40 00 00 60 + 326638 in 3554:f58a id=8 07 00 00 2c 08 ff 00 00 56 00 ff 00 56 00 00 68 + 326642 out 3554:f58a id=8 07 00 00 3c 08 ff c3 5c 37 ff ff 00 57 00 00 58 + 326642 in 3554:f58a id=8 07 00 00 34 08 ff 00 ff 57 2b a6 44 40 00 00 60 + 326646 out 3554:f58a id=8 07 00 00 44 08 ff 00 ff 57 ff 00 ff 57 00 00 50 + 326646 in 3554:f58a id=8 07 00 00 3c 08 ff c3 5c 37 ff ff 00 57 00 00 58 + 326651 in 3554:f58a id=8 07 00 00 44 08 ff 00 ff 57 ff 00 ff 57 00 00 50 + 328291 out 3554:f58a id=8 07 00 00 2c 08 ff 00 00 56 00 ff 00 56 00 00 68 + 328295 out 3554:f58a id=8 07 00 00 34 08 ff 00 ff 57 00 00 00 55 00 00 60 + 328295 in 3554:f58a id=8 07 00 00 2c 08 ff 00 00 56 00 ff 00 56 00 00 68 + 328298 out 3554:f58a id=8 07 00 00 3c 08 ff c3 5c 37 ff ff 00 57 00 00 58 + 328298 in 3554:f58a id=8 07 00 00 34 08 ff 00 ff 57 00 00 00 55 00 00 60 + 328303 out 3554:f58a id=8 07 00 00 44 08 ff 00 ff 57 ff 00 ff 57 00 00 50 + 328303 in 3554:f58a id=8 07 00 00 3c 08 ff c3 5c 37 ff ff 00 57 00 00 58 + 328309 in 3554:f58a id=8 07 00 00 44 08 ff 00 ff 57 ff 00 ff 57 00 00 50 + +=== changed it to black, changing back to orange (340225 ms) + 344711 out 3554:f58a id=8 07 00 00 2c 08 ff 00 00 56 00 ff 00 56 00 00 68 + 344715 out 3554:f58a id=8 07 00 00 34 08 ff 00 ff 57 96 a7 16 02 00 00 60 + 344715 in 3554:f58a id=8 07 00 00 2c 08 ff 00 00 56 00 ff 00 56 00 00 68 + 344719 out 3554:f58a id=8 07 00 00 3c 08 ff c3 5c 37 ff ff 00 57 00 00 58 + 344719 in 3554:f58a id=8 07 00 00 34 08 ff 00 ff 57 96 a7 16 02 00 00 60 + 344724 out 3554:f58a id=8 07 00 00 44 08 ff 00 ff 57 ff 00 ff 57 00 00 50 + 344724 in 3554:f58a id=8 07 00 00 3c 08 ff c3 5c 37 ff ff 00 57 00 00 58 + 344730 in 3554:f58a id=8 07 00 00 44 08 ff 00 ff 57 ff 00 ff 57 00 00 50 + 345571 out 3554:f58a id=8 07 00 00 2c 08 ff 00 00 56 00 ff 00 56 00 00 68 + 345576 out 3554:f58a id=8 07 00 00 34 08 ff 00 ff 57 a7 88 16 10 00 00 60 + 345576 in 3554:f58a id=8 07 00 00 2c 08 ff 00 00 56 00 ff 00 56 00 00 68 + 345581 out 3554:f58a id=8 07 00 00 3c 08 ff c3 5c 37 ff ff 00 57 00 00 58 + 345581 in 3554:f58a id=8 07 00 00 34 08 ff 00 ff 57 a7 88 16 10 00 00 60 + 345585 out 3554:f58a id=8 07 00 00 44 08 ff 00 ff 57 ff 00 ff 57 00 00 50 + 345585 in 3554:f58a id=8 07 00 00 3c 08 ff c3 5c 37 ff ff 00 57 00 00 58 + 345589 in 3554:f58a id=8 07 00 00 44 08 ff 00 ff 57 ff 00 ff 57 00 00 50 + 346517 out 3554:f58a id=8 07 00 00 2c 08 ff 00 00 56 00 ff 00 56 00 00 68 + 346521 out 3554:f58a id=8 07 00 00 34 08 ff 00 ff 57 df b6 20 a0 00 00 60 + 346521 in 3554:f58a id=8 07 00 00 2c 08 ff 00 00 56 00 ff 00 56 00 00 68 + 346525 out 3554:f58a id=8 07 00 00 3c 08 ff c3 5c 37 ff ff 00 57 00 00 58 + 346525 in 3554:f58a id=8 07 00 00 34 08 ff 00 ff 57 df b6 20 a0 00 00 60 + 346528 out 3554:f58a id=8 07 00 00 44 08 ff 00 ff 57 ff 00 ff 57 00 00 50 + 346528 in 3554:f58a id=8 07 00 00 3c 08 ff c3 5c 37 ff ff 00 57 00 00 58 + 346532 in 3554:f58a id=8 07 00 00 44 08 ff 00 ff 57 ff 00 ff 57 00 00 50 + +=== enabling straight line correction (377876 ms) + 379065 out 3554:f58a id=8 07 00 00 a9 0a 04 51 00 55 06 4f 01 54 00 55 ea + 379070 in 3554:f58a id=8 07 00 00 a9 0a 04 51 00 55 06 4f 01 54 00 55 ea + +=== disabling (381729 ms) + 382778 out 3554:f58a id=8 07 00 00 a9 0a 04 51 00 55 06 4f 00 55 00 55 ea + 382783 in 3554:f58a id=8 07 00 00 a9 0a 04 51 00 55 06 4f 00 55 00 55 ea + +=== enabling dpi light (always on) (393093 ms) + 393912 out 3554:f58a id=8 07 00 00 4c 08 01 54 80 d5 05 50 01 54 00 00 9e + 393916 in 3554:f58a id=8 07 00 00 4c 08 01 54 80 d5 05 50 01 54 00 00 9e + +=== changing it to breathing (402089 ms) + 403064 out 3554:f58a id=8 07 00 00 4c 08 02 53 80 d5 05 50 01 54 00 00 9e + 403069 in 3554:f58a id=8 07 00 00 4c 08 02 53 80 d5 05 50 01 54 00 00 9e + +=== changing breathing speed to slowest from fastest (options: slowest, medium fastest) (436244 ms) + 437525 out 3554:f58a id=8 07 00 00 4c 08 02 53 80 d5 01 54 01 54 00 00 9e + 437530 in 3554:f58a id=8 07 00 00 4c 08 02 53 80 d5 01 54 01 54 00 00 9e + +=== changing back to always on (444684 ms) + 445716 out 3554:f58a id=8 07 00 00 4c 08 01 54 80 d5 01 54 01 54 00 00 9e + 445720 in 3554:f58a id=8 07 00 00 4c 08 01 54 80 d5 01 54 01 54 00 00 9e + +=== changing brightness from medium to min (min, medium, max) (459891 ms) + 461295 out 3554:f58a id=8 07 00 00 4c 08 01 54 10 45 01 54 01 54 00 00 9e + 461300 in 3554:f58a id=8 07 00 00 4c 08 01 54 10 45 01 54 01 54 00 00 9e + +=== turning off dpi light effect (486691 ms) + 487735 out 3554:f58a id=8 07 00 00 4c 08 00 00 10 45 01 54 00 55 00 00 f3 + 487740 in 3554:f58a id=8 07 00 00 4c 08 00 00 10 45 01 54 00 55 00 00 f3 + +=== enabling ultra range mode (495739 ms) + 496913 out 3554:f58a id=8 16 00 00 00 0a 01 00 00 00 00 00 00 00 00 00 2c + 497010 in 3554:f58a id=8 16 00 00 00 0a 01 00 00 00 00 00 00 00 00 00 2c + +=== disabliing (501783 ms) + 502785 out 3554:f58a id=8 16 00 00 00 0a 00 00 00 00 00 00 00 00 00 00 2d + 502880 in 3554:f58a id=8 16 00 00 00 0a 00 00 00 00 00 00 00 00 00 00 2d diff --git a/docs/vxe-r1-pro-testing.md b/docs/vxe-r1-pro-testing.md new file mode 100644 index 00000000..205dce2f --- /dev/null +++ b/docs/vxe-r1-pro-testing.md @@ -0,0 +1,95 @@ +# VXE R1 Pro hardware notes + +This document records what was verified on a real VXE R1 Pro for the ATK +driver. Only the 1K receiver was tested; the wired transport is untested and +stays read-only. + +## Identity and transport + +- Receiver: VID/PID `0x3554:0xf58a`, product string "VXE NordicMouse 1K + Dongle". This is the same USB id as the R1 Pro Max receiver. +- Mouse identity (`GetMouseCIDMID`, command `0x10`): CID `0x02`, MID `0x08`, + firmware 1.20. +- Sensor: PAW3395 (50-DPI step codec). +- Configuration collection: usage page `0xff02`, usage `0x02`. + +ATK HUB lists the wired R1 Pro as CID/MID `2,7` on `0x3554:0xf58c`; the +hardware reports `2,8` through the receiver. + +### CID/MID is scoped by USB vendor + +Under ATK's `0x373b` vendor id, CID/MID `2,8` is the VXE R1 NK, a PAW3395SE +mouse. The receiver is not in the vendor catalog, so the driver used to fall +back to the only catalog entry with that pair and decode the R1 Pro with the +PAW3395SE codec. That codec has no code `0x07`, so a 400-DPI stage +(`07 07 00 47`) aborted the status read with a checksum error even though the +row's checksum was valid. + +Ten of the twelve Compx (`0x3554`) CID/MID pairs in the catalog name a +different mouse under `0x373b`. A CID/MID-only catalog match is therefore +accepted only when the entry belongs to the connected USB vendor, and the R1 +Pro is registered as a Compx-only identity. + +## Verified receiver behavior + +`captures/vxe-r1-pro/receiver-atk-hub.txt` and +`captures/vxe-r1-pro/receiver-atk-hub-profiles.txt` are logs of ATK HUB +(`v3-hub.atk.store`) changing each setting below. The frames match the R1 Pro +Max receiver protocol, so the R1 Pro reuses those write/echo helpers. Each +setting was then written by the driver on the same mouse, confirmed by +readback, and restored. + +| Setting | Row | Notes | +| --- | --- | --- | +| Polling rate (125–1,000 Hz) | 10-byte system row at `0x0000` | | +| DPI stage count, active stage | 10-byte system row at `0x0000` | Stage count was written by the driver only; HUB's stage-count change was not captured. | +| DPI stage value | 8-byte two-stage group from `0x000c` | 1,500 DPI is `1d 1d 00 1b`. HUB rewrites all four groups; the driver writes the one that changed. | +| Lift-off distance | pair at `0x000a` | 1 = 1 mm, 2 = 2 mm. | +| Debounce, Motion Sync, sleep, straight-line correction, ripple control | 10-byte advanced row at `0x00a9` | Offsets 0, 2, 4, 6, 8. | +| DPI stage colours | 8-byte two-colour group from `0x002c` | | +| DPI lighting | 8-byte row at `0x004c` | See below. | +| Ultra Long Range | command `0x16`, readback `0x17` | | +| Configuration bank (profile) 1–4 | command `0x0f`, readback `0x0e` | Zero-based bank at data offset 0; the receiver echoes the request about 100 ms later. | + +### Profiles and buttons + +The mouse holds four configuration banks. Switching to bank 2 through the +driver changed the reported DPI stages from 400/800/3,200/1,200 to +400/800/1,600/3,200, and switching back restored them, so EEPROM reads follow +the active bank as they do on the other R1s. + +The six button records at `0x0060`–`0x0074` use the R1 layout and are read +only. The stock assignments read as left, right, middle, back, forward and DPI +cycle. + +ATK HUB's "computer config" entries are stored on the PC: applying one selects +bank 4 and rewrites its rows from the host. The driver does not model them. + +### DPI lighting + +The row is `effect | brightness | speed | enabled`, each a value/checksum pair. +Always On and Breathing match the R1 Pro Max. Off differs: + +- ATK HUB sends `00 00 | brightness unchanged | speed | 00 55`. +- The mouse stores `02 53` in the effect pair regardless, so Off is carried by + the enabled flag alone. A row reading `02 53 80 d5 05 50 00 55` is Off. + +The driver sends HUB's Off row, does not require the effect pair to read back, +and decodes enabled = 0 as Off for this identity. + +### Sleep timer + +When the sleep timer changes, ATK HUB also writes the 6-byte row at `0x00b5` +(`01 54 | timer | 01 54`). The driver writes only `0x00a9`, as it does for the +R1 Pro Max; the readback confirms the value, but that the mouse then sleeps on +the new schedule was not timed. + +## Not enabled + +- Button-assignment writes and macros: not captured, and not implemented by + the driver for any R1. +- Performance Mode (`0x00b5` bytes 4–5): ATK HUB showed no such switch for + this mouse, so the driver neither reports nor writes it. +- Separate X/Y DPI: not tested. +- Wired transport: not tested. It is not on the verified-wired list, so + persistent writes stay blocked there. diff --git a/src/drivers/atk/hid.test.ts b/src/drivers/atk/hid.test.ts index 12d4c9ca..e3589a8b 100644 --- a/src/drivers/atk/hid.test.ts +++ b/src/drivers/atk/hid.test.ts @@ -1300,11 +1300,17 @@ test("a mouse behind the generic 8K dongle-L is decoded with the sensor its CID/ }); test("a CID/MID shared by models with different sensors stays on the generic codec behind a receiver", () => { - assert.equal(atkCatalogSensorForCidMid("2,77"), "PAW3395SE"); - assert.equal(atkCatalogSensorForCidMid("1,2"), "PAW3950Ultra"); - assert.equal(atkCatalogSensorForCidMid("2,5"), null); - assert.equal(atkCatalogSensorForCidMid("250,250"), null); - assert.equal(atkCatalogSensorForCidMid(null), null); + assert.equal(atkCatalogSensorForCidMid("2,77", 0x373b), "PAW3395SE"); + assert.equal(atkCatalogSensorForCidMid("1,2", 0x373b), "PAW3950Ultra"); + assert.equal(atkCatalogSensorForCidMid("2,5", 0x373b), null); + assert.equal(atkCatalogSensorForCidMid("250,250", 0x373b), null); + assert.equal(atkCatalogSensorForCidMid(null, 0x373b), null); + // CID/MID 2,8 is the VXE R1 NK under ATK's vendor id only; a Compx (0x3554) + // device reporting it is a different mouse and must not borrow that entry. + assert.equal(atkCatalogSensorForCidMid("2,8", 0x373b), "PAW3395SE"); + assert.equal(atkCatalogSensorForCidMid("2,8", 0x3554), null); + assert.equal(atkCatalogDevice(0x3554, 0xf58a, "2,8"), undefined); + assert.equal(atkCatalogDevice(0x373b, 0x10c9, "2,8")?.model, "VXE R1 NK"); assert.equal(atkCatalogDevice(0x373b, 0x1278, "2,77")?.model, "ATK X1 SE NK"); assert.equal(atkCatalogDevice(0x373b, 0x1278, "2,5"), undefined); }); diff --git a/src/drivers/atk/hid.ts b/src/drivers/atk/hid.ts index e3e88157..eec1b2f5 100644 --- a/src/drivers/atk/hid.ts +++ b/src/drivers/atk/hid.ts @@ -45,7 +45,7 @@ import { atkUnpackDpiStage, atkUnpackDpiStageForSensor, } from "@openmouse/protocol/atk"; -import { type AtkProduct, ATK_COMPX_PRODUCT_IDS, ATK_PRODUCTS, atkCatalogDevice, atkCatalogSensorForCidMid, atkCatalogSensorToSensor } from "./products.ts"; +import { type AtkProduct, ATK_COMPX_PRODUCT_IDS, ATK_COMPX_PRODUCTS, ATK_PRODUCTS, atkCatalogDevice, atkCatalogSensorForCidMid, atkCatalogSensorToSensor, atkProductFor } from "./products.ts"; import type { AtkDeviceDescriptor, AtkDeviceFeatures } from "./device-catalog.generated.ts"; import type { AtkSensor } from "@openmouse/protocol/atk"; @@ -399,6 +399,9 @@ export class AtkHidClient { dpiLighting: r1Extras && this.features().noDpiRGB !== true ? { modes: [0, 1, 2], brightness: [0, 1, 2], + // ATK HUB offers no brightness while breathing on these two, and + // setDpiLighting leaves the stored pair alone in that mode. + brightnessModes: this.isR1ProMax() || this.isR1Pro() ? [1] : undefined, speed: [0, 1, 2], } : undefined, }, @@ -424,7 +427,8 @@ export class AtkHidClient { motionSync: advanced[2] === 1, sleepTimeout: advanced[4] * SLEEP_STEP_SECONDS || null, rippleControl: advanced[8] === 1, - performanceMode: r1Extras?.performanceMode ?? a9PerformanceMode, + // ATK HUB offers no performance-mode switch for the R1 Pro. + performanceMode: this.isR1Pro() ? undefined : r1Extras?.performanceMode ?? a9PerformanceMode, longRangeMode: r1Extras?.longRangeMode, atkSensorMode: f1Extras?.sensorMode ?? null, atkAntiMistouchMs: f1Extras?.antiMistouchMs ?? null, @@ -800,6 +804,7 @@ export class AtkHidClient { async setPerformanceMode(enabled: boolean): Promise { await this.identify(); + if (this.isR1Pro()) throw new Error("Performance mode is not available on this connection."); const change = (block: number[]): void => { block.splice(4, 2, ...wePackScalarPair(enabled ? 1 : 0)); @@ -961,14 +966,19 @@ export class AtkHidClient { // Off = 00 00 | 00 00 | speed | 00 55 // Always On = 01 54 | brightness | speed | 01 54 // Breathing = 02 53 | preserve brightness | speed | 01 54 + // The R1 Pro shares that encoding, except that ATK HUB leaves its + // brightness pair untouched when switching the light off, and the mouse + // keeps its previous effect pair instead of storing 00 00: there, Off is + // carried by the trailing enabled flag alone. const block = Array.from(await this.read(REGISTER.dpiLighting, R1_DPI_LIGHTING_LENGTH)); - const proMax = this.isR1ProMax(); + const r1Pro = this.isR1Pro(); + const proMax = this.isR1ProMax() || r1Pro; const expectedEffect = proMax && mode === 0 ? [0, 0] : wePackScalarPair(mode === 2 ? 2 : 1); - const expectedBrightness = proMax && mode === 2 + const expectedBrightness = (proMax && mode === 2) || (r1Pro && mode === 0) ? [block[2]!, block[3]!] : mode === 0 ? [0, 0] @@ -988,7 +998,8 @@ export class AtkHidClient { const expectedSpeed = wePackScalarPair(R1_DPI_SPEED[speed]!); const expectedEnabled = wePackScalarPair(mode === 0 ? 0 : 1); const expected = [...expectedEffect, ...expectedBrightness, ...expectedSpeed, ...expectedEnabled]; - if (!expected.every((byte, index) => raw[index] === byte)) { + const firstChecked = r1Pro && mode === 0 ? expectedEffect.length : 0; + if (!expected.every((byte, index) => index < firstChecked || raw[index] === byte)) { throw new Error("The mouse did not retain its DPI lighting settings."); } @@ -1324,6 +1335,11 @@ export class AtkHidClient { if (brightnessIndex < 0 || speedIndex < 0 || (enabled !== 0 && enabled !== 1)) return null; + // The R1 Pro stores Off as enabled=0 and leaves the last effect in place. + if (this.isR1Pro() && enabled === 0) { + return { dpiLedMode: 0, dpiLedBrightness: brightnessIndex, dpiLedSpeed: speedIndex }; + } + // R1 Pro Max may report the trailing flag as 0 after reconnect even when // the stored effect is Breathing. Treat the effect field as authoritative. // Keep effect=1 + enabled=0 as the legacy Off encoding used by other R1s. @@ -1422,7 +1438,14 @@ export class AtkHidClient { const stage = sensor ? atkUnpackDpiStageForSensor(sensor, data) : atkUnpackDpiStage(data); - if (!stage) throw new Error("The mouse reported a DPI stage that failed its checksum."); + if (!stage) { + // A row can sum correctly and still hold a value this sensor's codec + // rejects, which points at a misidentified model rather than bad data. + const checksumValid = data.reduce((total, byte) => total + byte, 0) % 0x100 === 0x55; + throw new Error(checksumValid + ? "The mouse reported a DPI stage this sensor cannot produce; the model may be misidentified." + : "The mouse reported a DPI stage that failed its checksum."); + } return stage; } @@ -1583,7 +1606,7 @@ export class AtkHidClient { } this.identified = true; this.cidMid = `${reply[DATA_OFFSET]},${reply[DATA_OFFSET + 1]}`; - this.product = ATK_PRODUCTS[this.cidMid] ?? null; + this.product = atkProductFor(this.device.vendorId, this.cidMid); } /** @@ -1615,7 +1638,7 @@ export class AtkHidClient { */ private sensorKey(): AtkSensor | null { if (this.product) return this.product.sensor; - return atkCatalogSensorToSensor(this.catalogEntry()?.sensor ?? null) ?? atkCatalogSensorForCidMid(this.cidMid); + return atkCatalogSensorToSensor(this.catalogEntry()?.sensor ?? null) ?? atkCatalogSensorForCidMid(this.cidMid, this.device.vendorId); } private usesSharedR1Transport(): boolean { @@ -1635,10 +1658,21 @@ export class AtkHidClient { return this.product === ATK_PRODUCTS["2,27"]; } + /** VXE R1 Pro (Compx CID 2, MID 8), captured behind the F58A 1K dongle. */ + private isR1Pro(): boolean { + return this.device.vendorId === VENDOR_ID.vgn && this.product === ATK_COMPX_PRODUCTS["2,8"]; + } + + /** + * The F58A dongle's captured write/echo protocol. The R1 Pro Max and the R1 + * Pro both pair with this dongle and ATK HUB sends them the same rows, so + * the R1 Pro reuses the Pro Max receiver helpers for the settings that were + * captured on it; see docs/vxe-r1-pro-testing.md for what was not. + */ private usesVerifiedR1ProMaxReceiverTransport(): boolean { return this.device.vendorId === VENDOR_ID.vgn && this.device.productId === VXE_R1_PRO_MAX_RECEIVER_PID - && this.isR1ProMax(); + && (this.isR1ProMax() || this.isR1Pro()); } /** diff --git a/src/drivers/atk/products.ts b/src/drivers/atk/products.ts index 9a6d6992..66fb2944 100644 --- a/src/drivers/atk/products.ts +++ b/src/drivers/atk/products.ts @@ -53,19 +53,25 @@ export function atkCatalogDevice( ): AtkDeviceDescriptor | undefined { const byUsbId = atkDeviceForHid(vendorId, productId, cidMid); if (byUsbId || !cidMid || atkDevicesForHid(vendorId, productId).length > 0) return byUsbId; + // CID/MID numbering restarts per USB vendor: Compx (0x3554) "2,8" is the + // VXE R1 Pro while ATK (0x373b) "2,8" is the VXE R1 NK, a different sensor. + // A CID/MID-only match is trusted only within the connected vendor. const byCidMid = atkDevicesForCidMid(cidMid); - return byCidMid.length === 1 ? byCidMid[0] : undefined; + return byCidMid.length === 1 && byCidMid[0]!.vendorId === vendorId ? byCidMid[0] : undefined; } /** * Sensor shared by every catalog model with this CID/MID. Receivers enumerate * under their own USB id, so the paired mouse is known only by CID/MID; the * pair is not unique, but when every model sharing it has the same sensor the - * DPI codec is still unambiguous. + * DPI codec is still unambiguous. A pair listed only under another USB vendor + * is ignored, because the same pair names unrelated mice there. */ -export function atkCatalogSensorForCidMid(cidMid: string | null): AtkSensor | null { +export function atkCatalogSensorForCidMid(cidMid: string | null, vendorId: number): AtkSensor | null { if (!cidMid) return null; - const sensors = new Set(atkDevicesForCidMid(cidMid).map((device) => atkCatalogSensorToSensor(device.sensor))); + const devices = atkDevicesForCidMid(cidMid); + if (!devices.some((device) => device.vendorId === vendorId)) return null; + const sensors = new Set(devices.map((device) => atkCatalogSensorToSensor(device.sensor))); const [only] = sensors; return sensors.size === 1 && only ? only : null; } @@ -84,5 +90,27 @@ export const ATK_PRODUCTS: Record = { "2,83": { brand: "ATK", model: "A9 Plus Nearlink", sensor: "PAW3395", maxPollingHz: 1000, verified: true }, }; +/** + * Identities that exist only under Compx's USB vendor id (0x3554), where the + * same CID/MID means a different mouse than it does under ATK's 0x373b. + * + * "2,8" is the VXE R1 Pro as reported through the 0x3554:0xf58a 1K dongle + * (firmware 1.20). ATK HUB lists the wired mouse as "2,7", one below. The + * verified R1 ("2,12", listed "2,11") and R1 SE+ ("2,32", listed "2,31") + * entries above sit one above their HUB listings in the same way. + */ +export const ATK_COMPX_PRODUCTS: Record = { + "2,8": { brand: "VXE", model: "R1 Pro", sensor: "PAW3395", family: "r1", verified: true }, +}; + +const COMPX_VENDOR_ID = 0x3554; + +/** Hand-built identity for a CID/MID reply, scoped by the USB vendor that answered. */ +export function atkProductFor(vendorId: number, cidMid: string): AtkProduct | null { + return (vendorId === COMPX_VENDOR_ID ? ATK_COMPX_PRODUCTS[cidMid] : undefined) + ?? ATK_PRODUCTS[cidMid] + ?? null; +} + /** Known VXE R1-family transports under COMPX's shared vendor id. */ export const ATK_COMPX_PRODUCT_IDS: readonly number[] = [0xf58a, 0xf58c, 0xf58e, 0xf58f]; diff --git a/src/drivers/atk/r1-pro-max-hid.test.ts b/src/drivers/atk/r1-pro-max-hid.test.ts index 4d74c729..a65cabb6 100644 --- a/src/drivers/atk/r1-pro-max-hid.test.ts +++ b/src/drivers/atk/r1-pro-max-hid.test.ts @@ -787,4 +787,158 @@ test("R1 Pro Max accepts firmware-normalized Breathing state after reconnect", ( dpiLedBrightness: 1, dpiLedSpeed: 0, }); -}); \ No newline at end of file +}); +test("R1 Pro over the Compx 1K dongle decodes PAW3395 stages instead of borrowing the ATK-vendor R1 NK codec", async () => { + // Replies captured from a VXE R1 Pro (firmware 1.20) behind 0x3554:0xf58a + // "VXE NordicMouse 1K Dongle". It reports CID/MID 2,8, which under ATK's + // 0x373b vendor id is the PAW3395SE-based VXE R1 NK; that codec has no code + // 0x07, so the 400-DPI stage used to abort the whole status read. + const fake = device(0xf58a, "VXE NordicMouse 1K Dongle"); + (fake as unknown as FakeR1ProMaxDevice).replies = [ + reply(0x10, 0, [0x02, 0x08, 0x4b]), + reply(0x04, 0, [0x14, 0x00]), + reply(0x08, 0x0000, [0x01, 0x54, 0x04, 0x51, 0x03, 0x52]), + reply(0x08, 0x000c, [0x07, 0x07, 0x00, 0x47]), + reply(0x08, 0x0010, [0x0f, 0x0f, 0x00, 0x37]), + reply(0x08, 0x0014, [0x3f, 0x3f, 0x00, 0xd7]), + reply(0x08, 0x0018, [0x17, 0x17, 0x00, 0x27]), + reply(0x12, 0, [0x01, 0x20]), + reply(0x08, 0x000a, [0x01, 0x54]), + reply(0x08, 0x00a9, [0x04, 0x51, 0x00, 0x55, 0x06, 0x4f, 0x00, 0x55, 0x00, 0x55]), + reply(0x08, 0x00bd, [0xff, 0xff, 0xff, 0xff]), + reply(0x08, 0x00b5, [0x00, 0x55, 0x06, 0x4f, 0x01, 0x54]), + reply(0x08, 0x004c, [0x02, 0x53, 0x80, 0xd5, 0x05, 0x50, 0x00, 0x55]), + reply(0x08, 0x002c, [0xff, 0x00, 0x00, 0x56, 0x00, 0xff, 0x00, 0x56]), + reply(0x08, 0x0034, [0xff, 0x00, 0xff, 0x57, 0xff, 0xc3, 0x5c, 0x37]), + reply(0x17, 0, [0x00]), + reply(0x0e, 0, [0x00]), + reply(0x08, 0x0060, [0x01, 0x01, 0x00, 0x53, 0x01, 0x02, 0x00, 0x52]), + reply(0x08, 0x0068, [0x01, 0x04, 0x00, 0x50, 0x01, 0x08, 0x00, 0x4c]), + reply(0x08, 0x0070, [0x01, 0x10, 0x00, 0x44, 0x02, 0x01, 0x00, 0x52]), + ]; + + const client = new AtkHidClient(fake); + const status = await client.readStatus(); + + assert.deepEqual(status.dpiStageColors, ["#ff0000", "#00ff00", "#ff00ff", "#ffc35c"]); + assert.equal(status.dpiLedMode, 0, "enabled flag 0 is Off even with a Breathing effect pair stored"); + assert.deepEqual(status.ui?.dpiLighting?.brightnessModes, [1], "no brightness control while breathing"); + assert.equal(status.longRangeMode, false); + assert.equal(status.performanceMode, undefined); + assert.equal(status.activeProfile, 1); + assert.equal(status.atkProfileCount, 4); + assert.deepEqual( + status.atkButtonMappings?.map((mapping) => mapping.action), + ["Left click", "Right click", "Middle click", "Back", "Forward", "DPI cycle"], + ); + assert.equal(status.name, "VXE R1 Pro"); + assert.deepEqual(status.dpiStages, [400, 800, 3200, 1200]); + assert.equal(status.activeDpiStage, 3); + assert.equal(status.dpi, 1200); + assert.equal(status.pollingRateHz, 1000); + assert.equal(status.connectionDetail, "2.4 GHz receiver"); + assert.equal(status.atkCatalogFeatures, undefined, "no ATK-vendor catalog flags leak onto a Compx device"); + assert.equal(client.maxDpi(), 30000); +}); + +test("a DPI row with a valid checksum but an impossible sensor code is not reported as a checksum failure", async () => { + // CID/MID 2,29 on 0xf58f is the catalog's PAW3395SE-based R1 SE; 0x07 is + // one of the codes that sensor never uses. + const fake = device(0xf58f, "VXE R1 SE"); + (fake as unknown as FakeR1ProMaxDevice).replies = [ + reply(0x10, 0, [0x02, 0x1d]), + reply(0x04, 0, [0x14, 0x00]), + reply(0x08, 0x0000, [0x01, 0x54, 0x01, 0x54, 0x00, 0x55]), + reply(0x08, 0x000c, [0x07, 0x07, 0x00, 0x47]), + ]; + + await assert.rejects( + new AtkHidClient(fake).readStatus(), + /cannot produce; the model may be misidentified/, + ); +}); + +// Frames below were captured from ATK HUB (v3-hub.atk.store) driving a VXE R1 +// Pro, firmware 1.20, through the 0x3554:0xf58a 1K dongle. +const R1_PRO_IDENTITY = reply(0x10, 0, [0x02, 0x08, 0x4b]); +const R1_PRO_SYSTEM = [0x01, 0x54, 0x04, 0x51, 0x03, 0x52, 0x00, 0x55, 0x00, 0x55]; + +function r1ProReceiver(): FakeR1ProMaxDevice { + return device(0xf58a, "VXE NordicMouse 1K Dongle") as unknown as FakeR1ProMaxDevice; +} + +test("R1 Pro receiver writes a DPI stage as the vendor's two-stage group and waits for the echo", async () => { + const fake = r1ProReceiver(); + const group = [0x3f, 0x3f, 0x00, 0xd7, 0x1d, 0x1d, 0x00, 0x1b]; + fake.replies = [ + R1_PRO_IDENTITY, + reply(0x08, 0x0000, R1_PRO_SYSTEM.slice(0, 6)), + reply(0x08, 0x0014, [0x3f, 0x3f, 0x00, 0xd7, 0x17, 0x17, 0x00, 0x27]), + reply(0x08, 0x0018, [0x1d, 0x1d, 0x00, 0x1b]), + ]; + fake.writeReplies = [reply(0x07, 0x0014, group)]; + + const client = new AtkHidClient(fake as unknown as HIDDevice); + assert.equal(await client.setDpiStageValue(3, 1500), 1500); + + const sent = writes(fake as unknown as HIDDevice); + assert.equal(sent.length, 1); + assert.deepEqual([...sent[0]!.subarray(0, 13)], [0x07, 0x00, 0x00, 0x14, 0x08, ...group]); + assert.equal(sent[0]![15], 0x80, "frame checksum matches the captured vendor write"); +}); + +test("R1 Pro receiver changes polling through the complete system row", async () => { + const fake = r1ProReceiver(); + const row = [0x02, 0x53, ...R1_PRO_SYSTEM.slice(2)]; + fake.replies = [ + R1_PRO_IDENTITY, + reply(0x08, 0x0000, R1_PRO_SYSTEM), + reply(0x08, 0x0000, row.slice(0, 6)), + ]; + fake.writeReplies = [reply(0x07, 0x0000, row)]; + + const client = new AtkHidClient(fake as unknown as HIDDevice); + assert.equal(await client.setPollingRate(500), 500); + assert.deepEqual([...writes(fake as unknown as HIDDevice)[0]!.subarray(0, 15)], [0x07, 0x00, 0x00, 0x00, 0x0a, ...row]); +}); + +test("R1 Pro receiver turns DPI lighting off through the enabled flag and keeps the stored brightness", async () => { + const fake = r1ProReceiver(); + const sentRow = [0x00, 0x00, 0x10, 0x45, 0x01, 0x54, 0x00, 0x55]; + fake.replies = [ + R1_PRO_IDENTITY, + reply(0x08, 0x004c, [0x01, 0x54, 0x10, 0x45, 0x01, 0x54, 0x01, 0x54]), + // The mouse keeps a Breathing effect pair rather than the 00 00 it was sent. + reply(0x08, 0x004c, [0x02, 0x53, 0x10, 0x45, 0x01, 0x54, 0x00, 0x55]), + ]; + fake.writeReplies = [reply(0x07, 0x004c, sentRow)]; + + const client = new AtkHidClient(fake as unknown as HIDDevice); + await client.setDpiLighting(0, 0, 0); + + const sent = writes(fake as unknown as HIDDevice); + assert.deepEqual([...sent[0]!.subarray(0, 13)], [0x07, 0x00, 0x00, 0x4c, 0x08, ...sentRow]); + assert.equal(sent[0]![15], 0xf3, "frame checksum matches the captured vendor write"); +}); + +test("R1 Pro receiver switches configuration banks with the captured select/echo/readback exchange", async () => { + const fake = r1ProReceiver(); + const select = reply(0x0f, 0, [0x01]); + fake.replies = [R1_PRO_IDENTITY, select, reply(0x0e, 0, [0x01])]; + + const client = new AtkHidClient(fake as unknown as HIDDevice); + assert.equal(await client.setR1ActiveProfile(2), 2); + + const sent = fake.sent.map(({ data }) => [...data]).find((frame) => frame[0] === 0x0f); + assert.deepEqual(sent, select); + assert.equal(select[15], 0x3c, "frame checksum matches the captured vendor write"); +}); + +test("R1 Pro receiver refuses Performance Mode, which ATK HUB does not offer for it", async () => { + const fake = r1ProReceiver(); + fake.replies = [R1_PRO_IDENTITY]; + + const client = new AtkHidClient(fake as unknown as HIDDevice); + await assert.rejects(client.setPerformanceMode(true), /Performance mode is not available/); + assert.equal(writes(fake as unknown as HIDDevice).length, 0); +}); diff --git a/src/drivers/mouse-types.ts b/src/drivers/mouse-types.ts index 78bb6c0f..91643724 100644 --- a/src/drivers/mouse-types.ts +++ b/src/drivers/mouse-types.ts @@ -77,6 +77,11 @@ export interface MouseUiHints { dpiLighting?: { modes: readonly (0 | 1 | 2)[]; brightness: readonly number[]; + /** + * Modes in which brightness can be changed. Omitted when every lit mode + * accepts it; a mouse whose breathing effect has no brightness lists [1]. + */ + brightnessModes?: readonly (1 | 2)[]; speed: readonly number[]; /** Optional DPI-indicator-only sleep values in seconds. */ sleepTimeouts?: readonly number[]; From 476d30eab15ea5b6d8ee7fb30a36d48430e6edce Mon Sep 17 00:00:00 2001 From: wiz <76851476+wizpizz@users.noreply.github.com> Date: Sat, 14 Nov 2026 19:13:14 +0100 Subject: [PATCH 2/2] fix(atk): serialize advanced-row read/modify/write transactions Setters that patch one field of the shared 0x00a9 advanced row read the whole row, patch it and write it back. Two such setters running at once could both read the old row, and the second write would undo the first. Hold the whole transaction under a separate row lock; the inner reads and writes still use the per-exchange queue. --- src/drivers/atk/hid.ts | 74 ++++++++++++++++---------- src/drivers/atk/r1-pro-max-hid.test.ts | 28 ++++++++++ 2 files changed, 74 insertions(+), 28 deletions(-) diff --git a/src/drivers/atk/hid.ts b/src/drivers/atk/hid.ts index eec1b2f5..7867e8e0 100644 --- a/src/drivers/atk/hid.ts +++ b/src/drivers/atk/hid.ts @@ -156,6 +156,8 @@ export class AtkHidClient { readonly device: HIDDevice; private queue: Promise = Promise.resolve(); + /** Serializes whole read/patch/write transactions on shared EEPROM rows. */ + private rowQueue: Promise = Promise.resolve(); private lastStatus: MouseStatus | null = null; private product: AtkProduct | null = null; private identified = false; @@ -1184,10 +1186,12 @@ export class AtkHidClient { /** The advanced block is written whole, so read it back, patch one pair, write. */ private async writeAdvanced(offset: number, value: number): Promise { - const group = Array.from(await this.read(REGISTER.advanced, ADVANCED_LENGTH)); - group.splice(offset, 2, ...wePackScalarPair(value)); - await this.write(REGISTER.advanced, group); - return (await this.read(REGISTER.advanced, ADVANCED_LENGTH))[offset]; + return await this.inRowTransaction(async () => { + const group = Array.from(await this.read(REGISTER.advanced, ADVANCED_LENGTH)); + group.splice(offset, 2, ...wePackScalarPair(value)); + await this.write(REGISTER.advanced, group); + return (await this.read(REGISTER.advanced, ADVANCED_LENGTH))[offset]; + }); } /** @@ -1769,32 +1773,34 @@ export class AtkHidClient { } const address = REGISTER.advanced; - const block = Array.from(await this.read(address, ADVANCED_LENGTH)); - block.splice(offset, 2, ...wePackScalarPair(value)); - - const payload = weBuildCmdPayload( - WE_CMD_WRITE_EEPROM, - [ - 0, - (address >> 8) & 0xff, - address & 0xff, - block.length, - ...block, - ], - ); + return await this.inRowTransaction(async () => { + const block = Array.from(await this.read(address, ADVANCED_LENGTH)); + block.splice(offset, 2, ...wePackScalarPair(value)); + + const payload = weBuildCmdPayload( + WE_CMD_WRITE_EEPROM, + [ + 0, + (address >> 8) & 0xff, + address & 0xff, + block.length, + ...block, + ], + ); - await this.exchange( - payload, - (frame) => frame[0] === WE_CMD_WRITE_EEPROM - && frame[1] === 0 - && frame[2] === ((address >> 8) & 0xff) - && frame[3] === (address & 0xff) - && frame[4] === block.length - && this.hasValidChecksum(frame) - && block.every((byte, index) => frame[DATA_OFFSET + index] === byte), - ); + await this.exchange( + payload, + (frame) => frame[0] === WE_CMD_WRITE_EEPROM + && frame[1] === 0 + && frame[2] === ((address >> 8) & 0xff) + && frame[3] === (address & 0xff) + && frame[4] === block.length + && this.hasValidChecksum(frame) + && block.every((byte, index) => frame[DATA_OFFSET + index] === byte), + ); - return (await this.read(address, ADVANCED_LENGTH))[offset]!; + return (await this.read(address, ADVANCED_LENGTH))[offset]!; + }); } /** @@ -1957,6 +1963,18 @@ export class AtkHidClient { this.queue = started.catch(() => undefined); return await started; } + + /** + * Holds a whole read/patch/write of a shared row, so two setters patching + * different fields cannot both read the old row and overwrite each other. + * The task's own reads and writes still go through run(); this is a + * separate chain, so nesting cannot deadlock. + */ + private async inRowTransaction(task: () => Promise): Promise { + const started = this.rowQueue.then(task, task); + this.rowQueue = started.catch(() => undefined); + return await started; + } } function copyDataView(view: DataView): Uint8Array { diff --git a/src/drivers/atk/r1-pro-max-hid.test.ts b/src/drivers/atk/r1-pro-max-hid.test.ts index a65cabb6..392a5dc4 100644 --- a/src/drivers/atk/r1-pro-max-hid.test.ts +++ b/src/drivers/atk/r1-pro-max-hid.test.ts @@ -942,3 +942,31 @@ test("R1 Pro receiver refuses Performance Mode, which ATK HUB does not offer for await assert.rejects(client.setPerformanceMode(true), /Performance mode is not available/); assert.equal(writes(fake as unknown as HIDDevice).length, 0); }); + +test("R1 Pro Max receiver keeps concurrent advanced-row writes from overwriting each other", async () => { + const fake = device(0xf58a, "VXE R1 Pro Max Receiver"); + const hardware = fake as unknown as FakeR1ProMaxDevice; + // Stateful advanced row: reads return what the last write stored. + let row = [0x04, 0x51, 0x01, 0x54, 0x06, 0x4f, 0x01, 0x54, 0x01, 0x54]; + const send = hardware.sendReport.bind(hardware); + hardware.sendReport = async (reportId: number, data: ArrayBuffer) => { + const frame = new Uint8Array(data); + if (frame[0] === 0x10) hardware.replies = [reply(0x10, 0, [0x02, 0x1b])]; + if (frame[0] === 0x08 && frame[3] === 0xa9) hardware.replies = [reply(0x08, 0x00a9, row)]; + if (frame[0] === 0x07 && frame[3] === 0xa9) { + row = [...frame.subarray(5, 15)]; + hardware.writeReplies = [reply(0x07, 0x00a9, row)]; + } + await send(reportId, data); + }; + + const client = new AtkHidClient(fake); + const [motionSync, ripple] = await Promise.all([ + client.setMotionSync(false), + client.setRippleControl(false), + ]); + + assert.equal(motionSync, false); + assert.equal(ripple, false); + assert.deepEqual(row, [0x04, 0x51, 0x00, 0x55, 0x06, 0x4f, 0x01, 0x54, 0x00, 0x55]); +});