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

//////////////////////////////////////////////////////////////////////////
/// \file
/// \brief Interface definition for Metrolab THM1176/TFM1186 Instrument Manager.

//////////////////////////////////////////////////////////////////////////
///
/// \if thm1176_instrument_manager_doc
///
/// \mainpage Instrument Manager for Metrolab THM1176/TFM1186.
///
/// \section intro_sect Introduction
/// The THM1176 Instrument Manager is a high-level Qt Object abstraction of the Metrolab
/// Three-axis Hall Magnetometer THM1176 / Three-axis Fluxgate Magnetometer TFM1186.
///
/// \section summary_sect Summary
/// The THM1176 Instrument Manager consists of three objects, running in different threads:
///  	- MTL::CTHM1176InstrumentManager:       Public interface
///  	- MTL::CTHM1176InstrumentController:	VISA I/O
///  	- MTL::CTHM1176InstrumentScanner:       Periodically scans for connected instruments
///
/// The user only has to worry about the public interface; the two other objects are created and destroyed automatically.
///
/// The Manager relies on Qt for the multi-threading insfrastructure, and on the
/// THM1176 C++ API to communicate with the instrument.
///
/// The public interface of the THM1176 Instrument Manager consists of the methods of the MTL::CTHM1176InstrumentManager
/// class. These fall into three categories:
///     - Qt slots for a very limited number of actions: start and stop the Manager, and send a trigger.
///     - Get and Set methods for Qt properties. Some properties are read-only, and only have a Get method.
///     - Qt signals to notify of property changes.
///
/// The public interface of the THM1176 Instrument Manager is summarized in the tables below.
///
///	Startup and shutdown:
/// ---------------------
///     Method type                     |   Name                            |   Parameters
///     --------------------------------|-----------------------------------|-------------------------
///		Slot							|   Start                           |   (void)
///		Slot							|   Stop                            |   (void)
///
///	Basic instrument control:
/// -------------------------
///     Method type                     |   Name                            |   Parameters
///     --------------------------------|-----------------------------------|-------------------------
///		Property: Get, Notify			|   InstrumentList                  |   (\ref MTL::Instrument::CResourceList "CResourceList")
///		Property: Get, Set, Notify		|   CurrentInstrument               |   (\ref MTL::Instrument::tResourceName "tResourceName")
///		Property: Get, Set, Notify		|   OperatingMode                   |   (\ref MTL::eTHM1176OperatingMode "eTHM1176OperatingMode")
///		Property: Get, Notify			|   Measurement                     |   (\ref MTL::CMeasurement "CMeasurement")
///		Property: Get, Notify			|   ErrorList                       |   (\ref MTL::Instrument::THM1176Types::CErrorList "CErrorList")
///		Slot							|   SendTrigger                     |   (void)
///
///	Instrument information and parameter bounds:
/// --------------------------------------------
///     Method type                     |   Name                            |   Parameters
///     --------------------------------|-----------------------------------|-------------------------
///		Property: Get, Notify			|   Identification                  |   (\ref MTL::Instrument::THM1176Types::sIdentifier "sIdentifier")
///		Property: Get, Notify			|   RangeList                       |   (\ref MTL::Instrument::THM1176Types::CFluxList "CFluxList")
///		Property: Get, Notify			|   UnitsList                       |   (\ref MTL::CTHM1176UnitsList "CTHM1176UnitsList")
///		Property: Get, Notify			|   DivisorList                     |   (\ref MTL::Instrument::THM1176Types::CDivisorList "CDivisorList")
///		Property: Get, Notify			|   AveragingParmBounds             |   (sAveraging<sBoundedParm>)
///		Property: Get, Notify			|   TriggerParmBounds               |   (sInputTrigger<sBoundedParm>)
///		Property: Get, Notify			|   RangeParmBounds                 |   (sRange<sBoundedParm>)
///
/// Parameters:
/// -----------
///     Method type                     |   Name                            |   Parameters
///     --------------------------------|-----------------------------------|-------------------------
///		Property: Get, Set, Notify		|   AveragingParms                  |   (sAveraging<uParm>)
///		Property: Get, Set, Notify		|   TriggerParms                    |   (sInputTrigger<uParm>)
///		Property: Get, Set, Notify		|   OutputSelect                    |   (\ref MTL::Instrument::THM1176Types::sArbitraryMeasurements "sArbitraryMeasurements")
///		Property: Get, Set, Notify		|   SleepParm                       |   (bool)
///		Property: Get, Set, Notify		|   Units                           |   (\ref MTL::eTHM1176Units "eTHM1176Units")
///		Property: Get, Set, Notify		|   RangeParms                      |   (sRange<uParm>)
///		Property: Get, Set, Notify		|   CommFormat                      |   (\ref MTL::Instrument::THM1176Types::eCommunicationFormat "eCommunicationFormat")
///
/// Utilities:
/// ----------
///     Method type                     |   Name                            |   Parameters
///     --------------------------------|-----------------------------------|-------------------------
///     -                               |   SetCalibrationOverride          |   (bool)
///     -                               |   GetImmediateMeasurementPeriod   |   (sAveraging<uParm>, \ref MTL::Instrument::THM1176Types::F64 "F64")
///     -                               |   ConvertTimestamp                |   (\ref MTL::Instrument::THM1176Types::U64 "U64", \ref MTL::Instrument::THM1176Types::CAbsoluteTimestamp "CAbsoluteTimestamp")
///     -                               |   ReadInformationDates            |   (QDateTime, QDateTime)
///
/// \section using_sect Usage
/// 1.  Create a \ref MTL::CTHM1176InstrumentManager "CTHM1176InstrumentManager" object.
/// 2.  Invoke the \ref MTL::CTHM1176InstrumentManager.Start "Start" slot to initialize the Instrument Manager.
/// 3.  Wait for the \ref MTL::CTHM1176InstrumentManager.NotifyInstrumentList "NotifyInstrumentList" signal to obtain the list of detected instruments.
///     Alternatively, invoke the \ref MTL::CTHM1176InstrumentManager.GetInstrumentList "GetInstrumentList" slot.
/// 4.  Invoke the \ref MTL::CTHM1176InstrumentManager.SetCurrentInstrument "SetCurrentInstrument" slot to connect to the desired instrument.
///     At any time, you can use the \ref MTL::CTHM1176InstrumentManager.GetCurrentInstrument "GetCurrentInstrument" slot or the
///     \ref MTL::CTHM1176InstrumentManager.NotifyCurrentInstrument "NotifyCurrentInstrument" signal to retrieve the resource name of the current instrument.
/// 5.  Wait for the \ref MTL::CTHM1176InstrumentManager.NotifyOperatingMode "NotifyOperatingMode" signal to wait
///     until the instrument enters the \ref MTL::kTHM1176Idle "kTHM1176Idle" state.
///     You can also invoke the \ref MTL::CTHM1176InstrumentManager.GetOperatingMode "GetOperatingMode" at any time to get the operating mode.
/// 6.  Wait for the \ref MTL::CTHM1176InstrumentManager.NotifyIdentification "NotifyIdentification" signal to obtain the instrument identifier.
///     You can invoke the \ref MTL::CTHM1176InstrumentManager.GetIdentification "GetIdentification" slot to obtain the same information.
/// 7.  Wait for the:
///     - \ref MTL::CTHM1176InstrumentManager.NotifyRangeList "NotifyRangeList" signal to retrieve the list of ranges supported by this instrument,
///     - \ref MTL::CTHM1176InstrumentManager.NotifyUnitsList "NotifyUnitsList" signal to retrieve the list of units supported by this instrument,
///     - \ref MTL::CTHM1176InstrumentManager.NotifyDivisorList "NotifyDivisorList" signal to retrieve the divisors associated with each of these units,
///     - \ref MTL::CTHM1176InstrumentManager.NotifyAveragingParmBounds "NotifyAveragingParmBounds" signal to retrieve the bounds for the averaging parameter,
///     - \ref MTL::CTHM1176InstrumentManager.NotifyTriggerParmBounds "NotifyTriggerParmBounds" signal to retrieve the bounds for the trigger parameters, and
///     - \ref MTL::CTHM1176InstrumentManager.NotifyRangeParmBounds "NotifyRangeParmBounds" signal to retrieve the bounds for the range parameters.
///
///     Invoke the corresponding "Get" slots to retrieve the same instrument information at any time.
/// 8.  Invoke the:
///     - \ref MTL::CTHM1176InstrumentManager.SetAveragingParms "SetAveragingParms" slot to change the averaging parameter,
///     - \ref MTL::CTHM1176InstrumentManager.SetTriggerParms "SetTriggerParms" slot to change the trigger parameters,
///     - \ref MTL::CTHM1176InstrumentManager.SetOutputSelect "SetOutputSelect" slot to change the selection of data to be returned,
///     - \ref MTL::CTHM1176InstrumentManager.SetSleepParm "SetSleepParm" slot to select whether or not the instrument should sleep after each measurement,
///     - \ref MTL::CTHM1176InstrumentManager.SetUnits "SetSleepParm" slot to select the units in which the measurements are to be returned,
///     - \ref MTL::CTHM1176InstrumentManager.SetRangeParms "SetRangeParms" slot to change the range parameters, and
///     - \ref MTL::CTHM1176InstrumentManager.SetCommFormat "SetCommFormat" slot to change the data communication format.
///     - \ref MTL::CTHM1176InstrumentManager.SetCalibrationOverride "SetCalibrationOverride" slot to override the check for models that should not be calibrated.
///
///     Invoke the corresponding "Get" slots to obtain the current values of any of the above parameters,
///     or wait for the corresponding "Notify" signal to be notified of value changes.
/// 9.  Invoke the \ref MTL::CTHM1176InstrumentManager.SetOperatingMode "SetOperatingMode" slot to set the operating mode to
///     \ref MTL::kTHM1176Measure "kTHM1176Measure", to perform a single measurement,
///     or to \ref MTL::kTHM1176MeasureContinuously "kTHM1176MeasureContinuously" to perform continuous measurement.
/// 10. For bus-triggered acquisition, invoke the \ref MTL::CTHM1176InstrumentManager.SendTrigger "SendTrigger" slot to send the apropriate number of triggers.
/// 11. Wait for the \ref MTL::CTHM1176InstrumentManager.NotifyMeasurement "NotifyMeasurement" signal for a new set of measurements to arrive.
///     You can also invoke the \ref MTL::CTHM1176InstrumentManager.GetMeasurement "GetMeasurement" slot to retrieve the last measurement at any time.
/// 12. The \ref MTL::CTHM1176InstrumentManager.NotifyErrorList "NotifyErrorList" signal notifies you of any errors.
///     You can also retrieve the current error list with the \ref MTL::CTHM1176InstrumentManager.GetErrorList "GetErrorList" slot.
/// 13. Invoke the \ref MTL::CTHM1176InstrumentManager.SetOperatingMode "SetOperatingMode" slot to set the operating mode to
///     \ref MTL::kTHM1176CalibrateZeroOffset "kTHM1176CalibrateZeroOffset", to initiate the zero-offset calibration procedure.
///     Invoke the \ref MTL::CTHM1176InstrumentManager.SetOperatingMode "SetOperatingMode" slot to set the operating mode to
///     \ref MTL::kTHM1176RestoreZeroOffset "kTHM1176RestoreZeroOffset", to restore the zero-offset to factory settings.
///     In eiter case, wait for the \ref MTL::CTHM1176InstrumentManager.NotifyOperatingMode "NotifyOperatingMode" signal to wait
///     until the instrument reenters the \ref MTL::kTHM1176Idle "kTHM1176Idle" state.
/// 14. Invoke the \ref MTL::CTHM1176InstrumentManager.SetOperatingMode "SetOperatingMode" slot to set the operating mode to
///     \ref MTL::kTHM1176NotConnected "kTHM1176NotConnected", to disconnect from the instrument.
/// 15. Invoke the \ref MTL::CTHM1176InstrumentManager.Stop "Stop" slot to shut down the Instrument Manager.
///
/// \section examples_sect Examples
/// Any of the Instrument Manager tests can serve as example:
/// THM1176IM_Test01_Connect, THM1176IM_Test02_Measure or THM1176IM_Test03_Parameters.
/// \endif
///

