Shop Learn P1 Docs P2 Docs
USB Gamepad Implementation — Parallax Forums

USB Gamepad Implementation

This discussion was created from comments split from: ColecoVision Emulator.
«134

Comments

  • Speaking of, I kindof want to investigate what it'd take to add game controller support to the USB driver (ironically probably not very useful for the ColecoVision). I think the main issue is that there isn't a mandated report format and it instead is to be divined from a descriptor. Though having seen a lot of controllers, I think they are all very similar (all of them seem to agree that the 10th button is start, for example, even if that means that there are some button bits below that don't map to any physical button).

  • maccamacca Posts: 506
    edited 2022-04-10 14:50

    @Wuerfel_21 said:
    Seems to work great. You even do the correct thing and scan the entire 6 keys instead of stopping at a zero (which was a bug in the original keyboard handling code, which I see you just threw out entirely).

    Yes, not my first USB ride :)

    Speaking of, I kindof want to investigate what it'd take to add game controller support to the USB driver (ironically probably not very useful for the ColecoVision). I think the main issue is that there isn't a mandated report format and it instead is to be divined from a descriptor. Though having seen a lot of controllers, I think they are all very similar (all of them seem to agree that the 10th button is start, for example, even if that means that there are some button bits below that don't map to any physical button).

    I too would like to do that. I have contributed the initial gamepad support for the RaspberryPi USPi framework so I have some experience with it.
    I have to refresh the memories but if I remember correctly, there is a descriptor that defines the meaning of each bit in the HID report, then the application software must map the correct "bit" to what it expect, and there isn't a well-defined standard, so that there is a database of controllers to help auto-configuring the software.
    Decoding the report is already a nightmare in C, I can't imagine how it is in PAsm...

  • Yeah, the HID report. As said, I suspect that 90% of devices use a very similar report format, so maybe a full implementation isn't neccessary. Gonna boot up the linux laptop now and dump the HID descriptor of every USB controller in the house (there's a lot of them) to confirm that suspicion.

    But even if the mapping of bits to inputs is figured out, no one agrees on the numbering of the face buttons (though I've never seen one where they aren't buttons 1 through 4 in some order, same for shoulder buttons on 5/6 7/8 and select/start on 9/10), so that needs to be configurable somehow.

  • pik33pik33 Posts: 1,759
    edited 2022-04-10 17:10

    I too would like to do that. I have contributed the initial gamepad support for the RaspberryPi USPi framework so I have some experience with it.

    Forked immediately. I use Ultibo to program RPi - it is Free Pascal based but it accepts .a libraries compiled from C code. While Ultibo still have no USB joystick and MIDI support, this library, if I manage to link it with Ultibo, can patch the problem. I created RPi Zero based keyboard and mouse interface for a P2 and a RPi official keyboard (with a hub inside) - adding game devices and MIDI over USB to it can be useful

    I suspect that 90% of devices use a very similar report format

    There are problems with details. Keyboards and mice uses 2 types of reports, "boot" and full mode. The boot mode is the same for them all for BIOS to easily initialize and use. It is sufficient for a keyboard, it reports modifiers (1 byte) and up to 6 pressed keys.

    The mice are different animals. The boot protocol doesn't support the wheel (although it actually has a field for this). I had to switch the mouse protocol to the full mode in my RPi Zero. Then there was another problem: I detected at least 5 different mouse protocols. X and Y deltas can be 8, 12 and 16 bits, for example. What I did was an algorithm which does what it can to determine what type of protocol the mouse uses. It works but is still not 100% reliable and works only for the mice I have possibility to test. Cheapest and simplest mice use the simplest 8 bit type, but more advanced ones uses these more complex variants.

  • Wuerfel_21Wuerfel_21 Posts: 3,142
    edited 2022-04-10 18:10

    Well, I've gone through the 8 DInput devices that didn't hide fast enough and while I haven't analyzed the dumped descriptors yet, I've got some insights on button maps:

    • 1..4 as face buttons is universal (sample size: 7)

      • North-East-South-West is most common order (sample size: 4.5)
    • 5/6 and 7/8 as shoulder buttons is universal (sample size: 7)

      • if there is only one set, it is 5/6 (sample size: 2.5)
    • 9/10 as select/start is universal (sample size: 7)

    • 11/12 as stick click is universal (sample size: 3.5)

    Though now that I'm thinking about it, it'd probably be more useful to figure out how the Xbox protocol works. Lots of stuff supports it these days and it doesn't cause any button mapping and format guessing headaches. It's not HID though, so IDK how that works.

    EDIT: seems that it may be as simple as detecting that VID == 0x45E && PID == 0x028E and polling 20 bytes of data from endpoint 1

    EDIT 2: No, it's not that simple, only one of my XInput devices actually works like that. Detecting these is a bit tougher then, I guess.

    EDIT 3: Ok, I think there just isn't a good way to detect these (going off of how xboxdrv does it), but for our limited purposes I think detecting device class == 0xFF might be fine? Will read garbage/errors if you were to plug in something that also uses that value, but like, who cares.

    Interesting in that regard is that the SNES bluetooth reciever I've got (that works nicely with P1) has a hidden bonus feature wherein the USB port that you'd use for firmware flashing also presents as an XBox controller (with working analog sticks, oddly even).

    Also, mods plz split USB controller discussion into own thread.

  • maccamacca Posts: 506

    @Wuerfel_21 said:
    Well, I've gone through the 8 DInput devices that didn't hide fast enough and while I haven't analyzed the dumped descriptors yet, I've got some insights on button maps:

    While we wait for the thread split, have some fun with the attached code.
    I have modified the 1CogKbM driver to detect and configure the gamepad, the demo code decodes the report descriptor and shows how the controller sends the buttons data (data is shown only when something is changed, like a button pressed or released). I don't have many controllers here but looks working correctly with all of them, hope it works with yours too.
    There is still a lot of things to do and check for correctness, and I had to modify the keyboard and mouse detection so they are now exclusive, will go back to this once the gamepad works.

    PortA descriptor:
    05 (04) 01 usage page 1
    09 (08) 04 usage 4
    A1 (A0) 01 collection 1
    A1 (A0) 02 collection 2
    75 (74) 08 report size 8
    ...
    26 (24) 00FF logical max 255
    09 (08) 02 usage 2
    91 (90) 02 output
    C0 (C0) end collection
    C0 (C0) end collection
    PortA btn: 7F 7F 80 80 80 0F 00 00
    
  • Neato, will get to this after I'm done messing with adding save support to megayume ;) (for today, anyways)

    Relatedly, I have actually ordered two more pads (can never have enough?), one of them being the SEGA Saturn USB pad mentioned in the other thread. I really want to see those working.

  • Well, the aforementioned saving thing kinda works (need to figure out a good heuristic for when to save, currently only does it when you quit to menu), so USB time.

    ...

    Well, it did something, but only for four of my devices. That's all the basic controllers though. The ones that didn't work are the more sophisticated devices.

    So here's my findings:

    Speedlink Strike2 generic gamepads (SL-6535-TGN and SL-6535-SGN)

    I have two of these and I'm pretty sure these are supposed to be the same SKU aside from shell color (translucent green vs solid green), yet inexplicably they seem to be based on different chipsets (and have different mapping quirks in digital mode). The -TGN one also lacks stick click buttons.
    These both seem to report like this: XL YL ?? XR YR BH BB ?? The first ?? byte is zero on the -TGN and seems to be some strange noisy value related to left stick X on the -SGN. The second ?? byte always has bit 6 set. The -TGN also always sets bit 4. And on both, bit 7 corrosponds to the analog/digital state (interesting, since that usually isn't exposed on the host).

    Speedlink StrikeFX wireless generic gamepad (SL-6567-BK) (and related dongle)

    Doesn't work. Gives a "PortA unknown device" line (since it boots in XInput mode) but switching it to DInput just prints PortA event lines.

    Trust generic gamepad (no model number) (also has a PS2 connector on it)

    Works. Report looks like ?? YR XR XL YL BH BB ??. Yeah, weird order. Same BH BB button/hat structure as the Strike2 controllers. Interesting.

    Logitech Extreme 3D Pro flight stick

    Works. Report format is really funky (Y axis seems to be 12 bit and buttons aren't contiguous)

    Various Mayflash brand adapter products

    Don't work. In particular:
    - DolphinBar (W010) prints PortA event lines (even in keyboard/mouse mode)
    - Quad GameCube adapter (W012): prints PortA event lines
    - Dual SNES adapter (MF105): PortA unknown device, doesn't seem to turn on properly, mode light stays unlit.

  • maccamacca Posts: 506

    @Wuerfel_21 said:
    Well, it did something, but only for four of my devices. That's all the basic controllers though. The ones that didn't work are the more sophisticated devices.

    This is expected for now, some controllers needs an activation message, in the USPi source there is a special check for PS3 controllers (vendor=054c, product=0268), I guess that some of yours needs that message. And anyway, I'm not 100% sure that the detection works reliably.

    These both seem to report like this: XL YL ?? XR YR BH BB ?? The first ?? byte is zero on the -TGN and seems to be some strange noisy value related to left stick X on the -SGN. The second ?? byte always has bit 6 set. The -TGN also always sets bit 4. And on both, bit 7 corrosponds to the analog/digital state (interesting, since that usually isn't exposed on the host).

    The descriptor is a bit hard to decode visually, the actual input is defined as number of bits starting from an offset, this can span multiple bytes or start in the midle of a byte. I have almost finished the decoder so the next source will give more interesting results with separated axes, hats and buttons states.

    If you want to enable debug mode and uncomment the line 1CogKbM.spin2:2473 it outputs the raw descriptor bytes that can be pasted here https://eleccelerator.com/usbdescreqparser/ to have a more nicely formatted description (like the one I put before the decodeReport method).

    Speedlink StrikeFX wireless generic gamepad (SL-6567-BK) (and related dongle)

    Doesn't work. Gives a "PortA unknown device" line (since it boots in XInput mode) but switching it to DInput just prints PortA event lines.

    I think this is one of those PS3-like devices that needs the activation message.
    Just for reference, the source detects a gamepad with class=3 (hid), subclass=0, protocol=0 (debug mode shows these informations).

    Various Mayflash brand adapter products

    Don't work. In particular:
    - DolphinBar (W010) prints PortA event lines (even in keyboard/mouse mode)
    - Quad GameCube adapter (W012): prints PortA event lines
    - Dual SNES adapter (MF105): PortA unknown device, doesn't seem to turn on properly, mode light stays unlit.

    Once we have a more stable source we can investigate each not-working device to see if there are special things to do.

  • Wuerfel_21Wuerfel_21 Posts: 3,142
    edited 2022-04-12 09:17

    Ah yes, DEBUG shows some more data.

    The non-working wireless pad, when it connects in DInput/HID mode, repeatedly prints the class=$03, subclass=$00, protocol=$00, so yeah I guess it doesn't initialize properly? XInput mode relates four lines:

    class=$FF, subclass=$5D, protocol=$01
    class=$FF, subclass=$5D, protocol=$02
    class=$FF, subclass=$5D, protocol=$03
    class=$FF, subclass=$FD, protocol=$13
    

    EDIT: Tried the aforementioned bluetooth receiver that also enumerates as an XInput device, and that has the the same four lines. I guess class=$FF, subclass=$5D, protocol=$01 is the one we want to detect as a gamepad?

    The SNES adapter appears as a hub class device, so yeah, that won't work without general hub support.
    The other two adapter devices seem to have the same issue where the class is right but they don't init. Maybe the issue is with them is that they're supposed to enumerate as multiple devices. Though the PS/2 kb/mouse adapter also does that and it works fine (the keyboard part, anyways).

  • maccamacca Posts: 506

    Attached a new version, with the (almost) full report decoder, this should give more interesting results.

    PortA device idVendor=0E8F, idProduct=0003, bcdDevice=0100
    PortA gamepad configured, 5 axes, 1 hats, 12 buttons
    PortA [80 80 80 80 00 0F 00 00] axes [80 80 80 80 00] hats [0F] btn [000000000000]
    

    The program now shows also the device vendor, product and version, so we can better understand what's going on.
    Also added the PS3 check and enablement (hopefully, I don't have a PS3 controller...) and restored the original enumeration, the gamepad is enabled only if it doesn't find a keyboard or mouse.

    @Wuerfel_21 said:
    The non-working wireless pad, when it connects in DInput/HID mode, repeatedly prints the class=$03, subclass=$00, protocol=$00, so yeah I guess it doesn't initialize properly? XInput mode relates four lines:

    class=$FF, subclass=$5D, protocol=$01
    class=$FF, subclass=$5D, protocol=$02
    class=$FF, subclass=$5D, protocol=$03
    class=$FF, subclass=$FD, protocol=$13
    

    EDIT: Tried the aforementioned bluetooth receiver that also enumerates as an XInput device, and that has the the same four lines. I guess class=$FF, subclass=$5D, protocol=$01 is the one we want to detect as a gamepad?

    Probably, but it requires specific handling, class=$FF means vendor specific, so anyone can do whatever it wants with it. The Circle framework, which has a more enhanced USB gamepad support, has a number of specific classes for PS3, PS4, Switch, etc. all based on the vendor/product id. I think that the best thing to do is try to poll the device anyway and let the application software handle the exceptions by looking at the vendor/product numbers. As of now however the driver fails if doesn't find the hid class.

  • Wuerfel_21Wuerfel_21 Posts: 3,142
    edited 2022-04-12 12:57

    @macca said:
    Probably, but it requires specific handling, class=$FF means vendor specific, so anyone can do whatever it wants with it. The Circle framework, which has a more enhanced USB gamepad support, has a number of specific classes for PS3, PS4, Switch, etc. all based on the vendor/product id. I think that the best thing to do is try to poll the device anyway and let the application software handle the exceptions by looking at the vendor/product numbers. As of now however the driver fails if doesn't find the hid class.

    Problem is that there are a lot of XInput devices and having a huge list of IDs (see link to xboxdrv source from earlier) seems wasteful and impractical. If we can confirm that all XInput devices use subclass $5D, I think that'd be a reasonable way to detect them (since whatever other devices that use class $FF wouldn't work, anyways). Do you have one on hand?

    Will try the new code later, have to do some gardenwork first.

  • Okay, quickly tried the new code. Seems to not quite work. Detecting the hats works, but somethings wrong with the axes (or it's just not printing them as I'd expect). Buttons on the Strike2 pads seem to be in the wrong order (I think this is an issue of MSB/LSB firstness) and on the logitech flight stick, it only sees 4 buttons (buttons 8 through 12, that is).

    I've attached the descriptor for the flight stick (that I've dumped on the aforementioned Linux laptop).

  • maccamacca Posts: 506

    @Wuerfel_21 said:
    Problem is that there are a lot of XInput devices and having a huge list of IDs (see link to xboxdrv source from earlier) seems wasteful and impractical. If we can confirm that all XInput devices use subclass $5D, I think that'd be a reasonable way to detect them (since whatever other devices that use class $FF wouldn't work, anyways). Do you have one on hand?

    Took a quick look at the xboxdrv source and the xpad kernel module, all seems to use the vendor+product. Using the class and subclass may be a solution, the risk is that other devices may be wrongly detected, I guess that nobody will throw random usb devices in a Propeller box... Anyway vendor+product is just a long, not a big waste, and the check can be made only one time.

    I don't have xbox-like pads, I'll see if I can find one.

    Okay, quickly tried the new code. Seems to not quite work. Detecting the hats works, but somethings wrong with the axes (or it's just not printing them as I'd expect). Buttons on the Strike2 pads seem to be in the wrong order (I think this is an issue of MSB/LSB firstness) and on the logitech flight stick, it only sees 4 buttons (buttons 8 through 12, that is).

    I've attached the descriptor for the flight stick (that I've dumped on the aforementioned Linux laptop).

    From the descriptor, the axes issue should be just a formatting, it is 10 bits while the display shows a byte, change ser.fhex at line 218 with ser.dec and it should display correctly. Then there is a block with Push/Pop that I need to see what it means, 8 buttons are within that block but I don't expect it to be ignored. From what I see from the report, it should have 3 axes (2x10 bits, 1x8 bits), 1 hat (4 bits), 8+4 buttons. There are also sliders that are not supported. Maybe it is interfering somehow.

    The button order should be correct, the bits are readed lsb->msb from each byte, so 4 bits at offset 8, are bits 3..0 from second byte (unless I'm missing something).

  • Wuerfel_21Wuerfel_21 Posts: 3,142
    edited 2022-04-12 17:43

    Okay, here's some more investigation on the devices that don't work.

    StrikeFX wireless pad (DInput mode): fails at hset_idle. Driver crashes(?) if I comment out the ACK check (see image). (Other devices still work even if I get rid of it entirely so IDK what that's there for)

    Mayflash quad gamecube adapter: fails at set_protocol and then also at hset_idle. If ACK check is commented out for both, it will read the data, but gets slightly confused by the four-port nature of the beast. It figures out the hat and buttons for the first port though. Success? I think it also drops a byte off the report, the right trigger analog value isn't in there and since the left trigger is the last byte, I presume it drops it due to not accounting for the port number byte)
    (Pictured: controller in port 1, A button held)

    Mayflash DolphinBar: Works in gamepad mode with the same hack and the same 4-in-1 decoding issue. Almost like they're made by the same company or something. Keyboard/pointer mode does not properly configure (I presume because the second interface isn't really a mouse? idk, code to sphaghett and care too low)

    XInput funny business: With some more hacks (see attached file), XInput devices can be enumerated (class=$FF, subclass=$5D, protocol=$01). StrikeFX still crashes the driver, but the 8bitdo retro receiver does enumerate and poll, but it seems that the descriptor doesn't match the actual data format (weird that it actually returns one at all, since it's really not needed) and it seems to drop some bytes off the report (it's supposed to be 20 bytes; IIRC). I guess these just need to be hardcoded for XInput. Both the new pads that I've ordered are dual XInput/DInput, so that's gonna be a bit bigger sample set.

  • Wuerfel_21Wuerfel_21 Posts: 3,142
    edited 2022-04-12 17:29

    Oh, and here are the descriptors for the mayflash devices:

    (EDIT: and also the StrikeFX while I'm at it)

  • @macca said:

    @Wuerfel_21 said:
    Problem is that there are a lot of XInput devices and having a huge list of IDs (see link to xboxdrv source from earlier) seems wasteful and impractical. If we can confirm that all XInput devices use subclass $5D, I think that'd be a reasonable way to detect them (since whatever other devices that use class $FF wouldn't work, anyways). Do you have one on hand?

    Took a quick look at the xboxdrv source and the xpad kernel module, all seems to use the vendor+product. Using the class and subclass may be a solution, the risk is that other devices may be wrongly detected, I guess that nobody will throw random usb devices in a Propeller box... Anyway vendor+product is just a long, not a big waste, and the check can be made only one time.

    The bigger problem is that you'd need an exhaustive list of XInput device VID/PIDs, which, IDK, I just don't like the idea of. The worst that can really happen when it'd misdetects a device (which as you pointed out, when does that happen, anyways?) is reading bogus control data, which if you're reading game controllers to begin with is likely not a critical issue.

    I don't have xbox-like pads, I'll see if I can find one.

    Okay, quickly tried the new code. Seems to not quite work. Detecting the hats works, but somethings wrong with the axes (or it's just not printing them as I'd expect). Buttons on the Strike2 pads seem to be in the wrong order (I think this is an issue of MSB/LSB firstness) and on the logitech flight stick, it only sees 4 buttons (buttons 8 through 12, that is).

    I've attached the descriptor for the flight stick (that I've dumped on the aforementioned Linux laptop).

    From the descriptor, the axes issue should be just a formatting, it is 10 bits while the display shows a byte, change ser.fhex at line 218 with ser.dec and it should display correctly. Then there is a block with Push/Pop that I need to see what it means, 8 buttons are within that block but I don't expect it to be ignored. From what I see from the report, it should have 3 axes (2x10 bits, 1x8 bits), 1 hat (4 bits), 8+4 buttons. There are also sliders that are not supported. Maybe it is interfering somehow.

    Yep, it's 3 axes: X,Y and stick rotation. And yes, there's also a throttle control. The X and Y axis bits are not correctly mapped, the X in particular seems to get its MSBs from what are supposed to be LSBs and is thus a quite erratic)

    The button order should be correct, the bits are readed lsb->msb from each byte, so 4 bits at offset 8, are bits 3..0 from second byte (unless I'm missing something).

    Nope, it seems incorrect. For the Strike2 pads (which have the button numbers printed on them), the order they're printed in is: %4_3_2_1__12_11_10_9__8_7_6_5. Attached descriptor for that.

  • Wuerfel_21Wuerfel_21 Posts: 3,142
    edited 2022-04-12 18:22

    RE: missing report bytes

    oop, I just figured out that the demo is just hardcoded to only print the first 8. owie ouch.

    EDIT: there also seems to be an issue where it only updates if one of the first 8 bytes has changed, have to find where that is hardcoded.

  • Wuerfel_21Wuerfel_21 Posts: 3,142
    edited 2022-04-12 18:50

    Fixed(TM) the state compare length. Is slow, but the keyboard handler does even more slow things, so I guess it's fine(TM)

  • maccamacca Posts: 506
    edited 2022-04-12 20:36

    I have fixed the report decoder, I wrote that the sliders are not supported, but the decoder was decoding them as axis (doh!) which is wrong.
    I tried some of your reports, I saw that the buttons were defined in more than one block and the last block overwrites the previous, that's why the displayed buttons are less than expected. Shifting the bits with the number of already decoded buttons should have fixed that. I have yet to check the bit order but at least now you should see all of them.

    The result returned by some of your reports (haven't tried all yet) seems more correct now, so hopefully, the decoder is fixed.

    Also, changed (again) the device enumeration, now class=$FF is assumed to be a gamepad, I have absolutely no idea what will happen, the attempt to read the report descriptor should fail, but this won't trigger an error and the device should still be polled, if that works, the software needs to manually decode the report.

    Applied your comparison patch, thanks!

    Edit: the buttons state wasn't preserved correctly.

  • @macca said:
    I have fixed the report decoder, I wrote that the sliders are not supported, but the decoder was decoding them as axis (doh!) which is wrong.
    I tried some of your reports, I saw that the buttons were defined in more than one block and the last block overwrites the previous, that's why the displayed buttons are less than expected. Shifting the bits with the number of already decoded buttons should have fixed that. I have yet to check the bit order but at least now you should see all of them.

    The result returned by some of your reports (haven't tried all yet) seems more correct now, so hopefully, the decoder is fixed.

    Nope, still busted. It now acknowledges that the flight stick does infact have 12 buttons, but it still doesn't read them. Also, the X axis (and maybe also the Y axis, to a lesser extent?) are still busted. Tilt is fine though (well, it doesn't center quite properly anymore. I blame the guy I once knew who thought it was really funny to play Smash bros on it (AND WIN!!! HOW DID HE DO IT????)).

    The bit order issue is also still a thing.

    Also, changed (again) the device enumeration, now class=$FF is assumed to be a gamepad, I have absolutely no idea what will happen, the attempt to read the report descriptor should fail, but this won't trigger an error and the device should still be polled, if that works, the software needs to manually decode the report.

    That doesn't work, you need to check for subclass $5D and protocol $01, otherwise it picks up the other 3 interfaces. Also, you need to jump to #.gamepad directly, because otherwise it'll try picking it up as a keyboard (due to protocol $01). Also, it also needs ignoring NAK on the protocol/idle sets. Just didn't notice that because I already did it for the mayflash stuff.

    Also, I can't get your new version to work at all even if I apply those changes. Throws a nonsense error 30 and then restarts. The one I posted earlier works. If I diff them there's no meaningful difference. Seems to be some sort of memory corruption thing, as the crash behavior for the StrikeFX has also slightly changed. I've attached the new-code-but-with-my-changes for further inspection.

    I initially thought that we could just write a fake descriptor for the XInput report format and return, but this runs into the rather major issue that XInput reports the D-pad as 4 buttons rather than a hat angle, so that wouldn't work out. I guess just hardcoding the descriptor to a magic string "XBOX" and dealing with that as a special case when decoding the report could work.

  • Wuerfel_21Wuerfel_21 Posts: 3,142
    edited 2022-04-12 21:04

    @macca said:
    Edit: the buttons state wasn't preserved correctly.

    Yep, that works now. EDIT: though I think the tilt is messed up now. Or am I going mad?

    ...

    Wanna go on Discord or smth? I think realtime chat might be of use for figuring this stuff out.

  • roglohrogloh Posts: 4,521

    @macca said:
    I have fixed the report decoder, I wrote that the sliders are not supported, but the decoder was decoding them as axis (doh!) which is wrong.
    I tried some of your reports, I saw that the buttons were defined in more than one block and the last block overwrites the previous, that's why the displayed buttons are less than expected. Shifting the bits with the number of already decoded buttons should have fixed that. I have yet to check the bit order but at least now you should see all of them.

    The result returned by some of your reports (haven't tried all yet) seems more correct now, so hopefully, the decoder is fixed.

    Also, changed (again) the device enumeration, now class=$FF is assumed to be a gamepad, I have absolutely no idea what will happen, the attempt to read the report descriptor should fail, but this won't trigger an error and the device should still be polled, if that works, the software needs to manually decode the report.

    Applied your comparison patch, thanks!

    Edit: the buttons state wasn't preserved correctly.

    FWIW I tried this out with some generic USB gamepad of the type shown below and it seems to be working okay. The up/down/left/right buttons are being reported in the axes and the other 8 buttons are reported in the btn array.

    Mini Client + USB low/full speed keyboard/mouse/gamepad v0.1.4+r1
    Sysclock: 180000000, Clkmode: $10008FB, Baud: 2000000
    P2RevB+ detected, USB driver version v0.1.4+r1
    PortA started: cogID 1, event pin# 40
    PortA device idVendor=081F, idProduct=E401, bcdDevice=0100
    PortA gamepad configured, 2 axes, 0 hats, 10 buttons
    PortA [7F 7F 80 80 80 0F 00 00] axes [127 127] hats [] btn [0000000000]
    PortA [7F FF 80 80 80 0F 00 00] axes [127 255] hats [] btn [0000000000]
    PortA [7F 7F 80 80 80 0F 00 00] axes [127 127] hats [] btn [0000000000]
    ...
    
    
  • roglohrogloh Posts: 4,521

    Also just tried with a PS3 sixaxis over USB but it didn't work - although I wasn't really expecting it to.

    PortA device disconnected
    PortA device idVendor=054C, idProduct=0268, bcdDevice=0200
    PortA unknown device
    
  • maccamacca Posts: 506
    edited 2022-04-13 08:51

    @Wuerfel_21 said:
    That doesn't work, you need to check for subclass $5D and protocol $01, otherwise it picks up the other 3 interfaces. Also, you need to jump to #.gamepad directly, because otherwise it'll try picking it up as a keyboard (due to protocol $01). Also, it also needs ignoring NAK on the protocol/idle sets. Just didn't notice that because I already did it for the mayflash stuff.

    Ok, right, I have added the check for subclass and protocol, however you can't jump directly to .gamepad, you need to run .endp first to get the endpoint. To fix the keyboard issue it sets the protocol to NONE, this skips both keyboard and mouse and goes to .gamepad, that doesn't check it. If I haven't missed something... That code portion needs a refactoring before it gets too much convoluted.

    Yep, that works now. EDIT: though I think the tilt is messed up now. Or am I going mad?

    Ok, good, I was a bit worried that wasn't working...

    Anyway, the axes issue: the order in which they should appear to the application software is defined by the usage items, there are X, Y, Z, RX, RY and RZ, however the order in which are declared in the report may be a bit random:

    0x09, 0x32,        //     Usage (Z)
    0x09, 0x35,        //     Usage (Rz)
    0x09, 0x30,        //     Usage (X)
    0x09, 0x31,        //     Usage (Y)
    0x09, 0x00,        //     Usage (Undefined)
    

    Here should be presented as X,Y,Z,RZ but the decoder reads as Z,RZ,X,Y and presented as such, the array needs to be sorted correctly.

    The buttons issue: is clearly a bit manipulation of some sort when crossing the byte boundaries, reading one bit at a time instead of the whole size seems to have some "fix" but still not quite right. Still the bit order inside the byte is correct otherwise the 1-byte axes won't report the correct value. With your pad with 10 bit axes you should see if the middle value is correct (it should be 512 or 511, if the bits are swapped it should show another value).
    Maybe I haven't translated getBitUnsigned correctly from C, all these shifts and masks are driving me crazy...

    @rogloh said:
    Also just tried with a PS3 sixaxis over USB but it didn't work - although I wasn't really expecting it to.

    PortA device disconnected
    PortA device idVendor=054C, idProduct=0268, bcdDevice=0200
    PortA unknown device
    

    That's the controller that have the special activation message, it should work but clearly I missed something...

  • @macca said:

    @Wuerfel_21 said:
    That doesn't work, you need to check for subclass $5D and protocol $01, otherwise it picks up the other 3 interfaces. Also, you need to jump to #.gamepad directly, because otherwise it'll try picking it up as a keyboard (due to protocol $01). Also, it also needs ignoring NAK on the protocol/idle sets. Just didn't notice that because I already did it for the mayflash stuff.

    Ok, right, I have added the check for subclass and protocol, however you can't jump directly to .gamepad, you need to run .endp first to get the endpoint. To fix the keyboard issue it sets the protocol to NONE, this skips both keyboard and mouse and goes to .gamepad, that doesn't check it. If I haven't missed something... That code portion needs a refactoring before it gets too much convoluted.

    Ah yes. Still need to disable the ACK check for hset_idle (setProtocol isn't a problem with XInput? But it is a problem with other things it seems?).

    Also, there's some trailing commas on byte definitions in your code. Proptool chokes on these and I have to remove them every time. Can you remove them on your end?

    The buttons issue: is clearly a bit manipulation of some sort when crossing the byte boundaries, reading one bit at a time instead of the whole size seems to have some "fix" but still not quite right. Still the bit order inside the byte is correct otherwise the 1-byte axes won't report the correct value. With your pad with 10 bit axes you should see if the middle value is correct (it should be 512 or 511, if the bits are swapped it should show another value).
    Maybe I haven't translated getBitUnsigned correctly from C, all these shifts and masks are driving me crazy...

    Nope, still busted. Buttons on Strike2 are in wrong order and the flight stick still doesn't read properly. Here's with the stick centered (note: none of the axes return to perfect center, there's no built-in deadzone). Tilt is okay and does go from 0 to 255, it just physically doesn't center to ~128 anymore (I blame the aforementioned Smash bros shenanigans)

  • Also, I'm pretty sure you can just write getBitSigned like this:

    PRI getBitSigned(data, offset, length) : result
        return getBitUnsigned(data, offset, length) signx (length-1)
    
  • maccamacca Posts: 506
    edited 2022-04-13 14:59

    Ok, let's try this.

    I think I got the bits ordered correctly, I saw that Circle has a different bit manipulation function, translated that and looks working correctly.

    Before

    [11111100 10100001 10000111 10001010 00000000 01001000 00000000 11000000]
    [00000000000000000000001111110001 = 1009]
    [00000000000000000000001010000111 = 647]
    

    After, with new getBitUnsigned method

    [11111100 10100001 10000111 10001010 00000000 01001000 00000000 11000000]
    [00000000000000000000000111111100 = 508]
    [00000000000000000000000111101000 = 488]
    

    Seems more correct for the 10 bit axes.
    This also has effects on the buttons bits.

    @Wuerfel_21 said:
    Ah yes. Still need to disable the ACK check for hset_idle (setProtocol isn't a problem with XInput? But it is a problem with other things it seems?).

    Ok, until we can sort that out, I have disabled all ACK checks in .gamepad_config, if the device supports the message ok, otherwise don't care.
    Also @rogloh 's PS3 controller above should report something now.

    Also, there's some trailing commas on byte definitions in your code. Proptool chokes on these and I have to remove them every time. Can you remove them on your end?

    Yes sorry, removed.

  • @macca said:
    Ok, let's try this.

    I think I got the bits ordered correctly, I saw that Circle has a different bit manipulation function, translated that and looks working correctly.

    Before

    [11111100 10100001 10000111 10001010 00000000 01001000 00000000 11000000]
    [00000000000000000000001111110001 = 1009]
    [00000000000000000000001010000111 = 647]
    

    After, with new getBitUnsigned method

    [11111100 10100001 10000111 10001010 00000000 01001000 00000000 11000000]
    [00000000000000000000000111111100 = 508]
    [00000000000000000000000111101000 = 488]
    

    Seems more correct for the 10 bit axes.
    This also has effects on the buttons bits.

    Yep, both button order and 10 bit axis issues are fixed.

    Wireless pad still busted, but the error is a little different now (both XInput and DInput modes shown):

    It also seems to correctly decode the gamecube adapter now (though it is ofc still confused by the other 3 ports' reports):

  • maccamacca Posts: 506

    @Wuerfel_21 said:
    Yep, both button order and 10 bit axis issues are fixed.

    Good!

    Wireless pad still busted, but the error is a little different now (both XInput and DInput modes shown):

    I think the issue is that it doesn't like the report polling. I think these controllers needs a start command packet or something, like the PS3.

    It also seems to correctly decode the gamecube adapter now (though it is ofc still confused by the other 3 ports' reports):

    It's not really confused, the decoder should choose which report to decode based on the descriptor and the first byte ($01, $02, $03 or $04), currently the decoder stops at the first packet, the other are printed because handleGamepadUpdate prints them anyway but are ignored. It can be extended to include the other packets but it needs additional instances of buttons, hats and axis variables to associate to each.

Sign In or Register to comment.