/***************************************************************************
These C++ classes are copyright 1990, by William Herrera.
All those who put this code or its derivatives in a commercial product MUST
mention this copyright in their documentation for users of the products in
which this code or its derivative classes are used.  Otherwise, this code
may be freely distributed and freely used for any purpose.

Enhancements: 1991 by David Orme
	*  General cleanup.
			- I/O now takes advantage of C++ overloading.
			- Serial port I/O functionality now only in Serial class.
			- Modem functionality now only in Modem class.
	*  Possible to easily implement file Xfr prots now.
	*  CCITT CRC-16 class added							-- 2-20-1991
	*  BIOS Timer class added								-- 2-22-1991
	*  Optional timeout on all input routines added	-- 2-25-1991

***************************************************************************/

// file uart.hpp, class declaration for the uart class.
// see your modem manual (I used MultiTech's) or the IBM Technical
// reference manual for more information on the 8250 UART used in the PC.


#ifndef UART_HPP
#define UART_HPP 1

#include <dos.h>
#include <bool.h>


#ifdef __ZTC__

#include <int.h>

#ifndef inportb
#define inportb inp
#define outportb outp
#define inportw inpw
#define outportw outpw
#define disable int_off
#define enable int_on
#endif

#endif


// N. B.: Be VERY careful when using some PC hardware with COM1
// or COM2 at the same time this class or its derivative classes are set
// to use COM3 or COM4! This includes hardware incompatibilities with 
// certain serial rodents.  On the IBM PC, the interrupts for 
// COM1 & COM4 and for COM2 & COM3 are the same and tend to collide.

const int NUM_PORTS = 4;
// COM1 thru COM4, but see above.



// The 8250 UART uses some truly weird methods of signaling interrupt
// type.  The enum type below tries to make this into a hopefully more
// comprehensible enum set.

enum com_interrupt_t { 
		NONE_PENDING,
		RING,
		CARRIER, 
		NO_CARRIER,
		TRANSMIT_READY,
		TRANSMIT_FALSE_ALARM,
		RECEIVE_READY,
		OVERRUN_ERROR,
		PARITY_ERROR,
		FRAMING_ERROR,
		BREAK_RECEIVED,
		UNKNOWN_ERROR
	};                           


// Parity is a concept which is hard to represent as a set
// of integers.  The enum set below takes its values for the
// convenience of setting parity on the 8250 UART line control
// register (LCR).

enum parity_t
{
	NOPAR =  0x00,                // No parity 
	ODDPAR = 0x08,                // Odd parity 
	EVNPAR = 0x18,                // Even parity 
	STKPAR = 0x28,                // Stick parity 
	ZROPAR = 0x38           	  // Zero parity; not well documented
};

// This typedef helps the compiler sort out parameter types.
#ifdef __TURBOC__
typedef void interrupt (* DRIVER)(...);
#else ifdef __ZTC__
extern "C" {
typedef int (*DRIVER)(INT_DATA *);
};
#endif


// Here is the uart class itself.  It uses a method of calling derived
// class methods for base class functions which is occasionally buggy
// on TC++ 1.0 when using inline functions.  Take care, therefore, in
// any attempt to inline the member functions below, since they call
// virtual functions.

class uart
{
protected:
	static const int portvector_num[NUM_PORTS];
	static const char intmaskbit[NUM_PORTS];
	static char old_intmask[NUM_PORTS];
	static char old_MCR[NUM_PORTS];
	static char old_IER[NUM_PORTS];
#ifdef __TURBOC__
	static DRIVER old_driver[NUM_PORTS];
#else ifdef __ZTC__
	static void far * old_driver[NUM_PORTS];
#endif

public:
	uart();
	virtual ~uart();
	// note that there is a static virtual destructor "heap is corrupted" 
	// bug in certain ZTC versions of this code which may bite here.

	int RegisterDriver(int portnum, DRIVER driv);
	int RestoreDriver(int portnum);
	
	// These are constants of the PC 8250 UART.
	// From the MultiTech Systems Owners' Manual 
	// and the IBM Technical Reference Manual.
	// These are abstract and must be defined by a derived class.

	virtual unsigned int LCR() = 0;
	virtual unsigned int DLL() = 0;
	virtual unsigned int DLM() = 0;
	virtual unsigned int LSR() = 0;
	virtual unsigned int MCR() = 0;
	virtual unsigned int MSR() = 0;
	virtual unsigned int THR() = 0;
	virtual unsigned int RBR() = 0;
	virtual unsigned int IER() = 0;
	virtual unsigned int IIR() = 0;

	char GetLCR();
	char GetDLL();
	char GetDLM();
	char GetLSR();
	char GetMCR();
	char GetMSR();
	char GetRBR();
	char GetIER();
	char GetIIR();

	boolean GetLSR_THRE();

	void SetLCR(char byte);
	void SetDLL(char byte);
	void SetDLM(char byte);
	void SetMCR(char byte);
	void SetMSR(char byte);
	void SetLSR(char byte);
	void SetTHR(char byte);
	void SetIER(char byte);

	void SetIER_Recieve(boolean bit);
	void SetIER_Transmit(boolean bit);
	void SetIER_Line(boolean bit);
	void SetIER_Modem(boolean bit);

	void SetLCR_DLAB(boolean bit);

	void SetLSR_DR(boolean bit);
	
	void SetBaudRate(int speed);		
	int GetBaudRate();
	void SetSpeed(int speed) { SetBaudRate(speed); }
	int GetSpeed() { return GetBaudRate(); }

	void SetParity(parity_t p);
	parity_t GetParity();

	void SetWordLength(int len);
	int GetWordLength();
	void SetDataBits(int num) { SetWordLength(num); }
	int GetDataBits() { return GetWordLength(); }

	void SetStopBits(int num);
	int GetStopBits();


	void SetBreak();
	void StopBreak();
	void Break(int msec = 500);
	void Pause(int msec = 500);

	void SetCTS(boolean bit);
	void SetDSR(boolean bit);

	boolean CarrierPresent();

	boolean GetDTR();
	void SetDTR(boolean bit);

	com_interrupt_t GetIntrType();

	virtual void SetDoIfNoCarrier(void (*f)()) = 0;
	virtual void SetDoOnRing(void (*f)()) = 0;

	virtual void PurgeInput() = 0;
	virtual void FlushOutput() = 0;
	virtual void PurgeOutput() = 0;
	virtual boolean InputEmpty() = 0;
	virtual boolean OutputEmpty() = 0;
	virtual boolean OutputReady() = 0;

	// Note: the functions below do NO error checking.
	// You must do your error checking in your driver routine.

	virtual int GetChar();
	virtual void SendChar(char ch);
	virtual void TransmitChar(char ch);
	virtual int ReceiveChar();
};


#endif

// end of file uart.hpp