#pragma once

#include "THM1176InstrumentManagerTypes.h"

#if (THM1176_INSTRUMENT_TYPE_IS_VISA)
    #include "VISAInstrument.h"
    #define THM1176_RSRC_MGR_CLS	CVISAResourceManager
    #define THM1176_INSTR_CLS       CVISAInstrument
    #define THM1176_RSRC_FILTER     "USB[0-9]*::0x1BFA::0x0498::[0-9]+::INSTR"
    #include "VISAInstrument.h"
#elif (THM1176_INSTRUMENT_TYPE_IS_USBTMC)
    #include "USBTMCInstrument.h"
    #define THM1176_RSRC_MGR_CLS	CUSBTMCResourceManager
    #define THM1176_INSTR_CLS       CUSBTMCInstrument
    #define THM1176_RSRC_FILTER     "7162:1176"
    #include "USBTMCInstrument.h"
#else
    #error "One of THM1176_INSTRUMENT_TYPE_IS_VISA or ..._USBTMC must be defined"
#endif

#include <QtCore/QThread>
#include <QtCore/QTimer>
#include <QtCore/QString>
#include <QtCore/QDateTime>

using namespace MTL;
using namespace MTL::Instrument;
using namespace MTL::Instrument::THM1176Types;

//----------------------------------------------------------------------//
//	Type definitions													//
//----------------------------------------------------------------------//
namespace MTL
{
Q_NAMESPACE
Q_ENUM_NS(eTHM1176OperatingMode)
Q_ENUM_NS(eTHM1176Units)
}

