// Copyright (c) 2020 Metrolab Technology S.A., Geneva, Switzerland (www.metrolab.com)
// See the included file LICENSE.txt for the licensing conditions.

//////////////////////////////////////////////////////////////////////////
/// \file
/// \brief Abstract IEEE488 instrument class: interface definition.
///

#pragma once

#include "OSDefines.h"
#include "IEEE488InstrumentTypes.h"
#include "SCPIInstrumentBuffer.h"
#include "Synchronization.h"

using namespace MTL::Synchronization;

namespace MTL {
	namespace Instrument {
		//----------------------------------------------------------------------//
		/// \brief IEEE488 Instrument Resource Manager class.
		class CIEEE488ResourceManager
		{
		protected:
			mutable CMutex				m_Lock;		///< Lock onto the resource manager
			I32							m_Status;	///< Status of last operation

		public:
			// Constructors / destructors
			CIEEE488ResourceManager()			///< Constructor.
			{ }
			virtual ~CIEEE488ResourceManager()	///< Destructor.
			{ }

			// Initialization
			virtual bool Initialize() = 0;		///< Initialize the Resource Manager.

			// Resource utilities
			/// \brief Find IEEE488 resources.
			/// \param[out]	rList			List of matching resources.
			/// \param[in]	Filter			Grep expression to select resource names.
			/// \return True if successful.
			virtual bool FindResources(CResourceList & rList, std::string Filter = "?*") = 0;
			
			// Info
			I32 Status(void)					///< Return status of last operation
			{
				CLockGuard<CMutex> l_LockGuard(m_Lock);
				return m_Status;
			}

			/// \brief Return description of status word.
			/// \param[in]	Status			Status word.
			/// \return Status description.
			virtual std::string StatusDescription (I32 Status) = 0;
			
			virtual bool Timeout(void) = 0;		///< Last operation timed out
		};

		//----------------------------------------------------------------------//
        /// \brief IEEE488 instrument class.
		class CIEEE488Instrument
		{
        protected:
            static const I32 IEEE488_DEFAULT_TIMEOUT = 100; ///< Default timeout (ms)

		protected:
			mutable CRecursiveMutex		m_Lock;		///< Lock onto the class interface
			CIEEE488ResourceManager &	m_rRrsrcMan;///< Reference to the associated resource manager
			tResourceName				m_Rsrc;		///< Resource name of the instrument
			I32							m_Status;	///< Status of last operation
			U32							m_Timeout;	///< Timeout for operations
			
		public:
			// Constructors / destructors
			/// \brief Constructor.
			/// \param[in]  rRM		IEEE488 Instrument Resource Manager.
			/// \param[out] Rsrc	IEEE488 resource name.
			CIEEE488Instrument(CIEEE488ResourceManager & rRM, tResourceName Rsrc)
			: m_rRrsrcMan(rRM), m_Rsrc(Rsrc), m_Status(0), m_Timeout(IEEE488_DEFAULT_TIMEOUT)
			{ }
			virtual ~CIEEE488Instrument()		///< Destructor.
			{ }

			// Connection
			/// \brief Open a session to this IEEE488 instrument.
			/// \return True if successful.
			virtual bool Open(void) = 0;
			virtual void Close() = 0;			///< Close session to this instrument.
			virtual bool IsOpen() = 0;			///< Check whether a session to this instrument is open.

			// Info
			I32 Status(void)					///< Return status of last operation
			{
				CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
				return m_Status;
			}

			/// \brief Return description of status word.
			/// \param[in]	Status			Status word.
			/// \return Status description.
			virtual std::string StatusDescription (I32 Status) = 0;
			
			virtual bool Timeout(void) = 0;		///< Last operation timed out

			// Write / Read
			/// \brief Write to a IEEE488 instrument: C string variant.
			/// \param[in]	Str				Data to write.
			/// \return True if successful.
			virtual bool Write(const char * Str) = 0;
			
			/// \brief Write to a IEEE488 instrument: C++ string variant.
			/// \param[in]	rStr			Data to write.
			/// \return True if successful.
			virtual bool Write(const std::string & rStr) = 0;

			/// \brief Write to a IEEE488 instrument: SCPI buffer class variant.
			/// \param[in]	rBuf			Data to write.
			/// \return True if successful.
			virtual bool Write(const CSCPIBuffer & rBuf) = 0;

			/// \brief Read from a IEEE488 instrument: SCPI buffer class variant.
			/// \param[in]	rBuf			Buffer to receive the data.
			/// \param[in]	Append			Whether to append to the existing data.
			/// \return True if successful.
			virtual bool Read(CSCPIBuffer & rBuf, bool Append = false) = 0;
			
			// Other operations
			/// \brief	Set the timeout for this instrument.
			/// \param[in]	Timeout			Timeout for operations during this session, in ms.
			/// \return True if successful.
			bool SetTimeout(U32 Timeout)
			{
				CLockGuard<CRecursiveMutex> l_LockGuard(m_Lock);
				m_Timeout = Timeout;
				return true;
			}
			
			/// \brief	Return the timeout for this instrument.
			/// \return Timeout value.
			U32 GetTimeout(void)
			{
				return m_Timeout;
			}
			
			virtual bool Clear() = 0;			///< Clear the instrument.
			
			/// \brief Read status byte.
			/// \param[out]	rSTB			Status byte.
			/// \return True if successful.
			virtual bool ReadSTB(U16 & rSTB) = 0;
			
			/// \brief	Assert a trigger.
			/// \return True if successful.
			virtual bool AssertTrigger(void) = 0;

			// Lock / Unlock
			/// \brief Obtain an exclusive lock for this session
			/// \param[in]	Timeout			Timeout value, in ms.
			/// \return True if successful.
			virtual bool LockExclusive(U32 Timeout) = 0;
			
            virtual bool Unlock() = 0;                  ///< Unlock the session.

            virtual bool LockedExclusive() = 0;         ///< Check whether session is locked exclusively.

            virtual bool EnableEvent (void) = 0;        ///< Enable service requests

            virtual bool DisableEvent (void) = 0;       ///< Disable service requests

            virtual bool WaitOnEvent (U32 Timeout) = 0; ///< Wait for a service request

            virtual bool DiscardEvents (void) = 0;      ///< Discard service requests

        }; // class CIEEE488Instrument

    } // namespace MTL::Instrument
} // namespace MTL
