//===========================================================================//
// File:	PCSPAK.hh                                                           //
// Project: MUNGA           Brick: Platform-specific IO                      //
// Contents: PC serial packet interface class                                //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  -----------------------------------------------------------//
// 01/16/95  CPB  Initial coding.                                            //
//---------------------------------------------------------------------------//
// Copyright (C) 1995, Virtual World Entertainment, Inc. All rights reserved //
//                      PROPRIETARY and CONFIDENTIAL                         //
//===========================================================================//
#if !defined(L4PCSPAK_HPP)

#   define L4PCSPAK_HPP

#   if !defined(STYLE_HPP)
#      include <style.hpp>
#   endif

#	if defined(TRACE_RIO_RECEIVE_PACKET)
		extern BitTrace RIO_Receive_Packet;
#		define SET_RIO_RECEIVE_PACKET() RIO_Receive_Packet.Set()
#		define CLEAR_RIO_RECEIVE_PACKET() RIO_Receive_Packet.Clear()
#	else
#		define SET_RIO_RECEIVE_PACKET()
#		define CLEAR_RIO_RECEIVE_PACKET()
#	endif

#	if defined(TRACE_RIO_SEND_PACKET)
		extern BitTrace RIO_Send_Packet;
#		define SET_RIO_SEND_PACKET() RIO_Send_Packet.Set()
#		define CLEAR_RIO_SEND_PACKET() RIO_Send_Packet.Clear()
#	else
#		define SET_RIO_SEND_PACKET()
#		define CLEAR_RIO_SEND_PACKET()
#	endif

	class PCSerialPacket;
	class PCSerialPacketScanner;

	enum
	{
		PCSPAKInitErrDPMI = -2,
		PCSPAKInitErrAlloc = -1,
		PCSPAKInitOk = 0
	};

	extern "C" int				// see error codes, above
		PCSPAKInit(
			PCSerialPacket *ptr,
			Word rate,
			Word port,
			Word intnum,
			Byte *rxLength,
			Word rxMaximum,
			Byte *txLength,
			Word txMaximum
		);

	extern "C" void
		PCSPAKTerm(
			PCSerialPacket *ptr
		);

	extern "C" Logical
		PCSPAKTestInstance(
			PCSerialPacket *ptr
		);
								 
	extern "C" int
		PCSPAKReceive(
			PCSerialPacket *ptr,
			Byte *destPtr
		);

	extern "C" void
		PCSPAKSend(
			PCSerialPacket *ptr,
			Byte *srcPtr
		);

	extern "C" int
		PCSPAKActive(
			PCSerialPacket *ptr
		);

	extern "C" Word
		PCSPAKErrors(
			PCSerialPacket *ptr
		);

	extern "C" Logical
		PCSPAKIRQState();

	extern "C" int
		PCSPAKIsSignatureBad(
			const volatile PCSerialPacket *ptr
		);

	extern "C" int
		PCSPAKReceiveCount(
			PCSerialPacket *ptr
		);

	extern "C" int
		PCSPAKTransmitCount(
			PCSerialPacket *ptr
		);

	extern "C" void
		PCSPAKSetDTR(
			PCSerialPacket *ptr,
         Logical on
		);

	// WARNING**WARNING**WARNING**WARNING**WARNING**WARNING**WARNING**WARNING
	// Do NOT change ANY of the following lines without making
	// corresponding changes in PCSerial.asm!  PCSPAK.hh exists
	// ONLY to inform C++ compilers of the data and structures
	// used by PCSPAK.asm!
	// WARNING**WARNING**WARNING**WARNING**WARNING**WARNING**WARNING**WARNING
	
	// These are purposely grouped as two parameters in one equate.
	// The standard PC COM ports ALWAYS use these combinations.
#   define	PCSP_COM1	0x3F8,0x0C		// portAddress,interruptNumber
#   define	PCSP_COM2	0x2F8,0x0B
#   define	PCSP_COM3	0x3E8,0X0C
#   define	PCSP_COM4	0x2E8,0x0B

	// Data rates