//----------------------------------------------------------------------//
//	Qt meta-type declarations											//
//----------------------------------------------------------------------//
Q_DECLARE_METATYPE(eTHM1176Units)
Q_DECLARE_METATYPE(eTHM1176OperatingMode)
Q_DECLARE_METATYPE(eCommunicationFormat)

Q_DECLARE_METATYPE(tResourceName)

Q_DECLARE_METATYPE(sIdentifier)
Q_DECLARE_METATYPE(sArbitraryMeasurements)
Q_DECLARE_METATYPE(CMeasurement)

Q_DECLARE_METATYPE(CResourceList)
Q_DECLARE_METATYPE(CFluxList)
Q_DECLARE_METATYPE(CTHM1176UnitsList)
Q_DECLARE_METATYPE(CDivisorList)
Q_DECLARE_METATYPE(CErrorList)

Q_DECLARE_METATYPE(sAveraging<uParm>)
Q_DECLARE_METATYPE(sAveraging<sBoundedParm>)
Q_DECLARE_METATYPE(sInputTrigger<uParm>)
Q_DECLARE_METATYPE(sInputTrigger<sBoundedParm>)
Q_DECLARE_METATYPE(sRange<uParm>)
Q_DECLARE_METATYPE(sRange<sBoundedParm>)

//----------------------------------------------------------------------//
//	Qt meta-type declarations											//
//----------------------------------------------------------------------//
Q_DECLARE_METATYPE(THM1176_INSTR_CLS *)
Q_DECLARE_METATYPE(THM1176_RSRC_MGR_CLS *)

namespace MTL
{
//////////////////////////////////////////////////////////////////////////
///	 \brief THM1176 %Instrument Scanner class: scan for connected instruments.
///
/// The user need not worry about this object. It is created and destroyed automatically
/// by the THM1176 %Instrument Manager public interface.
///
///
class CTHM1176InstrumentScanner : public QObject
{
	Q_OBJECT

private:
	//----------------------------------------------------------------------//
	//	THM1176 Instrument Scanner constants								//
	//----------------------------------------------------------------------//
	static const U32	THM1176_SCAN_INTERVAL 		= 1000; // ms

	//----------------------------------------------------------------------//
	//	THM1176 Instrument Scanner class variables							//
	//----------------------------------------------------------------------//
	int									m_TimerID;
	CResourceList						m_InstrumentList;
    THM1176_RSRC_MGR_CLS *              m_pResourceManager;

	//----------------------------------------------------------------------//
	//	THM1176 Instrument Scanner private methods							//
	//----------------------------------------------------------------------//
	void	timerEvent					(QTimerEvent *					Event) override;
	void	HandleError 				(QString						Description,
										 QString						Context);

public:
	//----------------------------------------------------------------------//
	//	THM1176 Instrument Scanner constructor / destructor					//
	//----------------------------------------------------------------------//
    /// \brief Constructor.
	CTHM1176InstrumentScanner			(void) :
		m_pResourceManager(nullptr)
	{ }
    /// \brief Destructor.
	~CTHM1176InstrumentScanner			(void) override
	{ }

public slots:
	//----------------------------------------------------------------------//
	//	THM1176 Instrument Scanner slots									//
	//----------------------------------------------------------------------//
    /// \brief Initialize THM1176 %Instrument Scanner.
    /// \param[in]  pResourceManager    Pointer to the VISA Resource Manager.
    void	Start						(THM1176_RSRC_MGR_CLS *         pResourceManager);
    /// \brief Shut down THM1176 %Instrument Scanner.
	void	Stop						(void);

signals:
	//----------------------------------------------------------------------//
	//	THM1176 Instrument Scanner signals									//
	//----------------------------------------------------------------------//
    /// \brief An update to the instrument list is available.
    /// \param[in] InstrumentList       Updated instrument list.
	void	UpdateInstrumentList		(CResourceList					InstrumentList);
    /// \brief An update to the error list is available.
    /// \param[in] ErrorList            Updated error list.
	void	UpdateErrorList				(CErrorList						ErrorList);

}; // CTHM1176InstrumentScanner


//////////////////////////////////////////////////////////////////////////
/// \brief	THM1176 %Instrument Controller class: communicate with instrument.
///
/// The user need not worry about this object. It is created and destroyed automatically
/// by the THM1176 %Instrument Manager public interface.
///
class CTHM1176InstrumentController : public QObject
{
	Q_OBJECT

private:
	//----------------------------------------------------------------------//
	//	THM1176 Instrument Controller constants								//
	//----------------------------------------------------------------------//
    static constexpr U32	THM1176_CONNECT_TIMEOUT		= 5000;                 // ms
    static constexpr F32    MU0                         = 1.256637061436E-6f;   // Magnetic permeability of vacuum

	//----------------------------------------------------------------------//
	//	THM1176 Instrument Controller class variables						//
	//----------------------------------------------------------------------//
	// Connection
    THM1176_RSRC_MGR_CLS *				m_pResourceManager;
    CTHM1176Instrument<THM1176_INSTR_CLS, THM1176_RSRC_MGR_CLS> *
                                        m_pTHM1176;
	CResourceList						m_InstrumentList;
	tResourceName						m_CurrentInstrument;

	//	Instrument information and parameter bounds:
	sIdentifier							m_Identification;
	CFluxList							m_RangeList;
    CTHM1176UnitsList					m_UnitsList;
	CDivisorList						m_DivisorList;
	sAveraging<sBoundedParm>			m_AveragingParmBounds;
	sInputTrigger<sBoundedParm>			m_TriggerParmBounds;
	sRange<sBoundedParm>				m_RangeParmBounds;

	// Parameters
	sAveraging<uParm>					m_AveragingParms;
	sInputTrigger<uParm>				m_TriggerParms;
	sArbitraryMeasurements				m_OutputSelect;
	bool								m_SleepParm;
    eTHM1176Units						m_Units;
	sRange<uParm>						m_RangeParms;
	eCommunicationFormat				m_CommFormat;

	// Control parameters
	eTHM1176OperatingMode				m_OperatingMode;
	U16									m_TriggerCount;
	int									m_TimerID;
    bool                                m_CalibrationOverride;

