/*
 * sci interrupt handler
 *
 * A MSDOS device or application puts out <0x0d, 0x0a> as a new line.
 * A UNIX device or application puts out <0x0a> as a new line.
 *
 * Fri Aug  2 16:44:22 PDT 2002 - 52 usec
 *
 * $Id: sci.c,v 1.9 2002/08/03 17:52:57 tomdean Exp $
 */
#include <sys/regs.h>
#include <sys/ports_def.h>
#include <os.h>
#include <lcd.h>
#include <libeeprom.h>  /* lcd functions */

unsigned char *rx_next_char;
unsigned char *tx_next_char;

void sci() {
  register unsigned short idx;
  register msg_t *ptr;
  /* do whatever ... */
  DEBUG_ON(BIT04);
  if ((_io_ports[M6811_SCSR]&M6811_RDRF) ) {
	/*
	 * make sure we do NOT over-run the buffer
	 * we need room for this char and a terminating NULL
	 */
	if (rx_next_char > cur_sci_buf->buf + MSG_BUF_SIZE-2)
	  rx_next_char = cur_sci_buf->buf + MSG_BUF_SIZE-2;
	/* we have a char */
	__d8 = (unsigned short)_io_ports[M6811_SCDR];
	/* either 0x0d or 0x0a terminate the line */
	if ((__d8 == 0x0a) || (__d8 == 0x0d)) {
	  *rx_next_char = 0x00;
	  /* send buffer to cli or gps */
	  cur_sci_buf->empty = 0;
	  if (cur_sci_buf->buf[0] == '$') {
		/* queue the buffer to the gps task */
		idx=GPS_TASK;
	  } else {
		/* echo the buffer and queue the buffer to cli task */
		*rx_next_char++ = '\n';
		*rx_next_char = 0x00;
		sci_send(cur_sci_buf->buf);
		idx=CLI_TASK;
	  }
	  ptr = msg_queue[idx];
	  if (ptr == NULL) {
		/* new message head */
		msg_queue[idx] = cur_sci_buf;
		ptr = msg_queue[idx];
	  } else {
		/* append the message */
		while (ptr->next != NULL) ptr = ptr->next;
		ptr->next = cur_sci_buf;
		ptr = ptr->next;
	  }
	  if (ptr != NULL) ptr->next = NULL;

	  /*
	   * XXX fix me - add code to age sci buffers
	   * and mark empty after x ticks.
	   */
	  for (idx=0; idx < NUM_SCI; idx++) {
		if (sci_buf[idx].empty) break;  /* found an empty one */
	  }
	  if (idx == NUM_SCI) {
		/* oops, all the buffers are full */
		register unsigned char *p, *q;
		register unsigned short jdx;
		lcd_write_row_1("SCI ERROR - ALL BUFFERS FULL");
		p = error3;
		for (idx=0; idx < NUM_SCI; idx++) {
		  /* need 8 bytes for an empty buffer display */
		  if ((sci_buf[idx].empty == 0) && (p < error3+32) ) {
			/* put the buf num + $GPGSV, etc in error3 */
			q = sci_buf[idx].buf + 1;  /* don't need the $ */
			*p++ = idx+'0'; *p++ = ' ';
			for (jdx=0; jdx<5; jdx++) *p++ = *q++;
			*p++ = ' ';
		  }
		}
		error3[40] = 0;
		/*
		 * no need to mark it in use - we are going to hang in
		 * in an interrupt routine, reboot is the ONLY escape
		 */
		lcd_write_row_3(error3);
		/* and, hang! */
		while (1);
	  }
	  cur_sci_buf = &sci_buf[idx];
	  rx_next_char = sci_buf[idx].buf;  /* -> buf[0] */
	} else {
	  /*
	   * XXX fix me - add code to avoid buffer overflow
	   * Truncate the input or what???
	   */
	  *rx_next_char++ = (unsigned char)__d8;
	}
  } else if (_io_ports[M6811_SCSR]&M6811_TDRE) {
	if (*tx_next_char) {
	  _io_ports[M6811_SCDR] = *tx_next_char++;
	} else {
	  /* turn off tx */
	  _io_ports[M6811_SCCR2] &= ~(M6811_TE | M6811_TIE | M6811_TCIE);
	}
  }
  DEBUG_OFF(BIT04);
}

void sci_init() {
  register unsigned short idx;
  /* initialize the sci rx buffers */
  /*
   * initialize the sci
   * re, rie
   * te, tie, and, tcie are set when  transmit required
   */
  _io_ports[M6811_SCCR2] = M6811_RE | M6811_RIE;
  /* initialize the sci tx buffers */
  for (idx=0; idx<NUM_SCI; idx++) {
	sci_buf[idx].empty = 1;  /* mark all as empty */
  }
  cur_sci_buf = &sci_buf[0];
  rx_next_char = sci_buf[0].buf;
  
  return;
}
  
/*
 * send a buffer up the sci
 *
 * initialize tx and send the first char
 */
void sci_send(unsigned char *buf) {
  tx_next_char = buf;
  _io_ports[M6811_SCCR2] |= M6811_TE | M6811_TIE | M6811_TCIE;
  _io_ports[M6811_SCDR] = *tx_next_char++;

  return;
}
