/*************************************************************************
*	"rsctrl.c" : RS-232C 制御
*************************************************************************/

#include	<stdio.h>
#include	<stdlib.h>
#include	<stdarg.h>
#include	<string.h>
#include	<time.h>
#include	<dos.h>
#include	<msdos.cf>

#include	<splib.h>
#include	<setupif.h>
#define		_RSCTRL_MAIN
#include	"rsctrl.h"

#ifdef	__HIGHC__
#	pragma	On(Align_labels);
#endif

#ifndef	MALLOC
#	define	MALLOC	malloc
#endif
#ifndef	CALLOC
#	define	CALLOC	calloc
#endif
#ifndef	FREE
#	define	FREE	free
#endif

int		RS_reopen( int port, int md, int bp )
{
	int		 er;
	RSB_T	*rsb = RsCtrl[port].rsb;

	if ( rsb == NULL )
		return (ERR);

	RSB_DTR(port,1);		/*	DTR信号の保持	*/
	RSB_CLOSE(port);

#ifdef	_RS_FMC
	rsb->mode        = md;				/*	通信モード				*/
	rsb->baud        = bp;				/*	ボーレート				*/
//	rsb->rbuf        = 0;
//	rsb->rbuf_seg    = 0;
	rsb->stime       = 500;				/*	送信タイムアウト		*/
	rsb->rtime       = 500;				/*	受信タイムアウト		*/
	rsb->rinfbuf     = 0;				/*	受信通知アドレス		*/
	rsb->rinfbuf_seg = 0;
	rsb->extmode     = 0;				/*	拡張モード				*/
//	rsb->xon         = 0;				/*	XONコード(0x11)			*/
//	rsb->xoff        = 0;				/*	XOFFコード(0x13)		*/
//	rsb->obuf        = 0;
//	rsb->obuf_seg    = 0;
#else
#ifdef	_RS_N10
	rsb->mode    = md;				/*	通信モード				*/
	rsb->baud    = bp;				/*	ボーレート				*/
	rsb->stime   = 0;				/*	送信タイムアウト		*/
	rsb->rtime   = 0;				/*	受信タイムアウト		*/
	rsb->rinfbuf = 0;				/*	受信通知アドレス		*/
	rsb->extmode = 0;				/*	拡張モード				*/
	rsb->xon     = 0;				/*	XONコード(0x11)			*/
	rsb->xoff    = 0;				/*	XOFFコード(0x13)		*/
#endif
#ifdef	_RS_N11
	rsb->mode    = md & (~RSMD_EXINT);	/*	通信モード				*/
	rsb->baud    = bp;					/*	ボーレート				*/
	rsb->stime   = 0;					/*	送信タイムアウト		*/
	rsb->rtime   = 0;					/*	受信タイムアウト		*/
	rsb->rinfofs = 0;					/*	受信通知アドレス		*/
	rsb->rinfsel = 0;					/*	受信通知セレクタ		*/
	rsb->extmode = 0;					/*	拡張モード				*/
	rsb->xon     = 0;					/*	XONコード(0x11)			*/
	rsb->xoff    = 0;					/*	XOFFコード(0x13)		*/
	rsb->sendofs = 0;					/*	送信バッファアドレス	*/
	rsb->sendsel = 0;					/*	送信バッファセレクタ	*/
#endif
#endif
	RsCtrl[port].overFlag = 0;

#ifdef	_RS_FMC
	if ( (er = RSB_setpara(port, rsb)) == 0 )
#else
	if ( (er = RSB_Setpara(port, (char *)rsb)) == 0 )
#endif
	{
		er = RSB_OPEN(port);
		RSB_INITBUF( port );
	}

	return (er);
}

void	RS_close(int port)
{
	--RsCtrl[port].use;
	if ( RsCtrl[port].use <= 0 )
	{
		RsCtrl[port].use = 0;
		RSB_CLOSE( port );
	}
}

static	int		RsbLimMax = (3*RS_BUFSIZ/4) & 0xFFFFFF00;
static	int		RsbLimMin = (1*RS_BUFSIZ/4) & 0xFFFFFF00;