	//----------------------------------------------------------------------//
	//	THM1176 Instrument Controller private methods						//
	//----------------------------------------------------------------------//
	void	HandleError	 				(QString						Description,
										 QString						Context);
	void	ClearInstrumentInfo			(void);
	void	GetInstrumentInfo			(std::string					Context);
	void	GetInstrumentParameters		(std::string					Context);
    void    MakeUnitsList               (std::string					Context);
    void    GetCurrentUnits             (std::string					Context);
    void    TranslateUnits              (CMeasurement &                 Measurement,
                                         eUnits                         Units);
	void	PublishInstrumentInfo		(void);
	void	PublishInstrumentParameters	(void);
	void	timerEvent					(QTimerEvent *					Event) override;

public:
	//----------------------------------------------------------------------//
	//	THM1176 Instrument Controller constructor / destructor				//
	//----------------------------------------------------------------------//
    /// \brief Constructor.
	CTHM1176InstrumentController						(void) :
		m_pResourceManager(nullptr),
		m_pTHM1176(nullptr),
		m_SleepParm(false),
		m_Units(kT),
		m_CommFormat(kComFormatAscii),
		m_OperatingMode(kTHM1176NotConnected),
		m_TriggerCount(0),
        m_TimerID(0),
        m_CalibrationOverride(false)
	{
		m_AveragingParmBounds.clear();
		m_TriggerParmBounds.clear();
		m_RangeParmBounds.clear();

		m_AveragingParms.clear();
		m_TriggerParms.clear();
		m_OutputSelect.clear();
		m_RangeParms.clear();
	}

    /// \brief Destructor.
	~CTHM1176InstrumentController (void) override
	{ }

public slots:
	//----------------------------------------------------------------------//
	//	THM1176 Instrument Controller slots									//
	//----------------------------------------------------------------------//
	//	Startup and shutdown.
    /// \brief Initialize the %Instrument Controller.
    /// \param[in] pResourceManager     Pointer to VISA Resource Manager.
    void	Start						(THM1176_RSRC_MGR_CLS *         pResourceManager);

    /// \brief Shut down the %Instrument Controller.
	void	Stop						(void);

	//	Connection
    /// \brief Update the %Instrument Controller's copy of the list of detected instruments.
    /// \param[in] InstrumentList       Updated list of detected instruments.
	void	UpdateInstrumentList		(CResourceList					InstrumentList);

    /// \brief Select the instrument to connect to.
    /// \param[in] CurrentInstrument    Instrument's VISA resource name.
	void	SetCurrentInstrument		(tResourceName					CurrentInstrument);

	// Instrument control
    /// \brief Set operating mode.
    /// \param[in] OperatingMode        New operating mode.
	void	SetOperatingMode			(eTHM1176OperatingMode			OperatingMode);

    /// \brief Send a bus trigger.
	void	SendTrigger					(void);

	//	Parameters
    /// \brief Set the averaging parameters.
    /// \param[in] AveragingParms       Averaging parameters.
	void	SetAveragingParms			(sAveraging<uParm>				AveragingParms);

    /// \brief Set the trigger parameters.
    /// \param[in] TriggerParms         Trigger parameters.
	void	SetTriggerParms				(sInputTrigger<uParm>			TriggerParms);

    /// \brief Select what data is returned.
    /// \param[in] OutputSelect         Output selection parameters.
	void	SetOutputSelect				(sArbitraryMeasurements			OutputSelect);

    /// \brief Set whether or not the instrument sleeps after each measurement.
    /// \param[in]  SleepParm           Sleep parameter.
	void	SetSleepParm				(bool							SleepParm);

    /// \brief Select the measurement units.
    /// \param[in] Units                Measurement units.
    void	SetUnits					(eTHM1176Units					Units);

    /// \brief Set range parameters.
    /// \param[in] RangeParms           Range parameters.
	void	SetRangeParms				(sRange<uParm>					RangeParms);

    /// \brief Set communication format.
    /// \param[in] CommFormat           Communication format parameters.
	void	SetCommFormat				(eCommunicationFormat			CommFormat);    

    /// \brief Set whether or not to override the check for instruments whose
    ///     zero offset should not be calibrated.
    /// \param[in] Override             Override the check if true.
    void    SetCalibrationOverride      (bool Override);

signals:
	//----------------------------------------------------------------------//
	//	THM1176 Instrument Controller signals								//
	//----------------------------------------------------------------------//
	//	Basic instrument control:
    /// \brief Signal that current instrument selection has changed.
    /// \param[in] CurrentInstrument    VISA resource name of newly selected instrument.
	void	UpdateCurrentInstrument		(tResourceName					CurrentInstrument);

    /// \brief Signal to broadcast updated pointer to THM1176 %Instrument object.
    /// \param[in] pTHM1176             Updated pointer to THM1176 %Instrument object.
    void	UpdateInstrumentPointer		(CTHM1176Instrument<THM1176_INSTR_CLS, THM1176_RSRC_MGR_CLS> * pTHM1176);

    /// \brief Signal that the operating mode has changed.
    /// \param[in] OperatingMode        New operating mode.
	void	UpdateOperatingMode			(eTHM1176OperatingMode			OperatingMode);

    /// \brief Signal that a new measurement is available.
    /// \param[in] Measurement          New measurement.
	void	UpdateMeasurement			(CMeasurement					Measurement);

    /// \brief Signal that new errors have been reported.
    /// \param[in] LatestErrors         List of latest errors.
	void	UpdateErrorList				(CErrorList						LatestErrors);

	//	Instrument information and parameter bounds:
    /// \brief Signal to report identifier information for newly connected instrument.
    /// \param[in] Identification       %Instrument identifier information.
	void	UpdateIdentification		(sIdentifier					Identification);

    /// \brief Signal to report list of valid ranges for newly connected instrument.
    /// \param[in] RangeList            List of valid ranges.
    void	UpdateRangeList				(CFluxList						RangeList);

    /// \brief Signal to report list of valid measurement units for newly connected instrument.
    /// \param[in] UnitsList            List of measurement units valid for this instrument model.
    void	UpdateUnitsList				(CTHM1176UnitsList				UnitsList);

    /// \brief Signal to report divisors associated with valid measurement units for newly connected instrument.
    /// \param[in] DivisorList          List of divisors.
    void	UpdateDivisorList			(CDivisorList					DivisorList);

    /// \brief Signal to report bounds of averaging parameters for newly connected instrument.
    /// \param[in] AveragingParmBounds  Bounds for averaging parameters.
    void	UpdateAveragingParmBounds	(sAveraging<sBoundedParm>		AveragingParmBounds);

    /// \brief Signal to report bounds of trigger parameters for newly connected instrument.
    /// \param[in] TriggerParmBounds    Bounds for trigger parameters.
    void	UpdateTriggerParmBounds		(sInputTrigger<sBoundedParm>	TriggerParmBounds);

    /// \brief Signal to report bounds of range parameters for newly connected instrument.
    /// \param[in] RangeParmBounds      Bounds for range parameters.
    void	UpdateRangeParmBounds		(sRange<sBoundedParm>			RangeParmBounds);

