Close

Xbox One Adaptive controller

A project log for BlueRetro

Multiplayer Bluetooth controllers adapter for retro video game consoles

Jacques GagnonJacques Gagnon 06/28/2020 at 15:400 Comments

I got the Xbox adaptive controller for a few weeks now and it's quite an impressive device. Its goal is to help gamers with limited mobility. But once you know how it works you can actually use it to interface with any device you can think of others than gaming. I will document what I learned so far in this log.

I already added support for the controller in BlueRetro:

See my previous log post about Bluetooth first if you are new to Bluetooth.

The controller is pretty much a superset of the regular Xbox One S controller but in some case it behaves differently.

Discovery process

The adaptive controller report a different name than the original controller so this is an easy way to identify it.

{"Xbox Wireless Controller", XB1_S},
{"Xbox Adaptive Controller", XB1_ADAPTIVE},

A regular controller will make a few SDP request* to identify the host and use that information to either report a XInput style HID descriptor or a DInput style one. The adaptive controller, however, don't seem to do any SDP request and always report the DInput style HID descriptor.

*See packets 120, 126 & 129 in blueretro_xb1_s_inquiry.pcapng.

HID Descriptor

The adaptive controller got a really massive descriptor at over 1 KB in size. It's essentially an expanded version of the regular controller DInput descriptor. Report 2, 3 & 4 are identical. Seven new reports are included. Like the original controller each usage is aligned on 8 bytes boundary making parsing easier but take more space due to unused bits (Probably not an issue nowadays).

Report 1 first 16 bytes match the original report 1 exactly. It is the axes & buttons following the adaptive controller remapping functionality. The next 16 bytes again is a copy of the original report but with all usage code change to avoid usage collision in the descriptor. That copy report the raw values of the hardware ignoring any mapping configuration. 

/* Original Xbox One S dinput report 1 */
struct xb1_dinput_r1 {
    uint16_t lx; //16 bits
    uint16_t ly; //16 bits
    uint16_t rx; //16 bits
    uint16_t ry; //16 bits
    uint16_t lt; //10 bits
    uint16_t rt; //10 bits
    uint8_t hat; //4 bits
    uint16_t btns; //15 bits
    uint8_t view; //1 bit
};

/* Xbox adaptive report 1 */
struct xb1_adaptive_r1 {
    struct xb1_dinput_r1 mapped;
    struct xb1_dinput_r1 raw;
    uint8_t extra_btns; //4 bits
    uint8_t unknown; //4 bits
    uint8_t active_cfg; //8 bits
    uint8_t unknown2[20];
};

Then follow 22 new usages. The first one at byte offset 32 report the 4 extra buttons which only two (X1 & X2) got external connection. The other 2 are available only via USB joysticks. The third one at byte offset 34 report the currently used mapping 0 being the fixed default and 1, 2 & 3 reported while using either of the 3 mapping.

External accessories

Buttons

The controller expose 19x 3.5mm connectors to interface SPST button using mono plugs. The mapping function allows using buttons on axes but when pressed the maximum value is set on the axis. There is no way to configure a percentage of the max value to use.

The view (select) and menu (start) external buttons got a strange behavior. The embedded ones on the controller will report within the raw section of report 1. However when using the external button they are instead reported within the extra buttons 3 & 4 on byte offset 32.

Potentiometers

Only the LT & RT input allows using 10K potentiometer with a TRS plug and only when the function LT & RT are mapped to the input. Mapping a joystick direction on those input still result in a binary value 0 or max like for buttons input. 

The potentiometer is interface with the wiper on the tip and the track pins on the shield and ring. Logitech used TRRS plug but one of the ring is unused.

USB Joysticks

It is possible to connect two joysticks on the controller via the two USB A port. I was only able to test with Logitech Extreme 3D joystick as all my other USB gamepad I tested do nothing. I'm not sure if the adaptive controller support only specific USB device or it limit itself to only support HID Usage "Joystick".

Only the first 8 buttons are supported and are mapped differently if the joystick is using the left or right USB port. The USB joystick buttons are not configurable independently and will follow the configuration of their default value.

USB  LEFT        RIGHT
1    X1          View & X3
2    X2          Menu & X4
3    LJ          RJ
4    LB          RB
5    A           X
6    B           Y
7    View & X3   X1
8    Menu & X4   X2

Note that on the default mapping for X1 & X2 are configured as left stick UP and DOWN which is highly undesirable!

See Logitech USB joystick HID descriptor for reference.

Power

The adaptive controller got an internal battery but can be charge/power via an USB-C or a 5.5mm/2.5mm barrel jack with 5V/2A and center pin is positive  (Not the regular 5.5/2.1!!) . 

Discussions