#ifndef	lint
static char sccsid[] = "@(#) rs232.c 1.4 90/06/25";
#endif

#include "cbratp.h"
#include <stdio.h>
#include <fcntl.h>
#include <sys/time.h>
/*#include <sys/ioctl.h>*/
#include <sys/file.h>
/* #include <sys/types.h>*/
/*#include <sys/ttydev.h>*/
#include <termios.h>

extern char *host;		/* Name of remote host to contact */
static int inited = 0;

struct termios rs232_termios;
extern void exit();

#define BUFSIZE	1024

int	rs232_fd;
static int	rs232_icnt;
static u_char	*rs232_head;
static u_char	*rs232_tail;
static u_char	*rs232_optr;
static u_char	rs232_ibuf[BUFSIZE];
static u_char	rs232_obuf[MAXPKTSIZE];

long bytes_in;
long bytes_out;
long escapes_in;
long escapes_out;
/*
 * rs232init(p, baud, rtscts)
 *	opens 'p' as the raw io layer. sets the initial baudrate
 *	to the default or 'baud' if it is nonzero.  On a Sun,
 *	sets RTS/CTS flow control if 'rtscts' nonzero.
 *
 * Returns: 1 if successful
 *	    0 if failed
 */
rs232init(p, baud, rtscts)
    char *p;
    int baud;
    int rtscts;
{
    int ispeed;

    if (host == NULL) {
      return(0);

  } else {				/* Host != NULL */

      if ((rs232_fd = tcp_init(inited)) < 0) 
	  return(0);

      if (!inited)
	  inited = 1;

      rs232baudrate = 19200;		/* Arbitrary length */
  }

    min_timeout = 10000000 / rs232baudrate;
    rs232_optr = rs232_obuf;
    rs232_head = rs232_ibuf;
    rs232_tail = rs232_head;
    rs232_icnt = 0;

    return 1;
}

/*
 * set_baudrate(speed)
 *	sets the baudrate to speed.
 *	returns 0 if can't
 */
set_baudrate(speed)
    register int speed;
{
    register int i;

	return 1;
}

#ifdef	SUN
/*
 * setraw(fd, termios_p)
 * 	sets the line associated with fd to be 8 bit
 *	with no special characters.  Returns the new
 *	setting in *termios_p.
 */
setraw(fd, termios_p)
    int fd;
    register struct termios *termios_p;
{

}
#endif	SUN

/*
 * rs232rawkey()
 *	returns the next character off the input queue
 *	returns NEED_MORE if no characters available
 */
rs232rawkey()
{
    int	i;

    if (rs232_icnt == 0)
	return NEED_MORE;

    bytes_in++;
    rs232_icnt--;
    i = *rs232_head++ & 0xff;
    if (rs232_head == rs232_ibuf + BUFSIZE)
	rs232_head = rs232_ibuf;

    return i;
}

static int escaped;

/*
 * rs232in()
 *	returns the next charcter off the input queue
 *	escaped characters are expanded.
 *	returns START_STOP if the start/stop character was next
 *	returns NEED_MORE if there are no characters
 */
rs232in()
{
    register int	c;

    if ((c = rs232rawkey()) == NEED_MORE)
	return NEED_MORE;

    if (escaped) {
	escapes_in++;
	escaped = 0;
	return c ^ 0x20;
    }

    if (c == START_STOP)
	return START;

    if (c == ESCAPE_BYTE) {
	escaped = 1;
	c = rs232in();
    }

    return c;
}

/*
 * rs232ready()
 *	returns the number of characters in the input queue
 *	and fills the input queue from the raw device
 */
rs232ready()
{
    int	i = 0;
    fd_set read_fd;
    static struct timeval timeout = {0,0};

#if	ATARI||ATT
    while (rs232rdy() && rs232_icnt != BUFSIZE) {
	i = rs232key();
	*rs232_tail++ = i;
	if (rs232_tail == rs232_ibuf + BUFSIZE)
	    rs232_tail = rs232_ibuf;
	rs232_icnt++;
    }
#endif	ATARI||ATT

#ifdef	SUN
    if (host != NULL) {
      FD_ZERO(&read_fd);
      FD_SET(rs232_fd, &read_fd);
      if (!select(rs232_fd+1, &read_fd, (fd_set *)0, (fd_set *)0, &timeout))
	return rs232_icnt;
      i = 1;
    } else {
      if (ioctl(rs232_fd, FIONREAD, &i) < 0)
	perror("rs232ready");
      if (i <= 0)
	return rs232_icnt;
    }

    if (i > BUFSIZE - rs232_icnt)
	i = BUFSIZE - rs232_icnt;

    if (rs232_tail >= rs232_head) 
    {
	register int	above = rs232_ibuf + BUFSIZE - rs232_tail;

	if (above > i)
	    readn(rs232_fd, (char *) rs232_tail, i);
	else {
	    readn(rs232_fd, (char *) rs232_tail, above);
	    readn(rs232_fd, (char *) rs232_ibuf, i - above);
	}
    }
    else
	readn(rs232_fd, (char *) rs232_tail, i);
    rs232_icnt += i;
    rs232_tail += i;
    if (rs232_tail >= rs232_ibuf + BUFSIZE)
	rs232_tail -= BUFSIZE;
#endif	SUN

    return rs232_icnt;
}

