/****************************************************************************
*
*	(C) 2001 by Beck IPC GmbH
*
*
*
*
*	Beck IPC GmbH
*	Garbenheimerstr. 36-38
*	D-35578 Wetzlar
*	http://www.beck-ipc.com/chip
*
* ---------------------------------------------------------------------------
* Module		: IPC@CHIP SC12 API: fossil.c
*             Fossil interface, accessing the serial devices of the SC12
*				 Use memory model large!!
*
* Author		: Detlef Gerhardt
* Date			: 20.01.01
* ---------------------------------------------------------------------------
$Header: fossil.c, 12, 13.06.2002 16:29:11, Christoph Stoidner$

$Log:
 3    IPC@CHIP  1.2         12.03.01 13:20:34    Christoph Stoidner Changed
      Interrupt call in write block function. ("int86" to "int86x" to comitt the
      segment registers, too)
 2    IPC@CHIP  1.1         09.03.01 15:37:31    Christoph Stoidner removed
      printf call from WriteBlock function
 1    IPC@CHIP  1.0         09.03.01 15:35:57    Christoph Stoidner
$


* History		:
*
*  Vx.yy					Author	Changes
*
*             10.01.01      dg		Create
*             14.01.01      dg		Bugfix in fossil_setbaud,
*									ext. baudrates and line-control
*             27.01.01      dg		bugfix in fossil_setbaud()
*									baudrates now up to 115000 bps
              10.01.02      cs      correct comments
                                    add GetDriverInfo function
                                    add FOSSILVECT define
*
*****************************************************************************/

#include <dos.h>
#include <stdio.h>
#include "fossil.h"

#define FOSSILVECT 0x14

/*****************************************************************************
*
* initialize fossil interface
*
* port = 1: COM
* port = 0: EXT
* return = 0x1954: success
* return = 0: error
*/

int fossil_init(int port)
{
	union REGS inregs;
	union REGS outregs;

	inregs.h.ah = 0x04;
	inregs.x.dx = port;
	int86(FOSSILVECT,&inregs,&outregs);
	if (outregs.x.ax==0x1954) return outregs.x.ax;

   return 0;
}	// fossil_init()



/*****************************************************************************
*
* Deinitialize fossil interface
*
* port = 1: COM
* port = 0: EXT
*/

void fossil_deinit(int port)
{
	union REGS inregs;
	union REGS outregs;

	inregs.h.ah = 0x05;
	inregs.x.dx = port;
	int86( FOSSILVECT, &inregs, &outregs);
}	// fossil_deinit()



/*****************************************************************************
*
* Set baudrate
*
* standard values:
* port = 1: COM
* port = 0: EXT
* baudrate = 300,600,1200,2400,4800,9600,19200,38400
* parity:	0=non, 1=odd, 2=even, 3=mark, 4=space
* wordlen = 7,8
* stopbits = 1,2
* return = status (see fossil_status_request)
*
* extended values:
* baudrate = any values <= 115200
* parity:	0=non, 1=odd, 2=even, 3=mark, 4=space
*
* comment: 2 stop bits are only available if no parity is set
*/