RSB_T	*RS_open( int port )
{
	RSB_T				*rsb;

	RS_init();

	if ( (rsb = RsCtrl[port].rsb) == NULL )
	{
		if ( (rsb = CALLOC(sizeof(RSB_T),1)) == NULL )
			return (NULL);
		RsCtrl[port].rsb = rsb;
	}
#ifdef	_RS_FMC
#if	0
	{
		RSB_PARA	rsbPara;
		_far void	*ptr;
		size_t		bufsiz;

		RSB_rdrpara(port, &rsbPara );
		_FP_SEG(ptr) = rsbPara.rbuf_seg;
		_FP_OFF(ptr) = rsbPara.rbuf;
		bufsiz = *(_far unsigned int *)(ptr);
		RsbLimMax = 3 * bufsiz / 4;
		RsbLimMin = 1 * bufsiz / 4;
	}
#else
		RsbLimMax = 3 * 1024 / 4;
		RsbLimMin = 1 * 1024 / 4;
#endif
	if ( RsCtrl[port].use == 0 )
	{
		RSB_rdrpara(port, rsb );
		RSB_setpara(port, rsb);
		RSB_open(port);
		RsCtrl[port].overFlag = 0;
	}
#else
	/* NATIVE RS */
	{
		RSBUF_T				*rsBuf;
		if ( (rsBuf = RsCtrl[port].rsBuf) == NULL )
		{
			if ( (rsBuf = CALLOC(sizeof(RSBUF_T),1)) == NULL )
				return (NULL);
			rsBuf->len = RS_BUFSIZ;
			RsCtrl[port].rsBuf = rsBuf;
		}

		if ( RsCtrl[port].use == 0 )
		{
			static RSYSINF_T	*rsys = NULL;

			if ( rsys == NULL )
			{
				if ( (rsys = MALLOC(sizeof(RSYSINF_T))) == NULL )
					return (NULL);
				ESR_setupInfo(rsys);
			}
			rsb->baud = rsys->rs232c[port].baud;
			rsb->mode = rsys->rs232c[port].mode; /* & (~RSMD_EXINT); */
			rsb->rbuf = (char *)rsBuf;		/*	受信バッファアドレス	*/
			rsb->sel  = getds();			/*	セレクター値			*/
#ifdef		_RS_N11
			RSB_Setpara(port, (char *)rsb);
#endif
			RSB_OPEN(port);
			RsCtrl[port].overFlag = 0;
		}
	}
#endif
	++RsCtrl[port].use;

	return (rsb);
}

int		RS_chk(int port)
{
	int		len;

	if ( RsCtrl[port].use == 0 )
		return (ERR);

	RSB_READ(port,&len);
	if ( RsCtrl[port].overFlag == FALSE )
	{
		if ( len > RsbLimMax )
		{	RsCtrl[port].overFlag = TRUE;
			RSB_CTRL(port,0x02);
		}
	} else
	{
		if ( len < RsbLimMin )
		{	RsCtrl[port].overFlag = FALSE;
			RSB_CTRL(port,0x22);
		}
	}
	return (len);
}

int		RS_getc(int port)
{
	UINT	i;
	UINT	st;
	int		ch;

	if ( RsCtrl[port].use == 0 )
		return (ERR);

RETRY:
	i = 0;
	for(;;)
	{
		if ( RSB_RECEIVE(port,&ch,&st) == 0 )
			break;
		if ( ++i > RS_TIMEOUT_LIMIT )
		{	ch = 0;
			break;
		}
	}
	ch &= 0xFF;
#ifdef	_BPLUS_
	if ( ch == 0x05 && (RsCtrl[port].attr & RSATT_BP) )
	{
		BP_Term_ENQ(port);
		goto RETRY;
	} else if ( ch == 0x10 && (RsCtrl[port].attr & RSATT_BP) )
	{
		BP_DLE_Seen(port);
		goto RETRY;
	}
#endif
	return	(ch);
}