#ifdef	SUN
/*
 * readn(fd, ptr, n)
 *	reads n bytes from file descriptor fd to ptr.
 *	assumes that n bytes are guaranteed
 */
readn(fd, ptr, n)
    int	fd;
    register char *ptr;
    register int n;
{
    register int i;

    while ((i = read(fd, ptr, n)) >= 0 && (n -= i) > 0) {
#ifdef	DEBUG
	if (rs232_debug)
	    (void) fprintf(rs232_debugfile, "readn(%d)...\n", n);
#endif	DEBUG
	ptr += i;
    }
    if (host != NULL)
	if (i < 0) {			/* Lost socket */
	    close(fd);
	    do {
		sleep(20);
		fd = rs232init(NULL, 0, 0);
	    } while(fd = 0);
	}
}
#endif	SUN

/*
 * rs232oready()
 *	returns number of characters on raw output device being send
 */
rs232oready()
{
#ifdef	SUN
    int	i = 0;
    fd_set write_fd;
    static struct timeval timeout = {0,0};

    if (host != NULL) {
      FD_ZERO (&write_fd);
      FD_SET (rs232_fd, &write_fd);
      if (!select(rs232_fd+1, (fd_set *)0, &write_fd, (fd_set *)0, &timeout))
	return 1;
      return 0;
    }

    if (ioctl(rs232_fd, TIOCOUTQ, &i) < 0)
	perror("rs232oready");
    return i;
#endif	SUN

#ifdef ATT
    return !rs232ordy();
#endif ATT

#ifdef	ATARI
    /* ### flow cntrl bug return !rs232ordy(); */
    return 0;
#endif	ATARI
}

/*
 * rs232rawemit(c)
 *	write character c onto output queue
 */
rs232rawemit(c)
u_char	c;
{
    *rs232_optr++ = c;
}

/*
 * rs232flush()
 *	write all characters on output queue to raw output device
 */
rs232flush()
{
#ifndef	SUN
    register u_char *p;
#endif	/*SUN*/

    timeout = timer() + 1000 + 2 * MAXPKTSIZE * min_timeout/1000;
#ifdef	DEBUG
    if (*rs232_obuf&RETRY && rs232_debug) {
	u_char *cp = rs232_obuf;
	(void) fprintf(rs232_debugfile,
		    "retry: seq = %d, ack = %d, myseq = %d, myack = %d",
		    SEQ(*cp), ACK(*cp), reader.lastack, writer.frame);
	++cp;
	(void) fprintf(rs232_debugfile, "\tchannel = %d\n\t[ ", *cp);
	while (++cp != rs232_optr)
	    (void) fprintf(rs232_debugfile, "%02x ", *cp);
	(void) fprintf(rs232_debugfile, "]\n");
    }
#endif	DEBUG

#if ATARI||ATT
    for (p = rs232_obuf; p != rs232_optr; p++) {
	while (!rs232ordy())
	    ;
	rs232emit(*p);
    }
#endif ATARI||ATT

#ifdef SUN
    if (write(rs232_fd, (char *) rs232_obuf, rs232_optr - rs232_obuf) < 0)
	if (host == NULL)
	    perror("rs232write");
	else {
	    close (rs232_fd);
	    do {
		sleep(20);
	    } while (!rs232init(NULL, 0, 0));
	}
#endif	SUN

    rs232_optr = rs232_obuf;
}

/*
 * rs232out(c)
 *	write character c to the output queue escaping it if necessary
 */
rs232out(c)
    u_char	c;
{
    bytes_out++;
#ifdef ESCAPEDCONTROL
    if ( c < 0x20 || c == START_STOP || c == ESCAPE_BYTE || c == '~') {
#else
    if (c == START_STOP || c == ESCAPE_BYTE || c == '~') {
#endif
	escapes_out++;
	rs232rawemit(ESCAPE_BYTE);
	rs232rawemit(c^0x20);
	return;
    }
    rs232rawemit(c);
}

#ifndef	WIRETAP
#ifdef	SUN
#ifndef	HELPER
/*
 * con_emit(s)
 *	output string s to the console
 */
con_emit(s)
    char *s;
{
    (void) write(1, s, strlen(s));
}
#endif	/*HELPER*/
#endif	/*SUN*/
#endif	/*WIRETAP*/


