Shop OBEX P1 Docs P2 Docs Learn Events
USB Gamepad Implementation - Page 3 — Parallax Forums

USB Gamepad Implementation

13

Comments

  • RaymanRayman Posts: 14,640

    Will this work with Xbox one wired controller?

    Any chance of getting headphones/mic working?

  • @Rayman said:
    Will this work with Xbox one wired controller?

    I actually have no idea. Would have to plug one in and see what it does.

    Any chance of getting headphones/mic working?

    In theory yes, but in practice, "Why?".

  • Wuerfel_21Wuerfel_21 Posts: 5,052
    edited 2022-04-15 14:27

    Here's a wireshark capture of plugging the 8bitdo controller into a Linux machine (with X held down to force XInput as to avoid noise from the autodetect process) and moving the left stick around (had to open jstest-gtk as it apparently doesn't get polled if no program is reading it).
    Hmm, anything in there we aren't doing? I do see the LED set command in there, but that hangs when we do it, so one of the earlier packets must be the key. I think we also do set_configuration, soooo uhhh, idk. Those String requests? I wouldn't believe it.

    Would be handy to have a USB MITM device....

    (I also verfied what happens when we poll it: It just returns NAKs)

    EDIT: Wait no, the OUT is supposed to go to endpoint 2???

  • @Wuerfel_21 said:
    Here's a wireshark capture of plugging the 8bitdo controller into a Linux machine (with X held down to force XInput as to avoid noise from the autodetect process) and moving the left stick around (had to open jstest-gtk as it apparently doesn't get polled if no program is reading it).

    Is there a way to save a human-readable format ? I'm a bit too lazy to install wireshark...

    EDIT: Wait no, the OUT is supposed to go to endpoint 2???

    Possibly, however I don't think it is currently easy to send data to the out endpoint.

  • Wuerfel_21Wuerfel_21 Posts: 5,052
    edited 2022-04-15 15:11

    @macca said:

    @Wuerfel_21 said:
    Here's a wireshark capture of plugging the 8bitdo controller into a Linux machine (with X held down to force XInput as to avoid noise from the autodetect process) and moving the left stick around (had to open jstest-gtk as it apparently doesn't get polled if no program is reading it).

    Is there a way to save a human-readable format ? I'm a bit too lazy to install wireshark...

    Yes, but it's pretty hard to read.... (I've cut off the hub port reset sequence at the beginning and most of the polled data at the end for ease of reading) (0014008000000000000000000000000000000000 is the report for "X button held down", if you don't recognize it)

    EDIT: Wait no, the OUT is supposed to go to endpoint 2???

    Possibly, however I don't think it is currently easy to send data to the out endpoint.

    I tried and I think it works, because any other value other than 1<<15 causes failure, but still no data (and the LEDs don't set). Also tried sending a rumble packet, no dice.

                    loc     ptra, #led_cmd
                    mov     pkt_data,#3
                    mov     ep_addr_pid,hpad_ep_addr
                    setbyte ep_addr_pid,#PID_OUT,#0
                    add     ep_addr_pid,##1<<15
                    call    #calc_crc5
                    call    #txn_out
                    mov     ep_addr_pid, hctrl_ep_addr
    
  • @Wuerfel_21 said:
    Yes, but it's pretty hard to read.... (I've cut off the hub port reset sequence at the beginning and most of the polled data at the end for ease of reading) (0014008000000000000000000000000000000000 is the report for "X button held down", if you don't recognize it)

    Definitely the LEDs are written to the out endpoint 2.

    I tried and I think it works, because any other value other than 1<<15 causes failure, but still no data (and the LEDs don't set). Also tried sending a rumble packet, no dice.

                    loc     ptra, #led_cmd
                    mov     pkt_data,#3
                    mov     ep_addr_pid,hpad_ep_addr
                    setbyte ep_addr_pid,#PID_OUT,#0
                    add     ep_addr_pid,##1<<15
                    call    #calc_crc5
                    call    #txn_out
                    mov     ep_addr_pid, hctrl_ep_addr
    

    Hmmm.... hard to tell but don't think the ep_addr_pid will be correct, the add 1<<15 seems increment the endpoint number (ok), however the msb of endpoint seems still set, and for an out endpoint is must be reset (0x82 in, 0x02 out)

                    rdbyte  hr1, ptrb[ENDP_bAddress]
                    testb   hr1, #7                 wc      ' FIXME: define constant for endpoint IN/OUT bit
                    ...
                    shl     hr1, #8 + 7
                    ...
                    mov     hkbd_ep_addr, hctrl_ep_addr
                    and     hkbd_ep_addr, ##ADDR_MASK
                    or      hkbd_ep_addr, hr1               ' IN endpoint address
    

    You can try to fake the calculation by manually set hr1 to 0x02.

  • Wuerfel_21Wuerfel_21 Posts: 5,052
    edited 2022-04-15 17:04

    @macca said:

    I tried and I think it works, because any other value other than 1<<15 causes failure, but still no data (and the LEDs don't set). Also tried sending a rumble packet, no dice.

                    loc     ptra, #led_cmd
                    mov     pkt_data,#3
                    mov     ep_addr_pid,hpad_ep_addr
                    setbyte ep_addr_pid,#PID_OUT,#0
                    add     ep_addr_pid,##1<<15
                    call    #calc_crc5
                    call    #txn_out
                    mov     ep_addr_pid, hctrl_ep_addr
    

    Hmmm.... hard to tell but don't think the ep_addr_pid will be correct, the add 1<<15 seems increment the endpoint number (ok), however the msb of endpoint seems still set, and for an out endpoint is must be reset (0x82 in, 0x02 out)

                    rdbyte  hr1, ptrb[ENDP_bAddress]
                    testb   hr1, #7                 wc      ' FIXME: define constant for endpoint IN/OUT bit
                    ...
                    shl     hr1, #8 + 7
                    ...
                    mov     hkbd_ep_addr, hctrl_ep_addr
                    and     hkbd_ep_addr, ##ADDR_MASK
                    or      hkbd_ep_addr, hr1               ' IN endpoint address
    

    You can try to fake the calculation by manually set hr1 to 0x02.

    But the endpoint field in ep_addr_pid is only 4 bits. I don't think that applies here?

  • @Wuerfel_21 said:
    But the endpoint field in ep_addr_pid is only 4 bits. I don't think that applies here?

    Ah, yes, your are right, calc_crc5 clears it, I did a quick test and the two ends with only the endpoint value different.

  • So I guess it is to be concluded that the LED write is not what causes the pad to give up the goods.

  • Wuerfel_21Wuerfel_21 Posts: 5,052
    edited 2022-04-15 18:01

    So I've been messing about with the gamepad init code and just happened to plug in the StrikeFX dongle and IT WORKS NOW. Traced back my steps and it seems the trick is to skip trying to read a HID descriptor for XInput devices. I tried to avoid it initially but I guess I did something wrong then. Anyways now it works, cool.

    (And yes, StrikeFX in HID mode is still broken for some reason, lol)

    (Yep, the axes center at +128 instead of zero. Amazing. Analog triggers work nicely though.)

    Also interesting: It doesn't seem to respond to the LED/rumble commands, so I think that I may still be doing that wrong.

  • @Wuerfel_21 said:
    So I guess it is to be concluded that the LED write is not what causes the pad to give up the goods.

    I see that there are a number of packets between the led message submit and the completion (get descriptor for example), I don't know the low level details of USB, but maybe it is an asynchronous message ? I don't know if the driver can send and forget... or has queue of some kind...

    So I've been messing about with the gamepad init code and just happened to plug in the StrikeFX dongle and IT WORKS NOW. Traced back my steps and it seems the trick is to skip trying to read a HID descriptor for XInput devices. I tried to avoid it initially but I guess I did something wrong then. Anyways now it works, cool.

    Good. I was wondering if read the report descriptor for Xinput is really necessary, so the check can be moved before reading the descriptor ?

  • @macca said:

    @Wuerfel_21 said:
    So I guess it is to be concluded that the LED write is not what causes the pad to give up the goods.

    I see that there are a number of packets between the led message submit and the completion (get descriptor for example), I don't know the low level details of USB, but maybe it is an asynchronous message ? I don't know if the driver can send and forget... or has queue of some kind...

    Yeah. But it goes through, so I guess it just waits until the response. Since the StrikeFX is supposed to respond to LED and rumble messages and doesn't to mine, I can tell I'm still doing something wrong (I've also tried reloading the code with it still plugged in to rule out the possibility of the initial message getting dropped because the controller isn't connected to the dongle yet)

    So I've been messing about with the gamepad init code and just happened to plug in the StrikeFX dongle and IT WORKS NOW. Traced back my steps and it seems the trick is to skip trying to read a HID descriptor for XInput devices. I tried to avoid it initially but I guess I did something wrong then. Anyways now it works, cool.

    Good. I was wondering if read the report descriptor for Xinput is really necessary, so the check can be moved before reading the descriptor ?

    Yep, that's what I did.

  • Well, believe it or not, I got the XInput OUT messages to finally work. Turns out to be a DATA0/DATA1 issue. Lmao.

    This can set LEDs and trigger rumble on the StrikeFX and also the SN30Pro, but the latter still isn't polling any data.

                    loc     ptra, #led_cmd
                    mov     pkt_data,#3
                    'loc    ptra, #rumble_cmd
                    'mov    pkt_data,#8
                    bitl    hstatus, #DATAx_TGLB
                    mov     ep_addr_pid,hpad_ep_addr
                    setbyte ep_addr_pid,#PID_OUT,#0
                    add     ep_addr_pid,##1<<15
                    debug(uhex_long(ep_addr_pid))
                    call    #calc_crc5
                    call    #txn_out
                    mov     ep_addr_pid, hctrl_ep_addr
    
  • @Wuerfel_21 said:
    Well, believe it or not, I got the XInput OUT messages to finally work. Turns out to be a DATA0/DATA1 issue. Lmao.

    Very good!

    This can set LEDs and trigger rumble on the StrikeFX and also the SN30Pro, but the latter still isn't polling any data.

    Ok, I think we need some way to set these things from the application, some CMD_* to use with execCmd. AFAIK, it doesn't allow parameters, for LEDs should not be a problem to have CMD_SETLED1, CMD_SETLED2, ecc., for rumble however it needs something more detailed.

  • @macca said:

    @Wuerfel_21 said:
    Well, believe it or not, I got the XInput OUT messages to finally work. Turns out to be a DATA0/DATA1 issue. Lmao.

    Very good!

    This can set LEDs and trigger rumble on the StrikeFX and also the SN30Pro, but the latter still isn't polling any data.

    Ok, I think we need some way to set these things from the application, some CMD_* to use with execCmd. AFAIK, it doesn't allow parameters, for LEDs should not be a problem to have CMD_SETLED1, CMD_SETLED2, ecc., for rumble however it needs something more detailed.

    Rumble is a bit complex, ye. Though the XInput LEDs technically are, too, it seems that the pads I have on hand really only support the four regular indicator states ($02 through $05)

  • roglohrogloh Posts: 5,786
    edited 2022-04-16 02:21

    I found some information online regarding PS3 rumble controller commands....someone did a ESP32 bluetooth interface but I think the command bits would potentially be the same over USB. It also showed how to setup LED status bits too and get accelerometer/gyro readings.

    https://github.com/jvpernis/esp32-ps3/tree/master/src

    By the way the different buttons on the PS3 controller can report analog pressure as well (separately to normal digital press) via more axis data in the report.

  • I also have this old Logitech force feedback USB steering wheel controller for a PC. When I get a chance later today I'll try to hook it up and see if it reports anything in this code. Would be rather cool if they work too.

  • maccamacca Posts: 780
    edited 2022-04-18 07:20

    If I did everything right, today's update includes:

    1. Axis value normalization to -32768 / 32767 (word signed integer)
    2. PS3 and XInput LEDs message fix
    3. Console output changed to display the axis name and normalized value

    About the LEDs, seems that the PS3 mode needs the led command before the enable command, so this information must be set on startup. XInput LEDs on the other end, seems to have a number of funny modes so it deserves a dedicated command from the application.

    @rogloh said:
    By the way the different buttons on the PS3 controller can report analog pressure as well (separately to normal digital press) via more axis data in the report.

    Ah, yes, I remembered that the controller had this feature!
    I think that PS3 needs a dedicated decoder like XInput.

  • XInput axes got busted. Needs to be like this (*_AXIS are bits, so need to be encod-ed. Also changed the Y inversion to ones complement so it stays in 16 bit range):

      axis[encod X_AXIS] := word[data+ 6] signx 15 ' Left stick X
      axis[encod Y_AXIS] := (!word[data+ 8]) signx 15 ' Left stick Y (inverted)
      axis[encod Z_AXIS] := word[data+10] signx 15 ' Right stick X
      axis[encod RZ_AXIS] := (!word[data+12]) signx 15 ' Right stick Y (inverted)
      axis[encod RX_AXIS] := byte[data+4] ' left analog trigger
      axis[encod RY_AXIS] := byte[data+5] ' right analog trigger
    
  • maccamacca Posts: 780
    edited 2022-04-16 11:20

    @Wuerfel_21 said:
    XInput axes got busted. Needs to be like this (*_AXIS are bits, so need to be encod-ed. Also changed the Y inversion to ones complement so it stays in 16 bit range):

    Ahhhhh... no, those constants should be index numbers not bits, too much copy and paste... *_AXIS is the element index, HAS_*_AXIS is the bit!
    Package updated.

  • roglohrogloh Posts: 5,786
    edited 2022-04-17 01:22

    @rogloh said:
    I also have this old Logitech force feedback USB steering wheel controller for a PC. When I get a chance later today I'll try to hook it up and see if it reports anything in this code. Would be rather cool if they work too.

    Just hooked up this Logitech MOMO steering wheel controller to the P2 and it worked! :smile:

    Once USB is connected it lights the power LED on the steering wheel and actively resists turning the wheel. The amount of force feedback resisting turning the wheel seems very strong indeed by default but it still worked and lets me press all the 6 buttons on the front of the steering wheel, two paddle buttons, two gear change buttons. The steering wheel controls the X axis and the brake/accel pedals change the Y axis (each pedal pushed offsets from the center in a different axis direction).

    It would be nice to be able to control/reduce the amount of force feedback at some point and be able to light the other LED (which I think was meant to indicate force feedback is on) but I have no idea what controls that. The only scant information I found so far in a brief hunt was this...and whether it even applies to this particular wheel is unknown.
    https://www.microchip.com/forums/m573610.aspx

    Here's the data it reported with the latest version of this gamepad driver.

    roger$ loadp2 -t -b 2000000 MiniKbMObjDemo.binary 
    ( Entering terminal mode.  Press Ctrl-] or Ctrl-Z to exit. )
    Cog0  INIT $0000_0000 $0000_0000 load
    Cog0  INIT $0000_0404 $0000_0000 load
    Mini Client + USB low/full speed keyboard/mouse/gamepad v0.1.4+r3
    Sysclock: 180000000, Clkmode: $10008FB, Baud: 2000000
    Cog1  INIT $0000_3EA8 $0000_5A9C load
    Cog1  class=$03, subclass=$00, protocol=$00
    Cog1  Report Desc. $05, $01, $09, $04, $A1, $01, $A1, $02, $95, $01, $75, $0A, $15, $00, $26, $FF, $03, $35, $00, $46, $FF, $03, $09, $30, $81, $02, $95, $0A, $75, $01, $25, $01, $45, $01, $05, $09, $19, $01, $29, $0A, $81, $02, $06, $00, $FF, $09, $00, $95, $04, $81, $02, $95, $01, $75, $08, $26, $FF, $00, $46, $FF, $00, $05, $01, $09, $31, $81, $02, $95, $03, $06, $00, $FF, $09, $01, $81, $02, $C0, $A1, $02, $09, $02, $95, $07, $91, $02, $C0, $C0
    P2RevB+ detected, USB driver version v0.1.4+r3
    PortA started: cogID 1, event pin# 40
    PortA device idVendor=046D, idProduct=CA03, bcdDevice=0110
    PortA gamepad configured, 2 axes, 0 hats, 10 buttons
    PortA [FF 01 20 7F FF FF 82 00 00 00] axes [X:-33 Y:-129 Z:ND RX:ND RY:ND RZ:ND] hats [] btn [0000000000]
    PortA [FE 01 20 7F FF FF 82 00 00 00] axes [X:-97 Y:-129 Z:ND RX:ND RY:ND RZ:ND] hats [] btn [0000000000]
    PortA [FD 01 20 7F FF FF 82 00 00 00] axes [X:-161 Y:-129 Z:ND RX:ND RY:ND RZ:ND] hats [] btn [0000000000]
    PortA [FC 01 20 7F FF FF 82 00 00 00] axes [X:-225 Y:-129 Z:ND RX:ND RY:ND RZ:ND] hats [] btn [0000000000]
    PortA [FB 01 20 7F FF FF 82 00 00 00] axes [X:-289 Y:-129 Z:ND RX:ND RY:ND RZ:ND] hats [] btn [0000000000]
    
  • Huh, RE: Axis normalization.

    The XInput analog triggers are still going 0 to 255. The GC adapter (only HID device I can find that does analog triggers) ones are going -32k to +32k now. I don't think the descriptor declares them any different from the stick axes, so uhhhhhh. IDK what to do about all this.

  • @rogloh said:
    Just hooked up this Logitech MOMO steering wheel controller to the P2 and it worked! :smile:

    Very good!

    It would be nice to be able to control/reduce the amount of force feedback at some point and be able to light the other LED (which I think was meant to indicate force feedback is on) but I have no idea what controls that. The only scant information I found so far in a brief hunt was this...and whether it even applies to this particular wheel is unknown.
    https://www.microchip.com/forums/m573610.aspx

    This kind of settings are controller-specific and needs specialized methods for software applications. Currently the driver doesn't allow to send arbitrary messages from the application, see also the LED settings, it needs to implement some commands to allow that.

    @Wuerfel_21 said:
    Huh, RE: Axis normalization.

    The XInput analog triggers are still going 0 to 255. The GC adapter (only HID device I can find that does analog triggers) ones are going -32k to +32k now. I don't think the descriptor declares them any different from the stick axes, so uhhhhhh. IDK what to do about all this.

    Probably because I forgot to normalize them :)
    Package updated...
    (I'll purchase an XInput controller... it is already on the Amazon cart...)

  • maccamacca Posts: 780
    edited 2022-04-18 13:53

    Ready for a real world application ?

    Here is the Space Invaders arcade emulation from https://forums.parallax.com/discussion/172813/p2-space-invaders-8080-emulation with pasm-only USB support.

    It allows to play with a keyboard or a game controller. Driver support should be nearly at the level of the Spin driver, so includes XInput, PS3 and generic HID controllers, with some experimental modifications.

    Keyboard controls are LEFT/RIGHT arrows, SPACE to fire and ENTER to play.
    Gamepad controls are LEFT/RIGHT dpad, if present as hat, or LEFT stick (or whatever it is defined as X axis), A/B buttons (or equivalent) as fire, and START (or equivalent) to play.

    Beware that the controls are directed to the same pins used as buttons (4, 5, 6 and 7), since they are driven by the propeller I think is better to not have anything connected to them.

    Enjoy!

  • Haven't examined the code yet, but did plug in a bunch of stuff...

    • XInput is busted (no input at all)
    • Gamecube adapter is busted
    • Buttons on the flight stick don't work (recall, that's the one with the multiple button fields)
    • The X/Y axes shouldn't be ignored if a hat is present

    Otherwise works fine.

  • @Wuerfel_21 said:

    • XInput is busted (no input at all)
    • Gamecube adapter is busted

    Try now, XInput should work, not sure about the Gamecube adapter.

    • Buttons on the flight stick don't work (recall, that's the one with the multiple button fields)

    That should work... will check.

    • The X/Y axes shouldn't be ignored if a hat is present

    It is to simplify things.

  • Yep, XInput fixed.

  • @Wuerfel_21 said:

    • Gamecube adapter is busted

    Gamecube should work now, wrong action with the multiple reports id...

  • Nah, still doesn't. There's some issue with how the buttons are decoded, it seems. It only really picks up the hat control.

  • So, what about making the second port work? The driver seems to be written to really only work with one, so I guess some major rewriting would have to occur.

Sign In or Register to comment.