gizmo-platform / gizmo

https://gizmo-platform.github.io
ISC License
5 stars 3 forks source link

'field serve' crashes on windows because of bad gamepad axis index #1

Closed barulicm closed 8 months ago

barulicm commented 11 months ago

It looks like the F310 inputs get enumerated differently on windows vs linux.

The gizmo gamepad code expects 8 axes to be available.

With the switch on the back of the gamepad set to "X", gizmo sees 7 axes and 10 buttons. With that switch set to "D", there are 6 axes and 12 buttons.

On windows, gizmo crashes in gamepad.UpdateState

PS C:\Users\matth\Documents\BEST\Gizmo Dev\gizmo> .\gizmo field serve
2023-10-03T19:22:11.121-0400 [INFO]  field: Log level: level=info
2023-10-03T19:22:11.177-0400 [INFO]  field.gamepad-controller: Successfully bound controller: fid=field1:red jsid=0
2023-10-03T19:22:11.246-0400 [INFO]  field.web: HTTP is starting
2023-10-03T19:22:11.246-0400 [INFO]  field.mqtt: MQTT is starting
panic: runtime error: index out of range [7] with length 7

goroutine 52 [running]:
github.com/bestrobotics/gizmo/pkg/gamepad.(*JSController).UpdateState(0xc0000b0080, {0xc0002a2220, 0xa})
        C:/Users/matth/Documents/BEST/Gizmo Dev/gizmo/pkg/gamepad/gamepad.go:184 +0x611
github.com/bestrobotics/gizmo/pkg/gamepad.(*JSController).doRefreshAll.func1()
        C:/Users/matth/Documents/BEST/Gizmo Dev/gizmo/pkg/gamepad/gamepad.go:212 +0x39
created by github.com/bestrobotics/gizmo/pkg/gamepad.(*JSController).doRefreshAll in goroutine 29
        C:/Users/matth/Documents/BEST/Gizmo Dev/gizmo/pkg/gamepad/gamepad.go:211 +0xf8
Vaelatern commented 11 months ago

Interesting, so that's what that switch does. On Linux it only shows up correctly (as the correct device) on one of the switch settings.

the-maldridge commented 11 months ago

This is already fixed on the branch practice-mode. If you have a go compiler you can build from that and run gizmo field practice <number> to directly launch the field services and configure a single field quadrant called "practice". If everything worked correctly, the location indicator light will blink an extremely bright white light.

barulicm commented 11 months ago

I'm seeing the same behavior on the practice-mode branch. And it doesn't look like that branch touches the gamepad file.

barulicm commented 11 months ago

Interesting, so that's what that switch does. On Linux it only shows up correctly (as the correct device) on one of the switch settings.

That switch apparently changes between XInput and DirectInput standards.

Comparison of XInput and DirectInput features

the-maldridge commented 11 months ago

What the branch does is add a completely new target that doesn't try to initialize 4 gamepads at a time. On linux the input subsystem is robust enough that we can blind read from gamepads and buttons that aren't there and it won't segfault the program. It sounds like on Windows we needed to special case this to handle missing devices. I'm about to be away from my primary desktop for a few days, but I suspect I'm going to need to spool up a windows VM to test this.

Looking at what's failing though, windows isn't reporting the full number of buttons. I uploaded a program to the google drive in the directory "software/gamepad" that just dumps the information from the gamepad. Can you download that and try it and then post a screenshot of what it says? I'm really starting to wonder if windows isn't supplying the default button map.

barulicm commented 11 months ago

Drive won't let me download that exe because it thinks it's a virus.

Here's the info I got using the joysticktest app provided by https://github.com/0xcafed00d/joystick

Name: "Microsoft PC-joystick driver"

Axes: Index Mapping Negative Positive
0 Left stick horizontal left right
1 left stick vertical up down
2 triggers right trigger left trigger
3 right stick vertical up down
4 right stick horizontal left right
5 d-pad horizontal left right
6 d-pad vertical up down
Buttons: Index Mapping
0 A
1 B
2 X
3 Y
4 Left shoulder
5 Right shoulder
6 Back
7 Start
8 Left stick
9 Right stick
barulicm commented 10 months ago

