SukkoPera / PsxNewLib

Playstation controller interface library for Arduino
GNU General Public License v3.0
128 stars 27 forks source link

Guncon support #8

Closed sonik-br closed 3 years ago

sonik-br commented 3 years ago

Hi threre! This lib supports a ps1 guncon lightgun?

SukkoPera commented 3 years ago

Not at the moment. I see there's some protocol info here though: http://problemkaputt.de/psx-spx.htm#controllerslightgunsnamcoguncon.

sonik-br commented 3 years ago

Thanks. Since the guncon reports x and y coordinates, my plan is to map it as a usb hid mouse. I might try to contact this gui and see if he got it working https://forum.arduino.cc/index.php?topic=363629.0

SukkoPera commented 3 years ago

I'm not sure that can be done easily, as it does not provide direct X/Y coordinates but rather some timings relative to video signals. I think you should be in control of the latter in order to be able to get the actual X/Y coordinates.

What we can do easily is read the buttons.

sonik-br commented 3 years ago

I'm currently reading a guncon2 (USB) and it can be mapped to screen coords, Seems that the gc1 reports the same way. On the usb it reports 6 bytes. It contains the buttons and the axis values. It just needs to "auto calibrate"... By moving it in the axis and capturing the min/max values it reports. There are some linux drivers for the guncon that uses the printer port and they seems to work this same way. There's also a rust code to use the guncon via SPI on a raspiberry :)

SukkoPera commented 3 years ago

Well, I might have a go at adding support for it when I have time.

sonik-br commented 3 years ago

Thanks. I will give it a try too and post my findings here.

SukkoPera commented 3 years ago

Would you be able to test, if I sent you a modified version of the lib?

sonik-br commented 3 years ago

Sure. Might take a day or two as I have to setup it all here. Still need to cut my ps controller extension cable and connect it to my arduino. I have a spare Leonardo. Would it work? Have a Uno too but it's being used right now.

SukkoPera commented 3 years ago

If you want it to act as a USB device (e.g. a controller), you need a Leonardo.

You can get spare replacement ports or the shield I designed rather if you don't want to cut a cable.

sonik-br commented 3 years ago

I plan on getting the shield later but for now I will just wire the extension cable to the arduino. Cable is already cut :) Any advice on what pins to use on a Leonardo for CMD, DATA, CLK and ATTN?

SukkoPera commented 3 years ago

If you want to use the hardware SPI pins, those are only available on the ICSP connector on the Leonardo. Otherwise you can use any pins you like.

sonik-br commented 3 years ago

They make any difference when using the lib? Might be a dumb question but this is all new to me.

SukkoPera commented 3 years ago

If you're only testing the lib there's no big difference. HW SPI might be a little more reliable but more in theory than in practice.

You just need to update one line in the examples.

SukkoPera commented 3 years ago

I have added tentative Guncon support on a dedicated branch.

First of all please make sure you can get a standard controller working, then you can modify the example so that:

if (psx.getProtocol () == PSPROTO_GUNCON) {
  word x, y;
  if (psx.getGunconCoordinates (x, y)) {
    // Do what you want with the coordinates
  }
}

Buttons are mapped as follows:

Note that:

Let me know if you can get it working.

sonik-br commented 3 years ago

Cool! Should I use DumpButtonsBitBang or DumpButtonsHwSpi?

sonik-br commented 3 years ago

It's alive! Yay!!!

Seems to be reading correctly. I will try output it as a mouse. I'm getting a lot of:

Controller lost :( Controller found! Cannot enter config mode

It's normal? Even when pointing at the screen.

SukkoPera commented 3 years ago

No, that should not happen. Do you also get it with a standard controller?

So do the X/Y coordinates actually make sense?

sonik-br commented 3 years ago

Totally making sense :D I'm storing the minimum and maximum reported values, discarding when it's a error. The values I got after moving it in all directions of screen:

MinX = 74, MaxX = 449 MinY = 22, MaxY = 250

From what I know this can vary from tv to tv and also from NTSC to PAL standard.

Standard controller seems to not have this problem. I'm storing the values from the lest successful read. When it not read, it's common to have a last value of 1, 10. The "no light" code.

And here some readings. It get a lot of "1, 10". Even trying to keep my hand steady and pointing at the same area of tv.

23:43:24.672 -> analog: x = 282, y = 152 23:43:24.706 -> analog: x = 1, y = 10 23:43:24.706 -> analog: x = 1, y = 10 23:43:24.740 -> analog: x = 282, y = 152 23:43:24.740 -> analog: x = 284, y = 151 23:43:24.774 -> analog: x = 1, y = 10 23:43:24.807 -> analog: x = 1, y = 10 23:43:24.807 -> analog: x = 283, y = 151 23:43:24.842 -> analog: x = 283, y = 152 23:43:24.876 -> analog: x = 1, y = 10 23:43:24.876 -> analog: x = 283, y = 143 23:43:24.911 -> analog: x = 282, y = 152 23:43:24.911 -> analog: x = 1, y = 10 23:43:24.945 -> analog: x = 1, y = 10 23:43:24.979 -> analog: x = 282, y = 152 23:43:24.979 -> analog: x = 283, y = 151 23:43:25.013 -> analog: x = 1, y = 10 23:43:25.047 -> analog: x = 1, y = 10 23:43:25.047 -> analog: x = 283, y = 151 23:43:25.080 -> analog: x = 1, y = 10 23:43:25.080 -> analog: x = 1, y = 10 23:43:25.115 -> analog: x = 284, y = 151 23:43:25.149 -> analog: x = 282, y = 152 23:43:25.149 -> analog: x = 1, y = 32778 23:43:25.182 -> analog: x = 1, y = 10 23:43:25.216 -> analog: x = 282, y = 152 23:43:25.216 -> analog: x = 1, y = 85 23:43:25.250 -> analog: x = 1, y = 10 23:43:25.250 -> analog: x = 283, y = 144 23:43:25.284 -> analog: x = 283, y = 151 23:43:25.317 -> analog: x = 1, y = 10 23:43:25.317 -> analog: x = 1, y = 10 23:43:25.352 -> analog: x = 283, y = 151 23:43:25.385 -> analog: x = 282, y = 152 23:43:25.385 -> analog: x = 1, y = 10 23:43:25.419 -> analog: x = 1, y = 10

SukkoPera commented 3 years ago

That's what I expected: the Nocash docs state that

To avoid the BUSY error, one should read the gun shortly after begin of VBLANK (ie. AFTER rendering, but still BEFORE vsync).

Since you don't have access to video data, all you can do is continuosly poll the gun and only consider the valid readings.

They also say that

The absolute min/max coordinates may vary from TV set to TV set (some may show a few more pixels than others).

as you correctly reported.

I will tweak the code a little later.

sonik-br commented 3 years ago

Yeah. I will do some more testings. It might be possible to find the vsync timming in real time taking into account when it reports the error. But I don't know if it's worth the ammount of work to make it work.

I have two guns. One original from namco and a nameless one. Today I tested the nameless one. The arduino won't even recognize it. Wanted to test it as there's a chance of it not reporting the errors. This gun is a dual mode (gcon1 and gcon2 usb). Via usb it does not report any error at all.

None of this would be possible without your help and your fantastic lib! Thanks for helping me out :)

sonik-br commented 3 years ago

I just found out that another person is making a device to use the guncon as a mouse. It does have a input for the video sync. might be the definitive solution for this problem.

sonik-br commented 3 years ago

Good news! My code was based on the DumpButtonsBitBang example. Now I changed to PSX2USB. Seems like the read timing is different. Now the guncon "resets" itself way less. Its more stable. Another thing is that I removed the call to psx.enterConfigMode(). Seems that its not needed. And without it when the gun resets, it gets back way faster. Now its totally usable as a mouse pointer!

SukkoPera commented 3 years ago