	//	Parameters
    /// \brief Signal a change of the averaging parameters.
    /// \param[in] AveragingParms       New averaging parameters.
    void	UpdateAveragingParms		(sAveraging<uParm>				AveragingParms);

    /// \brief Signal a change of the trigger parameters.
    /// \param[in] TriggerParms         New trigger parameters.
    void	UpdateTriggerParms			(sInputTrigger<uParm>			TriggerParms);

    /// \brief Signal a change of the output selection parameters.
    /// \param[in] OutputSelect         New output selection parameters.
    void	UpdateOutputSelect			(sArbitraryMeasurements			OutputSelect);

    /// \brief Signal a change of the sleep parameter.
    /// \param[in] SleepParm            New sleep parameter.
    void	UpdateSleepParm				(bool							SleepParm);

    /// \brief Signal a change of the measurement units.
    /// \param[in] Units                New measurement units.
    void	UpdateUnits					(eTHM1176Units					Units);

    /// \brief Signal a change of the range parameters.
    /// \param[in] RangeParms           New range parameters.
    void	UpdateRangeParms			(sRange<uParm>					RangeParms);

    /// \brief Signal a change of the communication format.
    /// \param[in] CommFormat           New communication format.
    void	UpdateCommFormat			(eCommunicationFormat			CommFormat);

}; // CTHM1176InstrumentController


//////////////////////////////////////////////////////////////////////////
/// \brief	THM1176 %Instrument Manager class: public interface.
///
/// This object manages the public interface of the THM1176 %Instrument Manager.
/// It is the only object the user needs to deal with.
///
class CTHM1176InstrumentManager : public QObject
{
	Q_OBJECT

	//----------------------------------------------------------------------//
	//	THM1176 Instrument Manager properties								//
	//----------------------------------------------------------------------//
	//	Basic instrument control:
    /// \brief List of detected instruments.
    Q_PROPERTY(CResourceList				InstrumentList		READ GetInstrumentList										NOTIFY NotifyInstrumentList)
    /// \brief Currently connected instrument.
    Q_PROPERTY(tResourceName				CurrentInstrument	READ GetCurrentInstrument	WRITE SetCurrentInstrument		NOTIFY NotifyCurrentInstrument)
    /// \brief Current operating mode.
    Q_PROPERTY(eTHM1176OperatingMode		OperatingMode		READ GetOperatingMode		WRITE SetOperatingMode			NOTIFY NotifyOperatingMode)
    /// \brief Last measurement set returned.
    Q_PROPERTY(CMeasurement					Measurement			READ GetMeasurement                                         NOTIFY NotifyMeasurement)
    /// \brief Current error list.
    Q_PROPERTY(CErrorList                   ErrorList			READ GetErrorList											NOTIFY NotifyErrorList)

	//	Instrument information and parameter bounds:
    /// \brief Identification information of currently connected instrument.
    Q_PROPERTY(sIdentifier					Identification		READ GetIdentification										NOTIFY NotifyIdentification)
    /// \brief List of valid ranges for this instrument model.
    Q_PROPERTY(CFluxList					RangeList			READ GetRangeList											NOTIFY NotifyRangeList)
    /// \brief List of valid measurement units for this instrument model.
    Q_PROPERTY(CTHM1176UnitsList			UnitsList			READ GetUnitsList											NOTIFY NotifyUnitsList)
    /// \brief List of divisors for each measurement unit for this instrument model, to convert "base" units to the selected units.
    Q_PROPERTY(CDivisorList					DivisorList			READ GetDivisorList											NOTIFY NotifyDivisorList)
    /// \brief Bounds on averaging parameter.
    Q_PROPERTY(sAveraging<sBoundedParm>		AveragingParmBounds	READ GetAveragingParmBounds									NOTIFY NotifyAveragingParmBounds)
    /// \brief Bounds on trigger parameters.
    Q_PROPERTY(sInputTrigger<sBoundedParm>	TriggerParmBounds	READ GetTriggerParmBounds									NOTIFY NotifyTriggerParmBounds)
    /// \brief Bounds on range parameters.
    Q_PROPERTY(sRange<sBoundedParm>			RangeParmBounds		READ GetRangeParmBounds										NOTIFY NotifyRangeParmBounds)

	// Parameters:
    /// \brief Current averaging parameters.
    Q_PROPERTY(sAveraging<uParm>			AveragingParms		READ GetAveragingParms		WRITE SetAveragingParms			NOTIFY NotifyAveragingParms)
    /// \brief Current trigger parameters.
    Q_PROPERTY(sInputTrigger<uParm>			TriggerParms		READ GetTriggerParms		WRITE SetTriggerParms			NOTIFY NotifyTriggerParms)
    /// \brief Output selection parameters: select what data elements are returned.
    Q_PROPERTY(sArbitraryMeasurements		OutputSelect		READ GetOutputSelect		WRITE SetOutputSelect			NOTIFY NotifyOutputSelect)
    /// \brief Sleep parameter: true if instrument should sleep after each measurement.
    Q_PROPERTY(bool							SleepParm			READ GetSleepParm			WRITE SetSleepParm				NOTIFY NotifySleepParm)
    /// \brief Current measurement units.
    Q_PROPERTY(eTHM1176Units				Units				READ GetUnits				WRITE SetUnits					NOTIFY NotifyUnits)
    /// \brief Current range parameters.
    Q_PROPERTY(sRange<uParm>				RangeParms			READ GetRangeParms			WRITE SetRangeParms				NOTIFY NotifyRangeParms)
    /// \brief Current communication format parameter.
    Q_PROPERTY(eCommunicationFormat			CommFormat			READ GetCommFormat			WRITE SetCommFormat				NOTIFY NotifyCommFormat)

private:
	//----------------------------------------------------------------------//
	//	THM1176 Instrument Manager constants								//
	//----------------------------------------------------------------------//
	static const U8		THM1176_MIN_VERSION_WITH_ABORTREAD	= 4;

	//----------------------------------------------------------------------//
	//	THM1176 Instrument Manager class variables - properties				//
	//----------------------------------------------------------------------//
	//	Basic instrument control:
	CResourceList						m_InstrumentList;
	tResourceName						m_CurrentInstrument;
	eTHM1176OperatingMode				m_OperatingMode;
	CMeasurement						m_Measurement;
	CErrorList							m_ErrorList;

	//	Instrument information and parameter bounds:
	sIdentifier							m_Identification;
	CFluxList							m_RangeList;
    CTHM1176UnitsList					m_UnitsList;
	CDivisorList						m_DivisorList;
	sAveraging<sBoundedParm>			m_AveragingParmBounds;
	sInputTrigger<sBoundedParm>			m_TriggerParmBounds;
	sRange<sBoundedParm>				m_RangeParmBounds;

