Guncon support
sonik-br opened this issue ยท 47 comments
Hi threre!
This lib supports a ps1 guncon lightgun?
Not at the moment. I see there's some protocol info here though: http://problemkaputt.de/psx-spx.htm#controllerslightgunsnamcoguncon.
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
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.
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 :)
Well, I might have a go at adding support for it when I have time.
Thanks. I will give it a try too and post my findings here.
Would you be able to test, if I sent you a modified version of the lib?
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.
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.
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?
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.
They make any difference when using the lib?
Might be a dumb question but this is all new to me.
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.
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:
- A (Left side) -> Start
- B (Right side) -> Cross
- Trigger -> Circle
Note that:
- Coordinates X=0001h, Y=0005h indicate "unexpected light", i.e. sensed light during VSYNC (eg. from a Bulb or Sunlight).
- Coordinates X=0001h, Y=000Ah indicates "no light", this can mean either no light sensed at all (not aimed at screen, or screen too dark: ERROR) or no light sensed yet (when trying to read during rendering: BUSY).
Let me know if you can get it working.
Cool!
Should I use DumpButtonsBitBang or DumpButtonsHwSpi?
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.
No, that should not happen. Do you also get it with a standard controller?
So do the X/Y coordinates actually make sense?
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
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.
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 :)
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.
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!
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?
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
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.
Hi, any progress on this?
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.
Sure, or just put it here and I'll add it.
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
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.
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.
I will test the sketch.
For connecting a crt tv the cheaper way is to use an "hdmi2av" converter like this one
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 ;-)
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".
My bad :D
No problem :).
IIRC, you still have occasional read errors, right? Could you try if the following improves the situation?
- Set INTER_CMD_BYTE_DELAY to 50.
- 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 :/.
Thanks.
I will test it on the weekend. Needed some space on my desk and had to move the CRT.
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.
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.
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)
Hi!
My code is now on github
https://github.com/sonik-br/GunconDuino
Been playing some emulators with it and it's pretty stable!
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.
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?
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! :)
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.
Tested the sample and the updated lib. Seems to be working fine.