#   define	PCSP_300		0x0180		// 300 Baud
#   define	PCSP_1200	0x0060		// 1200 Baud
#   define	PCSP_2400	0x0030		// 2400 Baud
#   define	PCSP_9600	0x000C		// 9600 Baud
#   define	PCSP_19P2	0x0006		// 19200 Baud
#   define	PCSP_38P4	0x0003		// 38400 Baud
#   define	PCSP_115K	0x0001		// 115,200 Baud (not supported on all PC's)

	// This is for INTERNAL USE only (reflects structure in .ASM file)
	struct PCSerPackBuf
	{
		Word head, tail, tempHead, tempTail, count, tempIn, tempOut;
		Byte	data[512];		// was 256 before 7-13-95 cpb
		// WARNING: make ABSOLUTELY SURE this matches pcspak.asm
	};

	class PCSerialPacket
	{
		friend class PCSerialPacketScanner; 

	public:
		PCSerialPacket()
			{ }

		~PCSerialPacket()
			{
				PCSPAKTerm(this);
			}

		// Only call Initialize(...) ONCE during the lifetime of the object!
		int
			Initialize(
				Word rate,
				Word port,
				Word intNum,
				Byte *rxLengths,
				Word rxCount,
				Byte *txLengths,
				Word txCount
			)
				{
					return PCSPAKInit(
						this,
						rate,
						port,
						intNum,
						rxLengths,
						rxCount,
						txLengths,
						txCount
					);
				 }

		Logical
			TestInstance()
				{ return PCSPAKTestInstance(this); }

		int
			ReceivePacket(Byte *destPtr)	// returns len (zero if none)
				{
					SET_RIO_RECEIVE_PACKET();
					int result = PCSPAKReceive(this, destPtr);
					CLEAR_RIO_RECEIVE_PACKET();
					return result;
				}

		void
			SendPacket(Byte *srcPtr)		// sends packet
				{
					SET_RIO_SEND_PACKET();
					PCSPAKSend(this, srcPtr);
					CLEAR_RIO_SEND_PACKET();
				}

		// error bits returned by PCSerialPacket::Errors()
		enum ErrorBits {
			overrunError=0x0002,
			parityError=0x0004,
			framingError=0x0008,
			breakDetect=0x0010,
			initError=0x0100,
			txEarlyReply=0x0200,
			txAbandonPacket=0x0400,
			txRestart=0x0800,
			txNakReply=0x1000,
			rxSequenceError=0x2000,
			rxChecksumError=0x4000,
			rxCommandError=0x8000
		};

		int
			ReceiveQueueCount()
				{ return PCSPAKReceiveCount(this); }

		int
			TransmitQueueCount()
				{ return PCSPAKTransmitCount(this); }

		void
			SetDTR(Logical on)
				{ PCSPAKSetDTR(this, on); }

		int
			IsActive()
				{ return PCSPAKActive(this); }

		Word
			Errors()							// returns error value, clears it
				{ return PCSPAKErrors(this); }

#		if defined(USE_SIGNATURE)
			friend int
				Is_Signature_Bad(const volatile PCSerialPacket *ptr)
					{ return PCSPAKIsSignatureBad(ptr); }
#		endif

	protected:
		Word	portBase;
		Word	Error;

		Byte	enabled;
		Byte	txHoldOff;
		Byte	txReply;
		Byte	txState;
		Byte	txCount;
		Byte	txResetCount;
		Byte	txErrorCount;
		Byte	txIdleCount;
		Byte	txChecksum;
		Byte	txMaximum;

		Byte	rxFlags;
		Byte	rxState;
		Byte	rxCount;
		Byte	rxChecksum;
		Byte	rxMaximum;

		LWord	txLengthPtr;
		LWord	rxLengthPtr;
							  
		LWord intDataPtr;
//		LWord hackCount;   //WGR previously missing: seen in pcspak.asm

		PCSerPackBuf txBuf;
		PCSerPackBuf rxBuf;
	};

#endif

