/*****************************************************************************/
/*                                                                           */
/*  serialio.c      ;low-level serial I/O for the Handy Board                */
/*                  ;also works with the 6.270 board                         */
/*                                                                           */
/*  by                                                                       */
/*                                                                           */
/*  Dr. Fred G. Martin                                                       */
/*  Learning and Epistemology Group                                          */
/*  Media Laboratory                                                         */
/*  Massachusetts Institute of Technology                                    */
/*  fredm@media.mit.edu                                                      */
/*                                                                           */
/*****************************************************************************/
/*                                                                           */
/*  VERSION HISTORY:                                                         */
/*                                                                           */
/*  Whenever the program is updated, record it here.  Add new version info   */
/*  to the top of this list, so the newest version is always first.          */
/*                                                                           */
/*          28 Oct 2005         ;Added timeout selections and support for    */
/*                              ;Interactive C versions after 4.3. Changes   */
/*                              ;by Mark T. Tomczak (mtomczak@andrew.cmu.edu)*/
/*                                                                           */
/*  1.0     16 May 1997         ;initial code by Fred G. Martin              */
/*                                                                           */
/*****************************************************************************/
/*                                                                           */
/*  PUBLIC FUNCTIONS:                                                        */
/*                                                                           */
/*  These functions may be used freely by user programs.                     */
/*                                                                           */
/*  void disable_pcode_serial()     ;disable board handshaking with IC       */
/*                                  ;on the host computer, allowing user     */
/*                                  ;programs to receive serial data         */
/*                                                                           */
/*  void enable_pcode_serial()      ;enable board handshaking with IC on     */
/*                                  ;the host computer                       */
/*                                                                           */
/*   int serial_putchar(int timeout, int c) ;send a serial character.        */
/*                                          ;Specify a timeout. Returns      */
/*                                  ;true if character was sent before       */
/*                                  ;timeout, false otherwise                */
/*                                                                           */
/*  int serial_getchar(int timeout,int *dest) ;read a serial character.      */
/*                                            ;Specify a timeout; returns    */
/*                                            ;true if character was         */
/*                                            ;retrieved                     */
/*                                                                           */
/*****************************************************************************/
/*                                                                           */
/*  PUBLIC GLOBAL VARIABLES:                                                 */
/*                                                                           */
/*  These global variables may be accessed freely by user programs.  Any     */
/*  restrictions on their use (e.g., flags which are read-only) should be    */
/*  noted here.  It is suggested that global variables be named in all       */
/*  capital letters, to avoid confusion with local varibles which are        */
/*  defined within functions.                                                */
/*                                                                           */
/*      None.                                                                */
/*                                                                           */
/*****************************************************************************/
/*                                                                           */
/*  PRIVATE FUNCTIONS:                                                       */
/*                                                                           */
/*  These are internal functions which have no public entry points, and      */
/*  which user programs should not access directly.  It is suggested that    */
/*  private functions be named with a leading underscore (_), to avoid       */
/*  confusion with user-defined functions which might have the same name.    */
/*                                                                           */
/*      None.                                                                */
/*                                                                           */
/*****************************************************************************/
/*                                                                           */
/*  PRIVATE GLOBAL VARIABLES:                                                */
/*                                                                           */
/*  These are internal global variables which user programs should not       */
/*  access directly.  It is suggested that private global variables be       */
/*  named in all capital letters with a leading underscore (_), to avoid     */
/*  confusion with user-defined global variables which might have the same   */
/*  name.                                                                    */
/*                                                                           */
/*      None.                                                                */
/*                                                                           */
/*****************************************************************************/
/*                                                                           */
/*  EXTERNAL LIBRARY FILE DEPENDENCIES:                                      */
/*                                                                           */
/*  Any external functions or variables which are used but not defined in    */
/*  this file should be noted here.  List the external library filename,     */
/*  the library function, and the local calling function.                    */
/*                                                                           */
/*      None.                                                                */
/*                                                                           */
/*****************************************************************************/


/*****************************************************************************/
/*                                                                           */
/*                        global variable declarations                       */
/*                                                                           */
/*****************************************************************************/

/* declare global variables here */
int magic_val_0;    /* pcode value 1 for serial interrupt handler */
int magic_val_1;    /* pcode value 2 for serial interrupt handler */
int serial_stolen=0;/* if 1, serial has been commandeered by my code */



/*****************************************************************************/
/*                                                                           */
/*                            function declarations                          */
/*                                                                           */
/*****************************************************************************/


void disable_pcode_serial()     /* disable board handshaking with IC   */
/* on the host computer, allowing user */
/* programs to receive serial data     */
{
    if(serial_stolen==1)
      return;
    
    serial_stolen=1;

    /* store the values the serial board keeps */
    /* this code taken from forum topic:
       http://www.kipr.org/boards/viewtopic.php?t=168&sid=2c3428269845e6a4152dbd05125e6b06 */
        
    magic_val_0=peek(0x102b);
    magic_val_1=peek(0x102d);
    
    /* clobber magic values... am I killing an interrupt table
       here? Is that why it works? Hard to say without learning
       68hc11 assembler */
    poke(0x102b,0x30);
    poke(0x102d,0x0c); 
    poke(0x3c, 1);
}

/*****************************************************************************/

void enable_pcode_serial()      /* enable board handshaking with IC on */
/* the host computer                   */
{
    /* it would be a BAD thing to call this when it is
       not initialized */
    if(serial_stolen==0) return;
    
    /* restore magic numbers */
    poke (0x102b,magic_val_0);
    poke (0x102d,magic_val_1);
    poke(0x3c, 0);
}

/*****************************************************************************/

int serial_putchar(int timeout,int c)      /* send a serial character.*/
{
    long outtime=mseconds()+(long)(timeout);     /* wait until it's okay to send */
    
    while (!(peek(0x102e) & 0x80))
      {
        if(mseconds() > outtime)
          {
            return(0);
        }
    }
    poke(0x102f, c);                    /* send the character */
    return(1);
}

/*****************************************************************************/

int serial_getchar(int timeout, int *dest)            /* read a serial character.  */
{
    long outtime=mseconds() + (long)(timeout);
    while (!(peek(0x102e) & 0x20))           /* wait until a character arrives */
      {
        if(mseconds() > outtime)
          {
            return(0);
        }
    }    *dest= (peek(0x102f));              /* return it as an int */
    return (1);
}

/*****************************************************************************/



