/*************************************************************************
 * @(#) $Header: $
 * fastacc()
 *
 * Objective:
 *   Accumulate 8 bit numbers from an ISR into a long.  A 32 bit
 *   long is used because the distance number can become quite
 *   large and will quickly overflow a 16 bit int.
 *
 *   We need to measure travel distance accurately.  This requires
 *   encoders with high resolution.  But since the robot drives
 *   at fairly high speed, this means the accumulator ticks come
 *   fast and furious.  The only way to keep up on the FRC is
 *   to use interrupts.  The distance data from the ISR (Interrupt
 *   Service Routine) must then be communicated to the regular
 *   code loop in the user_routines.c or user_routines_fast.c file.
 *   Doing this without hazards is tricky.
 *
 * Approach #1:
 *   Have the ISR increment a long.  The user function wanting
 *   the data simply reads the long.
 * Hazard:
 *   The PIC processor in the FRC is basically an 8 bit computer.
 *   When the user function reads the distance it reads 8 bits
 *   at a time, accumulating those bytes into a long word.
 *   If the distance value stored in the long is updated by the
 *   ISR between bytes the value received can be a composite of
 *   two different values.  For instance consider the case where
 *   the distance goes between 255 (0x00ff) and 256 (0x0100)
 *   between reading byte 0 and byte 1.  Either number is OK
 *   for navigation.  But what user code sees is the composite
 *   value, 0x01ff, which is 511.  That is a big difference and
 *   is likely to throw off the navitation algorithm.
 *
 * Solution:
 *   We need to make sure that all communication between the
 *   ISR and the user code is via atomic operations.  That
 *   means the operations cannot be interrupted.
 *
 * Approach #2:
 *   Turn off interrupts when reading the distance from user code.
 * Advantage:
 *   Simple.
 * Disadvantage:
 *   Can result in lost counts.  In general we should avoid
 *   turning off interrupts if at all possible.
 *
 * Approach #3:
 *   In the ISR increment or decrement an 8 bit value.  In user
 *   code this byte can be read atomically.  It's value must be
 *   accumulated into a much larger variable (long).
 * Advantage:
 *   Communication from the ISR to user code is atomic.  It is
 *   not necessary to turn off interrupts at any time.
 * Disadvantage:
 *   Complicated.  The long distance value must be updated from
 *   the byte value often enough.  Basically this means there
 *   should be fewer than 126 interrupts between update calls.
 *   If we consider the case of an
 *   encoder with 128 counts per rotation, if the robot drives
 *   18 inches per rotation, the robot would have to go
 *     681 inch/sec = 18 inch/rot / (128 count/rot) * 126 count/update / 26ms/update * 1000ms/s
 *   Our actual robot travels 8 ft/sec or 96 inch/sec.
 *   Its wheels are 6 inch diameter.
 *   Required update period:
 *     185 ms/update = (18 inch/rot) / (96 inch/sec) / (128 count/rot) * (126 count/update) (1000 ms/sec)
 * Conclusion:
 *   Approach #3 meets all requirements and provides margin for
 *   the expected encoder and robot performance.
 */
#include "fastacc.h"

signed char fastacc(unsigned char isrvalue, long *accumulator)
{
  static unsigned char isrold=0;
  unsigned char isrcopy;
  signed char isrdiff;

  isrcopy = isrvalue;
  isrdiff = (signed char) (isrcopy-isrold);
  *accumulator += (long) isrdiff;
#if 0
  printf("\tisrdiff=isrcopy(%d,%x)-isrold(%d,%x); acc(%ld,%lx) += isrdiff(%d,%x)\n",
	 (unsigned int)isrcopy, (unsigned int)isrcopy, (unsigned int)isrold, (unsigned int)isrold, *accumulator, *accumulator, (int)isrdiff, (int)isrdiff);
#endif
  isrold = isrcopy;

  return(isrdiff);
}

