#include "fidoterm.h"
#include "mem.h"
#include <ascii.h>

/*
	FidoTerm hi-level console and modem I/O


get_console()
	Checks for aborting scripts; returns characters from the script
	text output or the physical keyboard. If a script is running it
	doesn't do much except check abort; it is presumed the script
	will take care of input. Returns a character or NUL.

put_console()
	Outputs a character to the console.

get_modem()
	Checks for aborting scripts; gets a character from the modem
	if conflg == 0, otherwise it gets input from the console via
	get_console() (for testing host type scripts). Returns a 
	character or -1. Characters received are shifted through the
	script shift register. Reads as many characters from the interrupt
	buffer to the local ring buffer as possible.

put_modem(c)
char c;
	Output a character to the modem, or if conflg == 1, to the local
	console. Do local echo ("half duplex") and autoLFs etc.


	Low level functions for FidoTerm.

These act directly on the modem port, and do not use the ring 
buffer. They are used for binary file transfers, modem commands
and the like.

modout(c)	Send a character to the modem.

modin(timer)	Input a character from the modem, with a time-
int timer;	out at (timer) tenths of a second, when you return
		TIMEOUT. Otherwise return the character received.
		Return value is an integer. If there are characters
		in the modem buffer, one of those is returned.

mputs(s)	Output a null-terminated string.

mbreak()	Cause a line break for 1/2 second.

cd()		Returns true if the RS-232 DCD line is true.

	--- Console Functions ---

All of these operate on the large character ring buffer. The
modem is polled for characters, and htey are placed within the ring
buffer. 

'chr_timer' indicates how long since the last character was
received.


poll()		Background poll for modem characters. This puts any
		available modem characters into the ring buffer, and
		drops any lost ones off the end.

mconin()	Waits for a character from the modem. 

mconstat()	Returns true if there is a character ready.

chkcon()	Returns a character from the modem if one is available,
		else returns 0. This returns characters from any script 
		file running.

keyhit()	Similar to chkcon(), except does not process characters
		from any script file. As for aborting downloads, etc.
*/

/* Get a character from the console. */

get_console() {
char c;

	if (c= getscr()) return(c);		/* script output character */

	if (key_timer < 50) return(NUL);	/* otherwise not time yet */
	key_timer= 0L;				/* reset the timer, */

	clkpoll();				/* do clock in RH corner */
	p_cursor();				/* put cursor in screen */

	if (conflg) return(NUL);		/* abort check etc elsewhen */

	c= keyhit();				/* read the keyboard */
	if (isscript()) {
		script_abort(c);		/* either check script abort */
		c= NUL;
	}
	return(c);				/* or return keystrokes */
}

/* Output a character to the console. */

put_console(c)
int c;
{
	if (c != -1) {
		if (parflg) c &= 0x7f;
		ansiout(c);
	}
}

/* Get a character from the modem, or keyboard if CONSOLE is on. */

/**/ static int file = -1;

get_modem() {
int c;
unsigned t;
char *cp;

	if (conflg) {					/* if CONSOLE on */
		c= keyhit();				/* check keystrokes */
		if (c == cmdchar) {
			script_abort(c);		/* and script abort */
			c= NUL;
		}
		if (c) {				/* if a character read */
			chr_timer= 0L;			/* restart timer */
			shiftin(c);			/* shift it in */
		}				
		return(c == NUL ? -1 : c);		/* -1 == no char */
	} 
/**/ /*	if (file == -1) file= open("TEST",OPEN_RO);
	if (read(file,&c,1) != 1) {
		close(file); file= -1;
		return(-1);
	}
	return(c);
*/
	poll();						/* char into ring buff */
	cp= ringout + 1;
	if (cp >= ringend) cp= ringbuff;		/* wrap ptr */
	if (cp == ringin) return(-1);			/* no char available */

	c= *cp;						/* read the char */
	ringout= cp;					/* new output ptr */
	if (parflg) c &= 0x7f;				/* (strip parity) */
	chr_timer= 0L;					/* restart timer */
	shiftin(c);					/* shift it in */
	return(c);
}

/* Write a character to the modem. */

put_modem(c)
char c;
{
	if (! c) return;			/* ignore NULs */

	if (conflg) {
		ansiout(c);
		if ((c == CR) && alfflg) put_modem(LF);
		return;
	}
	if (hdxflg) ansiout(c);			/* echo if half duplex */
	_mconout(parity(c,parflg));		/* send with parity */
	if ((c == CR) && alfflg) put_modem(LF);	/* do auto linefeeds */
}

/* Read characters from the serial driver and put them into a local ring
buffer. */

static poll() {

	while (_mconstat() && (ringin != ringout)) { /* while chars & room, */
		*ringin++= _mconin();		/* buffer a char */
		if (ringin >= ringend) 		/* wrap ptr at end */
			ringin= ringbuff;
	}
/**/	if (ringin == ringout) *ringin= '@';
}

/* If a character from the keyboard is present, return it, else
return 0. This function should not poll the ring buffer, nor get
characters from the script, since it is used to check for aborts,
etc during file transfers. */

keyhit() {

int c;		/* int not char */

	c= iskey();			/* sample keyboard, */
	if (c != -1) {			/* if one there, */
		if (c == 0) {		/* if IBM PC F-key leadin */
			while ((c= iskey()) == -1);
			c += 128;	/* get 2nd key, */
		}			/* set MSB */
	} else c= 0;			/* no key hit */
	return(c);
}

mbreak() {

	_mbreak(1);		/* start a break, */
	delay(50);		/* 1/2 sec delay */
	_mbreak(0);		/* break off */
}
/* Send a character to the modem. */

modout(c)
char c;
{
	_mconout(c);
	++char_out_count;
}

/* Output a null-terminated string. */

mputs(s)
char *s;
{
	while (*s) _mconout(*s++);
}

/* Return true if there's a character available from the modem, either
in the buffer or the port. */

modstat() {

	return(_mconstat());
}

/* Get a character from the modem, with a maximum wait time, in
centiseconds. Returns -1 if timeout. */

int modin(hundredths)
unsigned hundredths;
{
long til;

	if (_mconstat()) {
		++char_in_count;
		return(_mconin());		/* why wait? */
	}
	til= millisec + hundredths * 10L;	/* time to wait until */
	while (millisec < til) {
		if (_mconstat()) {
			++char_in_count;
			return(_mconin());
		}
	}
	return(-1);				/* timeout */
}

/* Return true if CD is set. */

cd() {

	return(_cd(cd_bit));
}

/* Flush the line and buffers of all characters until quiet for
(n) centiseconds. */

flush(n) 
int n;
{
	if (n) while (modin(n) != -1);
	else while (_mconstat()) _mconin();
}
/* Delay N centiseconds. Do nothing in the mean time. */

delay(n)
int n;
{
long til;

	til= millisec + n * 10L;
	while (millisec < til);
}
/* Set baud rate if not a fixed rate modem. */

setbaud(b)
unsigned b;
{
	if (! fixed_rate) baud(b);
}