	// Parameters:
	sAveraging<uParm>					m_AveragingParms;
	sInputTrigger<uParm>				m_TriggerParms;
	sArbitraryMeasurements				m_OutputSelect;
	bool								m_SleepParm;
    eTHM1176Units						m_Units;
	sRange<uParm>						m_RangeParms;
	eCommunicationFormat				m_CommFormat;

	//----------------------------------------------------------------------//
	//	THM1176 Instrument Manager class variables - other					//
	//----------------------------------------------------------------------//
	// Instrument Controller
    CTHM1176InstrumentController*		m_pInstrumentController;
	QThread								m_InstrumentControlThread;

	// Instrument Scanner
    CTHM1176InstrumentScanner*			m_pInstrumentScanner;
	QThread								m_InstrumentScanThread;

	// Instrument connection
    THM1176_RSRC_MGR_CLS *              m_pResourceManager;
    CTHM1176Instrument<THM1176_INSTR_CLS, THM1176_RSRC_MGR_CLS> *
                                        m_pTHM1176;

	//----------------------------------------------------------------------//
	//	THM1176 Instrument Manager private methods							//
	//----------------------------------------------------------------------//
	void	HandleError					(QString Description, QString Context);

public:
	//----------------------------------------------------------------------//
	//	THM1176 Instrument Manager public constants							//
	//----------------------------------------------------------------------//
    static const I32	THM1176_INST_MGR_ERROR		= 5000; ///< Additional error code: %Instrument Manager Error
    static const I32	THM1176_INST_CTLR_ERROR		= 5001; ///< Additional error code: %Instrument Controller Error
    static const I32	THM1176_INST_SCANNER_ERROR	= 5002; ///< Additional error code: %Instrument Scanner Error

	//----------------------------------------------------------------------//
	//	THM1176 Instrument Manager constructor / destructor					//
	//----------------------------------------------------------------------//
    /// \brief Constructor.
	CTHM1176InstrumentManager					(void) :
        m_OperatingMode(kTHM1176NotConnected),
		m_SleepParm(false),
		m_Units(kT),
		m_CommFormat(kComFormatAscii),
        m_pInstrumentController(nullptr),
        m_pInstrumentScanner(nullptr),
        m_pTHM1176(nullptr)
    {

        qRegisterMetaType<eTHM1176Units>();
		qRegisterMetaType<eTHM1176OperatingMode>();
		qRegisterMetaType<eCommunicationFormat>();

		qRegisterMetaType<tResourceName>();

		qRegisterMetaType<sIdentifier>();
		qRegisterMetaType<sArbitraryMeasurements>();
		qRegisterMetaType<CMeasurement>();

		qRegisterMetaType<CResourceList>();
		qRegisterMetaType<CFluxList>();
        qRegisterMetaType<CTHM1176UnitsList>();
		qRegisterMetaType<CDivisorList>();
		qRegisterMetaType<CErrorList>();

		qRegisterMetaType<sAveraging<uParm>>();
		qRegisterMetaType<sAveraging<sBoundedParm>>();
		qRegisterMetaType<sInputTrigger<uParm>>();
		qRegisterMetaType<sInputTrigger<sBoundedParm>>();
		qRegisterMetaType<sRange<uParm>>();
		qRegisterMetaType<sRange<sBoundedParm>>();

		// Meta-types to be passed internally.
        qRegisterMetaType<THM1176_RSRC_MGR_CLS *>();

	}

    /// \brief Destructor.
	~CTHM1176InstrumentManager (void)
	{ }

	//----------------------------------------------------------------------//
	//	THM1176 Instrument Manager property Get methods						//
	//----------------------------------------------------------------------//
	//	Basic instrument control:
    /// \brief Get the list of connected instruments.
    /// \return List of connected instruments.
    CResourceList						GetInstrumentList		(void);

    /// \brief Get VISA resource name of currently connected instrument.
    /// \return VISA resource name of currently connected instrument.
    tResourceName						GetCurrentInstrument	(void);

    /// \brief Get the current operating mode.
    /// \return Current operating mode.
    eTHM1176OperatingMode				GetOperatingMode		(void);

    /// \brief Get the test result of m_pTHM1176 pointer is Nullptr.
    /// \return Boolean.
    bool                                GetIsTHMNullptr		(void);

    /// \brief Get the last set of measurements.
    /// \return Last set of measurements.
	CMeasurement						GetMeasurement			(void);

    /// \brief Get the current error list.
    /// \return Current list of errors.
    CErrorList							GetErrorList			(void);

	//	Instrument information and parameter bounds:
    /// \brief Get the current instrument's identification information.
    /// \return %Instrument identification.
	sIdentifier							GetIdentification		(void);

    /// \brief Get list of valid ranges for this instrument model.
    /// \return List of ranges.
    CFluxList							GetRangeList			(void);

    /// \brief Get the list of valid measurement units for this instrument model.
    /// \return List of valid measurement units.
    CTHM1176UnitsList					GetUnitsList			(void);

    /// \brief Get the list of divisors associated with each measurement unit for this instrument model.
    /// \return List of divisors for each measurement unit.
    CDivisorList						GetDivisorList			(void);

    /// \brief Get the bounds on averaging parameters.
    /// \return Bounds on averaging parameters.
    sAveraging<sBoundedParm>			GetAveragingParmBounds	(void);

    /// \brief Get the bounds on trigger parameters.
    /// \return Bounds on trigger parameters.
    sInputTrigger<sBoundedParm>			GetTriggerParmBounds	(void);

    /// \brief Get the bounds on range parameters.
    /// \return Bounds on range parameters.
    sRange<sBoundedParm>				GetRangeParmBounds		(void);

	// Parameters:
    /// \brief Get the averaging parameters.
    /// \return Current value of averaging parameters.
    sAveraging<uParm>					GetAveragingParms		(void);

    /// \brief Get the trigger parameters.
    /// \return Current value of trigger parameters.
    sInputTrigger<uParm>				GetTriggerParms			(void);

    /// \brief Get the output selection parameters.
    /// \return Current value of output selection parameters.
    sArbitraryMeasurements				GetOutputSelect			(void);

    /// \brief Get the sleep parameter.
    /// \return Current value of sleep parameter.
    bool								GetSleepParm			(void);

    /// \brief Get the measurement units.
    /// \return Current measurement units.
    eTHM1176Units						GetUnits				(void);

    /// \brief Get the range parameters.
    /// \return  Current value of range parameters.
    sRange<uParm>						GetRangeParms			(void);

    /// \brief Get the communication format parameters.
    /// \return Current value of communication format parameter.
    eCommunicationFormat				GetCommFormat			(void);