int fossil_setbaud(int port, long baudrate, int parity, int wordlen, int stopbits)
{
	union REGS inregs;
	union REGS outregs;
	long baudtab[8] = {19200l,38400l,300l,600l,1200l,2400l,4800l,9600l};
	int baud_idx;
	long baud_max,baud_div;

   // check parameters
   for (baud_idx=0; baud_idx<=7; baud_idx++)
   {
     if (baudrate==baudtab[baud_idx]) break;
   }

   // init port
   if (baud_idx<=7)
   {
     // use function 0x00 for baudrates smaller 38400

     if (parity<0 || parity>2) return -1;
     if (parity==2)	parity = 3;
	  if (wordlen<7 || wordlen>8) return -1;
	  wordlen = wordlen - 5;
     if (stopbits<1 || stopbits>2) return -1;
	  stopbits--;

	  inregs.h.ah = 0x00;
	  inregs.h.al = wordlen + (stopbits<<2) + (parity<<3) + (baud_idx<<5);
     inregs.x.dx = port;
	  int86(0x14,&inregs,&outregs);
   } // if (baud_idx<=7)
   else
   {
     // use extended line control init for other baudrates
     if (parity<0 || parity>4) return -1;
     if (wordlen<7 || wordlen>8) return -1;

     // calculate divider value
	  // get max. baudrate value
     inregs.h.ah = 0x8A;
	  inregs.h.al = 2;	// mode: maximum baud rate
	  int86(0xA1,&inregs,&outregs);
	  baud_max = (long) outregs.x.ax + ((long) outregs.x.dx << 16);

	  // calc divider with integer rounding
	  baud_div = baud_max*10l / baudrate;
	  if ((baud_div % 10l) < 5l) baud_div = baud_max / baudrate;
	  else baud_div = baud_max / baudrate + 1;

	  inregs.x.cx = (unsigned int) baud_div;
	  inregs.h.ah = 0x81;	// Extended line control initialization
	  inregs.h.al = wordlen - 5;
	  inregs.h.bh = parity;
	  inregs.h.bl = stopbits - 1;
	  inregs.x.dx = port;
	  inregs.x.cx = (unsigned int) baud_div;
	  int86(0x14,&inregs,&outregs);

     // get status of port
     inregs.h.ah = 0x03;
     inregs.x.dx = port;
     int86(0x14,&inregs,&outregs);
   } // else (baud_idx<=7)
	return outregs.h.ah;
}	// fossil_setbaud()

/****************************************************************************/
//
// Put byte in output buffer (with wait)
//
// port = 1: COM
// port = 0: EXT
// ch: byte to send
// return = status (see fossil_status_request)

int fossil_putbyte_wait(int port, int ch)
{
	union REGS inregs;
	union REGS outregs;

	inregs.h.ah = 0x01;
	inregs.h.al = (char)ch;
	inregs.x.dx = port;
	int86( FOSSILVECT, &inregs, &outregs);
	return outregs.h.ah;

}	// fossil_putbyte_wait()


/****************************************************************************/
//
// Put byte in output buffer (without wait)
//
// port = 1: COM
// port = 0: EXT
// ch: byte to send
// return = 1: byte accepted
// return = 0: byte not accepted (output buffer full)
int fossil_putbyte(int port, int ch)
{
	union REGS inregs;
	union REGS outregs;

	inregs.h.ah = 0x0B;
	inregs.h.al = (char)ch;
	inregs.x.dx = port;
	int86( FOSSILVECT, &inregs, &outregs);
	return outregs.x.ax;

}	// fossil_putbyte()


/****************************************************************************/
//
// Get byte from input buffer (with wait)
//
// port = 1: COM
// port = 0: EXT
// return = received byte
int fossil_getbyte_wait(int port)
{
	union REGS inregs;
	union REGS outregs;

	inregs.h.ah = 0x02;
	inregs.x.dx = port;
	int86( FOSSILVECT, &inregs, &outregs);
	return (int)outregs.h.al;
}	// fossil_getbyte_wait()


/****************************************************************************/
//
// Peek if next byte is available (without removing it from input buffer)
//
// port = 1: COM
// port = 0: EXT
// return = received byte
// return = -1: no byte available
int fossil_peek_input(int port)
{
	union REGS inregs;
	union REGS outregs;

	inregs.h.ah = 0x0C;
	inregs.x.dx = port;
	int86( FOSSILVECT, &inregs, &outregs);
   if (outregs.x.ax==0xFFFF) return -1; // no data available

   return (int)outregs.h.al;
}	// fossil_peek_input()


/****************************************************************************/
//
// Status request
//
// port = 1: COM
// port = 0: EXT
// return = status
// bit 6: set if output buffer is empty.
// bit 5: set if output buffer is not full.
// bit 4: line break detected
// bit 3: framing error detected
// bit 2: parity error detected
// bit 1: set if overrun occured on receiver.
// bit 0: set if data is available in receiver buffer.
int fossil_status_request(int port)
{
	union REGS inregs;
	union REGS outregs;

	inregs.h.ah = 0x03;
	inregs.x.dx = port;
	int86( FOSSILVECT, &inregs, &outregs);
	return outregs.h.ah;
}	// fossil_status_request()


