[comp.sources.atari.st] v01i003: Joystick-reading routines

koreth@ssyx.ucsc.edu (Steven Grimm) (03/30/88)

Submitted-by: sirkm@ucscb.ucsc.edu (Greg Anderson)
Posting-number: Volume 1, Issue 
Archive-name: joyread

[Lots of STers seem to have trouble reading the joystick ports, which is much
 more painful on the ST than on the 8-bit.  These routines should help make
 it easier.  Note that these are just some routines, and not a complete
 program. -sg]

/*-------------------------------------------------------------------------
| Stick.c:  Joystick interupt service routine
|
| Placed in the public domain March 1988 by Greg Anderson.
|
|      The joystick demo by Steve Jankowski was instrumental to
|                  the creation of these routines.
|
|   Many thanks to Steven Grimm for providing essential information
|               and the aforementioned joystick demo.
|
|##########################################################################
| THESE ROUTINES ONLY WORK UNDER LASER C!  THEY MUST BE MODIFIED FOR
| OTHER C COMPILERS, _INCLUDING_ MEGAMAX C VERSION 1.xx!
| 
| MegaMax instructions:  A4 must be saved somewhere so that it is
|     available durring the isr.  Then, the isr can access joyinf
|     with "lea joyinf(A4),A1" instead of "lea joyinf,A1".
|##########################################################################
|
|     This package sets up an interupt to read the joystick on the
| ST.  The joystick is read via the ikbd--the intelligent keyboard
| interface chip.  The ikbd can be placed into "joystick-reading
| mode" by sending an appropriate command with Ikbdws().  This has
| two effects:  first, the mouse is disabled.  Second, the ikbd will
| be prompted to send a three-byte packet every time one of the
| joysticks changes states.  The packet is as follows:
|
|     [Stick #]  [State of Stick 0]  [State of Stick 1]
|
|     The first byte is $FE if stick 0 changed, or $FF if stick 1
| changed.  These routines ignore the first byte.
|     The next two bytes contain the states of sticks 0 and 1.
| There values will be the sum of:
|
|                  +1    (+128)
|                   |
|            +4 ---< >--- +8
|                   |
|                  +2
|
|     Add the apropriate value if the contact is down.  For example,
| if stick 0 is NW and the trigger has not been pressed, its
| current state will be 1 + 4 = 5.
|
|     These packets are sent to a routine pointed to by "joyvec".
| Joyvec is part of the structure returned by Kbdvbase().  Joyvec
| can be changed to point to an interupt service routine (isr) of
| our devising.  If this is done, the isr will find that A0 points
| to the first byte of the the packet sent by the ikbd.  The isr
| must be very short (less than 1ms exicution time).  Atari's docs
| of Kbdvbase indicate that a copy of the pointer to the packet is
| also deposited on the stack; however, this does not appear to be
| the case.
|
| Using these routines:
|
| Call stick_init() to set up the joystick isr and place the ikbd
|    into joystick send mode.  This will also disable the mouse.
|
| stick_exit() will return the ikbd to mouse send mode.  Your
|    program should do this before exiting.
|
|    Once the initialize routine has been called, the following
| commands are available:
|
| _stick(n):  Return the state of stick N.  (See above chart)
| stick(n) :  Return the direction of stick N.  (Minus the trigger)
| trig(n)  :  Return the state of the trigger on stick N.
| hstick(n):  Return the horizontal position of stick N.  (-1 to +1)
| vstick(n):  Return the vertical position of stick N.
|
-------------------------------------------------------------------------*/
#include <osbind.h>

char ikbdcmd[10];           /* Storage space for ikbd commands  */
#define SENDJOY   0x14      /* Send joystick packets            */
#define SENDMOUSE 0x08      /* Send mouse packets               */

extern joyisr();            /* Interupt service routine follows */
int (*oldjoyvec)();         /* Save old isr vector here         */

int initialized = 0;        /* Initialized flag                 */
unsigned char joyinf[2];    /* Holds data for joystick states   */

int joytab[4] = 	{ 0, -1, 1, 0 };
#define xstick(v)	joytab[ v & 0x03 ]

/*-------------------------------------------------------------------
| Initialize joystick isr
-------------------------------------------------------------------*/
void stick_init()
{
	kbdvecs *KB;

	/* Do nothing if joystick isr has been initialized */
	if (initialized)
		return;
	/* Put our isr into the joystick interupt vector slot */
	KB = Kbdvbase();
	oldjoyvec = KB->joyvec;
	KB->joyvec = joyisr;
	/* Tell ikbd to send joystick packets. */
	ikbdcmd[0] = SENDJOY;
	Ikbdws(0, ikbdcmd);
	initialized = 1;
}

/*-------------------------------------------------------------------
| End joystick mode--go back to sending mouse packets.
-------------------------------------------------------------------*/
void stick_exit()
{
	kbdvecs *KB;

	/* Do nothing if joystick isr not initialized */
	if (! initialized)
		return;
	/* Tell ikbd to go back to sending mouse packets */
	ikbdcmd[0] = SENDMOUSE;
	Ikbdws(0, ikbdcmd);
	/* Restore the old joystick interupt vector */
	KB = Kbdvbase();
	KB->joyvec = oldjoyvec;
	initialized = 0;
}

/*-------------------------------------------------------------------
| Here is the actual joystick interupt service routine.
|    Both stick 0 and stick 1 are placed into the variable
|    "joyinf".
-------------------------------------------------------------------*/
asm
{
joyisr:
	lea	joyinf,A1     /* "joyinf" holds data        */
	addq.l	#1,A0         /* We don't want first byte   */
	move.b	(A0)+,(A1)+   /* Joystick 0 state           */
	move.b	(A0)+,(A1)+   /* Joystick 1 state           */
	rts
}

/*-------------------------------------------------------------------
| Return the state of stick 0 or stick 1.
|    Bits 0-3 = stick direction, bit 7 = trigger.
-------------------------------------------------------------------*/
int _stick(n)
int n;
{
	return(joyinf[n]);
}

/*-------------------------------------------------------------------
| Return the direction bits of stick 0 or stick 1.
-------------------------------------------------------------------*/
int stick(n)
int n;
{
	return( joyinf[n] & 0x0F );
}

/*-------------------------------------------------------------------
| Return the state of the trigger of stick n:
-------------------------------------------------------------------*/
int trig(n)
int n;
{
	return( (joyinf[n] & 0x80) != 0 );
}

/*-------------------------------------------------------------------
| Return the horizontal state of stick n:
|    +1 = right, 0 = centered, & -1 = left
-------------------------------------------------------------------*/
int hstick(n)
int n;
{
	return(xstick(joyinf[n] / 4));
}

/*-------------------------------------------------------------------
| Return the vertical state of stick n:
|    +1 = down, 0 = centered, -1 = up.
-------------------------------------------------------------------*/
int vstick(n)
int n;
{
	return(xstick(joyinf[n]));
}