As of b1c7760, instead of crashing, gizmo repeatedly prints the following logs:

(run as .\gizmo.exe field practice 1234)

2023-10-17T00:23:28.756-0400 [INFO]  field.gamepad-controller: Successfully bound controller: fid=field1:practice jsid=0
2023-10-17T00:23:28.802-0400 [ERROR] field.gamepad-controller: Wrong joystick counts!: axis=7  buttons=10
2023-10-17T00:23:28.802-0400 [WARN]  field.gamepad-controller: Error polling joystick, attempting rebind: error="bad joystick read" field=field1:practice
Vaelatern commented 10 months ago

Times like this I wish I had a windows box available for this.

Can you please confirm it does so if you change the switch on the back to the other mode? I don't think so based on your original comment, that the other mode gives you 6 and 12, instead of 7 and 10, but just wanted to be sure.

Also can you please validate the model of joystick you are using? You said F310, any more specific information? I'd like to rule that out completely, if we can.

the-maldridge commented 10 months ago

These are exactly one off, I'm suspicious of an index change here between windows and linux which would be dumb. The log space is intended, as this prevents the crash and prints useful information.

Looking at your log entry though you're getting different behavior than we get on linux. On linux the triggers are read out independently. If I read your posting correctly, does this mean that you can't hold both triggers in at the same time? Likewise the button you're missing is the logo button which we use on linux to get a mapping of the gamepads during system setup, but isn't useful under windows (I suspect its still there, but is firing an event that the logitech driver would normally catch).

If this is correct, then we need to change the gamepad map on windows to account for the missing axis and missing buttons, but that's an easy fix.

barulicm commented 10 months ago

Can you please confirm it does so if you change the switch on the back to the other mode?

The test above was with the switch in XInpute mode. Switching to DirectInput shows the same message with 6 axes and 12 buttons.

Also can you please validate the model of joystick you are using?

I am using a Logitech Gamepad F310. P/N: 840-000058 M/N: G-U0002 Purchased via this Amazon listing: https://www.amazon.com/dp/B003VAHYQY

does this mean that you can't hold both triggers in at the same time?

Correct. Holding both triggers at the same time shows axis 2 reading 0.

For what it's worth, https://hardwaretester.com/gamepad is able to read the trigger axes independently and reads the logo button. This may be an issue with the Go gamepad library being used.

Vaelatern commented 10 months ago

@the-maldridge the F310 I have in my hands

Logitech Gamepad F310. P/N: 840-000058 M/N: G-U0001

This differs from the one @barulicm has in his hands by the M/N: G-U0001 vs. G-U0002 The amazon listing clearly has G-U0001 pictured. My google search does not turn up any information on G-U0002. Either the M/N is wrong, or there is a stealth difference.

barulicm commented 10 months ago

Apologies. That's a typo. image

Vaelatern commented 10 months ago

Alright, so we're back to a difference in how the ms logitech driver works vs. the linux world, or perhaps the addressing via the go lib

Vaelatern commented 10 months ago

I'm actually on "Weird indexing problems" and "Windows Driver" now. I also see 7 and 10 on gamepad tester as the high end number, but of course 0 is enumerated making my gamepad 8 and 11 axis and buttons.

The difference between reported vertical and horizontal in the below (my tests on my linux system) is not good news

Axes: Index Mapping Negative Positive
0 Left stick horizontal left right
1 left stick vertical up down
2 Left trigger normal pressed
3 right stick horizontal left right
4 right stick vertical up down
5 Right trigger normal pressed
6 d-pad horizontal left right
7 d-pad vertical up down
Buttons: Index Mapping
0 A
1 B
2 X
3 Y
4 Left shoulder
5 Right shoulder
6 Back
7 Start
8 Logo
9 Left stick
10 Right stick
the-maldridge commented 10 months ago

If this is just a mapping issue that's easy enough to fix, but it sounds like the joystick interface the cross platform driver uses is picking up a different I/O map depending on what OS its on (making it not very cross platform at all...). I think since the javascript API for the hardware tester can see everything without switching the mode, this is likely an issue with how the inputs are being un-muxed by the cross platform Go driver.

--Michael

On Tue, Oct 17, 2023 at 11:50 AM Toyam Cox @.***> wrote:

I'm actually on "Weird indexing problems" now. I also see 7 and 10 on gamepad tester as the high end number, but of course 0 is enumerated making my gamepad 8 and 11 axis and buttons.

The difference between reported vertical and horizontal in the below (my tests on my linux system) is not good news

Axes: Index Mapping Negative Positive 0 Left stick horizontal left right 1 left stick vertical up down 2 Left trigger normal pressed 3 right stick horizontal left right 4 right stick vertical up down 5 Right trigger normal pressed 6 d-pad horizontal left right 7 d-pad vertical up down

Buttons: Index Mapping 0 A 1 B 2 X 3 Y 4 Left shoulder 5 Right shoulder 6 Back 7 Start 8 Logo 9 Left stick 10 Right stick

— Reply to this email directly, view it on GitHub https://github.com/BESTRobotics/gizmo/issues/1#issuecomment-1766805317, or unsubscribe https://github.com/notifications/unsubscribe-auth/AARW3FVNAEBEQRBBSZ2DVALX72ZOLAVCNFSM6AAAAAA5RW7KRWVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTONRWHAYDKMZRG4 . You are receiving this because you were mentioned.Message ID: @.***>

-- the-maldridge @.***

the-maldridge commented 10 months ago

Progress.

With a dumb amount of testing and poking at things, I now understand what's going on. It also helped to rebuild my desktop to a point that I could comfortably keep a windows 11 VM spun up.

Background: In ye-olden days there was the 15 pin "game port" which windows polled as a series of disjointed ADC and GPIO pins, often via the sound card. This support is directly part of windows.h and as a result is mind-numbingly difficult to program for since its a part of the core kernel specification. Fast forward to 1995 and Microsoft releases DirectX promising to redefine graphics and game programming for the modern PC. With DirectX 1.0 came DirectInput, a dedicated I/O subsystem for gaming input devices. It supported some pretty insane capabilities for 1995 including an arbitrary limit on device count, up to 128 buttons, "POV smash" (holding the POV hat input down activating all buttons), and crucially 8-axis controllers. DirectInput though is part of DirectX, which makes it again a royal pain to program for, but not as bad as the kernel interface to the game port.

DirectInput is all good and well, but it didn't gel with Microsoft Game Studio's goals of making it easier to program a gaming experience on Windows, so in 2005 with the launch of the original XBox, Windows XP SP1 added the XInput API. The XInput API is much simpler than the DirectInput API, and matches conformance with its counterpart in the XBoxSDK. However, the XInput API is more limited, with only support for 4 axes, 10 buttons, 2 triggers and a POV hat.

Crucially, the two triggers appearing as the positive and negative of the same axis is a "feature" of the XInput driver. Why I have no idea since this isn't how trigger reads happen on the xbox, and as near as my research through old devnet articles and wikipedia goes it appears to be an intentional limitation. What's really dumb is that the raw device reads provide the axis information as independent fields in the input data stream, but the driver does not expose this to consumers.

So we are faced with a choice: We can either rewrite the driver stack for the gizmo on windows to consume the raw input stream from the gamepad and de-serialize it into the correct structure for the gizmo, or we can just flip the controllers into DirectInput mode and accept that this means that the two analog triggers will become digital buttons, but everything works with the same button map everywhere.

In the interests of time, I'm inclined to just go with DirectInput mode mapping, which while less featureful doesn't require me to break out the Windows Input Debugger. I will try to get a build out the door tonight that uses the DirectInput which should fix this problem at least for the time being. Its worth pointing out that Microsoft has formally deprecated DirectInput along with the rest of DirectX and XInput for that matter as well in favor of GameInput which is an entirely new set of proprietary system APIs. Given the legendary support from Microsoft for legacy applications and devices, I think we're probably able to get away with this usage of a legacy system API that's been in widespread production use since 1991.

the-maldridge commented 10 months ago

Alright, some hammering on this and I have a build that I've now tested on linux and windows that works. Analog triggers have been sacrificed to make this work. Builds past ce5e29e handle the windows case correctly when the gamepad is in DirectInput mode.

the-maldridge commented 8 months ago

Closing this out as we are now past the hurdle and this is working.