void	RS_putc(int port, int ch)
{
	if ( RsCtrl[port].use == 0 )
		return;

#ifdef	_RS_FMC
	{
		UINT			st;

		RSB_send(port,ch,&st);
	}
#else
	{
		unsigned int	status, serial;

		if ( RSB_Status(port,&status,&serial) == 0 )
		{
			clock_t		clk;

			if ( !(serial & 2) )
			{	/* CTS 信号がOFF（送信できない）	*/
				int		i;

				for ( i = 0; i < 5; ++i )
				{
					clk = H_CLOCK2(0) + 5 * CLOCKS_PER_SEC / 100;	/* 0.05秒	*/
					while ( clk > H_CLOCK2(clk) )
						;
					if ( RSB_Status(port,&status,&serial) )
						return;
					if ( serial & 2 )
						break;
				}
			}

			clk = H_CLOCK2(0) + 50 * CLOCKS_PER_SEC / 100;	/* 0.5秒	*/
			do
			{
				int		ret;

				if ( (ret = RSB_Send(port,ch,&status)) == 0 )
					break;
				switch ( ret )
				{
					case 2:	/* 範囲以外のポート				*/
					case 3:	/* 拡張カードが接続されていない	*/
					case 4:	/* 回線がオープンされていない	*/
						return;
					case 8:	/* タイムアウト					*/
					default:
						break;
				}
			} while ( clk > H_CLOCK2(clk) );
		}
	}
#endif
}

void	RS_puts( int port, CONST char *s )
{
	while ( *s )
	{
		RS_putc( port, (*s) & 0xFF );
		++s;
	}
}

void	RS_printf( int port, CONST char *form, ... )
{
	va_list		arg;
	char		tmp[BUFSIZ];

	va_start( arg, form );
	vsprintf( tmp, form, arg );
	va_end(arg);
	RS_puts( port, tmp );
}

void	RS_breakOut( int port, int tm )
{
	if ( RsCtrl[port].use == 0 )
		return;
	RSB_BREAK(port, tm );
}

static	char	rsInit = FALSE;

/*************************************************************************
*	一時停止処理（子プロセス呼び出しのため）
*-------------------------------------------------------------------------
*	※	この関数を使った後には，必ずRS_continue を実行すること
*************************************************************************/

void	RS_pause(void)
{
	int		port;

	if ( rsInit )
	{
		for ( port = 0; port < RS_PORTNUM; ++port )
		{
			if ( RsCtrl[port].use > 0 )
			{
				if ( RsCtrl[port].overFlag == FALSE )
				{
					RsCtrl[port].overFlag = TRUE;
					RSB_CTRL(port,0x02);
				}
				RSB_DTR(port,1);		/*	DTR信号の保持	*/
				RSB_CLOSE(port);
			}
		}
#ifndef	_RS_FMC
		RSB_End();
#endif
	}
}

/*************************************************************************
*	再開処理（子プロセス呼び出しのため）
*************************************************************************/
void	RS_continue(void)
{
	int		port;

	if ( rsInit )
	{
#ifndef	_RS_FMC
		RSB_Init();
#endif
		for ( port = 0; port < RS_PORTNUM; ++port )
		{
			if ( RsCtrl[port].use > 0 )
			{
#ifdef			_RS_FMC
				RSB_setpara(port, RsCtrl[port].rsb );
#else
				RSB_Setpara(port, (char *)RsCtrl[port].rsb );
#endif
				RSB_OPEN(port);
			}
		}
	}
}

int		RS_init(void)
{
#ifdef	_RS_FMC
	return (0);
#else
	if ( rsInit )
		return (NORMAL);
	else
	{	rsInit = TRUE;
		return RSB_Init();
	}
#endif
}

int		RS_end(void)
{
#ifdef	_RS_FMC
	return (0);
#else
	if ( rsInit )
	{
		int		port;
		for ( port = 0; port < RS_PORTNUM; ++port )
		{
			while ( RsCtrl[port].use > 0 )
				RS_close( port );
		}
		return	RSB_End();
	} else
		return (NORMAL);
#endif
}