/****************************************************************************/
//
// Flush output buffer (with wait)
//
// port = 1: COM
// port = 0: EXT
// return = none
void fossil_flush_output(int port)
{
	union REGS inregs;
	union REGS outregs;

	inregs.h.ah = 0x08;
	inregs.x.dx = port;
	int86( FOSSILVECT, &inregs, &outregs);
}	// fossil_flush_output()


/****************************************************************************/
//
// Purge output buffer
//
// port = 1: COM
// port = 0: EXT
// return = none
void fossil_purge_output(int port)
{
	union REGS inregs;
	union REGS outregs;

	inregs.h.ah = 0x09;
	inregs.x.dx = port;
	int86( FOSSILVECT, &inregs, &outregs);
}	// fossil_purge_output()


/****************************************************************************/
//
// Purge input buffer
//
// port = 1: COM
// port = 0: EXT
// return = none
void fossil_purge_input(int port)
{
	union REGS inregs;
	union REGS outregs;

	inregs.h.ah = 0x0A;
	inregs.x.dx = port;
	int86( FOSSILVECT, &inregs, &outregs);
}	// fossil_purge_input()


/****************************************************************************/
//
// Enable/disable flow control
//
// port = 1: COM
// port = 0: EXT
// flowcontrol:
// 0: XON/XOFF on transmit (watch for XOFF while sending)
// 1: RTS/CTS (CTS on transmit/RTS on receive)
// 2: reserved
// 3: XON/XOFF on receive (send XOFF when buffer near full)
// 4-7: ignored
// both XON/XOFF and CTS/RTS is not allowed at the same time.
// XON/XOFF mode is only available, if serialdma access is disabled at chip.ini
//
// return = none
void fossil_set_flowcontrol(int port, int flowctrl)
{
	union REGS inregs;
	union REGS outregs;

	inregs.h.ah = 0x0F;
	inregs.h.al = flowctrl;
	inregs.x.dx = port;
	int86( FOSSILVECT, &inregs, &outregs);
}	// fossil_set_flowcontrol()


/****************************************************************************/
//
// Read block from input buffer
//
// port = 1: COM
// port = 0: EXT
// buffer: pointer to buffer for input data
// count: maximum number of bytes to transfer.
//
// return = number of bytes transfered
unsigned int fossil_readblock(int port, unsigned char *buffer, unsigned int count)
{
	struct SREGS sregs;
	union REGS inregs;
	union REGS outregs;

	inregs.h.ah = 0x18;
	inregs.x.cx = count;
	inregs.x.dx = port;
	sregs.es    = FP_SEG(buffer);
	inregs.x.di = FP_OFF(buffer);
	int86x( FOSSILVECT, &inregs, &outregs, &sregs);
   return (unsigned int)outregs.x.ax;
}	// fossil_readblock()


/****************************************************************************/
//
// Write block to output buffer
//
// port = 1: COM
// port = 0: EXT
// buffer: pointer to buffer for output data
// count: maximum number of bytes to transfer
//
// return = actual number of bytes to transfer (may be limited by space in output buffer)
unsigned int fossil_writeblock(int port, unsigned char *buffer, unsigned int count)
{
	struct SREGS sregs;
	union REGS inregs;
	union REGS outregs;

	inregs.h.ah = 0x19;
	inregs.x.cx = count;
	inregs.x.dx = port;
	sregs.es    = FP_SEG(buffer);
	inregs.x.di = FP_OFF(buffer);
	int86x( FOSSILVECT, &inregs, &outregs, &sregs);
	return outregs.x.ax;
}	// fossil_writeblock()


