Shop OBEX P1 Docs P2 Docs Learn Events
P2 USB Host driver (re-)development thread - Page 7 — Parallax Forums

P2 USB Host driver (re-)development thread

145791015

Comments

  • roglohrogloh Posts: 5,837
    edited 2023-05-11 08:50

    I did some detective work deciphering things and it looks like this Griffin Powermate thing should be a HID device with one button and one axis.

    I decoded the Report Descriptor data listed here

    Cog2 pb = $711C, pb = $05, $0C, $09, $01, $A1, $01, $05, $09, $19, $01, $29, $01, $15, $00, $25, $01, $75, $01, $95, $01, $81, $02, $75, $07, $95, $01, $81, $01, $05, $01, $09, $33, $15, $81, $25, $7F, $75, $08, $95, $01, $81, $02, $05, $0C, $09, $01, $15, $00, $26, $FF, $00, $75, $08, $95, $04, $81, $02, $09, $01, $75, $08, $95, $01, $91, $02, $09, $01, $75, $08, $95, $08, $B1, $02, $C0

    into this information below. Maybe the current gamepad capable USB code doesn't like reports in this format or there is something elsewhere that prevents it from being detected correctly? @Wuerfel_21 or @macca do you know what might be needed for this USB device to work as a gamepad? It might have something to do with these usage pages...?

    $05 $0C UsagePage($C)
    $09 $01 Usage(1)
    $A1 $01 Collection(Application)
    $05 $09 UsagePage(9)
    $19 $01 UsageMinimum(1)
    $29 $01 UsageMaximum(1)
    $15 $00 LogicalMinimum(0)
    $25 $01 LogicalMaximum(1)
    $75 $01 ReportSize(1)
    $95 $01 ReportCount(1)
    $81 $02 Input(Data,Variable,Absolute)
    $75 $07 ReportSize(7)
    $95 $01 ReportCount(1)
    $81 $01 Input(Constant)
    $05 $01 UsagePage(1)
    $09 $33 Usage($33)
    $15 $81 LogicalMinimum(-127)
    $25 $7F LogicalMaximum(127)
    $75 $08 ReportSize(8)
    $95 $01 ReportCount(1)
    $81 $02 Input(Data,Variable,Absolute)
    $05 $0C UsagePage($C)
    $09 $01 Usage(1)
    $15 $00 LogicalMinimum(0)
    $26 $FF $00 LogicalMaximum($00ff)
    $75 $08 ReportSize(8)
    $95 $04 ReportCount(4)
    $81 $02 Input(Data,Variable,Absolute)
    $09 $01 Usage(1)
    $75 $08 ReportSize(8)
    $95 $01 ReportCount(1)
    $91 $02 Output(Data,Variable,Absolute)
    $09 $01 Usage(1)
    $75 $08 ReportSize(8)
    $95 $08 ReportCount(8)
    $B1 $02 Feature(2)
    $C0     End Collection()
    
  • @rogloh said:
    into this information below. Maybe the current gamepad capable USB code doesn't like reports in this format or there is something elsewhere that prevents it from being detected correctly? @Wuerfel_21 or @macca do you know what might be needed for this USB device to work as a gamepad? It might have something to do with these usage pages...?

    Yes, the usage statements are not recognized by the current hid decoder (it uses JOYSTICK and GAMEPAD only, the usage reported is POINTER).
    It could be added as a known usage, in the hope that doesn't cause other issues.

  • roglohrogloh Posts: 5,837
    edited 2023-05-11 09:13

    @macca said:

    @rogloh said:
    into this information below. Maybe the current gamepad capable USB code doesn't like reports in this format or there is something elsewhere that prevents it from being detected correctly? @Wuerfel_21 or @macca do you know what might be needed for this USB device to work as a gamepad? It might have something to do with these usage pages...?

    Yes, the usage statements are not recognized by the current hid decoder (it uses JOYSTICK and GAMEPAD only, the usage reported is POINTER).
    It could be added as a known usage, in the hope that doesn't cause other issues.

    Thanks Macca, am having a look now at some way to patch into the code in that area just to see if I can get something going with this device.

    BTW: I reckon this controller would make a good spinner for one of those breakout arcade type games where you only need a single axis. Plus other things like a digital etch a sketch if you had two of them (depending on its sensitivity).

  • pik33pik33 Posts: 2,383

    It also seems to show up detected on screen only after I actually spin the encoder wheel, not immediately after I plug it in which is strange.

    The same behavior with the retrofun joystick interface. It doesn't show up until you move the joystick.

  • Weird. Maybe some type of sleep or power saving function built into it?

  • No, it's a "bug" in the device FW where it doesn't respond to the initial poll.

    More later.

  • roglohrogloh Posts: 5,837
    edited 2023-05-11 13:43

    Well I was able to get this device to respond if I added this line to usnew.spin2

    I get one button and one axis now, however it behaves more like a mouse with an 8 bit delta value of $ff or 1 depending on the direction I rotate in. So it's not really an axis like a gamepad. If I spin it fast I see bigger deltas. Single button works.

    What's strange is that the last delta value is retained as 1 or $ff when I don't move the dial, it doesn't appear to reset back to 0 until I press (or release) the button after spinning ceases. I'm not sure if it might be because whenever there is no reply then the reported data is just left as the same as it was before in the driver. Perhaps this device doesn't respond to interrupt IN queries successfully if there is no change in state, like replying with a NAK or something. Not sure there.

    One thing I was surprised to learn when digging around all this code is that the HID report descriptor is being re-parsed each time a gamepad IN report occurs. That seems like quite a bit of work every time. Would it be more efficient to parse it once at start when the device is initialized etc, and setup some known list of fields to pull out from the report for the different gamepad parameters like hats/axes/buttons? Maybe it's just more overall code for doing that.

    Also the hidpad_to_vga program reports this axis in 16 bit format even though this is defined as an 8 bit value. It prints as -32768 or -32767. So something weird there.

  • @rogloh said:
    Well I was able to get this device to respond if I added this line to usnew.spin2

    Good.

    I get one button and one axis now, however it behaves more like a mouse with an 8 bit delta value of $ff or 1 depending on the direction I rotate in. So it's not really an axis like a gamepad. If I spin it fast I see bigger deltas. Single button works.

    Looks like the mouse motion, it returns the delta since the last read. Seems reasonable if the knob rotates indefinitely.

    What's strange is that the last delta value is retained as 1 or $ff when I don't move the dial, it doesn't appear to reset back to 0 until I press (or release) the button after spinning ceases. I'm not sure if it might be because whenever there is no reply then the reported data is just left as the same as it was before in the driver. Perhaps this device doesn't respond to interrupt IN queries successfully if there is no change in state, like replying with a NAK or something. Not sure there.

    If I understand correctly, it seems to act like a mouse, it sends a report only when there is something to report (you are right, when no report is returned it sends a NAK), so the last value is not retained, the buffer is never updated. I think usbnew still has the same notification of mine so when no report is read, the application doesn't receive any notification and must do nothing.

    One thing I was surprised to learn when digging around all this code is that the HID report descriptor is being re-parsed each time a gamepad IN report occurs. That seems like quite a bit of work every time. Would it be more efficient to parse it once at start when the device is initialized etc, and setup some known list of fields to pull out from the report for the different gamepad parameters like hats/axes/buttons? Maybe it's just more overall code for doing that.

    I believe it would be more complicated than processing the descriptor each time.

    Also the hidpad_to_vga program reports this axis in 16 bit format even though this is defined as an 8 bit value. It prints as -32768 or -32767. So something weird there.

    Nothing weird there, gamepad axes are normalized to 16 bit signed to be consistent with each other.

  • pik33pik33 Posts: 2,383

    I did an experiment and connected a touch screen.

    It appeared as a pad!

    It displays nonsense on the screen: "axes" changes from 0 to 3 when I move the finger, x and Y also blinks, but when idle, the last displayed values are somewhat correlated to the touched place.

    The conclusion: a touch scren can be added to the driver.

    It is one more important device for "industrial" purposes (as "they" complains we can only do a retrocomputing).

  • roglohrogloh Posts: 5,837
    edited 2023-05-11 16:28

    I found another old USB HID device I had lying about and tried it, hoping it might be able to report its data as button state. It might let you remotely read pressed buttons on a P2 for example.

    It shows up as a gamepad when a button is pressed but its report descriptor UsagePage value seems to be vendor specific, it would need to be faked to get it to work and obviously no buttons or axes are actually getting decoded.

    I sort of wonder if there is a good way to support a mix of other USB HID devices if the UsagePage/Usage field parsing becomes slightly more flexible. Even if it needs some table of allowed values to be configured perhaps. Not simple I know, as there are likely a plethora of combinations possible, and not all are related to gamepads per se but they still might make good input controllers for general use on a P2.

    $06, $A0, $FF, UsagePage($ffa0)
    $09, $01, Usage(1)
    $A1, $01, Collection(Application)
    $09, $01, Usage(1)
    $15, $00, LogicalMin(0)
    $26, $FF, $00,  LogicalMax($00ff)
    $75, $08, ReportSize(8)
    $95, $08, ReportCount(8)
    $81, $02, Input(Data,Variable,Absolute)
    $C0       End Collection()
    

    I also have this old USB IR remote for a PlayStation3 which might be simpler to get working as it was already designed for controlling PS3's and so probably uses the same button mapping as an actual controller. Unfortunately it needs work too, it didn't work off the bat and seems flaky to initialize. I do see 12 buttons 5 axes and a hatswitch but it randomly connects/reconnects and only sporadically even populates the IN report when I press buttons. Maybe its batteries are dead or something. EDIT: Nope 3.2V for its coin cell.

    Here's its Report Descriptor

    $05, $01, UsagePage(GenericDesktop)
    $09, $04, Usage(Joystick)
    $A1, $01, Collection(Application)
    $A1, $02, Collection(Logical)
    $75, $08, ReportSize(8)
    $95, $05, ReportCount(5)
    $15, $00, LogicalMinimum(0)
    $26, $FF, $00, LogicalMaximum($00ff)
    $35, $00, PhysicalMinimum(0)
    $46, $FF, $00, PhysicalMaximum($00ff)
    $09, $30, Usage(X)
    $09, $31, Usage(Y)
    $09, $32, Usage(Z)
    $09, $32, Usage(Z) ' weird to have 2 copies of this
    $09, $35, Usage(Rz)
    $81, $02, Input(Data,Variable,Absolute)
    $75, $04, ReportSize(4)
    $95, $01, ReportCount(1)
    $25, $07, LogicalMaximum(7)
    $46, $3B, $01, PhysicalMaximum($13B)
    $65, $14, Unit($14)
    $09, $39, Usage(HatSwitch)
    $81, $42, Input(Data,Variable,Absolute,NullState)
    $65, $00, Unit(0)
    $75, $01, ReportSize(1)
    $95, $0C, ReportCount(12)
    $25, $01, LogicalMaximum(1)
    $45, $01, PhysicalMaximum(1)
    $05, $09, UsagePage(Buttons)
    $19, $01, UsageMinimum(1)
    $29, $0C, UsageMaximum(12)
    $81, $02, Input(Data,Variable,Absolute)
    $06, $00, $FF, UsagePage($ff00)
    $75, $01, ReportSize(1)
    $95, $08, ReportCount(8)
    $25, $01, LogicalMaximum(1)
    $45, $01, PhysicalMaximum(1)
    $09, $01, Usage(1)
    $81, $02, Input(Data,Variable,Absolute)
    $C0, End Collection()
    $A1, $02, Collection(Logical)
    $75, $08, ReportSize(8)
    $95, $07, ReportCount(7)
    $46, $FF, $00, PhysicalMaximum($00ff)
    $26, $FF, $00, LogicalMaximum($00ff)
    $09, $02, Usage(2)
    $91, $02, Output(Data,Variable,Absolute)
    $C0, End Collection()
    $C0  End Collection()
    
  • @rogloh said:
    I found another old USB HID device I had lying about and tried it, hoping it might be able to report its data as button state. It might let you remotely read pressed buttons on a P2 for example.

    It shows up as a gamepad when a button is pressed but its report descriptor UsagePage value seems to be vendor specific, it would need to be faked to get it to work and obviously no buttons or axes are actually getting decoded.

    Theoretically, the change you did for the knob should also work for this (the usage page is simply ignored in that case), however the buttons are not defined as single bits like the knob, there are 8 bytes that I guess are mapped to the buttons (don't know why they are 8 bits, but that's it...). The decoder doesn't have a field to handle this kind of buttons so are ignored.

    I also have this old USB IR remote for a PlayStation3 which might be simpler to get working as it was already designed for controlling PS3's and so probably uses the same button mapping as an actual controller. Unfortunately it needs work too, it didn't work off the bat. Maybe batteries are dead or something.

    I don't see issues with this report, it should work as a gamepad.

    I sort of wonder if there is a good way to support a mix of other USB HID devices if the UsagePage parsing becomes slightly more flexible. Even if it needs some table of allowed values to be configured perhaps. Not simple I know, as there are likely a plethora of combinations possible, and not all are related to gamepads per se.

    The current hid parser is tailored specifically for gamepad use, things that are not known are ignored. It needs at least to be rewritten as a full decoder with proper nesting and usage handlings, then the application needs to know how to access each element, and this is where the mess begins.

  • Wuerfel_21Wuerfel_21 Posts: 5,105
    edited 2023-05-11 16:48

    I've just added the keyboard LED stuff (capslock etc) to usbnew. Have fun with that I guess. It's mostly macca's code, with an extra function to read the current LED state. There's no set function.


    RE: strange one-off devices

    I won't add support to the driver because
    a) I don't have the specific ones and can't do testing (incl. regression testing!)
    b) I want to avoid bloat that isn't easily conditional-compiled away (Remember, the input code area in NeoYume is ~12k. I will not make the driver (with EmuPad compiled in) larger than that, because then it would fail at my own use-case. Though I think there's some leeway there if I get rid of the flexspin runtime)


    RE: 7 port hubs

    I see macca added support for them. I really should add those, too, but I'd kinda have to claw out those 768 bytes of buffer space from somewhere. Pain.


    RE: hidpad devices only showing up after input

    For the intended gamepad usecase, you'd ideally only use the device after a button press, anyways (i.e. show "press start" screen and then assign the device slot that presses start to the player)

    It would be nice if they did show up in the test program immediately though.

  • @Wuerfel_21 said:

    RE: 7 port hubs

    I see macca added support for them. I really should add those, too, but I'd kinda have to claw out those 768 bytes of buffer space from somewhere. Pain.

    Actually I just realized that the additional hid buffers are not really necessary because I have limited the gamepads to 4 (first 4 ports in my case, still bound to the port number).
    If I remember correctly, you have restored the keyboard private buffer, so you may only need to map the gamepads to a buffer with your numbering.
    Unless you want to support 7 players...

  • Wuerfel_21Wuerfel_21 Posts: 5,105
    edited 2023-05-11 17:24

    @macca said:
    Actually I just realized that the additional hid buffers are not really necessary because I have limited the gamepads to 4 (first 4 ports in my case, still bound to the port number).

    Oh, yea, I see that. Well that's not really much better than the current state of only being able to plug stuff into the first four ports.

    If I remember correctly, you have restored the keyboard private buffer, so you may only need to map the gamepads to a buffer with your numbering.

    I already got rid of the individual report buffers (raw report stays in urx_buf), I only have the descriptor buffers left. I also already download the descriptor for mice right now, in preparation of fumbling the HID parser code to read full mouse reports (should really only entail different usages and not normalizing axes).

    I wonder to what extent con_desc_buff really needs to be a separate area?

    Also, a lot more of the cog registers could be converted to RES.

    Unless you want to support 7 players...

    If I were to make a PC Engine emulator... (supports 5 players as standard)

  • @Wuerfel_21 said:
    I wonder to what extent con_desc_buff really needs to be a separate area?

    To the extent that it causes sadness if I try to mess with it, it seems.

  • Okay, on the aforementioned memory usage concerns, I just checked:

    The input area in NeoYume is exactly $3000 = 12288 bytes. I already had to trim this multiple times because the main code kept growing. I consider this a reasonable size target.

    Current usbnew + startup code + spin runtime is 10424 bytes. (The runtime is ~256 bytes (I just changed the compiler flags to disable fcache, which cut it down a lot)). This means there's 1864 bytes left, which should be enough to fit the 768 bytes needed for 3 extra descriptor buffers and still have over 1KiB left.

    Other concern: I don't think I actually have a 7-port hub laying around.

  • pik33pik33 Posts: 2,383

    I have now to hack the driver to add a function that returns the raw gamepad reports to make use of the touch screen I mentioned earlier, that presents itself as a pad if connected. It seems to return proper x and y positions interleaved with other stuff. To test tomorrow, i have it at the university.

  • @pik33 said:
    I have now to hack the driver to add a function that returns the raw gamepad reports to make use of the touch screen I mentioned earlier, that presents itself as a pad if connected. It seems to return proper x and y positions interleaved with other stuff. To test tomorrow, i have it at the university.

    Something something report IDs, they aren't really handled that well right now.

  • In other news, I've been able to kick loose some 340 bytes by implementing what I like to call "the great RES-ification". The driver had a lot of pre-initialized registers that it also explicitly clears out. I've now changed all of these to RES allocation.

  • Other size-saving idea: I could add a conditional compile option to overlay some of the buffers with the cog/lut code. This would obviously not allow you to stop the driver and restart it later (which I don't think you currently can, for there is no stop method - should fix that). The combined cog+lut code should (?) be at least 2k, so it should be possible to fit 7 HID buffers and the configuration buffer into that space, which would make that version even leaner than the current driver.

  • @Wuerfel_21 said:
    Other size-saving idea: I could add a conditional compile option to overlay some of the buffers with the cog/lut code. This would obviously not allow you to stop the driver and restart it later (which I don't think you currently can, for there is no stop method - should fix that). The combined cog+lut code should (?) be at least 2k, so it should be possible to fit 7 HID buffers and the configuration buffer into that space, which would make that version even leaner than the current driver.

    I feel your pain and remember trying to get everything to all fit in my own drivers though that was primarily done in PASM2.

    If you get really desperate and down to your last longs you might be able to overlay something at the usb_host_start address in the COG. There might be 11 longs there before it jumps to the main processing code. Plus 18 more longs in the set_speed_low and host_reset function (LUT space) are doing revA P2 stuff plus the extra long state of it in COGRAM. Looks like someone already commented out some support for that older P2 rev elsewhere in the HUB code, so you could probably free those too. I feel like I owe you some longs for putting in mouse reposition stuff which added 3 longs. :wink:

    Using conditional code makes sense and will help a lot. In fact for a more general purpose USB host driver (not your HID only compacted one for NeoYume etc), it would be essential to have some way to include support for various different USB classes without bloating it fully with everything present all the time if you don't need those devices. Probably it would just need to become flexspin only, PropTool just makes it too hard to do that type of stuff.

  • roglohrogloh Posts: 5,837
    edited 2023-05-12 05:31

    @Wuerfel_21 you can add another working controller to your list. Logitech MOMO racing wheel force feedback.

    ID 046DCA03 - 2 axes, 10 buttons

    • Wheel - X axis, turn left negative, turn right positive
    • Accel - negative Y axis
    • Brake - positive Y axis (pressing both accel & brake also zeroes output - essentially a difference gets sent)
    • Button states in reported order:
    • b0 = left paddle
    • b1 = right paddle
    • b2 = top left steering wheel button
    • b3 = top right steering wheel button
    • b4 = middle left steering wheel button
    • b5 = middle right steering wheel button
    • b6 = bottom left steering wheel button
    • b7 = bottom right steering wheel button
    • b8 = gear stick down button
    • b9 = gear stick up button

    Note: This wheel is reasonably heavy by default with no force feedback control applied. I found without it's power supply connected it's a bit lighter to turn the wheel. I think the controller probably needs data written to it to fully disable or adjust the amount of feedback that is applied after it starts up.
    This GitHub project may possibly be of use to anyone who desires USB information that could help control force feedback on these types of wheels:
    https://github.com/berarma/new-lg4ff

  • roglohrogloh Posts: 5,837
    edited 2023-05-12 10:12

    Total two line hack but it worked! Now turning the Powermate wheel thing I have moves the mouse X and reports its button in the left click state. Mouse Y value is left unchanged. Works awesomely. Can't believe it. :smile::smile: Of course you would never do this in the real world. Best to look for the device ID specifically but I wanted to see what happened...

  • @rogloh said:
    Plus 18 more longs in the set_speed_low and host_reset function (LUT space) are doing revA P2 stuff plus the extra long state of it in COGRAM. Looks like someone already commented out some support for that older P2 rev elsewhere in the HUB code, so you could probably free those too.

    Check latest version, I already removed all RevA related code.

  • @rogloh said:
    @Wuerfel_21 you can add another working controller to your list. Logitech MOMO racing wheel force feedback.

    Nice.

    The feedback wheel I have doesn't work, needs special driver (that has never been updated past Win XP...). Has a whacky USB/PS2/Xbox/Gamecube squid thing though.

  • Wuerfel_21Wuerfel_21 Posts: 5,105
    edited 2023-05-15 16:40

    Oh man, the 7-port hub I ordered is just two cascaded 4-ports (so 3 ports actually usable). Maybe they don't exist for USB 3.0 due to all the extra pins. Will try getting a 2.0 hub instead...

    EDIT: Also, doesn't work with lowspeed devices?

  • @Wuerfel_21 said:
    EDIT: Also, doesn't work with lowspeed devices?

    That seems unusual. There are still plenty of low speed USB devices around and you'd expect USB3.0 hubs to still fall back to support those as well.

    Was that low speed device issue found with an actual PC, or just the current P2 driver software?

  • Wuerfel_21Wuerfel_21 Posts: 5,105
    edited 2023-05-16 00:06

    Just the P2. I suspect that cheap USB 3.0 hub chips weren't tested properly with fullspeed hosts because they're exceedingly rare. If a hub is in highspeed mode, it only talks to the host in highspeed and every FS/LS device message is translated by the hub. But I didn't really look into it much further. The hub also came with the world's sketchiest wall adapter... Also didn't bother with cheapo 2.0 Hubs, went to ebay and ordered a used one that I am reasonably sure is a true 7-port.

  • RaymanRayman Posts: 14,744

    Somebody once said here somewhere that all usb hub chips are four port.

  • evanhevanh Posts: 16,023

    That makes sense. The common sizes are 4 (one hub), 7 (two hubs), 10 (three hubs) and 16 (five hubs). I found one exception in the local supplies - https://www.pbtech.co.nz/product/USBORC1006/Orico-12-Port-Commercial-High-Speed-Desktop-Multi I suspect it might be a five hub design anyway.

Sign In or Register to comment.