The PSX2USB timing is slightly slower (50 times per second instead of 60). I'd say that can hardly make a difference but you never know :). Most PSX controller are really fussy about timing, actually. I can't tell how many attempts I had to make to find timing values that worked with all controllers,

On this topic, you can also try playing a bit with the values at the top of PsxControllerBitBang.h and/or PsxNewLib.h. Maybe increasing them a bit can improve stability.

Removing the config mode stuff was a good idea, now we know that the Guncon has no config mode, so it was pretty useless.

I will make a slight change to the API as soon as I have time. Would you contribute your Guncon to mouse sketch once we are done?

sonik-br commented 3 years ago

Sure! I will post it on github. I'm not a experienced C coder. Right now I'm just using your lib and another one for the mouse. My code just translate the values and set the mouse position. It still needs proper calibration to have "eye sight" targeting. Would be cool to set the offset values via serial commands. Here's a video of it in action https://youtu.be/K-l4DoSJf2s

SukkoPera commented 3 years ago

Great! No problem, I will "fine-tune" your code and turn it into an example for this library.

I have just done the API change, please update from the branch. Now you should just check that:

if (psx.getGunconCoordinates (x, y) == GUNCON_OK) {
  // ...
}

This should simplify your code.

SukkoPera commented 3 years ago

Hi, any progress on this?

sonik-br commented 3 years ago

It's working but it still needs a proper way to calibrate. I'm messing with the timings. Reading it at 120hz makes the cursor move very smooth. It currently maps to an absolute mouse. Tested in windows 10. Still need to test o linux and older windows. This weekend I was also testing a guncon2 (it uses usb connection) on linux. The driver maps it to a joystick. Not very useful BUT the MAME emulator works this way. With this info now I also want to map the original guncon to a joystick (using your lib). If it works I think it would be a good addition to PsxNewLib :) Want to take a look at the mouse sketch? I can upload it to the guncon branch.

SukkoPera commented 3 years ago

Sure, or just put it here and I'll add it.

sonik-br commented 3 years ago

It's bundled with a modified version of the AbsMouse lib. Might be possible to not even use it. The only change is in the cpp file, method move(uint16_t x, uint16_t y). Original code is commented. And I had no luck using a not official guncon. Any advice? GunconAbsMouse_Sample.zip

SukkoPera commented 3 years ago

Thanks, I will add it to the examples ASAP. I will switch it to the HID Library later on, since it has an AbsoluteMouse implementation and I plan to use it for the joystick examples too.

I'm also trying to get hold of a Guncon at a decent price, but it's harder than it might seem. Even then, I have no idea of how to connect a CRT to one of my PCs. I guess I'll have to use one of my RasPis.

On a side note, I think you can user psx.buttonJustPressed() in the sketch instead of keeping track of whether buttons are pressed or not.

SukkoPera commented 3 years ago

OK, I have added and "polished" the sketch. I didn't even test if it compiles at the moment, it would be great if you could do that and make sure it still works.

sonik-br commented 3 years ago

I will test the sketch.

For connecting a crt tv the cheaper way is to use an "hdmi2av" converter like this one hdmi2av Not great image quality and lot of noise on the signal. But works for testing the guncon.

There's a trick I use for testing too. Connect to the tv any device with a rca composite video signal that can display a bright image. Like a dvd player, a game console or the rpi. Connect the guncon to it and point to the screen. The guncon will read the signal. You will just not have the PC image on the tv ;-)

sonik-br commented 3 years ago

Updated Sketch still works. But it needs some small fixes to compile. Missing the declaration of method dstart. And some calls to psx.buttonJustReleased are missing the instance psx. It's just calling "buttonJustReleased".

SukkoPera commented 3 years ago

Thanks, but I thought I had already fixed those (1ec0c6cdd02f4a8575582db953432b78f7736043)...

sonik-br commented 3 years ago

My bad :D

SukkoPera commented 3 years ago

No problem :).

IIRC, you still have occasional read errors, right? Could you try if the following improves the situation?

  1. Set INTER_CMD_BYTE_DELAY to 50.
  2. Set ATTN_DELAY to 100.

