pcsx2 icon indicating copy to clipboard operation
pcsx2 copied to clipboard

USB: Add train controller emulation

Open joestringer opened this issue 1 year ago • 44 comments

Description of Changes

Emulate a range of "Densha Mascon" train controllers originally sold by Taito, such as TCP20009, TCP20011, TCP20014. Built using datasheets courtesy of @marcriera and other contributors at https://marcriera.github.io/ddgo-controller-docs/ .

Type 2 Shinkansen Ryojōhen
type2 shinkansen ryojouhen

Rationale behind Changes

Lever-based controllers provide an advantage over the standard DualShock emulation for some games, as these controllers physically hold an axis in a particular level without requiring the player to actively apply pressure. These changes allow players with lever-based controllers to play Densha de Go! titles such as:

  • Densha de GO! 3 Tsūkin-hen
  • Densha de GO! Final
  • Densha de GO! Professional 2
  • Densha de GO! Ryojōhen
  • Densha de GO! San'yō Shinkansen-hen

Suggested Testing Steps

The ddgo-controller-docs website describes these controllers and lists the compatible titles. I have tested these with my own USB Zuiki One-Handle MasCon controller for Nintendo Switch. Given the way that the hardware maps into the emulated controller, the best subtype for this particular hardware controller is the "Type 2" controller. Some games will change the input scheme and number of power/brake notch settings based on the selected subtype variant.

Related: #4763

joestringer avatar Aug 18 '24 22:08 joestringer

cc @sonik-br this might be interesting to you. I have not tested the "USB passthrough" mode but I believe that this should allow original Densha De GO! USB controllers to work correctly with this patch.

joestringer avatar Aug 18 '24 23:08 joestringer

Fixed a couple of CI complaints - extraneous xml tags in the vcxproj file, and I forgot to add the new files to the CMakeLists.txt, leading to linker failures in the CI builds. These should be resolved now.

joestringer avatar Aug 19 '24 00:08 joestringer

cc @sonik-br this might be interesting to you. I have not tested the "USB passthrough" mode but I believe that this should allow original Densha De GO! USB controllers to work correctly with this patch.

Amazing work! I can try and report back. There's a build to download or I need to build from source?

sonik-br avatar Aug 19 '24 12:08 sonik-br

There's a build to download or I need to build from source?

You can download the CI artifacts from the checks tab, make sure to pick your OS.

image

kamfretoz avatar Aug 19 '24 12:08 kamfretoz

Not sure how to use usb passthrough. The device is not HID and does not shows as a gamepad under windows. I need to install generic a usb driver with zadig?

sonik-br avatar Aug 19 '24 17:08 sonik-br

Not sure how to use usb passthrough. The device is not HID and does not shows as a gamepad under windows. I need to install generic a usb driver with zadig?

Won't work. Only HID controllers like DGOC-44U will work

Florin9doi avatar Aug 19 '24 17:08 Florin9doi

Won't work. Only HID controllers like DGOC-44U will work

Ah ok! I can emulate this device using a rp2040 then. Can try it later this week.

sonik-br avatar Aug 19 '24 18:08 sonik-br

@Florin9doi @IlDucci thanks for the reviews! I believe I've addressed all of your comments.

joestringer avatar Aug 20 '24 05:08 joestringer

I could no get passthrough to work. I'm emulating a PC Two Handle (DGOC-44U) using the descriptors from marcriera. Need any special setting?

sonik-br avatar Aug 20 '24 12:08 sonik-br

What kind of passthrough do you expect? You'll still have to map the axes and buttons , but the axes values won't stick to predefined values and will be sent unchanged.

Florin9doi avatar Aug 20 '24 13:08 Florin9doi

What kind of passthrough do you expect? You'll still have to map the axes and buttons , but the axes values won't stick to predefined values and will be sent unchanged.

Brake axis can't be mapped. It does not pick any movement on the map screen. But the axis is working as I can test on windows and on the PC version of the game (DDGO Final)

sonik-br avatar Aug 20 '24 13:08 sonik-br

The brake's range is too limited and is ignored? Try to map a random button then open PCSX2.ini and change Brake=Xinput-X/ButtonY to Brake=Dinput-x/FullAxis1

Florin9doi avatar Aug 20 '24 13:08 Florin9doi

