Joystick interrupt service routine
Stick.c: Joystick interrupt 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 during the isr. Then, the isr can access joyinf with "lea joyinf(A4),A1" instead of "lea joyinf,A1".
###############################
This package sets up an interrupt 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 appropriate 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 interrupt 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 execution 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.
Stick.c
#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]));
}