Please try the two mods both alone and together and let me know if they help.

PS: I managed to score a GunCon but it'll take a while before I can put my hands on it :/.

sonik-br commented 3 years ago

Thanks. I will test it on the weekend. Needed some space on my desk and had to move the CRT.

sonik-br commented 3 years ago

Tested. Found out that the disconnects only happen when outputting HID commands. Weird. Maybe it have a negative impact on the read timing? Using default values and not reporting the mouse coords I have zero disconnects and errors.

Now the tests:

With only INTER_CMD_BYTE_DELAY=50 Zero disconnects

With only ATTN_DELAY=100 Some disconnects

With both INTER_CMD_BYTE_DELAY=50 and ATTN_DELAY=100 Some disconnects

All tests made without reporting mouse coords. When enabling, it will do some disconnects. But it's very fast to recover.

Another test I've done is to chance the pooling interval. Using the default (50) it get like 4 sequential good reads and 4 sequential GUNCON_NO_LIGHT. Using a way faster interval, like "1000U / 200U", it gets lot of good reads and like one or two GUNCON_NO_LIGHT. This way I can just count the amount of sequential GUNCON_NO_LIGHT. And if it's less than 3, then just return the last good read value.

SukkoPera commented 3 years ago

That sounds weird. Can you try putting a noInterrupts() just before the read, and a interrupts() right afterwards? I don't know how the USB reporting works in detail and it might interrupt the polling, even though it shouldn't be too much dependent on perfect timing.

INTER_CMD_BYTE_DELAY suggests that proper handling of ACKs from the controller should be the next thing to do. I'll try to work on it.

Thanks for your help. If you want to submit changes for the example feel free to.

sonik-br commented 3 years ago

With noInterrupts/interrupts, I got zero disconnects. :D But still got some GUNCON_OTHER_ERROR.

Then I remembered that the HID module have an autoreport feature. After disabling it and calling report at the end of the loop, all errors are gone!

With the noInterrupts trick and hid autoreport off, I could test with a ultra hi pooling rate of "1000U / 400U" with no errors at all. Amazing!

Now I'm trying to understand how MAME and other emulators handle a "offscreen shot". Used to reload in some games. I can't really put the mouse cursor oy the joystick axis to an off screen position. Think I have to simulate a button press (mapped to the reload function in the emulator)

sonik-br commented 3 years ago

Hi! My code is now on github https://github.com/sonik-br/GunconDuino

Been playing some emulators with it and it's pretty stable!

SukkoPera commented 3 years ago

Sorry for the delay, been pretty busy.

Nice job! Would you prefer to keep your work separate or shall I update the example in the main library? I'm fine both ways, it's your job so it's your choice :). I'd happily add a link if you prefer to keep it separate.

sonik-br commented 3 years ago

You can update the example in the lib. I still have some ideas for it. Will let you know if/when I update it :) And I still need to make it work with third party controllers. Any idea why it wont work?

SukkoPera commented 3 years ago

OK, I have updated the ATTN_DELAY and INTER_CMD_BYTE_DELAY values after your testing. I have also tried to sync the example to your code. I don't intend to make it an exact copy of it (unless you want so), it should only showcase the base functionalities.

So if you can do one final test, I will then merge the code into the master branch.

I can't say why it doesn't work with third-party controllers, maybe they require more tweaking of the values, or lower pull-ups, try 1k.

Oh, by the way, are you sure you're not missing an AbsMouse.init (MAX_MOUSE_VALUE, MAX_MOUSE_VALUE, false); line in your sketch? Otherwise you are NOT disabling autoreports, as far as I understand! :)

sonik-br commented 3 years ago

I can test it in the weekend. And I have removed the autoreport feature from AbsMouse. No need to call init() anymore. Please update your copy of the library too.

sonik-br commented 3 years ago

Tested the sample and the updated lib. Seems to be working fine.

SukkoPera commented 3 years ago

All changes merged to master in 632e893, thanks a lot for your help.

Going to release a new version including everything in a couple of minutes.