home *** CD-ROM | disk | FTP | other *** search
/ Virtual Reality Zone / VRZONE.ISO / mac / PC / PCGLOVE / GLOVE / PREVIOUS / NEWGLOVE.C < prev    next >
C/C++ Source or Header  |  1991-10-28  |  14KB  |  481 lines

  1. /**********************************************************************
  2.  
  3.   Originally "power.c" (c) manfredo 9/91 (manfredo@opal.cs.tu-berlin.de)
  4.   Developed on an ATARI 1040ST with TC 1.1 using a logic analyzer to get
  5.   the correct timings.
  6.  
  7. **********************************************************************/
  8. /*********************************************************************
  9.               ported to PC compatibles by
  10.                  Greg Alt 10/91
  11.  
  12.                 galt@peruvian.utah.edu
  13.              or galt@es.dsd.com
  14.  
  15. **********************************************************************/
  16. /*********************************************************************
  17.  
  18.  Substantially rewritten by Dave Stampe (c) 1991: PWRFILT.C
  19.   No cash, no warranty, no flames.
  20.   This stuff works great, so gimme credit.
  21.  
  22.  Goals <achieved> were:
  23.  
  24.   Higher speed, smaller code.
  25.   Polled operation is now possible.
  26.   Graphics test (VGA)
  27.   Noise reduction added, gets rid of 99.5% of noise with NO DELAY!
  28.  
  29.   This runs on a 486/25 with an i/o card. 
  30.   Someone should adapt it for the usual printer port adapter.
  31.   It was compiled with Turbo C++ 2.0 but will probably
  32.   work on any Turbo C directly. MSC will need library calls checked.
  33.  
  34.  
  35.  dstamp@watserv1.uwaterloo.ca            17/10/91
  36. **********************************************************************/
  37.  
  38. /*********************************************************************
  39.   Re-converted to use printer port by Dave Stampe and Bernie Roehl.
  40.                                         October 18, 1991.
  41.  
  42.   I also split off Dave's graphics code into a separate file, and put some
  43.   of the stuff that was shared between the two into glove.h
  44.  
  45.   I also added a little judicious whitespace here and there to enhance
  46.   readability, and made a whole bunch of globals static.
  47.  
  48.   I also added init_glove(mode) and glove_read(glov), the latter of which
  49.   calls getglove(glov), deglitch(glov) and dehyst(glov).
  50.  
  51.                                       --Bernie, October 18-19 1991
  52.  ********************************************************************/
  53.  
  54. /* More changes:
  55.  
  56.    init_glove() now auto-calibrates.  A new function (available outside
  57.    of this module) called "udelay" delays for a certain number of micro-
  58.    seconds.  Calls to fdelay have been replaced by udelay(),
  59.    and the D2BITS and D2BYTES values are now in microseconds.
  60.  
  61.    init_glove() now takes an additional parameter, a pointer to a
  62.    function (currently unused).
  63.  
  64.                                       --Bernie Roehl, October 21 1991
  65.  */
  66.  
  67. /* Interrupt-driven operation is now implemented!  Simply specify IHIRES
  68.    (for interrupt-driven high-resolution mode).
  69.  
  70.    Also, based on suggestions by Dave Stampe, I've:
  71.        - put the calibration stuff into a separate routine
  72.        - gone back to using counts instead of microseconds in most
  73.          places (for performance reasons; it saves a MULT instruction);
  74.        - udelay() is now gone, and a uconvert() macro does the conversion
  75.  
  76.     I have also:
  77.        - renamed the functions so they all begin with "glove_"; they
  78.          are now named glove_init(), glove_read() and glove_quit()
  79.  
  80.                                  -- Bernie Roehl, October 29 1991
  81.  */
  82.  
  83. #include <stdio.h>
  84. #include <stdlib.h>
  85. #include <dos.h>
  86. #include <bios.h>
  87. #include <signal.h>
  88.  
  89. #include "glove.h"
  90.  
  91. #define PC_PRINTER  1   /* use the PC Printer port for i/o */
  92.  
  93. #define D2BITS        5            /* microseconds */
  94. #define D2BYTES        96            /* microseconds */
  95. #define SAMPLE_TIME    4            /* milliseconds */
  96.  
  97. #ifdef PC_PRINTER
  98. #define INPORT  0x379           /* i/o port addresses */
  99. #define OUTPORT 0x378
  100. /* bits from parallel port */
  101. #define        GDATA           0x10    /* PG data in */
  102. #define        GLATCH          0x02    /* PG latch out */
  103. #define        GCLOCK          0x01    /* PG clock out */
  104. #define        GCLOLAT         0x03    /* clock + latch */
  105. #define     SHIFTVAL        4       /* shift data right 4 bits */
  106. #endif
  107.  
  108. #ifdef DSTAMPE         /* stuff from here down to #else is i/o card-specific */
  109. #define INPORT  0x2A0           /* i/o port addresses */
  110. #define OUTPORT 0x2A0
  111. /* bits for i/o ports */
  112. #define        GDATA           0x01    /* PG data in */
  113. #define        GLATCH          0x02    /* PG latch out */
  114. #define        GCLOCK          0x01    /* PG clock out */
  115. #define        GCLOLAT         0x03    /* clock + latch */
  116. #define     SHIFTVAL        0       /* don't shift */
  117. #endif
  118.  
  119. static unsigned long bitdelay, bytedelay, longdelay;
  120.  
  121. static void fdelay(unsigned long val)
  122.     {
  123.     while (val--);
  124.     }
  125.  
  126. static unsigned long microfactor = 0L;  /* usec/iteration times 91 */
  127.  
  128. #define uconvert(microseconds) (((microseconds) * microfactor)/91)
  129.  
  130. void slowdelay()
  131.     {
  132.     fdelay(longdelay);
  133.     }
  134.  
  135. /* defines for output line pair control */
  136.  
  137. #define     C0L0()       outportb(OUTPORT, 0)        /* clock 0 latch 0 */
  138. #define     C0L1()       outportb(OUTPORT, GLATCH)   /* clock 0 latch 1 */
  139. #define     C1L0()       outportb(OUTPORT, GCLOCK)   /* clock 1 latch 0 */
  140. #define     C1L1()       outportb(OUTPORT, GCLOLAT)  /* clock 1 latch 1 */
  141.  
  142. static unsigned char getbyte()  /* read a byte from glove <rolled code> */
  143.     {
  144.     register int i;
  145.     register unsigned char x = 0;
  146.     
  147.     C1L0();                /* generate a reset (latch) pulse */
  148.     C1L1();
  149.     fdelay(bitdelay);            /* hold for 3 us */
  150.     fdelay(bitdelay);            /* and another 3 */
  151.     C1L0();
  152.     fdelay(bitdelay);            /* hold for 3 us */
  153.     fdelay(bitdelay);            /* and another 3 */
  154.  
  155.     for(i = 0; i < 8; i++)
  156.         {
  157.         x = (x << 1) + ((inportb(INPORT) & GDATA) >> SHIFTVAL); 
  158.         C0L0();
  159.         C1L0();  /* pulse */
  160.         }
  161.     return x;  /* return the byte */
  162.     }
  163.  
  164. void getglove(glove_data *buf)      /* read 6 byte data packet */
  165.     {
  166.     register unsigned char *bp = (char *) buf;
  167.     register int i;
  168.     for (i = 0; i < 6; ++i) {
  169.         *bp++ = getbyte();    /* read data */
  170.         fdelay(bytedelay);
  171.         }
  172.     /* throwaways (speeds up polling later) */
  173.     getbyte();    
  174.     fdelay(bytedelay);
  175.     getbyte();
  176.     }
  177.  
  178. /*  HIRES ENTRY CODES 
  179. byte:
  180. 1- any value between $05 and $31
  181. 2- only $C1 and $81 work OK
  182. 3- no effect
  183. 4- no effect
  184. 5- no effect
  185. 6- only $FF works
  186. 7- seems to affect read rate slightly, 1 fastest
  187. */
  188.  
  189. static int hires_code[7] = { 0x06, 0xC1, 0x08, 0x00, 0x02, 0xFF, 0x01 };
  190.  
  191. void Hires()    /* enter HIRES mode <rolled code- speed unimportant> */
  192.     {
  193.     int i,j,k;
  194.               /* dummy read 4 bits from glove:  */
  195.     C1L0(); C1L1();    /* generate a reset (latch) pulse */
  196.     fdelay(bitdelay);    /* delay for 6 us */
  197.     fdelay(bitdelay);
  198.     C1L0();
  199.     fdelay(bitdelay);    /* delay for 6 us */
  200.     fdelay(bitdelay);
  201.  
  202.     C0L0(); C1L0();    /* pulse clock */
  203.     fdelay(bitdelay);
  204.     C0L0(); C1L0();    /* pulse clock */
  205.     fdelay(bitdelay);
  206.     C0L0(); C1L0();    /* pulse clock */
  207.     fdelay(bitdelay);
  208.     C0L0(); C1L0();    /* pulse clock */
  209.  
  210.          /* handshake for command code? */
  211.     C1L0();
  212.     fdelay(uconvert(7212));   /* 7212 us delay */
  213.     C1L1();
  214.     fdelay(uconvert(2260));   /* 2260 us delay */
  215.  
  216.     for (i = 0; i < 7; i++)   /* send 7 bytes */
  217.         {
  218.         k = hires_code[i];
  219.         for (j = 0; j < 8; j++)     /* 8 bits per byte, MSB first */
  220.             {
  221.             if (k & 0x80) 
  222.                 {
  223.                 C1L1(); 
  224.                 C0L1();
  225.                 C1L1();
  226.                 }
  227.             else
  228.                 {
  229.                 C1L0(); 
  230.                 C0L0();
  231.                 C1L0();
  232.                 }
  233.             k <<= 1;
  234.             fdelay(bitdelay);
  235.             }
  236.         fdelay(bytedelay);
  237.         }
  238.  
  239.     fdelay(uconvert(892));    /* 892 us delay (end of 7. byte) */
  240.  
  241.     C1L0();         /* drop the reset line */
  242.     fdelay(uconvert(40000));   /* some time for the glove controller to relax */
  243.     }
  244.  
  245. #define XHYST 2            /* hysterisis for X, Y low noise reduction */
  246. #define YHYST 2            /* 2 eliminates +/-3 quanta of noise */
  247.  
  248. #define XACC 8                  /* X, Y maximum accel/decel level. Should */
  249. #define YACC 8            /* be 6-10, but too high limits gesturing */
  250.  
  251. #define XXTEND 2        /* stretches deglitching time */
  252. #define YXTEND 1
  253.  
  254. static int ox = -1000;            /* last x,y for hysterisis */
  255. static int oy = -1000;
  256.  
  257. static void dehyst(glove_data *g)        /* hysterisis deglitch (low noise removal) */
  258.     {
  259.     int x = g->x;
  260.     int y = g->y;
  261.  
  262.     if(g->keys==0) ox = oy = 0;    /* handle recentering ("0"key or "Center") */
  263.  
  264.     if(x-ox>XHYST) ox = x-XHYST;    /* X hysterisis */
  265.     if(ox-x>XHYST) ox = x+XHYST;
  266.  
  267.     if(y-oy>YHYST) oy = y-YHYST;    /* Y hysterisis */
  268.     if(oy-y>YHYST) oy = y+YHYST;
  269.  
  270.     g->x = ox;            /* replace present X,Y data */
  271.     g->y = oy;
  272.     }
  273.  
  274. static int x1 = 0;        /* delayed 1 sample (for smoothed velocity test) */
  275. static int y1 = 0;
  276. static int x2 = 0;        /* delayed 2 samples */
  277. static int y2 = 0;
  278. static int lx = 0;        /* last good X,Y speed */
  279. static int ly = 0;
  280. static int lax = 0;        /* bad data "stretch" counter */
  281. static int lay = 0;
  282. static int lsx = 0;        /* X,Y "hold" values to replace bad data */
  283. static int lsy = 0;
  284. static int lcx = 0;        /* last X,Y speed for accel. calc. */
  285. static int lcy = 0;
  286.  
  287. static void deglitch(glove_data *g)
  288. {
  289.     int vx, vy;
  290.  
  291.     int x = g->x;
  292.     int y = g->y;
  293.  
  294.     if(g->keys == 0)        /* reset on recentering ("0" or "Center" key) */
  295.         {
  296.         x1 = x2 = y1 = y2 = 0;
  297.         lx = ly = lax = lay = 0;
  298.         lsx = lsy = lcx = lcy = 0;
  299.         }
  300.  
  301.     vx = x-((x1+x2)>>1);        /* smoothed velocity */
  302.     vy = y-((y1+y2)>>1);
  303.  
  304.     x2 = x1;            /* update last values */
  305.     x1 = g->x;
  306.  
  307.     y2 = y1;
  308.     y1 = g->y;
  309.  
  310.     if (abs(lcx-vx) > XACC) lax = XXTEND;    /* check for extreme acceleration */
  311.     if (lax == 0) lx = vx;                   /* save only good velocity        */
  312.     lcx = vx;                              /* save velocity for next accel.  */
  313.  
  314.     if (abs(lcy-vy) > YACC) lay = YXTEND;    /* same deal for Y accel. */
  315.     if (lay == 0) ly = vy;
  316.     lcy = vy;
  317.  
  318.     if (lax != 0)        /* hold X pos'n if glitch */
  319.         {
  320.         g->x = lsx;
  321.         lax--;
  322.         }
  323.  
  324.     if (lay != 0)             /* hold Y pos'n if glitch */
  325.         {
  326.         lay--;
  327.         g->y = lsy;
  328.         }
  329.  
  330.     lsx = g->x;        /* save position for X,Y hold */
  331.     lsy = g->y;
  332.  
  333.     /* g->y = x;*/
  334.     }
  335.  
  336. static void calibrate()
  337.     {
  338.     unsigned long n;
  339.     /* calibrate timing loop; note that instead of dividing by 18.2,
  340.        we multiply by 5 now and divide by 91 later */
  341.     n = biostime(0, 0L);
  342.     fdelay(1000000);  /* divide by a milllion to get microfactor */
  343.     microfactor = (biostime(0, 0L) - n) * 5;
  344.     bitdelay = uconvert(D2BITS);
  345.     bytedelay = uconvert(D2BYTES);
  346.     longdelay = uconvert(14720);
  347.     }
  348.  
  349. static int glovemode = HIRES;        /* operating mode of glove */
  350. static void (*upcall)() = NULL;        /* user's function to call up to */
  351. static unsigned char uses_ints = 0;    /* non-zero if we're interrupt-driven */
  352. static glove_data glove_int_data;    /* our copy of the most recent data */
  353.  
  354. /* Following is the number of our ticks per real tick, rounded up */
  355. #define DIVISOR ((55+SAMPLE_TIME/2)/SAMPLE_TIME)
  356.  
  357. #define UNUSED_VECT 128                /* unused interrupt vector (we hope!) */ 
  358.  
  359. static void interrupt (*oldint8)() = NULL;    /* previous interrupt handler */
  360. static void interrupt (*oldunused)() = NULL;  /* previous unused vector */
  361.  
  362. static unsigned n_ints = 0;        /* number of interrupts since oldint8 called */
  363. static unsigned unready = 0;    /* number of times glove has been not ready */
  364.  
  365. static void interrupt int8()
  366.     {
  367.     disable();
  368.     if (++n_ints >= DIVISOR) {   /* call previous int 8 handler periodically */
  369.         n_ints = 0;
  370.         geninterrupt(UNUSED_VECT);
  371.         }
  372.     else
  373.         outportb(0x20, 0x20);        /* signal EOI */
  374.     if (getbyte() != 0xA0) {
  375.         if (++unready > 500) {        /* glove not responding... reset it */
  376.             if (glovemode == IHIRES)
  377.                 Hires();
  378.             unready = 0;
  379.             }
  380.         return;
  381.         }
  382.     unready = 0;
  383.     getglove(&glove_int_data);
  384.     deglitch(&glove_int_data);        /* remove spikes and jumps */
  385.     dehyst(&glove_int_data);          /* add hysteresis to remove LL noise */
  386.     ++glove_int_data.nmissed;        /* flag data as new */
  387.     if (upcall) (*upcall)();        /* upcall to application */
  388.     }
  389.  
  390. #define TIMER_CONTROL 0x43        /* timer control register */
  391. #define TIMER_0       0x40        /* timer zero data register */
  392. #define TIMER_MODE    0x36        /* byte to write to control register */
  393.  
  394. int glove_init(int mode, void (*function)())
  395.     {
  396.     calibrate();
  397.     if (mode == LORES) mode = HIRES;
  398.     if (mode == ILORES) mode = IHIRES;    
  399.     if (mode == HIRES || mode == IHIRES) Hires();
  400.     glove_int_data.nmissed = 0;  /* go this one, start counter again! */
  401.     if (mode == ILORES || mode == IHIRES) {        /* an interrupt mode */
  402.         void glove_quit();
  403.         unsigned rate;
  404.         uses_ints = 1;
  405.         oldint8 = getvect(8);
  406.         oldunused = getvect(UNUSED_VECT);
  407.         setvect(UNUSED_VECT, oldint8);
  408.         setvect(8, int8);
  409.         rate = 65535/DIVISOR;
  410.         /* reprogram timer */
  411.         disable();
  412.         outportb(TIMER_CONTROL, TIMER_MODE);    /* timer control port */
  413.         outportb(TIMER_0, rate & 0xFF);            /* low byte to timer zero */
  414.         outportb(TIMER_0, (rate >> 8) & 0xFF);    /* high byte to timer zero */
  415.         /* make sure we clean up at exit or on errors */
  416.         atexit(glove_quit);
  417.         signal(SIGABRT, glove_quit);
  418.         signal(SIGFPE, glove_quit);
  419.         signal(SIGINT, glove_quit);
  420.         enable();
  421.         }
  422.     else
  423.         uses_ints = 0;
  424.     glovemode = mode;
  425.     upcall = function;
  426.     return glovemode;     /* returns mode actually set */
  427.     }
  428.  
  429. int glove_read(glove_data *glov)
  430.     {
  431.     if (uses_ints) {    /* interrupt-driven */
  432.         disable();
  433.         *glov = glove_int_data;
  434.         glove_int_data.nmissed = 0;
  435.         enable();
  436.         return glov->nmissed;
  437.         }
  438.     /* polled operation */
  439.     getglove(glov);        /* retrieve the data */
  440.     deglitch(glov);        /* remove spikes and jumps */
  441.     dehyst(glov);          /* add hysteresis to remove LL noise */
  442.     glove_int_data = *glov;
  443.     return 1;            /* always new data */
  444.     }
  445.  
  446. int glove_ready()    /* returns 1 if glove ready, 0 otherwise */
  447.     {
  448.     if (uses_ints)  /* interrupt handler makes sure there's always data */
  449.         return 1;
  450.     if (getbyte() == 0xA0) {    /* ready */
  451.         unready = 0;
  452.         if (upcall) (*upcall)();
  453.         return 1;
  454.         }
  455.     /* not ready */
  456.     if (++unready > 500) {  /* glove not responding... reset it */
  457.         unready = 0;
  458.         if (glovemode == HIRES || glovemode == IHIRES)
  459.             Hires();
  460.         }
  461.     return 0;
  462.     }
  463.  
  464. void glove_quit()
  465.     {
  466.     if (uses_ints) {
  467.         disable();
  468.         /* reprogram timer */
  469.         outportb(TIMER_CONTROL, TIMER_MODE);
  470.         outportb(TIMER_0, 0);    /* low byte */
  471.         outportb(TIMER_0, 0);    /* high byte */
  472.         setvect(8, oldint8);
  473.         setvect(UNUSED_VECT, oldunused);
  474.         signal(SIGABRT, SIG_DFL);
  475.         signal(SIGFPE, SIG_DFL);
  476.         signal(SIGINT, SIG_DFL);
  477.         enable();
  478.         }
  479.     upcall = NULL;
  480.     }
  481.