Still not working. Tested with fullaxis0 and fullaxis1.

[USB1]
Type = DenshaCon
DenshaCon_A = DInput-0/Button1
DenshaCon_B = DInput-0/Button0
DenshaCon_C = DInput-0/Button2
DenshaCon_D = DInput-0/Button3
DenshaCon_Select = DInput-0/Button4
DenshaCon_Start = DInput-0/Button5
DenshaCon_Up = DInput-0/Button6
DenshaCon_Right = DInput-0/Button9
DenshaCon_Down = DInput-0/Button7
DenshaCon_Left = DInput-0/Button8
DenshaCon_Power = DInput-0/+Axis1~
DenshaCon_Brake = DInput-0/FullAxis0
DenshaCon_Passthrough = true

Also tested with

DenshaCon_Power = DInput-0/FullAxis1
DenshaCon_Brake = DInput-0/FullAxis0

sonik-br avatar Aug 20 '24 14:08 sonik-br

@Florin9doi @IlDucci I've resolved your latest feedback 🚀

@sonik-br thanks for testing. Do the other buttons and power lever work in-game or are all of the controls broken? If they work, does the lever increase the number of power notches that you expect?

I also wonder if the brake axis is a much higher number. For my controller, despite there being only a single lever with two axes (power, brake), SDL represents these with positive/negative axis 7.

joestringer avatar Aug 21 '24 04:08 joestringer

@joestringer buttons and dpad works in-game. Power lever does not. The game think it's always on max power. image

sonik-br avatar Aug 21 '24 11:08 sonik-br

@sonik-br Hmm OK. Early on I did encounter similar issues while initially developing the support. I can't do much about the brake since that relies on the input library to pull the values into the point where this feature processes it. Unless you're able to resolve that problem, the idea of the passthrough mode feature/patch might not make sense.

That said to debug further about what's going on with the power axis, you could try pulling this new version with debug logging here:

https://github.com/joestringer/pcsx2/actions

You might need to remap the controls again, I'm not sure. But after that you can go to Tools -> Enable Log Window or Enable File Logging. When you run the game, the log will spam lines about the brake and power values. If you can start with the controller with brakes and power off, then move the power lever step by step from released up to full power and back down, it will log all the input values. If you scan up through the logs until you see logs printing different values for the power axis and share those logs, it would help to understand the range of values that are being pulled into this code. Separately if you can figure out the brake, then it would also help to have the same log data lines with the varying brake input values.

joestringer avatar Aug 22 '24 03:08 joestringer

@joestringer tested... Forcing it on the ini file to fullaxis as:

TrainController_Power = DInput-0/FullAxis1
TrainController_Brake = DInput-0/FullAxis0

Brake only shows as FF on it's first position and FF on all other positions. Power shows as:

P5 80 P4 A0 P3 Be P2 D3 P1 ED N FF Transiton FF

All tests doe using direct input.

And interesting: Same results with and without passthrough mode

sonik-br avatar Aug 22 '24 23:08 sonik-br

And interesting: Same results with and without passthrough mode

Oh yeah maybe I didn't explain well. The logs you see are presenting the raw input from DInput, before this code processes the values to output to the game. So the passthrough mode doesn't have an effect on the values you see there. That's normal.

I can't really explain the discrepancy.. If you're running a DGOC-44U, then these docs describe the notches as:

N P1 P2 P3 P4 P5 Transition
0x81 0x6D 0x54 0x3F 0x21 0x00 0xFF

Comparing this with the values that you have presented, there values are very different:

N P1 P2 P3 P4 P5 Transition
0xFF 0xED 0xD3 0xBe 0xA0 0x80 0xFF

The passthrough mode was written with the idea in mind that the values from the input library would be identical to the selected subtype of controller. But even if I look through the other controller types in the Marc Riera datasheets, I can't find any controller types that match the values you are reporting.

One interesting thing about the bitpatterns you report is that the bit at offset 0x80 is always set. On average across the values they're all around 0x7E-0x80 higher than the value reported by the docs. This makes me wonder whether either model you have works differently somehow, or if perhaps the values get treated as signed values that get set negative somewhere, or if somehow the input library is doing some conversions that cause a skewing of the values into the upper range.. Not sure if FullAxis vs. +Axis vs -Axis configuration could have this sort of impact as well.