/****************************************************************************/
//
// Set RS485 mode
//
// port = 1: COM
// port = 0: EXT
// mode =
//    0: TxEnable low active
//    1: TxEnable high active
//    2: Disable RS485 mode
//
// return = none
//
// Comment: By default the RTS0 and RTS1 signal (pin) is used to enable/disable the
// transmitter (TxEnable)
void fossil_set_rs485(int port, int mode)
{
	union REGS inregs;
	union REGS outregs;

	inregs.h.ah = 0x80;
	inregs.h.al = mode;
	inregs.x.dx = port;
	int86( FOSSILVECT, &inregs, &outregs);

}	// fossil_set_rs485()


/****************************************************************************/
//
// Set RS485 transmitter enable pin
//
// port = 1: COM
// port = 0: EXT
// pin = 0..13
//
// return = none
//
// Comment: By default the RTS0 and RTS1 signal (pin) is used to enable/disable
// the transmitter. (TxEnable)
// To change the default, call this function before you call the RS485 Enable function.
// This function let's you select any PIO from 0-13 as TxEnable, but not any makes sense.
void fossil_set_rs485_txenable(int port, int pin)
{
	union REGS inregs;
	union REGS outregs;

	inregs.h.ah = 0x82;
	inregs.h.al = pin;
	inregs.x.dx = port;
	int86( FOSSILVECT, &inregs, &outregs);
}	// fossil_set_rs485_txenable()


/****************************************************************************/
//
// Extended line control initialization
//
// port = 1: COM
// port = 0: EXT
// baud_divider: baudrate divider (for maximum baudrate see HAL function 0x8A)
// parity =
//	  0: no parity
//   1: odd parity
//   2: even parity
//   3: mark parity (always 1)
//   4: space parity (always 0)
// wordlen = 7,8
// stopbits = 1,2
//
// return = none
void fossil_set_extctrl(int port, int baud_divider, int parity, int wordlen, int stopbits)
{
	union REGS inregs;
	union REGS outregs;

	if (parity<0 || parity>4) return;
	if (wordlen<7 || wordlen>8) return;
	if (stopbits<1 || stopbits>2) return;

	inregs.h.ah = 0x81;
	inregs.h.al = wordlen-5;
   inregs.h.bh = parity;
	inregs.h.bl = stopbits-1;
	inregs.x.cx = baud_divider;
	inregs.x.dx = port;
	int86( FOSSILVECT, &inregs, &outregs);
}	// fossil_set_rs485_txenable()



/****************************************************************************/
//
// Get Driver Info
//
// port = 1: COM
// port = 0: EXT
// drv_info: driver Infos
//
// return = Number of bytes actually transfered
int fossil_get_driver_info(int port, FossilDriverInfo_t *drv_info)
{
	union  REGS  inregs;
	union  REGS  outregs;
   struct SREGS segregs;

	inregs.h.ah = 0x1B;
	inregs.x.cx = sizeof(FossilDriverInfo_t);
	inregs.x.dx = port;
   segregs.es  = FP_SEG(drv_info);
   inregs.x.di = FP_OFF(drv_info);
	int86( FOSSILVECT, &inregs, &outregs);

   return outregs.x.ax;
}	// fossil_get_driver_info()

/*****************************************************************************
*
* send Break
*
* port = 1: COM
* port = 0: EXT
  longbreak =
     0: short break
     1: long break
* return none
*/

void fossil_send_break(int port, unsigned char longbreak )
{
	union REGS inregs;

	inregs.h.ah = 0x83;
   inregs.h.al = longbreak;
	inregs.x.dx = port;
	int86(FOSSILVECT,&inregs,&outregs);
   return;
}	// fossil_init()


/*****************************************************************************
*
* get number or bytes currently in UART
*
* port = 1: COM
* port = 0: EXT
* return = number of bytes in UART
*/

int fossil_get_bytes_in_uart(int port)
{
	union REGS inregs;
	union REGS outregs;

	inregs.h.ah = 0xA0;
	inregs.x.dx = port;
	int86(FOSSILVECT,&inregs,&outregs);
   return outregs.x.ax;
}	// fossil_init()


/****************************************************************************/
// end of file
/****************************************************************************/