    /// \brief Get measurement interval for Immediate Trigger, for a given averaging parameter.
    /// \param[in]	rAvg                Averaging setting.
    /// \param[out]	rPeriod             Corresponding measurement period, in s.
    /// \return True if successful.
    bool                                GetImmediateMeasurementPeriod(const sAveraging<uParm> & rAvg, F64 & rPeriod);

    /// \brief Convert a raw timestamp to UNIX Epoch time and nanoseconds.
    /// \param[in]	RawTimestamp		Raw timestamp returned by instrument.
    /// \param[out]	rTimestamp			Timestamp as UNIX Epoch time and nanoseconds.
    /// \return True if successful.
    inline bool                         ConvertTimestamp        (const U64 RawTimestamp, CAbsoluteTimestamp & rTimestamp)
    {
        if (m_pTHM1176 == nullptr)
        {
            HandleError("Instrument not connected", __func__);
            return false;
        }
        else
        {
            return m_pTHM1176->ConvertTimestamp(RawTimestamp, rTimestamp);
        }
    }; // CTHM1176InstrumentManager::ConvertTimestamp

    /// \brief Fetch the intrument's date information.
    /// \param[out]	rManufacturingDate	Manufacturing date as QDateTime.
    /// \param[out]	rCalibrationDate	Calibration date as QDateTime.
    /// \return True if successful.
    bool                                ReadInformationDates    (QDateTime & rManufacturingDate, QDateTime & rCalibrationDate);


public slots:
	//----------------------------------------------------------------------//
	//	THM1176 Instrument Manager property Set methods						//
	//----------------------------------------------------------------------//
	//	Basic instrument control:
    /// \brief Connect a new instrument.
    /// \param[in] CurrentInstrument    VISA resource name of instrument to connect.
    void	SetCurrentInstrument		(tResourceName					CurrentInstrument);

    /// \brief Set a new operating mode, for example to start measuring.
    /// \param[in] OperatingMode        Desired operting mode.
    void	SetOperatingMode			(eTHM1176OperatingMode			OperatingMode);

	//	Parameters:
    /// \brief Set the averaging parameters.
    /// \param[in] AveragingParms       Desired value of averaging parameters.
    void	SetAveragingParms			(sAveraging<uParm>				AveragingParms);

    /// \brief Set the trigger parameters.
    /// \param[in] TriggerParms         Desired value of trigger parameters.
    void	SetTriggerParms				(sInputTrigger<uParm>			TriggerParms);

    /// \brief Set the output selection parameters.
    /// \param[in] OutputSelect         Desired value of output selection parameters.
    void	SetOutputSelect				(sArbitraryMeasurements			OutputSelect);

    /// \brief Set the sleep parameter.
    /// \param[in] SleepParm            Desired value of sleep parameter.
    void	SetSleepParm				(bool							SleepParm);

    /// \brief Set the measurement units.
    /// \param[in] Units                Desired measurement units.
    void	SetUnits					(eTHM1176Units					Units);

    /// \brief Set the range parameters.
    /// \param[in] RangeParms           Desired value of range parameters.
    void	SetRangeParms				(sRange<uParm>					RangeParms);

    /// \brief Set the communication format parameters.
    /// \param[in] CommFormat           Desired value of communication format parameters.
    void	SetCommFormat				(eCommunicationFormat			CommFormat);

private slots:
	//----------------------------------------------------------------------//
	//	THM1176 Instrument Manager communication with Instrument Scanner	//
	//----------------------------------------------------------------------//
	void	UpdateInstrumentList		(CResourceList					InstrumentList);

	//----------------------------------------------------------------------//
	//	THM1176 Instrument Manager communication with Instrument Controller	//
	//----------------------------------------------------------------------//
	//	Basic instrument control:
	void	UpdateCurrentInstrument		(tResourceName					CurrentInstrument);
    void	UpdateInstrumentPointer		(CTHM1176Instrument<THM1176_INSTR_CLS, THM1176_RSRC_MGR_CLS> * pTHM1176);
	void	UpdateOperatingMode			(eTHM1176OperatingMode			OperatingMode);
	void	UpdateMeasurement			(CMeasurement					Measurement);
	void	UpdateErrorList				(CErrorList						ErrorList);

	//	Instrument information and parameter bounds:
	void	UpdateIdentification		(sIdentifier					Identification);
	void	UpdateRangeList				(CFluxList						RangeList);
    void	UpdateUnitsList				(CTHM1176UnitsList				UnitsList);
	void	UpdateDivisorList			(CDivisorList					DivisorList);
	void	UpdateAveragingParmBounds	(sAveraging<sBoundedParm>		AveragingParmBounds);
	void	UpdateTriggerParmBounds		(sInputTrigger<sBoundedParm>	TriggerParmBounds);
	void	UpdateRangeParmBounds		(sRange<sBoundedParm>			RangeParmBounds);

	// Parameters
	void	UpdateAveragingParms		(sAveraging<uParm>				AveragingParms);
	void	UpdateTriggerParms			(sInputTrigger<uParm>			TriggerParms);
	void	UpdateOutputSelect			(sArbitraryMeasurements			OutputSelect);
	void	UpdateSleepParm				(bool							SleepParm);
    void	UpdateUnits					(eTHM1176Units					Units);
	void	UpdateRangeParms			(sRange<uParm>					RangeParms);
	void	UpdateCommFormat			(eCommunicationFormat			CommFormat);

public slots:
	//----------------------------------------------------------------------//
	//	THM1176 Instrument Manager slots									//
	//----------------------------------------------------------------------//
	// Startup and shutdown:
    /// \brief Initialize the THM1176 %Instrument Manager.
	void	Start						(void);

    /// \brief Shut down the THM1176 %Instrument Manager.
	void	Stop						(void);

signals:
    //----------------------------------------------------------------------//
    //	THM1176 Instrument Manager instrument control signals				//
    //----------------------------------------------------------------------//
    /// \brief Send a bus trigger to the instrument (both slot and signal).
    ///
    /// *Note:*
    /// Invoke this signal as if it were a slot. This will emit a signal to the
    /// THM1176 Inastrument Controller, which will actually emit the bus trigger.
    void	SendTrigger					(void);

    /// \brief Set whether or not to override the check for instruments whose
    ///     zero offset should not be calibrated.
    /// \param[in] Override             Override the check if true.
    ///
    /// *Note:*
    /// Invoke this signal as if it were a slot. This will emit a signal to the
    /// THM1176 Inastrument Controller, which will actually set the parameter.
    void    SetCalibrationOverride      (bool Override);


    //----------------------------------------------------------------------//
	//	THM1176 Instrument Manager property change notifications			//
	//----------------------------------------------------------------------//
	//	Basic instrument control:
    /// \brief Notify that the list of detected instruments has changed.
    /// \param[in] InstrumentList       List of detected instruments.
    void	NotifyInstrumentList		(CResourceList					InstrumentList);

