Main Restorations Software Audio/Jukebox/MP3 Everything Else Buy/Sell/Trade
Project Announcements Monitor/Video GroovyMAME Merit/JVL Touchscreen Meet Up Retail Vendors
Driving & Racing Woodworking Software Support Forums Consoles Project Arcade Reviews
Automated Projects Artwork Frontend Support Forums Pinball Forum Discussion Old Boards
Raspberry Pi & Dev Board controls.dat Linux Miscellaneous Arcade Wiki Discussion Old Archives
Lightguns --- Bug Reports --- Site News

Unread posts | New Replies | Recent posts | Rules | Chatroom | Wiki | File Repository | RSS | Submit news

  

Author Topic: Attempting to hack and document GunCon2 for Linux, FreeBSD, and MacOS X.  (Read 9743 times)

0 Members and 1 Guest are viewing this topic.

Numbski

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 296
  • Last login:April 04, 2011, 08:16:59 pm
    • Numbski
Okie, I started this.  I e-mailed acorns asking if he might share he sources, but with no luck. :(  So I started out on my own.  I started writing about this over at the SDLMAME boards, but since there are more people here that have been following this, I might have better luck tracking it here.

Here's the original thread:

http://www.bannister.org/forums/ubbthreads.php?ubb=showflat&Number=25264&page=0

What I've come to is that the gun sends a default binary over and over again in this pattern:

FF FF 01 00 05 00

They are hex values, and the first 3 values control the button presses.  Here is the matrix of those first three values:

First:
3 - Down-Left
6 - Up-Left
7 - Left
9 - Down-Right
B - Down
C - Up-Right
D - Right
E - Up
F - Control Pad not pressed

Second:
1 - A + B + C
3 - A + B
5 - A + C
7 - A
9 - B + C
B - B
D - C
F - Neither A, B, nor C is pressed.

Third:
1 - Select + Start + Trigger
3 - Select + Start
5 - Start + Trigger
7 - Start
9 - Select + Trigger
B - Select
D - Trigger
F - Neither Select, Start, nor Trigger Pressed


I got these by plugging into my FreeBSD box, which gave me a generic character device (/dev/ugen0.1).  I just pressed buttons and did a cat /dev/ugen0.1 > guncon2.log, then opened guncon2.log in a hex editor.  This is in my arcade cab, and I haven't wired up a circuit to get a composite video signal to the gun to figure out how it handles tracking.  I'm still holding out hope that Acorns will give me a shout on how it handles that so that maybe either one of the mame devs can just merge the support in directly, or at least I can hack the stock FreeBSD mouse driver to accept the gun as a valid mouse device. :\  Whatever the case, if it's documented, it's more likely that a skilled programmer can jump in and do something with this.
Build a man a fire, keep him warm for the night.
Set a man on fire, keep him warm for the rest of his life.

Silver

  • Wiki Contributor
  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 1662
  • Last login:May 07, 2019, 06:22:24 am
  • Cunning like the Fox.
    • Mods'n'Mods
Re: Attempting to hack and document GunCon2 for Linux, FreeBSD, and MacOS X.
« Reply #1 on: December 05, 2006, 07:29:44 pm »
Hi,

There is Guncon2 Linux driver available here:

http://mywebpages.comcast.net/bgoines78/

Someone else then wrote a Linux driver for the LCD Topgun, based on the above, here:

http://kaillera.com/topgun/

The Topgun is basically Guncon2 compatible, but it has these values hard coded:

X Min =  160
X Max =  672
Y Min = 32
Y Max = 224

as it has its own internal calibration (it always sends values within that range to the PC).

Hope that helps...

Numbski

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 296
  • Last login:April 04, 2011, 08:16:59 pm
    • Numbski
Re: Attempting to hack and document GunCon2 for Linux, FreeBSD, and MacOS X.
« Reply #2 on: December 05, 2006, 08:34:00 pm »
As is posted elsewhere here, that uses the PS2 control API (ie, it is intended for Linux running ON the PS2, and thus can't be used) which I don't have access to.

Got my gun wired up to my arcadevga card, and trying to do comparisons now.

As you see above, I've figured out that the first 3 (maybe 4?) values are the buttons.  Well, since we can elimate those, here's the default state again:

FF FF 01 00 05 00

Now, here's a sample of tracking:

FF FF A6 03 F0 00

I appears that the next 6 values are used for tracking.  I kinda expected to find an X-Axis and a Y-Axis.  I vaguely recall there being two settings for the GunCon2... 100Hz and something else?  Someone want to clear me up on this?

What I need to do is find a way to view these hex values in real-time.  Probalby hack together a perl script that runs a constant dump of /dev/ugen0.1 and converts it to readable hex.  Ideally updating the 6 hex pairs and not just spewing garbage, that way I can quickly determine what is X-Axis and what is Y-Axis.
Build a man a fire, keep him warm for the night.
Set a man on fire, keep him warm for the rest of his life.

Numbski

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 296
  • Last login:April 04, 2011, 08:16:59 pm
    • Numbski
Re: Attempting to hack and document GunCon2 for Linux, FreeBSD, and MacOS X.
« Reply #3 on: December 05, 2006, 09:36:26 pm »
I'm looking over that topgun driver, and it's puzzling...the output from the gun in that driver doesn't even come close to matching what I've observed:

input_report_key(dev, BTN_TRIGGER, !(data[1] & 0x20));
   input_report_key(dev, BTN_A,       !(data[0] & 0x04));
   input_report_key(dev, BTN_B,       !(data[0] & 0x08));
   input_report_key(dev, BTN_C,       !(data[0] & 0x02));
   input_report_key(dev, BTN_START,   !(data[1] & 0x80));
   input_report_key(dev, BTN_SELECT,  !(data[1] & 0x40));

   if(!(data[0] & 0x10)) x+=-1;
   if(!(data[0] & 0x40)) x+=1;
   if(!(data[0] & 0x80)) y+=-1;
   if(!(data[0] & 0x20)) y+=1;
Trigger is 0x20?  I'm geting it at 0x00D .  I'm sure that there's a mathematical conversion I'm missing here, but beats me what it is...
Build a man a fire, keep him warm for the night.
Set a man on fire, keep him warm for the rest of his life.

2600

  • Trade Count: (+7)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 1630
  • Last login:June 05, 2017, 10:20:56 am
  • I want my own arcade controls!
Re: Attempting to hack and document GunCon2 for Linux, FreeBSD, and MacOS X.
« Reply #4 on: December 05, 2006, 09:44:41 pm »
Endianness??

Numbski

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 296
  • Last login:April 04, 2011, 08:16:59 pm
    • Numbski
Re: Attempting to hack and document GunCon2 for Linux, FreeBSD, and MacOS X.
« Reply #5 on: December 06, 2006, 09:23:01 am »
dewhodewhadehuh??

 :laugh2:

Sorry, should explain that I'm not really a programmer, I just pretend to be one.  Quick tutorial please?  How would endianness throw the values so far off?  Quick background on me...I'm a network engineer, and I have a mild amount of coding experience using perl.  Please be gentle. :)

(Just look it up on wikipedia: http://en.wikipedia.org/wiki/Endianness ....and figures.  byte ordering.  Gee, not dealing with byte order here AT ALL. :P  Now I need to figure out what order is being used and how.  I have NO IDEA how to do that.   :dunno )
« Last Edit: December 06, 2006, 09:26:45 am by Numbski »
Build a man a fire, keep him warm for the night.
Set a man on fire, keep him warm for the rest of his life.

Numbski

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 296
  • Last login:April 04, 2011, 08:16:59 pm
    • Numbski
Re: Attempting to hack and document GunCon2 for Linux, FreeBSD, and MacOS X.
« Reply #6 on: December 06, 2006, 09:37:00 am »
Crap.   I never knew that Little-Endian meant the byte order was FLIPPED.  WTF???

Why on earth would you store your bytes backwards?

 :soapbox:

(This, my friends, is why I went into MIS and not CS.)

So...yeah, byte order could be reversed to what these guys were seeing.  Lovely.

Still doesn't make any sense.  Take our trigger example again.  This is what the gun returns for me when the trigger is pulled:

FF DF 01 00 05 00

Now, if I have big-endian, and they were small endian, then it would be this:

00 05 00 01 DF FF

The TopGun driver says it's looking for trigger input at 0x20.  I'm presuming that 0x20 is a hex number (as 0x notation suggest), meaning each place is actually 16 and not 10, so 20 is really 2x16, or 32 bits in.  Still makes no sense at all to me. :\  At some point today I'm giong to try to hack together a perl script that gives me the current value being spit out by /dev/ugen0.1 so that at very least I can identify what values are messed with by x-axis and y-axis.
« Last Edit: December 06, 2006, 09:46:15 am by Numbski »
Build a man a fire, keep him warm for the night.
Set a man on fire, keep him warm for the rest of his life.

Numbski

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 296
  • Last login:April 04, 2011, 08:16:59 pm
    • Numbski
Re: Attempting to hack and document GunCon2 for Linux, FreeBSD, and MacOS X.
« Reply #7 on: December 06, 2006, 10:38:37 am »
Just occurred to me to try looking at this as hex octets.  Don't know why...

FF FF 01 00 05 00

So...

255 255 1 0 5 0

The last 4 values don't really change doing that.

My tracking example was:
ff ff a6 03 f0 00

255 255 166 240 0

So it looks like octets 1 and 2 are button values, octets 3 and 4 are tracking values, and octet 5 is....padding?  Maybe a delimiter?  But that means at no time can you track larger than 255 in any given direction?  We know that isn't true based on what you say about the Top Gun driver:

X Min =  160
X Max =  672
Y Min = 32
Y Max = 224

672 > 255.  Hmm....
Build a man a fire, keep him warm for the night.
Set a man on fire, keep him warm for the rest of his life.

2600

  • Trade Count: (+7)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 1630
  • Last login:June 05, 2017, 10:20:56 am
  • I want my own arcade controls!
Re: Attempting to hack and document GunCon2 for Linux, FreeBSD, and MacOS X.
« Reply #8 on: December 06, 2006, 10:39:21 am »
Ok, actually took a second to look at what you are saying.  It's not an Endian Issue, not sure why I said that.  But hey you learned something new.

I am having trouble of thinking of how to best describe this to you.  I'm not sure if you have a grasp on bits, bytes, or hex notation and I don't have time provide a lot of help.

I only glanced at it and could be wrong so double check, but here's the trigger example:

FF FF  01 00 05 00 is your default.
FF DF 01 00 05 00 is when the trigger is pulled.

FF is hex notation for 1111 1111 in binary.
DF is hex notation for 1101 1111 in binary.

Notice only one bit changed when the trigger was pulled.  The example code is masking that bit and if that bit is zero then the trigger is pulled.

That's the gist of it, sorry don't have time to help more.

Numbski

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 296
  • Last login:April 04, 2011, 08:16:59 pm
    • Numbski
Re: Attempting to hack and document GunCon2 for Linux, FreeBSD, and MacOS X.
« Reply #9 on: December 06, 2006, 10:42:09 am »
Actually, I'm pretty good with it from doing subnet calculations, so yeah, I should have realized that as soon as I started looking at hex that only individual bits changed.  I need to break this out in binary (which I was lazy and trying to avoid doing), and I'm sure a pattern will emerge from that.
Build a man a fire, keep him warm for the night.
Set a man on fire, keep him warm for the rest of his life.

Numbski

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 296
  • Last login:April 04, 2011, 08:16:59 pm
    • Numbski
Re: Attempting to hack and document GunCon2 for Linux, FreeBSD, and MacOS X.
« Reply #10 on: December 06, 2006, 11:35:52 am »
Default:
1111 1111 1111 1111   (FF or 255) - Control Pad and A,B, and C buttons

1111 1111 1111 1111 (FF or 255) - Select, Start, and Trigger (anything else?)

0000 0000 0000 0001 (01 or 1)   - Unknown, suspect X-Axis

0000 0000 0000 0000 (zero)      - Unknown?

0000 0000 0000 0101 (05 or 5)   - Unknown, suspect Y-Axis

0000 0000 0000 0000 (zero)      - Unknown?

So we have 6 octets (actually bytes...I'm used to saing octets from subnetting!).  It could be that the buttons are 8-bit and the
X and Y axis are 16 bits each.  8-Bit has values of 0-255 for a total of 256 possible
values, whereas 16 -bit would be 0-65535, or a total of 65536 possible values.

I won't know for sure until I can hack up a little tracking program, but here's
the data I already have in binary notation, masked off by byte:

First, a lookup table to keep things simple for the binary-impared:

Code: [Select]
0000 - 0
0001 - 1
0010 - 2
0011 - 3
0100 - 4
0101 - 5
0110 - 6
0111 - 7
1000 - 8
1001 - 9
1010 - A
1011 - B
1100 - C
1101 - D
1110 - E
1111 - F

The following has been edited.  Thanks to Waremonger for correcting me on sig figs. :)

First Byte (Control Pad Nibble)
0111 1111 - Left - bit 8
1011 1111 - Down - bit 7
1101 1111 - Right - bit 6
1110 1111 - Up - bit 5
1111 1111 - Nothing Pressed

First Byte (Buttons Nibble)
1111 0111 - A - bit 4
1111 1011 - B - bit 3
1111 1101 - C - bit 2
1111 1110 - ? - bit 1
1111 1111 - Nothing Pressed

Second Byte (Select, Start, Trigger Nibble)
0111 1111 - Start - bit 8
1011 1111 - Select - bit 7
1101 1111 - Trigger - bit 6
1110 1111 - ? - bit 5
1111 1111 - Nothing Pressed

So what it boils down to here is that all bits default to on, and
when a button is pressed, that button switches to a 0.

For example, up is 1110 (bit 1), and right is 1101 (bit 2), if I want up-right,
I get 1100, as the 1st and 2nd bits become 0's.

So....yay!  It's starting to make sense. :) 2 bytes down, 3 bytes to go. :)
« Last Edit: December 07, 2006, 09:57:39 am by Numbski »
Build a man a fire, keep him warm for the night.
Set a man on fire, keep him warm for the rest of his life.

Numbski

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 296
  • Last login:April 04, 2011, 08:16:59 pm
    • Numbski
Re: Attempting to hack and document GunCon2 for Linux, FreeBSD, and MacOS X.
« Reply #11 on: December 06, 2006, 01:13:32 pm »
Okay, here's the status script I've hacked up.  It displays the status in hex based on my original observation:

Code: [Select]
#!/usr/bin/perl -w

use Term::Cap;

# What is the character device for the gun?
$guncon = '/dev/ugen0.1';

# clearing out our status...just in case.
$status = undef;
$value = undef;

if (!-c $guncon) {
        print "$guncon is not a character device!\n";
        exit;
}
if (!-r $guncon) {
        print "$guncon exists, but you aren't allowed to read it!\n";
        exit;
}

# See if we can figure out what your terminal speed is...
# We'll presume 9600bps if nothing else.
$OSPEED = 9600;
eval {
    require POSIX;
    my $termios = POSIX::Termios->new();
    $termios->getattr;
    $OSPEED = $termios->getospeed;
};
$terminal = Term::Cap->Tgetent({OSPEED=>$OSPEED});
#$terminal->Tputs('cl', 1, STDOUT);
$clear = $terminal->Tputs('cl');

# Try to open a filehandle to the gun character device.
print "Attempting to open gun at $guncon...\n";
open GUN, $guncon or die "Can't open $guncon : $!\n";

# Switch us to binary mode scotty!  Read the status and print it.
while(1){
        binmode GUN;
        sysread(GUN,$status, 20);
        foreach $value(split(//, $status)) {
                printf("%02x ", ord($value));
        }
        $status = undef;
        $value = undef;
        print "\nPress Ctrl-C to exit\n";
        print $clear;
}

What it appears to be at this point is that the third byte is the horizontal axis, and the fifth byte is the vertical axis.  I'm trying to figure out what the 4th and 6th bytes do now.
Build a man a fire, keep him warm for the night.
Set a man on fire, keep him warm for the rest of his life.

Numbski

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 296
  • Last login:April 04, 2011, 08:16:59 pm
    • Numbski
Re: Attempting to hack and document GunCon2 for Linux, FreeBSD, and MacOS X.
« Reply #12 on: December 06, 2006, 01:21:49 pm »
Ah ha... it looks like the 4th byte provides the third numerical place for the horizontal axis.  When I wave the gun SLOOOWLY from left to right across the screen, the 3rd byte runs up very fast, and the 4th byte slowly counts 0-5.  It doesn't look like the 6th byte ever changes, although in theory I guess it could be the 3rd placeholder for the vertical axis.  Perhaps I can use the other two drivers as a reference for determining sane values there and adjust the script to return actual X/Y values along with only returning what buttons are really pressed?
Build a man a fire, keep him warm for the night.
Set a man on fire, keep him warm for the rest of his life.

Numbski

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 296
  • Last login:April 04, 2011, 08:16:59 pm
    • Numbski
Re: Attempting to hack and document GunCon2 for Linux, FreeBSD, and MacOS X.
« Reply #13 on: December 06, 2006, 02:20:56 pm »
Okay, latest version of my script.  If anyone else could test this it would be much appreciated!  Just want to make sure I'm not barking up the wrong tree.  That, and the value of horizontal2 is something of an oddity.  I'm just not getting consistent results.

Code: [Select]
#!/usr/bin/perl -w

use Term::Cap;

# What is the character device for the gun?
$guncon = '/dev/ugen0.1';

# clearing out our status...just in case.
$status = undef;
$value = undef;


# Define our byte hash
$byte{ '0' } = 'Buttons1';
$byte{ '1' } = 'Buttons2';
$byte{ '2' } = 'Horizontal1';
$byte{ '3' } = 'Horizontal2';
$byte{ '4' } = 'Vertical1';
$byte{ '5' } = 'Vertical2';

if (!-c $guncon) {
        print "$guncon is not a character device!\n";
        exit;
}
if (!-r $guncon) {
        print "$guncon exists, but you aren't allowed to read it!\n";
        exit;
}

# See if we can figure out what your terminal speed is...
# We'll presume 9600bps if nothing else.
$OSPEED = 9600;
eval {
    require POSIX;
    my $termios = POSIX::Termios->new();
    $termios->getattr;
    $OSPEED = $termios->getospeed;
};
$terminal = Term::Cap->Tgetent({OSPEED=>$OSPEED});
#$terminal->Tputs('cl', 1, STDOUT);
$clear = $terminal->Tputs('cl');

# Try to open a filehandle to the gun character device.
print "Attempting to open gun at $guncon...\n";
open GUN, $guncon or die "Can't open $guncon : $!\n";

print "$guncon opened successfully.  Proceeding to read...\n";

# Switch us to binary mode scotty!  Read the status and print it.
while(1){
        binmode GUN;
        sysread(GUN,$status, 6);

        $i=0;
        $value=undef
        $tempvalue=undef;

        # Our bytes are split and handled individually...
        foreach $value(split(//, $status)) {
                $tempvalue = sprintf("%08b ", ord($value));

                print "$byte{$i}:\t$tempvalue\n";

        $i++;
        }

        $status = undef;
        $value = undef;
        $tempvalue=undef;
        print "\nPress Ctrl-C to exit\n";
        print $clear;
}
Build a man a fire, keep him warm for the night.
Set a man on fire, keep him warm for the rest of his life.

Numbski

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 296
  • Last login:April 04, 2011, 08:16:59 pm
    • Numbski
Re: Attempting to hack and document GunCon2 for Linux, FreeBSD, and MacOS X.
« Reply #14 on: December 06, 2006, 02:37:38 pm »
It occurs to me that bytes 3 and 5 should probably default to 0 and not 1 and 5. :)  I'm wondering if I shouldn't adjust my script to autmagically substract 1 and 5 from the reported values?  Or does someone know if that's an expected behavior?  Also, it looks like the upper-left corner of the screen is 0/0.  It jumps straight from 5 (00000101) to 00010011, or 19 on the vertical axis.  Horizontal it jumps from 1 to 22 (00010110).  So who knows...that's probably why you have to use a calibration routine...
« Last Edit: December 06, 2006, 03:26:03 pm by Numbski »
Build a man a fire, keep him warm for the night.
Set a man on fire, keep him warm for the rest of his life.

Numbski

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 296
  • Last login:April 04, 2011, 08:16:59 pm
    • Numbski
Re: Attempting to hack and document GunCon2 for Linux, FreeBSD, and MacOS X.
« Reply #15 on: December 06, 2006, 04:01:32 pm »
Okay, as I have posted elsewhere, this may be the closest I could ever hope to come to personally writing a driver for the GunCon2.  This script identifies your position on the screen, and whatever button presses are done.  The only presumption is makes is that you already have a character device to access the gun.  FreeBSD does it by default, and I know how to do it on Gentoo, although I haven't tested it.  Hopefully someone can pick this up and write legit drivers with it.

Come to think of it, I could probably use a bit more perl "glue" and map the buttons to keystrokes, but I don't know how I would use the values for X and Y axis to move the mouse around. Never tried it. :P





Code: [Select]
#!/usr/bin/perl

use Term::Cap;

# What is the character device for the gun?
$guncon = '/dev/ugen0.1';

# clearing out our status...just in case.
$status = undef;
$value = undef;
$tempvalue = undef;

# Define our byte hash
$byte{ '0' } = 'Buttons';
$byte{ '1' } = 'Buttons';
$byte{ '2' } = 'Horizontal1';
$byte{ '3' } = 'Horizontal2';
$byte{ '4' } = 'Vertical1';
$byte{ '5' } = 'Vertical2';




# Check to make sure this is a character device AND that
# you actually have permission to read from it.
if (!-c $guncon) {
        print "$guncon is not a character device!\n";
        exit;
}
if (!-r $guncon) {
        print "$guncon exists, but you aren't allowed to read it!\n";
        exit;
}

# See if we can figure out what your terminal speed is...
# We'll presume 9600bps if nothing else.  This is so that
# we can refresh your display correctly.
$OSPEED = 9600;
eval {
    require POSIX;
    my $termios = POSIX::Termios->new();
    $termios->getattr;
    $OSPEED = $termios->getospeed;
};
$terminal = Term::Cap->Tgetent({OSPEED=>$OSPEED});
$clear = $terminal->Tputs('cl');


# Try to open a filehandle to the gun character device.
print "Attempting to open gun at $guncon...\n";
open GUN, $guncon or die "Can't open $guncon : $!\n";

print "$guncon opened successfully.  Proceeding to read...\n";

# Switch us to binary mode Scotty!  Read the status and print it.
while(1){
        binmode GUN;

        # Read in 6 bytes, which is precisely the length of the
        # GunCon2's updates.  Probably could just use read and
        # not sysread here, but I was getting some funky behavior
        # before.
        sysread(GUN,$status, 6);

        # $i is just a counter to keep track of what byte we're on.
        $i=0;

        # More paranoia to make sure we have a clean slate to work from.
        $value=undef
        $tempvalue=undef;

        # Our bytes are split and handled individually...
        foreach $value(split(//, $status)) {

                # If this is one of the button bytes, use binary,
                # otherwise use decimal.
                if($i >= 2){
                        $tempvalue = sprintf("%04d ", ord($value));
                }
                else{
                        $tempvalue = sprintf("%08b ", ord($value));
                }

                # Work with the buttons on the first byte.
                if($i == 0){
                        @digits = split(undef,$tempvalue);
                        $tempvalue = "";
                        if ($digits[0] == 0){
                                $tempvalue .= " Left"
                        }
                        if ($digits[1] == 0){
                                $tempvalue .= " Down"
                        }
                        if ($digits[2] == 0){
                                $tempvalue .= " Right"
                        }
                        if ($digits[3] == 0){
                                $tempvalue .= " Up"
                        }
                        if ($digits[4] == 0){
                                $tempvalue .= " A"
                        }
                        if ($digits[5] == 0){
                                $tempvalue .= " B"
                        }
                        if ($digits[6] == 0){
                                $tempvalue .= " C"
                        }

                }

                # And then the buttons on the second byte.
                if($i == 1){
                        @digits = split(undef,$tempvalue);
                        $tempvalue = "";
                        if ($digits[0] == 0){
                                $tempvalue .= " Start"
                        }
                        if ($digits[1] == 0){
                                $tempvalue .= " Select"
                        }
                        if ($digits[2] == 0){
                                $tempvalue .= " Trigger"
                        }
                }

                if ($i == 2){
                        $tempvalue = $tempvalue - 1;
                }
                if ($i == 4){
                        $tempvalue = $tempvalue - 5;
                }
                print "$byte{$i}:\t$tempvalue\n";

        # Increment our byte counter.
        $i++;
        }

        # Clean the slate for the next update.
        $status = undef;
        $value = undef;
        $tempvalue=undef;

        # Print the rest of the status screen and clear it for the next
        # iteration.
        print "\nPress Ctrl-C to exit\n";
        print $clear;
}
« Last Edit: December 06, 2006, 04:25:46 pm by Numbski »
Build a man a fire, keep him warm for the night.
Set a man on fire, keep him warm for the rest of his life.

Numbski

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 296
  • Last login:April 04, 2011, 08:16:59 pm
    • Numbski
Re: Attempting to hack and document GunCon2 for Linux, FreeBSD, and MacOS X.
« Reply #16 on: December 06, 2006, 04:39:19 pm »
One last thing, here's all of the pertinent data about the device as per MacOS X. :)

Build a man a fire, keep him warm for the night.
Set a man on fire, keep him warm for the rest of his life.

Numbski

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 296
  • Last login:April 04, 2011, 08:16:59 pm
    • Numbski
Re: Attempting to hack and document GunCon2 for Linux, FreeBSD, and MacOS X.
« Reply #17 on: December 06, 2006, 07:28:04 pm »
Heh, I got impatient. :)

I found a module - X11::GuiTest that allows me to force mouse movement and clicks from the script.  It works well enough that I too get to experience the "rolling x" problem. :D


(UPDATE!!!  No rolling X!  I had a typo on one of my variables.  It WOIKS!   Lags like all get out, but it does in fact work!)

For grins, here's that code:

Code: [Select]
#!/usr/bin/perl

use Term::Cap;
use X11::GUITest qw/
        ClickMouseButton
        MoveMouseAbs
/;

# What is the character device for the gun?
$guncon = '/dev/ugen0.1';

# clearing out our status...just in case.
$status = undef;
$value = undef;
$tempvalue = undef;

# Define our byte hash
$byte{ '0' } = 'Buttons';
$byte{ '1' } = 'Buttons';
$byte{ '2' } = 'X-Axis';
$byte{ '3' } = 'X-Mult';
$byte{ '4' } = 'Y-Axis';
$byte{ '5' } = 'Y-Mult';




# Check to make sure this is a character device AND that
# you actually have permission to read from it.
if (!-c $guncon) {
        print "$guncon is not a character device!\n";
        exit;
}
if (!-r $guncon) {
        print "$guncon exists, but you aren't allowed to read it!\n";
        exit;
}

# See if we can figure out what your terminal speed is...
# We'll presume 9600bps if nothing else.  This is so that
# we can refresh your display correctly.
$OSPEED = 9600;
eval {
    require POSIX;
    my $termios = POSIX::Termios->new();
    $termios->getattr;
    $OSPEED = $termios->getospeed;
};
$terminal = Term::Cap->Tgetent({OSPEED=>$OSPEED});
$clear = $terminal->Tputs('cl');


# Try to open a filehandle to the gun character device.
print "Attempting to open gun at $guncon...\n";
open GUN, $guncon or die "Can't open $guncon : $!\n";

print "$guncon opened successfully.  Proceeding to read...\n";

# Switch us to binary mode Scotty!  Read the status and print it.
while(1){
        binmode GUN;

        # Read in 6 bytes, which is precisely the length of the
        # GunCon2's updates.  Probably could just use read and
        # not sysread here, but I was getting some funky behavior
        # before.
        sysread(GUN,$status, 6);

        # $i is just a counter to keep track of what byte we're on.
        $i=0;

        # More paranoia to make sure we have a clean slate to work from.
        $value=undef
        $tempvalue=undef;

        # Our bytes are split and handled individually...
        foreach $value(split(//, $status)) {

                # If this is one of the button bytes, use binary,
                # otherwise use decimal.
                if($i >= 2){
                        $tempvalue = sprintf("%04d ", ord($value));
                }
                else{
                        $tempvalue = sprintf("%08b ", ord($value));
                }

                # Work with the buttons on the first byte.
                if($i == 0){
                        @digits = split(undef,$tempvalue);
                        $tempvalue = "";
                        if ($digits[0] == 0){
                                $tempvalue .= " Left"
                        }
                        if ($digits[1] == 0){
                                $tempvalue .= " Down"
                        }
                        if ($digits[2] == 0){
                                $tempvalue .= " Right"
                        }
                        if ($digits[3] == 0){
                                $tempvalue .= " Up"
                        }
                        if ($digits[4] == 0){
                                $tempvalue .= " A"
                        }
                        if ($digits[5] == 0){
                                $tempvalue .= " B"
                        }
                        if ($digits[6] == 0){
                                $tempvalue .= " C"
                        }

                }

                # And then the buttons on the second byte.
                if($i == 1){
                        @digits = split(undef,$tempvalue);
                        $tempvalue = "";
                        if ($digits[0] == 0){
                                $tempvalue .= " Start"
                        }
                        if ($digits[1] == 0){
                                $tempvalue .= " Select"
                        }
                        if ($digits[2] == 0){
                                $tempvalue .= " Trigger";
                                ClickMouseButton(1);
                        }
                }

                if ($i == 2){
                        $tempvalue = $tempvalue - 1;
                        $xpos = $tempvalue;

                if ($i == 3){
                        if($tempvalue > 0){
                                $xmult = $tempvalue;
                        }
                }

                }
                if ($i == 4){
                        $tempvalue = $tempvalue - 5;
                        $ypos = $tempvalue;
                }

                if ($i == 5){
                        if($tempvalue > 0){
                                $ymult = $tempvalue;
                        }
                }

                print "$byte{$i}:\t$tempvalue\n";

                # If we got both X and Y coordinates, move the mouse.
                if($xmult){
                        $xpos=$xpos*$xmult;
                }
                if($ymult){
                        $xpos=$xpos*$xmult;
                }

                if ($xpos && $ypos){
                        MoveMouseAbs $xpos,$ypos;
                }

        # Increment our byte counter.
        $i++;
        }

        # Clean the slate for the next update.
        $status = undef;
        $value = undef;
        $tempvalue=undef;
        $xpos = undef;
        $ypos = undef;
        $xmult = undef;
        $ymult = undef;

        # Print the rest of the status screen and clear it for the next
        # iteration.
        print "\nPress Ctrl-C to exit\n";
        print $clear;
}

Now....how the heck does one fix the "rolling x"? ;)
« Last Edit: December 06, 2006, 07:41:16 pm by Numbski »
Build a man a fire, keep him warm for the night.
Set a man on fire, keep him warm for the rest of his life.

Numbski

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 296
  • Last login:April 04, 2011, 08:16:59 pm
    • Numbski
Re: Attempting to hack and document GunCon2 for Linux, FreeBSD, and MacOS X.
« Reply #18 on: December 06, 2006, 08:08:33 pm »
Hmm.  Fixed the lag.  Now the gun is just plain inaccurate depending upon where on-screen I'm firing.  Sometimes it's dead on.  Other times....eh, not so much.

I fixed the lag by only moving the mouse when the trigger gets pulled rather than trying to constantly track.  Now results are more or less instantaneous, but off-target.  Hey, I've already gotten MUCH further than I'd anticipated possible.  So there. :P

Code: [Select]
#!/usr/bin/perl

use Term::Cap;
use X11::GUITest qw/
        ClickMouseButton
        MoveMouseAbs
/;

# What is the character device for the gun?
$guncon = '/dev/ugen0.1';

# clearing out our status...just in case.
$status = undef;
$value = undef;
$tempvalue = undef;

# Define our byte hash
$byte{ '0' } = 'Buttons';
$byte{ '1' } = 'Buttons';
$byte{ '2' } = 'X-Axis';
$byte{ '3' } = 'X-Mult';
$byte{ '4' } = 'Y-Axis';
$byte{ '5' } = 'Y-Mult';




# Check to make sure this is a character device AND that
# you actually have permission to read from it.
if (!-c $guncon) {
        print "$guncon is not a character device!\n";
        exit;
}
if (!-r $guncon) {
        print "$guncon exists, but you aren't allowed to read it!\n";
        exit;
}

# See if we can figure out what your terminal speed is...
# We'll presume 9600bps if nothing else.  This is so that
# we can refresh your display correctly.
$OSPEED = 9600;
eval {
    require POSIX;
    my $termios = POSIX::Termios->new();
    $termios->getattr;
    $OSPEED = $termios->getospeed;
};
$terminal = Term::Cap->Tgetent({OSPEED=>$OSPEED});
$clear = $terminal->Tputs('cl');


# Try to open a filehandle to the gun character device.
print "Attempting to open gun at $guncon...\n";
open GUN, $guncon or die "Can't open $guncon : $!\n";

print "$guncon opened successfully.  Proceeding to read...\n";

# Switch us to binary mode Scotty!  Read the status and print it.
while(1){
        binmode GUN;

        # Read in 6 bytes, which is precisely the length of the
        # GunCon2's updates.  Probably could just use read and
        # not sysread here, but I was getting some funky behavior
        # before.
        sysread(GUN,$status, 6);

        # $i is just a counter to keep track of what byte we're on.
        $i=0;

        # More paranoia to make sure we have a clean slate to work from.
        $value=undef
        $tempvalue=undef;

        # Our bytes are split and handled individually...
        foreach $value(split(//, $status)) {
                # Determines whether we're firing this time or not.
                $fire = 0;

                # If this is one of the button bytes, use binary,
                # otherwise use decimal.
                if($i >= 2){
                        $tempvalue = sprintf("%04d ", ord($value));
                }
                else{
                        $tempvalue = sprintf("%08b ", ord($value));
                }

                # Work with the buttons on the first byte.
                if($i == 0){
                        @digits = split(undef,$tempvalue);
                        $tempvalue = "";
                        if ($digits[0] == 0){
                                $tempvalue .= " Left";
                        }
                        if ($digits[1] == 0){
                                $tempvalue .= " Down";
                        }
                        if ($digits[2] == 0){
                                $tempvalue .= " Right";
                        }
                        if ($digits[3] == 0){
                                $tempvalue .= " Up";
                        }
                        if ($digits[4] == 0){
                                $tempvalue .= " A";

                        }
                        if ($digits[5] == 0){
                                $tempvalue .= " B";
                        }
                        if ($digits[6] == 0){
                                $tempvalue .= " C";
                        }

                }

                # And then the buttons on the second byte.
                if($i == 1){
                        @digits = split(undef,$tempvalue);
                        $tempvalue = "";
                        if ($digits[0] == 0){
                                $tempvalue .= " Start";
                        }
                        if ($digits[1] == 0){
                                $tempvalue .= " Select";
                        }
                        if ($digits[2] == 0){
                                $tempvalue .= " Trigger";
                                $fire = 1;
                        }
                }

                if ($i == 2){
                        $tempvalue = $tempvalue - 1;
                        $xpos = $tempvalue;

                if ($i == 3){
                        if($tempvalue > 0){
                                $xmult = $tempvalue;
                        }
                }

                }
                if ($i == 4){
                        $tempvalue = $tempvalue - 5;
                        $ypos = $tempvalue;
                }

                if ($i == 5){
                        if($tempvalue > 0){
                                $ymult = $tempvalue;
                        }
                }

                print "$byte{$i}:\t$tempvalue\n";


                if($fire >= 1){

                        # If we got both X and Y coordinates, move the mouse.
                        if($xmult >= 1){
                                $xpos=$xpos+($xmult*256);
                        }
        #               if($ymult){
        #                       $xpos=$xpos*$xmult;
        #               }

                        MoveMouseAbs $xpos , $ypos;
                        print "Mouse Moved to $xpos x $ypos\n";
                        ClickMouseButton(1);


                }

        # Increment our byte counter.
        $i++;
        }

        # Clean the slate for the next update.
        $status = undef;
        $value = undef;
        $tempvalue=undef;

        # Print the rest of the status screen and clear it for the next
        # iteration.
        print "\nPress Ctrl-C to exit\n";
        print $clear;
}
Build a man a fire, keep him warm for the night.
Set a man on fire, keep him warm for the rest of his life.

Numbski

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 296
  • Last login:April 04, 2011, 08:16:59 pm
    • Numbski
Re: Attempting to hack and document GunCon2 for Linux, FreeBSD, and MacOS X.
« Reply #19 on: December 06, 2006, 10:52:57 pm »
Now that I've had some time to play with my own hack, I'm noticing some very peculiar behavior.

On the X-Axis, I start at 001 decimal, with my third place holding at 0.  It then immediately jumps to 35, with the third placeholder at 1.  It then increments as expected to 255, then the third placeholder becomes 2.  We get 0-255 on that, third placeholder becomes a 3.  Then it gets odd.  Right around dead center of the screen.  With the third placeholder at 3, I get 0-~35, then it jumps back to the third placeholder being a 0 again, and starts counting from 0-255, then the third placeholder becomes a 1.

The problem is relatively obvious: there are areas of the X-Axis that repeat!  But how?  Why on earth is the guncon detecting the same X-Axis twice?  I have the screen resolution set relatively low as it is.

Given what I'm seeing here, it has 0,0-255, 1,0-255, 2,0-255, and 3,0-32.

800 pixels wide, yet my screen is nowhere NEAR 800 pixels wide the way I'm testing.  Plus, I'm getting repeats.  Grr...have no idea how this thing tracks on the X-Axis.  Y-Axis seems to be behaving just fine.
Build a man a fire, keep him warm for the night.
Set a man on fire, keep him warm for the rest of his life.

Numbski

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 296
  • Last login:April 04, 2011, 08:16:59 pm
    • Numbski
Re: Attempting to hack and document GunCon2 for Linux, FreeBSD, and MacOS X.
« Reply #20 on: December 07, 2006, 11:28:42 am »
I'm going to start by copying my little binary cheat-sheet again:

Code: [Select]
0000 - 0
0001 - 1
0010 - 2
0011 - 3
0100 - 4
0101 - 5
0110 - 6
0111 - 7
1000 - 8
1001 - 9
1010 - A
1011 - B
1100 - C
1101 - D
1110 - E
1111 - F

If someone can help me reconcile this math problem too, I'd appreciate it.  From the TopGun Driver:

Code: [Select]
input_report_key(dev, BTN_A,       !(data[0] & 0x04));
input_report_key(dev, BTN_B,       !(data[0] & 0x08));
input_report_key(dev, BTN_C,       !(data[0] & 0x02));
input_report_key(dev, BTN_TRIGGER, !(data[1] & 0x20));
input_report_key(dev, BTN_START,   !(data[1] & 0x80));
input_report_key(dev, BTN_SELECT,  !(data[1] & 0x40));

I've figured out that the data[0] array is the first byte from the left, and data[1] is the second byte from the left, so we're in agreement there.  data[0] then looks like this:

Code: [Select]
0111 1111 - Left - bit 8
1011 1111 - Down - bit 7
1101 1111 - Right - bit 6
1110 1111 - Up - bit 5
1111 0111 - A - bit 4
1111 1011 - B - bit 3
1111 1101 - C - bit 2
1111 1110 - ? - bit 1

He says the C button is 0x02. Correct.
He says the A button is 0x04.  No....0x04 is the third bit, or the B button.  A button is the 4th bit, but not 0x04.
He says the B button is 0x08.  Hmm?  0x08 is the 4th bit.  The A button.  Hmm???

Even more bizarre.  Here's data[1]:

Code: [Select]
0111 1111 - Start - bit 8
1011 1111 - Select - bit 7
1101 1111 - Trigger - bit 6
1110 1111 - ? - bit 5

He says the trigger is 0x20.  Bit 6.  That's correct.
He says that select is 0x40.  That's bit 7.  That's correct.
He says that start is 0x08.  That's bit 8.  So is he suffering from A/B button dislexia, or am I?

(Update: Just verified that my code is correct.  So unless the TopGun has A and B flipped, I'm right and he's wrong. :P  Also chatting on AIM with Acorns as we speak.  w00t!)
« Last Edit: December 07, 2006, 12:01:20 pm by Numbski »
Build a man a fire, keep him warm for the night.
Set a man on fire, keep him warm for the rest of his life.

Smog

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 178
  • Last login:April 30, 2007, 06:50:51 am
  • .357
    • How to make a cheap GunCon2 work on your PC
Re: Attempting to hack and document GunCon2 for Linux, FreeBSD, and MacOS X.
« Reply #21 on: December 19, 2006, 06:43:26 am »
start is 0x80

#define BUTTON_B      0x0400
#define BUTTON_TRIGGER_1   0x0020
#define BUTTON_TRIGGER_2   0x0800
#define BUTTON_TRIGGER_3   0x0200
#define BUTTON_SELECT   0x0040
#define BUTTON_START   0x0080
#define DPAD_UP                   0x1000
#define DPAD_DOWN   0x4000
#define DPAD_RIGHT               0x8000
#define DPAD_LEFT      0x2000

Obviously after you have NEGATED the 2 bytes
« Last Edit: December 19, 2006, 06:45:35 am by Smog »
GunCon2PC Driver on http://guncon2pc.no-ip.org/

Numbski

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 296
  • Last login:April 04, 2011, 08:16:59 pm
    • Numbski
Re: Attempting to hack and document GunCon2 for Linux, FreeBSD, and MacOS X.
« Reply #22 on: December 21, 2006, 10:11:32 am »
Thanks for the clarification smog. :)

I've been struggling through FreeBSD's header files trying to figure out what mechanism it uses to read HID input.  No luck so far.  What I was hoping to do was use libusb to handle detection, attach, and detach, and use most of the existing code to handle reading from the gun.  Then use ifdef statements to hand it off to each OS based on what headers and functions they use to get HID input.

Doesn't help that I really am not a programmer though. :\
Build a man a fire, keep him warm for the night.
Set a man on fire, keep him warm for the rest of his life.

Smog

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 178
  • Last login:April 30, 2007, 06:50:51 am
  • .357
    • How to make a cheap GunCon2 work on your PC
Re: Attempting to hack and document GunCon2 for Linux, FreeBSD, and MacOS X.
« Reply #23 on: December 21, 2006, 06:09:15 pm »
Don't know much about drivers under linux (even if I usually work with C/UNIX). However I implemented an HID minidriver (provides information to the upper GENERIC HID native driver) for the gun in windows ... if you need any help on the HID interface definition you're welcome.
GunCon2PC Driver on http://guncon2pc.no-ip.org/

Numbski

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 296
  • Last login:April 04, 2011, 08:16:59 pm
    • Numbski
Re: Attempting to hack and document GunCon2 for Linux, FreeBSD, and MacOS X.
« Reply #24 on: December 23, 2006, 12:13:32 pm »
That would help a TON.  I'm wading through whitepapers in what little free time I have and I'm having a hard time making heads or tails of it. :\
Build a man a fire, keep him warm for the night.
Set a man on fire, keep him warm for the rest of his life.

Numbski

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 296
  • Last login:April 04, 2011, 08:16:59 pm
    • Numbski
Re: Attempting to hack and document GunCon2 for Linux, FreeBSD, and MacOS X.
« Reply #25 on: February 24, 2007, 10:18:35 pm »
I have a question for you edumacated programmers out there.

My script above has a couple of obvious flaws that I can point out:

1.  Button states do not persist from one loop to the next - ie, if you keep the trigger pulled, it's like a turbo button effect.  I need to track the state of the button from on instance to the next.

2.  Should I really just be reading every 6 bytes like that as fast as the processor can possibly do it, or is there a more efficient way to go about this?  Perhaps some sort of buffering effect?  Somewhere in the back of my brain it's screaming that I should be using a "while" loop there rather than for each...

Other than that, I now understand that the repetition on the X-axis is the definition of the rolling X problem.  It only exists on the first-party guncon 2's.  If I can more efficiently read input and track button states from update to update, this script will actually be usable to provide a rudimentary mouse driver under X11.  I can then add support for Win32::GuiTest, so that the Gun can be used as a mouse under windows. :)  The catch of course is getting a character device.

Man I wish I could code even a little bit of c or c++ driver code. :(
Build a man a fire, keep him warm for the night.
Set a man on fire, keep him warm for the rest of his life.

Silver

  • Wiki Contributor
  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 1662
  • Last login:May 07, 2019, 06:22:24 am
  • Cunning like the Fox.
    • Mods'n'Mods
Re: Attempting to hack and document GunCon2 for Linux, FreeBSD, and MacOS X.
« Reply #26 on: February 28, 2007, 07:29:22 pm »
Can't really help with the programming in perl, but:

1) Persistent states. You would need to store the state of each button in a variable/array, and then compare states on your next "loop" to read values from the gun.

2)Effeciency. I'm sure there is a whole world of good device driver coding practices out there, but at the very least you need to instruct your program to "Do System Events" or whatever on a repeating basis within your loop. VB6 and .NET allow you to use DoEvents() IIRC but this is basic and designed more for programs rather than always running device drivers.

You may find there is a simple perl command to wait/pass priority over to the system which will gain you the lower overhead you need.

notaburger

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 175
  • Last login:February 23, 2019, 01:37:10 am
  • I want my own arcade controls!
i've only done a little bit of programming (none in perl) but i always did what silver did for storing key strokes

in this case i would have an array storing all of my previous keystrokes

keep up the good work, this is starting to look very promising

Numbski

  • Trade Count: (0)
  • Full Member
  • ***
  • Offline Offline
  • Posts: 296
  • Last login:April 04, 2011, 08:16:59 pm
    • Numbski
Looks like I could use this for event handling:

http://search.cpan.org/~vparseval/Event-Lib-1.01/lib/Event/Lib.pm
Build a man a fire, keep him warm for the night.
Set a man on fire, keep him warm for the rest of his life.