//===========================================================================//
// File:	RIO.hh                                                              //
// Project: MUNGA           Brick: Platform-specific IO                      //
// Contents: Remote I/O interface class                                      //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  -----------------------------------------------------------//
// 01/30/95  CPB  Initial coding.                                            //
//---------------------------------------------------------------------------//
// Copyright (C) 1995, Virtual World Entertainment, Inc. All rights reserved //
//                      PROPRIETARY and CONFIDENTIAL                         //
//===========================================================================//
#if !defined(L4RIO_HPP)

#	define L4RIO_HPP

#	if !defined(L4PCSPAK_HPP)
#		include "l4pcspak.hpp"
#	endif

#	if !defined(NOTATION_HPP)
#		include <notation.hpp>
#	endif

#	if !defined(AVERAGE_HPP)
#		include <average.hpp>
#	endif

	// These are purposely grouped as two parameters in one equate
	// (See PCSPAK.HH).
	// The standard PC COM ports ALWAYS use these combinations.
#	define	RIO_COM1	PCSP_COM1
#	define	RIO_COM2	PCSP_COM2
#	define	RIO_COM3	PCSP_COM3
#	define	RIO_COM4	PCSP_COM4


	class FilterChannel SIGNATURED
	{
	public:
		static const char *highName;
		static const char *centerName;
		static const char *lowName;
		static const char *joystickXName;
		static const char *joystickYName;
		static const char *throttleName;
		static const char *leftPedalName;
		static const char *rightPedalName;

		enum AlignMode { unaligned, normal };
		enum PolarMode { unipolar, bipolar };

		FilterChannel();
		FilterChannel(
			NotationFile *init_file,
			const char *page_name,
			int default_min, int default_max
		);
		FilterChannel(
			NotationFile *init_file,
			const char *page_name,
			int default_min, int default_center, int default_max
		);
		~FilterChannel();
		void
			SetPolarity(PolarMode newPolarity);
		void
			SetDeadBand(Scalar amount_of_deadband);
		virtual void
			BeginAlignment();
		virtual void
			EndAlignment(NotationFile *init_file=NULL);
		virtual Scalar
			Update(int value);
		Logical
			TestInstance() const;

	protected:
		void
			CalculateDeadBands();

		const char *pageName;
		PolarMode	polarity;
		AlignMode	mode;
		int			previousValue, min, max, center;
		int			lowerRange, lowerDeadband;
		int			upperRange, upperDeadband;
		Scalar		deadbandScalar;
		Logical		valuesFromFile;
		AverageOf<int> average;
	};


	class RIO;

	class Ranger SIGNATURED
	{
		friend class RIO;
	protected:
		Ranger(
			const char *page_name,
			int default_min,
			int default_max,
			Scalar deadband_scalar
		);

		~Ranger();

		void
			ForceToZero();
		void
			SetDeadBand(Scalar amount_of_deadband);
		Scalar
			Update(int input);
		Logical
			TestInstance() const;
		void
			Statistics(NotationFile *stat_file);

		const char
			*pageName;
		Logical
			sampledInputFlag;
		int
			offset,
			hardwareMinimum,
         hardwareMaximum,
         hardwareRange,
			deadbandInteger,
			highestInput,
			lowestInput;
	};

	class RIO :
		public PCSerialPacket
	{
	protected:
		enum RIOCommand{
			CheckRequest=0x80,
			VersionRequest,
			AnalogRequest,
			ResetRequest,
			LampRequest,
			CheckReply,
			VersionReply,
			AnalogReply,
			ButtonPressed,
			ButtonReleased,
			KeyPressed,
			KeyReleased,
			TestModeChange
		};

	public:
		enum RIOStatusType {
			BoardOk=0, BoardMissing=1, BoardBad=2,
			LampBad=3,
			RestartCount=4, AbandonCount=5, FullBufferCount=6
		};

		enum LampState{
			solid=0, flashSlow=1, flashMed=2, flashFast=3,
			state1Off=0x00, state1Dim=0x04, state1Bright=0x0C,
			state2Off=0x00, state2Dim=0x10, state2Bright=0x30,
		};

		enum RIOEventType {
			ButtonPressedEvent,
			ButtonReleasedEvent,
			KeyEvent,
			AnalogEvent,
			VersionEvent
		};

		struct RIOKeyPair
		{
			int	Unit;
			int	Key;
		};

		struct RIOEvent
		{
			RIOEventType	Type;
			union
			{
				int				Unit;
				RIOKeyPair		Keyboard;
			}Data;
		};

		RIO(Word port, Word intNum, Logical perform_tests = True);
		~RIO();

		Logical
			TestInstance() const;

		Logical
			GetNextEvent(RIOEvent *destinationPointer);

		void
			ForceCenterJoystick(),
			SetJoystickDeadBand(Scalar dead_band),
			SetThrottleDeadBand(Scalar dead_band),
			SetPedalsDeadBand(Scalar dead_band);

		void
			RequestCheck(),
			RequestVersion(),
			RequestAnalogUpdate();

		void
			GeneralReset(),
			ResetThrottle(),
			ResetLeftPedal(),
			ResetRightPedal(),
			ResetVerticalJoystick(),
			ResetHorizontalJoystick();

		void
			SetLamp(int lampNumber, int state);

		void
			TestCheckReply(int type, int location)
				{
					RIO::reply_check_string[1] = (Byte) (type & 0x7F);
					RIO::reply_check_string[2] = (Byte) (location & 0x7F);
					SendPacket((Byte *)reply_check_string);
				}

		void
			TestVersionReply(int major, int minor)
				{
					RIO::reply_version_string[1] = (Byte) (major & 0x7F);
					RIO::reply_version_string[2] = (Byte) (minor & 0x7F);
					SendPacket((Byte *)reply_version_string);
				}

		void
			TestAnalogReply()
				{
						SendPacket((Byte *)reply_analog_string);
				}

		void
			TestButtonPressed(int button)
				{
					RIO::reply_button_press_string[1] = (Byte) (button & 0x7F);
					SendPacket((Byte *)reply_button_press_string);
				}

		void
			TestButtonReleased(int button)
				{
					RIO::reply_button_release_string[1] = (Byte) (button & 0x7F);
					SendPacket((Byte *)reply_button_release_string);
				}

		void
			TestKeyPressed(int board, int key)
				{
					RIO::reply_key_press_string[1] = (Byte) (board & 0x7F);
					RIO::reply_key_press_string[2] = (Byte) (key & 0x7F);
					SendPacket((Byte *)reply_key_press_string);
				}

		void
			TestKeyReleased(int board, int key)
				{
					RIO::reply_key_release_string[1] = (Byte) (board & 0x7F);
					RIO::reply_key_release_string[2] = (Byte) (key & 0x7F);
					SendPacket((Byte *)reply_key_release_string);
				}

		void
			TestEnterTestMode()
				{SendPacket((Byte *)reply_test_enter_string);}

		void
			TestExitTestMode()
				{SendPacket((Byte *)reply_test_exit_string);}

		int
			ReceiveQueueCount()
				{ return PCSerialPacket::ReceiveQueueCount(); }

		int
			TransmitQueueCount()
				{ return PCSerialPacket::TransmitQueueCount(); }

		int
			TestModeActive;

		Scalar
			Throttle, LeftPedal, RightPedal, JoystickX, JoystickY;

		int
      	MajorRevision, MinorRevision;

		int	remoteRetryCount;
		int	remoteAbandonCount;
		int	remoteFullBufferCount;
		int	lineErrorCount;
		int	abandonCount;
		int	overrunCount;

		int	discardCount;		// used by BeginAnalogCalibration()

	protected:
		void
			OpenFailureFile();

		void
			CloseFailureFile();

		void
			CheckErrors();

		Logical
			operational;
		Ranger
			*leftPedalRanger, *rightPedalRanger;
		Ranger
			*throttleRanger;
		Ranger
			*joystickXRanger, *joystickYRanger;
		NotationFile
			*failureFile;
		int
			failureFileOpenCount;

		static Byte reply_check_string[];
		static Byte reply_version_string[];
		static Byte reply_analog_string[];
		static Byte reply_button_press_string[];
		static Byte reply_button_release_string[];
		static Byte reply_key_press_string[];
		static Byte reply_key_release_string[];
		static Byte reply_test_enter_string[];
		static Byte reply_test_exit_string[];
	};

#endif