    /// \brief Notify that the currently connected instrument has changed.
    /// \param[in] CurrentInstrument    VISA resource name of currently connected instrument.
    void	NotifyCurrentInstrument		(tResourceName					CurrentInstrument);

    /// \brief Notify that the operating mode has changed.
    /// \param[in] OperatingMode        New operating mode.
    void	NotifyOperatingMode			(eTHM1176OperatingMode			OperatingMode);

    /// \brief Notify that a new set of measurements is available.
    /// \param[in] Measurement          Most recent set of measurements.
    void	NotifyMeasurement			(CMeasurement					Measurement);

    /// \brief Notify that new errors are present.
    /// \param[in] ErrorList            List of errors.
    void	NotifyErrorList				(CErrorList						ErrorList);

	//	Instrument information and parameter bounds:
    /// \brief Notify that the instrument identification information has changed.
    /// \param[in] Identification       %Instrument identification.
    void	NotifyIdentification		(sIdentifier					Identification);

    /// \brief Notify that the list of valid ranges has changed.
    /// \param[in] RangeList            New list of ranges.
    void	NotifyRangeList				(CFluxList						RangeList);

    /// \brief Notify that the list of valid measurement units has changed.
    /// \param[in] UnitsList            New ist of valid measurement units.
    void	NotifyUnitsList				(CTHM1176UnitsList				UnitsList);

    /// \brief Notify that the list of divisors associated with each measurement unit for this instrument model has changed.
    /// \param[in] DivisorList          List of divisors for each measurement unit.
    void	NotifyDivisorList			(CDivisorList					DivisorList);

    /// \brief Notify that the bounds on averaging parameters have changed.
    /// \param[in] AveragingParmBounds  New bounds on averaging parameters
    void	NotifyAveragingParmBounds	(sAveraging<sBoundedParm>		AveragingParmBounds);

    /// \brief Notify that the bounds on trigger parameters have changed.
    /// \param[in] TriggerParmBounds    New bounds on trigger parameters
    void	NotifyTriggerParmBounds		(sInputTrigger<sBoundedParm>	TriggerParmBounds);

    /// \brief Notify that the bounds on range parameters have changed.
    /// \param[in] RangeParmBounds      New bounds on range parameters
    void	NotifyRangeParmBounds		(sRange<sBoundedParm>			RangeParmBounds);

	// Parameters:
    /// \brief Notify that the averaging parameters have changed.
    /// \param[in] AveragingParms       New value of averaging parameters.
    void	NotifyAveragingParms		(sAveraging<uParm>				AveragingParms);

    /// \brief Notify that the trigger parameters have changed.
    /// \param[in] TriggerParms         New value of trigger parameters.
    void	NotifyTriggerParms			(sInputTrigger<uParm>			TriggerParms);

    /// \brief Notify that the output selection parameters have changed.
    /// \param[in] OutputSelect         New value of output selection parameters.
    void	NotifyOutputSelect			(sArbitraryMeasurements			OutputSelect);

    /// \brief Notify that the sleep parameter has changed.
    /// \param[in] SleepParm            New value of sleep parameters.
    void	NotifySleepParm				(bool							SleepParm);

    /// \brief Notify that the measurement units have changed.
    /// \param[in] Units                New measurement units.
    void	NotifyUnits					(eTHM1176Units					Units);

    /// \brief Notify that the range parameters have changed.
    /// \param[in] RangeParms           New value of range parameters.
    void	NotifyRangeParms			(sRange<uParm>					RangeParms);

    /// \brief Notify that the communication format parameters have changed.
    /// \param[in] CommFormat           New value of communication format parameters.
    void	NotifyCommFormat			(eCommunicationFormat			CommFormat);

	//----------------------------------------------------------------------//
	//	THM1176 Instrument Manager internal signals							//
	//----------------------------------------------------------------------//
    /// \brief Internal signal to start the %Instrument Scanner.
    /// \param[in] pResourceManager     Pointer to VISA Resource Manager.
    void	StartInstrumentScanner		(THM1176_RSRC_MGR_CLS *         pResourceManager);

    /// \brief Internal signal to stop the %Instrument Scanner.
	void	StopInstrumentScanner		(void);

    /// \brief Internal signal to start to %Instrument Controller.
    /// \param[in] pResourceManager     Pointer to VISA Resource Manager.
    void	StartInstrumentController	(THM1176_RSRC_MGR_CLS *         pResourceManager);

    /// \brief Internal signal to stop the %Instrument Controller.
	void	StopInstrumentController	(void);

	//----------------------------------------------------------------------//
	//	THM1176 Instrument Manager communication with Instrument Controller	//
	//----------------------------------------------------------------------//
	//	Basic instrument control:
    /// \brief Internal signal to relay the instrument selection to the %Instrument Controller.
    /// \param[in] CurrentInstrument    VISA resource name for the newly selected instrument.
	void	RelayCurrentInstrument		(tResourceName					CurrentInstrument);

    /// \brief Internal signal to relay the operating mode selection to the %Instrument Controller.
    /// \param[in] OperatingMode        Newly selected operating mode.
    void	RelayOperatingMode			(eTHM1176OperatingMode			OperatingMode);

	// Parameters
    /// \brief Internal signal to relay the averaging parameters to the %Instrument Controller.
    /// \param[in] AveragingParms       Newly selected averaging parameters.
    void	RelayAveragingParms			(sAveraging<uParm>				AveragingParms);

    /// \brief Internal signal to relay the trigger parameters to the %Instrument Controller.
    /// \param[in] TriggerParms         Newly selected trigger parameters.
    void	RelayTriggerParms			(sInputTrigger<uParm>			TriggerParms);

    /// \brief Internal signal to relay the output selection parameters to the %Instrument Controller.
    /// \param[in] OutputSelect         Newly selected output selection parameters.
    void	RelayOutputSelect			(sArbitraryMeasurements			OutputSelect);

    /// \brief Internal signal to relay the sleep parameter to the %Instrument Controller.
    /// \param SleepParm                Newly selected sleep parameter.
    void	RelaySleepParm				(bool							SleepParm);

    /// \brief Internal signal to relay the measurement units to the %Instrument Controller.
    /// \param[in] Units                Newly selected measurement units.
    void	RelayUnits					(eTHM1176Units					Units);

    /// \brief Internal signal to relay the range parameters to the %Instrument Controller.
    /// \param[in] RangeParms           Newly selected range parameters.
    void	RelayRangeParms				(sRange<uParm>					RangeParms);

    /// \brief Internal signal to relay the communications format to the %Instrument Controller.
    /// \param[in] CommFormat           Newly selected communications format.
    void	RelayCommFormat				(eCommunicationFormat			CommFormat);

}; // CTHM1176InstrumentManager

} // namespace MTL