Technically it's not that difficult to try to adjust for this, but it's a bit hard for me to picture the range of devices that may be impacted by this behaviour - is this a general property of all of the original controllers so I should apply a filter automatically in passthrough mode? Or is it that the axis needs to be configured in a particular way to cause these results? Will a fix I come up with help or hurt the emulation of this controller? I'd welcome input from upstream PCSX2 devs if they have ideas on how to best handle this. I guess I could add another separate setting option called "DGOC-44U compatibility" if we think that it's this specific controller that has this behaviour. On the other hand, another option is just to remove passthrough mode if it's not going to fully work for someone.

In the mean time, just to see if it could work, I added a hack to the latest builds over here to try to have the right behaviour for your environment: https://github.com/joestringer/pcsx2/actions . The code is in https://github.com/joestringer/pcsx2/pull/2.

Brake only shows as FF on it's first position and FF on all other positions.

OK. That confirms that Dinput isn't processing the brake signal at all. Pretty much what we expected since you can't even configure it through the UI.

joestringer avatar Aug 23 '24 02:08 joestringer

@joestringer I'm not exactly using a real "DGOC-44U"... It's a PS2 Type 2 device with a custom made usb adapter that outputs like a DGOC-44U. But I don't think that's the problem as the PC version of the game detects and uses the device correctly.

Btw looks like the power axis is working as half axis, right? It goes from 0x80 to 0xff. It's like if dinput apply some kind of range calibration.

sonik-br avatar Aug 23 '24 04:08 sonik-br

Try to switch from dinput to sdl

Florin9doi avatar Aug 23 '24 04:08 Florin9doi

Testing under windows joy.cpl

Neutral image

P5 image

sonik-br avatar Aug 23 '24 04:08 sonik-br

Yeah if you can try SDL, that would be good. But I would not suggest using the latest build I shared from my GitHub fork, maybe try the previous one that you tested earlier with the debug logging, or just pick up the build from this PR. The latest build on my fork will mess with the input as it gets passed through.

joestringer avatar Aug 23 '24 04:08 joestringer

joy.cpl output there looks good, matches the spec I expected.

joestringer avatar Aug 23 '24 04:08 joestringer

SDL raw, with the same build as before P5 ff P4 be P3 82 P2 57 P1 24 N 00 Transiton 00

sonik-br avatar Aug 23 '24 04:08 sonik-br

Those latest numbers look more like the scale is inverted and spread across the full range of a byte rather than limiting to around half the range. That I could see being part of how the input is processed and rendered into floats before handing to this patch.

Is that configuration with a half axis or a full axis configured? Also, does brake work with SDL or do you see the same issue with the brakes?

joestringer avatar Aug 23 '24 04:08 joestringer

Shinkansen controller USB passthrough isn't working - it says both handles have a value of 0, and actually moving the physical controller does nothing. Especially annoying, as "removing" the virtual USB freezes the game.

mario032106 avatar Aug 23 '24 05:08 mario032106

@mario032106 thanks for trying it out! Would you be able to also share the console logs, similar to the information I asked for in this comment? There could be something fairly simple that I got wrong since I don't have the hardware to test with. You can try with these builds (windows link) or wait for non-Windows builds at the top here.

joestringer avatar Aug 23 '24 05:08 joestringer

@joestringer Used that exact build, and had it log to console. Both handles started at 0. No input was registered, not even the face buttons. Mapped it to the keyboard to check if it even worked, and it did, so either it's a problem with my controller (unlikely, as AutoTrainTAS recognizes it just fine, as does Final on an actual PS2) or USB passthrough.

mario032106 avatar Aug 23 '24 05:08 mario032106

@mario032106 and to confirm is that using SDL for the input? The logs print the raw values pulled from the input library, so if those are printing zeroes regardless of the input then it's due to an issue in the code before this code even gets executed. The log is just printing what values hit this code, before this code processes the values.

joestringer avatar Aug 23 '24 06:08 joestringer

Shinkansen controller USB passthrough isn't working - it says both handles have a value of 0, and actually moving the physical controller does nothing. Especially annoying, as "removing" the virtual USB freezes the game.

There is no USB passthrough , only axis passthrough. A real Shinkansen wont work unless you have a 3rd party HID driver

Florin9doi avatar Aug 23 '24 06:08 Florin9doi