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

//////////////////////////////////////////////////////////////////////////
/// \file
/// \brief Test code for THM1176 Instrument Manager: Measure

#include <thread>
#include <chrono>
#include <ctime>
#include <iostream>

#include <QtTest>
#include <QSignalSpy>

#include "CTHM1176InstrumentManager.h"

using namespace MTL;

#define THM1176_PROMPT_TIME         10      // s
#define THM1176_BOOT_N_SCAN_TIME	15000 // ms
#define THM1176_CONNECT_TIME		5000 // ms
#define THM1176_CHANGE_PARM_TIME	1000 // ms
#define THM1176_RESET_TIME			1000 // ms
#define THM1176_MEASURE_TIME		20000 // ms
#define THM1176_CALIBRATE_TIME		10000 // ms

static const F64 THM1176_IMMEDIATE_TIME_PER_ACQ			(1.0281823091218700E+05);	// ns
static const F64 THM1176_IMMEDIATE_TIME_PER_MEAS		(4.4532792007542600E+04);	// ns

static CTHM1176InstrumentManager	Manager;

//----------------------------------------------------------------------//
//	Utility functions													//
//----------------------------------------------------------------------//
static void PromptAndWait(std::string Prompt)
{
    std::string l_Space     = ("" == Prompt) ? "" : " ";
    std::string l_Message   = ">>> " + Prompt + l_Space + "(Will continue in " + std::to_string(THM1176_PROMPT_TIME) + " seconds) <<<";
    QWARN(" ");
    QWARN(l_Message.c_str());
    QThread::currentThread()->sleep(THM1176_PROMPT_TIME);
}

F64	PeriodOfImmediateTrigger (sAveraging<uParm> Averaging)
{
	return 1E-9 * (THM1176_IMMEDIATE_TIME_PER_MEAS + Averaging.NoPoints * THM1176_IMMEDIATE_TIME_PER_ACQ);
}

//----------------------------------------------------------------------//
//	Test class definition                                               //
//----------------------------------------------------------------------//
class THM1176IM_Test02_Measure: public QObject
{
    Q_OBJECT

public:
    THM1176IM_Test02_Measure();
    ~THM1176IM_Test02_Measure();

private:
    QList<QVariant>					m_Arguments;

    CResourceList					m_ResourceList;
    tResourceName					m_THM1176Selected;
    sIdentifier						m_Identification;
    CFluxList						m_RangeList;
    CTHM1176UnitsList				m_UnitsList;
    CDivisorList					m_DivisorList;
    sAveraging<sBoundedParm>		m_AveragingBounds;
    sInputTrigger<sBoundedParm>		m_TriggerBounds;
    sRange<sBoundedParm>			m_RangeBounds;

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

    eTHM1176OperatingMode			m_OperatingMode;
    CMeasurement					m_Measurement;
    CErrorList						m_LatestErrors;

private slots:

    /// \brief Test case initialization.
    void initTestCase(void);

    /// \brief Test case cleanup.
    void cleanupTestCase(void);

    /// \brief Test setting SetOperatingMode to Measure Immediate,N.
    void TestSetOperatingMode_Immediate(void);

    /// \brief Test setting SetOperatingMode to Measure Triggered,N.
    void TestSetOperatingMode_Triggered(void);

    /// \brief Test setting SetOperatingMode to Measure Timed,N.
    void TestSetOperatingMode_Timed(void);

    /// \brief Test setting SetOperatingMode to Measure Timed,2000.
    void TestSetOperatingMode_TimedLong(void);

    /// \brief Test setting SetOperatingMode to Measure Immediate,Continuous.
    void TestSetOperatingMode_ImmediateContinuous(void);

    /// \brief Test setting SetOperatingMode to Measure Timed,Continuous.
    void TestSetOperatingMode_TimedContinuous(void);

    /// \brief Test setting SetOperatingMode to Measure Triggered,Continuous.
    void TestSetOperatingMode_TriggeredContinuous(void);

    /// \brief Test setting SetOperatingMode to Calibrate Zero Offset.
    void TestSetOperatingMode_CalibrateRestore(void);

    /// \brief Test setting SetOperatingMode to Calibrate Zero Offset.
    void TestUtilities(void);

};

//----------------------------------------------------------------------//
//	Test case constructor and destructor								//
//----------------------------------------------------------------------//
THM1176IM_Test02_Measure::THM1176IM_Test02_Measure()
{

}

THM1176IM_Test02_Measure::~THM1176IM_Test02_Measure()
{

}

//----------------------------------------------------------------------//
//	Test case initialization and cleanup								//
//----------------------------------------------------------------------//
void THM1176IM_Test02_Measure::initTestCase(void)
{
	QList<QVariant>					m_Arguments;

	// Start the Instrument Manager.
	Manager.Start();

	// Create Signal Spies to retrieve instrument list, instrument info, parameters and possible errors.
	QSignalSpy	l_NotifyInstrumentListSpy(&Manager, SIGNAL(NotifyInstrumentList(CResourceList)));
	QSignalSpy	l_NotifyCurrentInstrumentSpy(&Manager, SIGNAL(NotifyCurrentInstrument(tResourceName)));

	QSignalSpy	l_NotifyIdentificationSpy(&Manager, SIGNAL(NotifyIdentification(sIdentifier)));
	QSignalSpy	l_NotifyRangeListSpy(&Manager, SIGNAL(NotifyRangeList(CFluxList)));
    QSignalSpy	l_NotifyUnitsListSpy(&Manager, SIGNAL(NotifyUnitsList(CTHM1176UnitsList)));
	QSignalSpy	l_NotifyDivisorListSpy(&Manager, SIGNAL(NotifyDivisorList(CDivisorList)));
	QSignalSpy	l_NotifyAveragingParmBoundsSpy(&Manager, SIGNAL(NotifyAveragingParmBounds(sAveraging<sBoundedParm>)));
	QSignalSpy	l_NotifyTriggerParmBoundsSpy(&Manager, SIGNAL(NotifyTriggerParmBounds(sInputTrigger<sBoundedParm>)));
	QSignalSpy	l_NotifyRangeParmBoundsSpy(&Manager, SIGNAL(NotifyRangeParmBounds(sRange<sBoundedParm>)));

	QSignalSpy	l_NotifyAveragingParmsSpy(&Manager, SIGNAL(NotifyAveragingParms(sAveraging<uParm>)));
	QSignalSpy	l_NotifyTriggerParmsSpy(&Manager, SIGNAL(NotifyTriggerParms(sInputTrigger<uParm>)));
	QSignalSpy	l_NotifyOutputSelectSpy(&Manager, SIGNAL(NotifyOutputSelect(sArbitraryMeasurements)));
	QSignalSpy	l_NotifySleepParmSpy(&Manager, SIGNAL(NotifySleepParm(bool)));
    QSignalSpy	l_NotifyUnitsSpy(&Manager, SIGNAL(NotifyUnits(eTHM1176Units)));
	QSignalSpy	l_NotifyRangeParmsSpy(&Manager, SIGNAL(NotifyRangeParms(sRange<uParm>)));
	QSignalSpy	l_NotifyCommFormatSpy(&Manager, SIGNAL(NotifyCommFormat(eCommunicationFormat)));

	QSignalSpy	l_NotifyOperatingModeSpy(&Manager, SIGNAL(NotifyOperatingMode(eTHM1176OperatingMode)));
	QSignalSpy	l_NotifyErrorListSpy(&Manager, SIGNAL(NotifyErrorList(CErrorList)));

	// Plug in the THM.
	PromptAndWait("Please plug in a THM");
	l_NotifyInstrumentListSpy.wait(THM1176_BOOT_N_SCAN_TIME);
	QCOMPARE(l_NotifyInstrumentListSpy.count(), 1);
	m_Arguments = l_NotifyInstrumentListSpy.takeFirst();
	m_ResourceList = qvariant_cast<CResourceList>(m_Arguments.at(0));
	QCOMPARE(m_ResourceList.size(), 1ul);

	// Select the THM.
	m_THM1176Selected = m_ResourceList[0];
	Manager.SetCurrentInstrument(m_THM1176Selected);

	// Wait for it to become Idle.
	l_NotifyOperatingModeSpy.wait(THM1176_CONNECT_TIME);
	QCOMPARE(l_NotifyOperatingModeSpy.count(), 1);
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176Idle);

	// Retrieve the current instrument.
	QCOMPARE(l_NotifyCurrentInstrumentSpy.count(), 1);
	m_Arguments = l_NotifyCurrentInstrumentSpy.takeFirst();
	m_THM1176Selected = qvariant_cast<tResourceName>(m_Arguments.at(0));
	QCOMPARE(m_THM1176Selected, m_ResourceList[0]);

	// Retrieve instrument information and parameter bounds for this THM.
	QCOMPARE(l_NotifyIdentificationSpy.count(), 1);
	m_Arguments = l_NotifyIdentificationSpy.takeFirst();
	m_Identification = qvariant_cast<sIdentifier>(m_Arguments.at(0));
	QVERIFY(!m_Identification.Manufacturer.empty() && !m_Identification.Model.empty() && m_Identification.SerialNumber != 0);

	QCOMPARE(l_NotifyRangeListSpy.count(), 1);
	m_Arguments = l_NotifyRangeListSpy.takeFirst();
	m_RangeList = qvariant_cast<CFluxList>(m_Arguments.at(0));
	QVERIFY(!m_RangeList.empty());

	QCOMPARE(l_NotifyUnitsListSpy.count(), 1);
	m_Arguments		= l_NotifyUnitsListSpy.takeFirst();
    m_UnitsList		= qvariant_cast<CTHM1176UnitsList>(m_Arguments.at(0));
	QVERIFY(!m_UnitsList.empty());

	QCOMPARE(l_NotifyDivisorListSpy.count(), 1);
	m_Arguments		= l_NotifyDivisorListSpy.takeFirst();
	m_DivisorList	= qvariant_cast<CDivisorList>(m_Arguments.at(0));
	QVERIFY(!m_DivisorList.empty());

	QCOMPARE(l_NotifyAveragingParmBoundsSpy.count(), 1);
	m_Arguments = l_NotifyAveragingParmBoundsSpy.takeFirst();
	m_AveragingBounds = qvariant_cast<sAveraging<sBoundedParm>>(m_Arguments.at(0));
	QVERIFY(m_AveragingBounds.NoPoints.Val != 0 && m_AveragingBounds.NoPoints.Min != 0 &&
			m_AveragingBounds.NoPoints.Max != 0 && m_AveragingBounds.NoPoints.Def != 0);

	QCOMPARE(l_NotifyTriggerParmBoundsSpy.count(), 1);
	m_Arguments = l_NotifyTriggerParmBoundsSpy.takeFirst();
	m_TriggerBounds = qvariant_cast<sInputTrigger<sBoundedParm>>(m_Arguments.at(0));
	QVERIFY(m_TriggerBounds.Period_s.Val != 0 && m_TriggerBounds.Period_s.Min != 0 &&
			m_TriggerBounds.Period_s.Max != 0 && m_TriggerBounds.Period_s.Def != 0 &&
			m_TriggerBounds.Count.Val != 0 && m_TriggerBounds.Count.Min != 0 &&
			m_TriggerBounds.Count.Max != 0 && m_TriggerBounds.Count.Def != 0);

	QCOMPARE(l_NotifyRangeParmBoundsSpy.count(), 1);
	m_Arguments = l_NotifyRangeParmBoundsSpy.takeFirst();
	m_RangeBounds = qvariant_cast<sRange<sBoundedParm>>(m_Arguments.at(0));
	QVERIFY(m_RangeBounds.Range.Val != 0 && m_RangeBounds.Range.Min != 0 &&
			m_RangeBounds.Range.Max != 0 && m_RangeBounds.Range.Def != 0);

	// Retrieve the current parameters for this instrument.
	QCOMPARE(l_NotifyAveragingParmsSpy.count(), 1);
	m_Arguments = l_NotifyAveragingParmsSpy.takeFirst();
	m_AveragingParms = qvariant_cast<sAveraging<uParm>>(m_Arguments.at(0));
	QVERIFY(m_AveragingParms.NoPoints > 0);

	QCOMPARE(l_NotifyTriggerParmsSpy.count(), 1);
	m_Arguments = l_NotifyTriggerParmsSpy.takeFirst();
	m_Trigger = qvariant_cast<sInputTrigger<uParm>>(m_Arguments.at(0));
	QVERIFY(m_Trigger.Period_s > 0. && m_Trigger.Count > 0);

	QCOMPARE(l_NotifyOutputSelectSpy.count(), 1);
	m_Arguments = l_NotifyOutputSelectSpy.takeFirst();
	m_OutputSelect = qvariant_cast<sArbitraryMeasurements>(m_Arguments.at(0));

	QCOMPARE(l_NotifySleepParmSpy.count(), 1);
	m_Arguments = l_NotifySleepParmSpy.takeFirst();
	m_SleepParm = qvariant_cast<bool>(m_Arguments.at(0));

	QCOMPARE(l_NotifyUnitsSpy.count(), 1);
	m_Arguments = l_NotifyUnitsSpy.takeFirst();
    m_Units = qvariant_cast<eTHM1176Units>(m_Arguments.at(0));

	QCOMPARE(l_NotifyRangeParmsSpy.count(), 1);
	m_Arguments = l_NotifyRangeParmsSpy.takeFirst();
	m_RangeParms = qvariant_cast<sRange<uParm>>(m_Arguments.at(0));

	QCOMPARE(l_NotifyCommFormatSpy.count(), 1);
	m_Arguments = l_NotifyCommFormatSpy.takeFirst();
	m_CommFormat = qvariant_cast<eCommunicationFormat>(m_Arguments.at(0));

	// We expect no errors.
	QCOMPARE(l_NotifyErrorListSpy.count(), 0);

    std::cout << "- Connected to " + m_Identification.Model + ", S/N " + std::to_string(m_Identification.SerialNumber) << std::endl;

} // THM1176IM_Test02_Measure::initTestCase

void THM1176IM_Test02_Measure::cleanupTestCase(void)
{
	Manager.Stop();
}

//////////////////////////////////////////////////////////////////////////
/// \test   Test THM1176 Instrument Manager: Test setting SetOperatingMode to Measure Immediate,N:
///	- Emit SetOperatingMode = Reset:
///		- Should receive NotifyOperatingMode = Reset, Idle
///	- Set SetTriggerParms to Immediate,1:
///		- Should not receive NotifyErrorList
///	- Emit SetOperatingMode = Measure:
///		- Should receive NotifyOperatingMode = Measure, Idle
///		- Should receive NotifyMeasurement length 1
///		- Should not receive NotifyErrorList
///	- Set SetTriggerParms to Immediate,10:
///		- Should not receive NotifyErrorList
///	- Set SetOutputSelect to Bx, no By, Bz, no T, Time, 10:
///		- Should not receive NotifyErrorList
///	- Emit SetOperatingMode = Measure:
///		- Should receive NotifyOperatingMode = Measure, Idle
///		- Should receive NotifyMeasurement as requested
///		- Should not receive NotifyErrorList
void THM1176IM_Test02_Measure::TestSetOperatingMode_Immediate(void)
{
	// Create  Signal Spies to retrieve measurement result, operating mode, and possible errors.
	QSignalSpy	l_NotifyMeasurementSpy(&Manager, SIGNAL(NotifyMeasurement(CMeasurement)));
	QSignalSpy	l_NotifyOperatingModeSpy(&Manager, SIGNAL(NotifyOperatingMode(eTHM1176OperatingMode)));
	QSignalSpy	l_NotifyErrorListSpy(&Manager, SIGNAL(NotifyErrorList(CErrorList)));

	//	- Emit SetOperatingMode = Reset:
	//		- Should receive NotifyOperatingMode = Reset, Idle
	Manager.SetOperatingMode(kTHM1176Reset);

	l_NotifyOperatingModeSpy.wait(THM1176_RESET_TIME);
	QVERIFY(l_NotifyOperatingModeSpy.count() > 0);
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176Reset);
	if (l_NotifyOperatingModeSpy.count() <= 0)
	{
		l_NotifyOperatingModeSpy.wait(THM1176_RESET_TIME);
		QCOMPARE(l_NotifyOperatingModeSpy.count(), 1);
	}
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176Idle);

	m_AveragingParms		= Manager.GetAveragingParms();
	m_Trigger				= Manager.GetTriggerParms();
	m_OutputSelect			= Manager.GetOutputSelect();
	m_SleepParm				= Manager.GetSleepParm();
	m_Units					= Manager.GetUnits();
	m_RangeParms			= Manager.GetRangeParms();
	m_CommFormat			= Manager.GetCommFormat();

    std::cout << "- Reset " << m_Identification.Model << ", S/N " << m_Identification.SerialNumber << std::endl;

	//	- Set SetTriggerParms to Immediate,1:
	//		- Should not receive NotifyErrorList
	m_Trigger.Source	= kInputTrigSrcImmediate;
	m_Trigger.Count		= 1;
	Manager.SetTriggerParms(m_Trigger);

	l_NotifyErrorListSpy.wait(THM1176_CHANGE_PARM_TIME);
	QCOMPARE(l_NotifyErrorListSpy.count(), 0);

	//	- Emit SetOperatingMode = Measure:
	//		- Should receive NotifyOperatingMode = Measure, Idle
	//		- Should receive NotifyMeasurement length 1
	//		- Should not receive NotifyErrorList
	Manager.SetOperatingMode(kTHM1176Measure);

	l_NotifyOperatingModeSpy.wait(THM1176_MEASURE_TIME);
	QVERIFY(l_NotifyOperatingModeSpy.count() > 0);
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176Measure);
	if (l_NotifyOperatingModeSpy.count() <= 0)
	{
		l_NotifyOperatingModeSpy.wait(THM1176_MEASURE_TIME);
		QCOMPARE(l_NotifyOperatingModeSpy.count(), 1);
	}
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176Idle);

	QCOMPARE(l_NotifyMeasurementSpy.count(), 1);
	m_Arguments = l_NotifyMeasurementSpy.takeFirst();
	m_Measurement = qvariant_cast<CMeasurement> (m_Arguments.at(0));
	QCOMPARE(m_Measurement.Bx.size(), 1ul);
	QCOMPARE(m_Measurement.By.size(), 1ul);
	QCOMPARE(m_Measurement.Bz.size(), 1ul);
    QCOMPARE(m_Measurement.Units, MTL::kT);
	QVERIFY(m_Measurement.Temp != 0);
	QCOMPARE(m_Measurement.TimestampList.size(), 1ul);
	QVERIFY(m_Measurement.AveragingParms == m_AveragingParms);
	QCOMPARE(m_Measurement.TriggerParms.Source, m_Trigger.Source);
	QCOMPARE(m_Measurement.TriggerParms.Count, m_Trigger.Count);
	QCOMPARE(m_Measurement.TriggerParms.Period_s, PeriodOfImmediateTrigger(m_AveragingParms));
	QVERIFY(m_Measurement.OutputSelect == m_OutputSelect);
	QVERIFY(m_Measurement.SleepParm == m_SleepParm);
	QVERIFY(m_Measurement.RangeParms.Auto == m_RangeParms.Auto &&
			(m_RangeParms.Auto || m_Measurement.RangeParms.Range == m_RangeParms.Range));
	QVERIFY(m_Measurement.CommFormat == m_CommFormat);
	QCOMPARE(m_Measurement.Warnings.size(), 0ul);

	QCOMPARE(l_NotifyErrorListSpy.count(), 0);

    std::cout << "- Measured Immediate,1: B = (" << m_Measurement.Bx[0] << ", " << m_Measurement.By[0] << ", " << m_Measurement.Bz[0] << ") [T], "
    "Temp = " << m_Measurement.Temp << ", Timestamp = " << m_Measurement.TimestampList[0] << std::endl;

	//	- Set SetTriggerParms to Immediate,10:
	//		- Should not receive NotifyErrorList
	m_Trigger.Source	= kInputTrigSrcImmediate;
	m_Trigger.Count		= 10;
	Manager.SetTriggerParms(m_Trigger);

	l_NotifyErrorListSpy.wait(THM1176_CHANGE_PARM_TIME);
	QCOMPARE(l_NotifyErrorListSpy.count(), 0);

	//	- Set SetOutputSelect to Bx, no By, Bz, no T, Time, 10:
	//		- Should not receive NotifyErrorList
	m_OutputSelect.Bx				= true;
	m_OutputSelect.By				= false;
	m_OutputSelect.Bz				= true;
	m_OutputSelect.Temperature		= false;
	m_OutputSelect.Timestamp		= true;
	m_OutputSelect.NoMeasurements	= 10;
	Manager.SetOutputSelect(m_OutputSelect);

	l_NotifyErrorListSpy.wait(THM1176_CHANGE_PARM_TIME);
	QCOMPARE(l_NotifyErrorListSpy.count(), 0);

	//	- Emit SetOperatingMode = Measure:
	//		- Should receive NotifyOperatingMode = Measure, Idle
	//		- Should receive NotifyMeasurement as requested
	//		- Should not receive NotifyErrorList
	Manager.SetOperatingMode(kTHM1176Measure);

	l_NotifyOperatingModeSpy.wait(THM1176_MEASURE_TIME);
	QVERIFY(l_NotifyOperatingModeSpy.count() > 0);
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176Measure);
	if (l_NotifyOperatingModeSpy.count() <= 0)
	{
		l_NotifyOperatingModeSpy.wait(THM1176_MEASURE_TIME);
		QCOMPARE(l_NotifyOperatingModeSpy.count(), 1);
	}
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176Idle);

	QCOMPARE(l_NotifyMeasurementSpy.count(), 1);
	m_Arguments = l_NotifyMeasurementSpy.takeFirst();
	m_Measurement = qvariant_cast<CMeasurement> (m_Arguments.at(0));
	QCOMPARE(m_Measurement.Bx.size(), 10ul);
	QCOMPARE(m_Measurement.By.size(), 0ul);
	QCOMPARE(m_Measurement.Bz.size(), 10ul);
    QCOMPARE(m_Measurement.Units, MTL::kT);
	QVERIFY(m_Measurement.Temp == 0);
	QCOMPARE(m_Measurement.TimestampList.size(), 10ul);
	QVERIFY(m_Measurement.AveragingParms == m_AveragingParms);
	QCOMPARE(m_Measurement.TriggerParms.Source, m_Trigger.Source);
	QCOMPARE(m_Measurement.TriggerParms.Count, m_Trigger.Count);
	QCOMPARE(m_Measurement.TriggerParms.Period_s, PeriodOfImmediateTrigger(m_AveragingParms));
	QVERIFY(m_Measurement.OutputSelect == m_OutputSelect);
	QVERIFY(m_Measurement.SleepParm == m_SleepParm);
	QVERIFY(m_Measurement.RangeParms.Auto == m_RangeParms.Auto &&
			(m_RangeParms.Auto || m_Measurement.RangeParms.Range == m_RangeParms.Range));
	QVERIFY(m_Measurement.CommFormat == m_CommFormat);
	QCOMPARE(m_Measurement.Warnings.size(), 1ul);
	QCOMPARE(m_Measurement.Warnings[0].Code, THM1176_NO_ANGLE_CORRECTION_CODE);

	QCOMPARE(l_NotifyErrorListSpy.count(), 0);

    std::cout << "- Measured Immediate,10: B[] = (" << m_Measurement.Bx[0] << "..., N/A , " << m_Measurement.Bz[0] << "...) [T], "
    "Temp = N/A , Timestamp = " << m_Measurement.TimestampList[0] << std::endl;

} // THM1176IM_Test02_Measure::TestSetOperatingMode_Immediate

//////////////////////////////////////////////////////////////////////////
/// \test   Test THM1176 Instrument Manager: Test setting SetOperatingMode to Measure Triggered,N:
///	- Emit SetOperatingMode = Reset:
///		- Should receive NotifyOperatingMode = Reset, Idle
///	- Set SetTriggerParms to Triggered,1:
///		- Should not receive NotifyErrorList
///	- Emit SetOperatingMode = Measure:
///		- Should receive NotifyOperatingMode = Measure
///		- Should not receive NotifyErrorList
///	- Emit SendTrigger:
///		- Should receive NotifyOperatingMode = Idle
///		- Should receive NotifyMeasurement length 1
///		- Should not receive NotifyErrorList
///	- Set SetTriggerParms to Triggered,10:
///		- Should not receive NotifyErrorList
///	- Set SetOutputSelect to Bx, no By, Bz, no T, Time, 10:
///		- Should not receive NotifyErrorList
///	- Emit SetOperatingMode = Measure:
///		- Should receive NotifyOperatingMode = Measure
///		- Should not receive NotifyErrorList
///	- Emit SendTrigger 10x:
///		- Should receive NotifyOperatingMode = Idle
///		- Should receive NotifyMeasurement as requested
///		- Should not receive NotifyErrorList
///	- Emit SetOperatingMode = Measure:
///		- Should receive NotifyOperatingMode = Measure
///		- Should not receive NotifyErrorList
///	- Emit SendTrigger 5x, then emit SetOperatingMode = Idle:
///		- Should receive NotifyOperatingMode = Idle
///		- Should not receive NotifyMeasurement
///		- Should not receive NotifyErrorList
///	- Emit SendTrigger:
///		- Should receive NotifyErrorList
void THM1176IM_Test02_Measure::TestSetOperatingMode_Triggered(void)
{
	// Create  Signal Spies to retrieve measurement result, operating mode, and possible errors.
	QSignalSpy	l_NotifyMeasurementSpy(&Manager, SIGNAL(NotifyMeasurement(CMeasurement)));
	QSignalSpy	l_NotifyOperatingModeSpy(&Manager, SIGNAL(NotifyOperatingMode(eTHM1176OperatingMode)));
	QSignalSpy	l_NotifyErrorListSpy(&Manager, SIGNAL(NotifyErrorList(CErrorList)));

	//	- Emit SetOperatingMode = Reset:
	//		- Should receive NotifyOperatingMode = Reset, Idle
	Manager.SetOperatingMode(kTHM1176Reset);

	l_NotifyOperatingModeSpy.wait(THM1176_RESET_TIME);
	QVERIFY(l_NotifyOperatingModeSpy.count() > 0);
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176Reset);
	if (l_NotifyOperatingModeSpy.count() <= 0)
	{
		l_NotifyOperatingModeSpy.wait(THM1176_RESET_TIME);
		QCOMPARE(l_NotifyOperatingModeSpy.count(), 1);
	}
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176Idle);

	m_AveragingParms		= Manager.GetAveragingParms();
	m_Trigger				= Manager.GetTriggerParms();
	m_OutputSelect			= Manager.GetOutputSelect();
	m_SleepParm				= Manager.GetSleepParm();
	m_Units					= Manager.GetUnits();
	m_RangeParms			= Manager.GetRangeParms();
	m_CommFormat			= Manager.GetCommFormat();

    std::cout << "- Reset " << m_Identification.Model << ", S/N " << m_Identification.SerialNumber << std::endl;

	//	- Set SetTriggerParms to Triggered,1:
	//		- Should not receive NotifyErrorList
	m_Trigger.Source	= kInputTrigSrcBus;
	m_Trigger.Count		= 1;
	Manager.SetTriggerParms(m_Trigger);

	l_NotifyErrorListSpy.wait(THM1176_CHANGE_PARM_TIME);
	QCOMPARE(l_NotifyErrorListSpy.count(), 0);

	//	- Emit SetOperatingMode = Measure:
	//		- Should receive NotifyOperatingMode = Measure
	//		- Should not receive NotifyErrorList
	Manager.SetOperatingMode(kTHM1176Measure);

	l_NotifyOperatingModeSpy.wait(THM1176_MEASURE_TIME);
	QCOMPARE(l_NotifyOperatingModeSpy.count(), 1);
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176Measure);

	QCOMPARE(l_NotifyErrorListSpy.count(), 0);

	//	- Emit SendTrigger:
	//		- Should receive NotifyOperatingMode = Idle
	//		- Should receive NotifyMeasurement length 1
	//		- Should not receive NotifyErrorList
    QThread::currentThread()->msleep(100);
    Manager.SendTrigger();

	l_NotifyOperatingModeSpy.wait(THM1176_MEASURE_TIME);
	QCOMPARE(l_NotifyOperatingModeSpy.count(), 1);
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176Idle);

	QCOMPARE(l_NotifyMeasurementSpy.count(), 1);
	m_Arguments = l_NotifyMeasurementSpy.takeFirst();
	m_Measurement = qvariant_cast<CMeasurement> (m_Arguments.at(0));
	QCOMPARE(m_Measurement.Bx.size(), 1ul);
	QCOMPARE(m_Measurement.By.size(), 1ul);
	QCOMPARE(m_Measurement.Bz.size(), 1ul);
    QCOMPARE(m_Measurement.Units, MTL::kT);
	QVERIFY(m_Measurement.Temp != 0);
	QCOMPARE(m_Measurement.TimestampList.size(), 1ul);
	QVERIFY(m_Measurement.AveragingParms == m_AveragingParms);
	QCOMPARE(m_Measurement.TriggerParms.Source, m_Trigger.Source);
	QCOMPARE(m_Measurement.TriggerParms.Count, m_Trigger.Count);
	QCOMPARE(m_Measurement.TriggerParms.Period_s, 0.);
	QVERIFY(m_Measurement.OutputSelect == m_OutputSelect);
	QVERIFY(m_Measurement.SleepParm == m_SleepParm);
	QVERIFY(m_Measurement.RangeParms.Auto == m_RangeParms.Auto &&
			(m_RangeParms.Auto || m_Measurement.RangeParms.Range == m_RangeParms.Range));
	QVERIFY(m_Measurement.CommFormat == m_CommFormat);
	QCOMPARE(m_Measurement.Warnings.size(), 0ul);

	QCOMPARE(l_NotifyErrorListSpy.count(), 0);

    std::cout << "- Measured Triggered,1: B = (" << m_Measurement.Bx[0] << ", " << m_Measurement.By[0] << ", " << m_Measurement.Bz[0] << ") [T], "
    "Temp = " << m_Measurement.Temp << ", Timestamp = " << m_Measurement.TimestampList[0] << std::endl;

	//	- Set SetTriggerParms to Triggered,10:
	//		- Should not receive NotifyErrorList
	m_Trigger.Source	= kInputTrigSrcBus;
	m_Trigger.Count		= 10;
	Manager.SetTriggerParms(m_Trigger);

	l_NotifyErrorListSpy.wait(THM1176_CHANGE_PARM_TIME);
	QCOMPARE(l_NotifyErrorListSpy.count(), 0);

	//	- Set SetOutputSelect to Bx, no By, Bz, no T, Time, 10:
	//		- Should not receive NotifyErrorList
	m_OutputSelect.Bx				= true;
	m_OutputSelect.By				= false;
	m_OutputSelect.Bz				= true;
	m_OutputSelect.Temperature		= false;
	m_OutputSelect.Timestamp		= true;
	m_OutputSelect.NoMeasurements	= 10;
	Manager.SetOutputSelect(m_OutputSelect);

	l_NotifyErrorListSpy.wait(THM1176_CHANGE_PARM_TIME);
	QCOMPARE(l_NotifyErrorListSpy.count(), 0);

	//	- Emit SetOperatingMode = Measure:
	//		- Should receive NotifyOperatingMode = Measure
	//		- Should not receive NotifyErrorList
	Manager.SetOperatingMode(kTHM1176Measure);

	l_NotifyOperatingModeSpy.wait(THM1176_MEASURE_TIME);
	QCOMPARE(l_NotifyOperatingModeSpy.count(), 1);
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176Measure);

	QCOMPARE(l_NotifyErrorListSpy.count(), 0);

	//	- Emit SendTrigger 10x:
	//		- Should receive NotifyOperatingMode = Idle
	//		- Should receive NotifyMeasurement as requested
	//		- Should not receive NotifyErrorList
    QThread::currentThread()->msleep(100);
    for (int i = 0; i < 10; i++)
	{
		Manager.SendTrigger();
        QThread::currentThread()->msleep(100);
	}

	l_NotifyOperatingModeSpy.wait(THM1176_MEASURE_TIME);
	QCOMPARE(l_NotifyOperatingModeSpy.count(), 1);
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176Idle);

	QCOMPARE(l_NotifyMeasurementSpy.count(), 1);
	m_Arguments = l_NotifyMeasurementSpy.takeFirst();
	m_Measurement = qvariant_cast<CMeasurement> (m_Arguments.at(0));
	QCOMPARE(m_Measurement.Bx.size(), 10ul);
	QCOMPARE(m_Measurement.By.size(), 0ul);
	QCOMPARE(m_Measurement.Bz.size(), 10ul);
    QCOMPARE(m_Measurement.Units, MTL::kT);
	QVERIFY(m_Measurement.Temp == 0);
	QCOMPARE(m_Measurement.TimestampList.size(), 10ul);
	QVERIFY(m_Measurement.AveragingParms == m_AveragingParms);
	QCOMPARE(m_Measurement.TriggerParms.Source, m_Trigger.Source);
	QCOMPARE(m_Measurement.TriggerParms.Count, m_Trigger.Count);
    QVERIFY(m_Measurement.TriggerParms.Period_s > 80e-3 && m_Measurement.TriggerParms.Period_s < 120e-3);
	QVERIFY(m_Measurement.OutputSelect == m_OutputSelect);
	QVERIFY(m_Measurement.SleepParm == m_SleepParm);
	QVERIFY(m_Measurement.RangeParms.Auto == m_RangeParms.Auto &&
			(m_RangeParms.Auto || m_Measurement.RangeParms.Range == m_RangeParms.Range));
	QVERIFY(m_Measurement.CommFormat == m_CommFormat);
	QCOMPARE(m_Measurement.Warnings.size(), 1ul);
	QCOMPARE(m_Measurement.Warnings[0].Code, THM1176_NO_ANGLE_CORRECTION_CODE);

	QCOMPARE(l_NotifyErrorListSpy.count(), 0);

    std::cout << "- Measured Triggered,10: B[] = (" << m_Measurement.Bx[0] << "..., N/A , " << m_Measurement.Bz[0] << "...) [T], "
    "Temp = N/A , TimestampList = " << m_Measurement.TimestampList[0] << "..." << std::endl;

	l_NotifyErrorListSpy.wait(THM1176_CHANGE_PARM_TIME);
	QCOMPARE(l_NotifyErrorListSpy.count(), 0);

	//	- Emit SetOperatingMode = Measure:
	//		- Should receive NotifyOperatingMode = Measure
	//		- Should not receive NotifyErrorList
	Manager.SetOperatingMode(kTHM1176Measure);

	l_NotifyOperatingModeSpy.wait(THM1176_MEASURE_TIME);
	QCOMPARE(l_NotifyOperatingModeSpy.count(), 1);
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176Measure);

	QCOMPARE(l_NotifyErrorListSpy.count(), 0);

	//	- Emit SendTrigger 5x, then emit SetOperatingMode = Idle:
	//		- Should receive NotifyOperatingMode = Idle
	//		- Should not receive NotifyMeasurement
	//		- Should not receive NotifyErrorList
    QThread::currentThread()->msleep(100);
    for (int i = 0; i < 5; i++)
	{
		Manager.SendTrigger();
        QThread::currentThread()->msleep(100);
	}
	Manager.SetOperatingMode(kTHM1176Idle);

	l_NotifyOperatingModeSpy.wait(THM1176_MEASURE_TIME);
	QCOMPARE(l_NotifyOperatingModeSpy.count(), 1);
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176Idle);

	QCOMPARE(l_NotifyMeasurementSpy.count(), 0);
	QCOMPARE(l_NotifyErrorListSpy.count(), 0);

    std::cout << "- Measured Triggered,10, sent 5 triggers, and aborted" << std::endl;

	//	- Emit SendTrigger:
	//		- Should receive NotifyErrorList
    QThread::currentThread()->msleep(100);
    Manager.SendTrigger();

	l_NotifyErrorListSpy.wait(THM1176_MEASURE_TIME);
	QCOMPARE(l_NotifyErrorListSpy.count(), 1);
	m_Arguments = l_NotifyErrorListSpy.takeFirst();
	m_LatestErrors = qvariant_cast<CErrorList>(m_Arguments.at(0));
	QCOMPARE(m_LatestErrors.size(), 1ul);

    std::cout << "- Sending spurious trigger returned error: "
	<< m_LatestErrors[0].Code << ", "
	<< m_LatestErrors[0].Context << ": "
    << m_LatestErrors[0].Description << std::endl;

} // THM1176IM_Test02_Measure::TestSetOperatingMode_Triggered

//////////////////////////////////////////////////////////////////////////
/// \test   Test THM1176 Instrument Manager: Test setting SetOperatingMode to Measure Timed,N:
///	- Emit SetOperatingMode = Reset:
///		- Should receive NotifyOperatingMode = Reset, Idle
///	- Set SetTriggerParms to Timed,0.1,1:
///		- Should not receive NotifyErrorList
///	- Emit SetOperatingMode = Measure:
///		- Should receive NotifyOperatingMode = Measure, Idle
///		- Should receive NotifyMeasurement length 1
///		- Should not receive NotifyErrorList
///	- Set SetTriggerParms to Timed,0.1,10:
///		- Should not receive NotifyErrorList
///	- Set SetOutputSelect to Bx, no By, Bz, no T, Time, 10:
///		- Should not receive NotifyErrorList
///	- Emit SetOperatingMode = Measure:
///		- Should receive NotifyOperatingMode = Measure, Idle
///		- Should receive NotifyMeasurement as requested
///		- Should not receive NotifyErrorList
void THM1176IM_Test02_Measure::TestSetOperatingMode_Timed(void)
{
	// Create  Signal Spies to retrieve measurement result, operating mode, and possible errors.
	QSignalSpy	l_NotifyMeasurementSpy(&Manager, SIGNAL(NotifyMeasurement(CMeasurement)));
	QSignalSpy	l_NotifyOperatingModeSpy(&Manager, SIGNAL(NotifyOperatingMode(eTHM1176OperatingMode)));
	QSignalSpy	l_NotifyErrorListSpy(&Manager, SIGNAL(NotifyErrorList(CErrorList)));

	//	- Emit SetOperatingMode = Reset:
	//		- Should receive NotifyOperatingMode = Reset, Idle
	Manager.SetOperatingMode(kTHM1176Reset);

	l_NotifyOperatingModeSpy.wait(THM1176_RESET_TIME);
	QVERIFY(l_NotifyOperatingModeSpy.count() > 0);
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176Reset);
	if (l_NotifyOperatingModeSpy.count() <= 0)
	{
		l_NotifyOperatingModeSpy.wait(THM1176_RESET_TIME);
		QCOMPARE(l_NotifyOperatingModeSpy.count(), 1);
	}
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176Idle);

	m_AveragingParms		= Manager.GetAveragingParms();
	m_Trigger				= Manager.GetTriggerParms();
	m_OutputSelect			= Manager.GetOutputSelect();
	m_SleepParm				= Manager.GetSleepParm();
	m_Units					= Manager.GetUnits();
	m_RangeParms			= Manager.GetRangeParms();
	m_CommFormat			= Manager.GetCommFormat();

    std::cout << "- Reset " << m_Identification.Model << ", S/N " << m_Identification.SerialNumber << std::endl;

	//	- Set SetTriggerParms to Timed,0.1,1:
	//		- Should not receive NotifyErrorList
	m_Trigger.Source	= kInputTrigSrcTimer;
	m_Trigger.Period_s	= 0.1;
	m_Trigger.Count		= 1;
	Manager.SetTriggerParms(m_Trigger);

	l_NotifyErrorListSpy.wait(THM1176_CHANGE_PARM_TIME);
	QCOMPARE(l_NotifyErrorListSpy.count(), 0);

	//	- Emit SetOperatingMode = Measure:
	//		- Should receive NotifyOperatingMode = Measure, Idle
	//		- Should receive NotifyMeasurement length 1
	//		- Should not receive NotifyErrorList
	Manager.SetOperatingMode(kTHM1176Measure);

	l_NotifyOperatingModeSpy.wait(THM1176_MEASURE_TIME);
	QVERIFY(l_NotifyOperatingModeSpy.count() > 0);
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176Measure);
	if (l_NotifyOperatingModeSpy.count() <= 0)
	{
		l_NotifyOperatingModeSpy.wait(THM1176_MEASURE_TIME);
		QCOMPARE(l_NotifyOperatingModeSpy.count(), 1);
	}
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176Idle);

	QCOMPARE(l_NotifyMeasurementSpy.count(), 1);
	m_Arguments = l_NotifyMeasurementSpy.takeFirst();
	m_Measurement = qvariant_cast<CMeasurement> (m_Arguments.at(0));
	QCOMPARE(m_Measurement.Bx.size(), 1ul);
	QCOMPARE(m_Measurement.By.size(), 1ul);
	QCOMPARE(m_Measurement.Bz.size(), 1ul);
    QCOMPARE(m_Measurement.Units, MTL::kT);
	QVERIFY(m_Measurement.Temp != 0);
	QCOMPARE(m_Measurement.TimestampList.size(), 1ul);
	QVERIFY(m_Measurement.AveragingParms == m_AveragingParms);
	QCOMPARE(m_Measurement.TriggerParms.Source, m_Trigger.Source);
	QCOMPARE(m_Measurement.TriggerParms.Count, m_Trigger.Count);
	QCOMPARE(m_Measurement.TriggerParms.Period_s, m_Trigger.Period_s);
	QVERIFY(m_Measurement.OutputSelect == m_OutputSelect);
	QVERIFY(m_Measurement.SleepParm == m_SleepParm);
	QVERIFY(m_Measurement.RangeParms.Auto == m_RangeParms.Auto &&
			(m_RangeParms.Auto || m_Measurement.RangeParms.Range == m_RangeParms.Range));
	QVERIFY(m_Measurement.CommFormat == m_CommFormat);
	QCOMPARE(m_Measurement.Warnings.size(), 0ul);

	QCOMPARE(l_NotifyErrorListSpy.count(), 0);

    std::cout << "- Measured Timed,0.1,1: B = (" << m_Measurement.Bx[0] << ", " << m_Measurement.By[0] << ", " << m_Measurement.Bz[0] << ") [T], "
    "Temp = " << m_Measurement.Temp << ", Timestamp = " << m_Measurement.TimestampList[0] << std::endl;

	//	- Set SetTriggerParms to Timed,0.1,10:
	//		- Should not receive NotifyErrorList
	m_Trigger.Source	= kInputTrigSrcTimer;
	m_Trigger.Period_s	= 0.1;
	m_Trigger.Count		= 10;
	Manager.SetTriggerParms(m_Trigger);

	l_NotifyErrorListSpy.wait(THM1176_CHANGE_PARM_TIME);
	QCOMPARE(l_NotifyErrorListSpy.count(), 0);

	//	- Set SetOutputSelect to Bx, no By, Bz, no T, Time, 10:
	//		- Should not receive NotifyErrorList
	m_OutputSelect.Bx				= true;
	m_OutputSelect.By				= false;
	m_OutputSelect.Bz				= true;
	m_OutputSelect.Temperature		= false;
	m_OutputSelect.Timestamp		= true;
	m_OutputSelect.NoMeasurements	= 10;
	Manager.SetOutputSelect(m_OutputSelect);

	l_NotifyErrorListSpy.wait(THM1176_CHANGE_PARM_TIME);
	QCOMPARE(l_NotifyErrorListSpy.count(), 0);

	//	- Emit SetOperatingMode = Measure:
	//		- Should receive NotifyOperatingMode = Measure, Idle
	//		- Should receive NotifyMeasurement as requested
	//		- Should not receive NotifyErrorList
	Manager.SetOperatingMode(kTHM1176Measure);

	l_NotifyOperatingModeSpy.wait(THM1176_MEASURE_TIME);
	QVERIFY(l_NotifyOperatingModeSpy.count() > 0);
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176Measure);
	if (l_NotifyOperatingModeSpy.count() <= 0)
	{
		l_NotifyOperatingModeSpy.wait(THM1176_MEASURE_TIME);
		QCOMPARE(l_NotifyOperatingModeSpy.count(), 1);
	}
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176Idle);

	QCOMPARE(l_NotifyMeasurementSpy.count(), 1);
	m_Arguments = l_NotifyMeasurementSpy.takeFirst();
	m_Measurement = qvariant_cast<CMeasurement> (m_Arguments.at(0));
	QCOMPARE(m_Measurement.Bx.size(), 10ul);
	QCOMPARE(m_Measurement.By.size(), 0ul);
	QCOMPARE(m_Measurement.Bz.size(), 10ul);
    QCOMPARE(m_Measurement.Units, MTL::kT);
	QVERIFY(m_Measurement.Temp == 0);
	QCOMPARE(m_Measurement.TimestampList.size(), 10ul);
	QVERIFY(m_Measurement.AveragingParms == m_AveragingParms);
	QCOMPARE(m_Measurement.TriggerParms.Source, m_Trigger.Source);
	QCOMPARE(m_Measurement.TriggerParms.Count, m_Trigger.Count);
	QCOMPARE(m_Measurement.TriggerParms.Period_s, m_Trigger.Period_s);
	QVERIFY(m_Measurement.OutputSelect == m_OutputSelect);
	QVERIFY(m_Measurement.SleepParm == m_SleepParm);
	QVERIFY(m_Measurement.RangeParms.Auto == m_RangeParms.Auto &&
			(m_RangeParms.Auto || m_Measurement.RangeParms.Range == m_RangeParms.Range));
	QVERIFY(m_Measurement.CommFormat == m_CommFormat);
	QCOMPARE(m_Measurement.Warnings.size(), 1ul);
	QCOMPARE(m_Measurement.Warnings[0].Code, THM1176_NO_ANGLE_CORRECTION_CODE);

	QCOMPARE(l_NotifyErrorListSpy.count(), 0);

    std::cout << "- Measured Timed,0.1,10: B[] = (" << m_Measurement.Bx[0] << "..., N/A , " << m_Measurement.Bz[0] << "...) [T], "
    "Temp = N/A , TimestampList[] = " << m_Measurement.TimestampList[0] << "..." << std::endl;

} // THM1176IM_Test02_Measure::TestSetOperatingMode_Timed

//////////////////////////////////////////////////////////////////////////
/// \test   Test THM1176 Instrument Manager: Test setting SetOperatingMode to Measure Timed,0.0005, 4000, CommFormat to Integer:
///	- Emit SetOperatingMode = Reset:
///		- Should receive NotifyOperatingMode = Reset, Idle
///	- Set SetTriggerParms to Timed,0.0005,1:
///		- Should not receive NotifyErrorList
/// - Set AveragingParms to 1
///     - Should not receive NotifyErrorList
/// - Set CommFormat to Binary
///     - Should not receive NotifyErrorList
///	- Emit SetOperatingMode = Measure:
///		- Should receive NotifyOperatingMode = Measure, Idle
///		- Should receive NotifyMeasurement length 1
///		- Should not receive NotifyErrorList
///     - Should take roughly 2-4 seconds
void THM1176IM_Test02_Measure::TestSetOperatingMode_TimedLong(void)
{
    // Create  Signal Spies to retrieve measurement result, operating mode, and possible errors.
    QSignalSpy	l_NotifyMeasurementSpy(&Manager, SIGNAL(NotifyMeasurement(CMeasurement)));
    QSignalSpy	l_NotifyOperatingModeSpy(&Manager, SIGNAL(NotifyOperatingMode(eTHM1176OperatingMode)));
    QSignalSpy	l_NotifyErrorListSpy(&Manager, SIGNAL(NotifyErrorList(CErrorList)));

    //	- Emit SetOperatingMode = Reset:
    //		- Should receive NotifyOperatingMode = Reset, Idle
    Manager.SetOperatingMode(kTHM1176Reset);

    l_NotifyOperatingModeSpy.wait(THM1176_RESET_TIME);
    QVERIFY(l_NotifyOperatingModeSpy.count() > 0);
    m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
    m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
    QCOMPARE(m_OperatingMode, kTHM1176Reset);
    if (l_NotifyOperatingModeSpy.count() <= 0)
    {
        l_NotifyOperatingModeSpy.wait(THM1176_RESET_TIME);
        QCOMPARE(l_NotifyOperatingModeSpy.count(), 1);
    }
    m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
    m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
    QCOMPARE(m_OperatingMode, kTHM1176Idle);

    m_AveragingParms		= Manager.GetAveragingParms();
    m_Trigger				= Manager.GetTriggerParms();
    m_OutputSelect			= Manager.GetOutputSelect();
    m_SleepParm				= Manager.GetSleepParm();
    m_Units					= Manager.GetUnits();
    m_RangeParms			= Manager.GetRangeParms();
    m_CommFormat			= Manager.GetCommFormat();

    std::cout << "- Reset " << m_Identification.Model << ", S/N " << m_Identification.SerialNumber << std::endl;

    //	- Set SetTriggerParms to Timed,0.0005,1:
    //		- Should not receive NotifyErrorList
    m_Trigger.Source	= kInputTrigSrcTimer;
    m_Trigger.Period_s	= 0.0005;
    m_Trigger.Count		= 4000;
    Manager.SetTriggerParms(m_Trigger);

    l_NotifyErrorListSpy.wait(THM1176_CHANGE_PARM_TIME);
    QCOMPARE(l_NotifyErrorListSpy.count(), 0);

    // - Set AveragingParms to 1
    //     - Should not receive NotifyErrorList
    m_AveragingParms.NoPoints = 1;
    Manager.SetAveragingParms(m_AveragingParms);

    l_NotifyErrorListSpy.wait(THM1176_CHANGE_PARM_TIME);
    QCOMPARE(l_NotifyErrorListSpy.count(), 0);

    //	- Set SetOutputSelect to Bx, By, Bz, T, Time, 4000:
    //		- Should not receive NotifyErrorList
    m_OutputSelect.Bx				= true;
    m_OutputSelect.By				= true;
    m_OutputSelect.Bz				= true;
    m_OutputSelect.Temperature		= true;
    m_OutputSelect.Timestamp		= true;
    m_OutputSelect.NoMeasurements	= 4000;
    Manager.SetOutputSelect(m_OutputSelect);

    l_NotifyErrorListSpy.wait(THM1176_CHANGE_PARM_TIME);
    QCOMPARE(l_NotifyErrorListSpy.count(), 0);

    // - Set CommFormat to Binary
    //     - Should not receive NotifyErrorList
    m_CommFormat = kComFormatInteger;
    Manager.SetCommFormat(m_CommFormat);

    l_NotifyErrorListSpy.wait(THM1176_CHANGE_PARM_TIME);
    QCOMPARE(l_NotifyErrorListSpy.count(), 0);

    //	- Emit SetOperatingMode = Measure:
    //		- Should receive NotifyOperatingMode = Measure, Idle
    //		- Should receive NotifyMeasurement as requested
    //		- Should not receive NotifyErrorList
    //      - Should take roughly 2-4 seconds
    auto l_StartTime = std::chrono::high_resolution_clock::now();
    Manager.SetOperatingMode(kTHM1176Measure);

    l_NotifyOperatingModeSpy.wait(THM1176_MEASURE_TIME);
    QVERIFY(l_NotifyOperatingModeSpy.count() > 0);
    m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
    m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
    QCOMPARE(m_OperatingMode, kTHM1176Measure);
    if (l_NotifyOperatingModeSpy.count() <= 0)
    {
        l_NotifyOperatingModeSpy.wait(THM1176_MEASURE_TIME);
        QCOMPARE(l_NotifyOperatingModeSpy.count(), 1);
    }
    m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
    m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
    QCOMPARE(m_OperatingMode, kTHM1176Idle);

    auto l_StopTime = std::chrono::high_resolution_clock::now();

    QCOMPARE(l_NotifyMeasurementSpy.count(), 1);
    m_Arguments = l_NotifyMeasurementSpy.takeFirst();
    m_Measurement = qvariant_cast<CMeasurement> (m_Arguments.at(0));
    QCOMPARE(m_Measurement.Bx.size(), 4000ul);
    QCOMPARE(m_Measurement.By.size(), 4000ul);
    QCOMPARE(m_Measurement.Bz.size(), 4000ul);
    QCOMPARE(m_Measurement.Units, MTL::kT);
    QVERIFY(m_Measurement.Temp > 0);
    QCOMPARE(m_Measurement.TimestampList.size(), 4000ul);
    QVERIFY(m_Measurement.AveragingParms == m_AveragingParms);
    QCOMPARE(m_Measurement.TriggerParms.Source, m_Trigger.Source);
    QCOMPARE(m_Measurement.TriggerParms.Count, m_Trigger.Count);
    QCOMPARE(m_Measurement.TriggerParms.Period_s, m_Trigger.Period_s);
    QVERIFY(m_Measurement.OutputSelect == m_OutputSelect);
    QVERIFY(m_Measurement.SleepParm == m_SleepParm);
    QVERIFY(m_Measurement.RangeParms.Auto == m_RangeParms.Auto &&
            (m_RangeParms.Auto || m_Measurement.RangeParms.Range == m_RangeParms.Range));
    QVERIFY(m_Measurement.CommFormat == m_CommFormat);
    QCOMPARE(m_Measurement.Warnings.size(), 0ul);

    QCOMPARE(l_NotifyErrorListSpy.count(), 0);

    auto l_TimeElapsed = std::chrono::duration_cast<std::chrono::milliseconds>(l_StopTime - l_StartTime).count();
    QVERIFY(l_TimeElapsed > 2000 && l_TimeElapsed < 4000);

    std::cout << "- Measured Timed,0.0005,4000 B[] = (" << m_Measurement.Bx[0] << "..., " << m_Measurement.By[0] << "..., " << m_Measurement.Bz[0] << "...) [T], "
    "Temp = " << m_Measurement.Temp << ", TimestampList[] = " << m_Measurement.TimestampList[0] << "..." << std::endl;

} // THM1176IM_Test02_Measure::TestSetOperatingMode_TimedLong

//////////////////////////////////////////////////////////////////////////
/// \test   Test THM1176 Instrument Manager: Test setting SetOperatingMode to Measure Immediate,Continuous:
///	- Emit SetOperatingMode = Reset:
///		- Should receive NotifyOperatingMode = Reset, Idle
///	- Set SetTriggerParms to Immediate,1:
///		- Should not receive NotifyErrorList
///	- Emit SetOperatingMode = Measure,Continuous:
///		- Should receive NotifyOperatingMode = Measure,Continuous
///		- 10x: Should receive NotifyMeasurement length 1
///		- Should not receive fatal errors in NotifyErrorList
///	- Emit SetOperatingMode = Idle:
///		- Should receive NotifyOperatingMode = Idle
///		- Should not receive NotifyErrorList
void THM1176IM_Test02_Measure::TestSetOperatingMode_ImmediateContinuous(void)
{
	// Create  Signal Spies to retrieve measurement result, operating mode, and possible errors.
	QSignalSpy	l_NotifyMeasurementSpy(&Manager, SIGNAL(NotifyMeasurement(CMeasurement)));
	QSignalSpy	l_NotifyOperatingModeSpy(&Manager, SIGNAL(NotifyOperatingMode(eTHM1176OperatingMode)));
	QSignalSpy	l_NotifyErrorListSpy(&Manager, SIGNAL(NotifyErrorList(CErrorList)));

	//	- Emit SetOperatingMode = Reset:
	//		- Should receive NotifyOperatingMode = Reset, Idle
	Manager.SetOperatingMode(kTHM1176Reset);

	l_NotifyOperatingModeSpy.wait(THM1176_RESET_TIME);
	QVERIFY(l_NotifyOperatingModeSpy.count() > 0);
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176Reset);
	if (l_NotifyOperatingModeSpy.count() <= 0)
	{
		l_NotifyOperatingModeSpy.wait(THM1176_RESET_TIME);
		QCOMPARE(l_NotifyOperatingModeSpy.count(), 1);
	}
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176Idle);

	m_AveragingParms		= Manager.GetAveragingParms();
	m_Trigger				= Manager.GetTriggerParms();
	m_OutputSelect			= Manager.GetOutputSelect();
	m_SleepParm				= Manager.GetSleepParm();
	m_Units					= Manager.GetUnits();
	m_RangeParms			= Manager.GetRangeParms();
	m_CommFormat			= Manager.GetCommFormat();

    std::cout << "- Reset " << m_Identification.Model << ", S/N " << m_Identification.SerialNumber << std::endl;

	//	- Set SetTriggerParms to Immediate,1:
	//		- Should not receive NotifyErrorList
	m_Trigger.Source	= kInputTrigSrcImmediate;
	m_Trigger.Period_s	= 0.1;
	m_Trigger.Count		= 1;
	Manager.SetTriggerParms(m_Trigger);

	l_NotifyErrorListSpy.wait(THM1176_CHANGE_PARM_TIME);
	QCOMPARE(l_NotifyErrorListSpy.count(), 0);

	//	- Emit SetOperatingMode = Measure,Continuous:
	//		- Should receive NotifyOperatingMode = Measure,Continuous
	//		- 10x: Should receive NotifyMeasurement length 1
	//		- Should not receive NotifyErrorList
	Manager.SetOperatingMode(kTHM1176MeasureContinuously);

	l_NotifyOperatingModeSpy.wait(THM1176_MEASURE_TIME);
	QCOMPARE(l_NotifyOperatingModeSpy.count(), 1);
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176MeasureContinuously);

	for (int i = 0; i < 10; i++)
	{
		l_NotifyMeasurementSpy.wait(THM1176_MEASURE_TIME);
		QVERIFY(l_NotifyMeasurementSpy.count() > 0);
		m_Arguments = l_NotifyMeasurementSpy.takeFirst();
		m_Measurement = qvariant_cast<CMeasurement> (m_Arguments.at(0));
		QCOMPARE(m_Measurement.Bx.size(), 1ul);
		QCOMPARE(m_Measurement.By.size(), 1ul);
		QCOMPARE(m_Measurement.Bz.size(), 1ul);
        QCOMPARE(m_Measurement.Units, MTL::kT);
		QVERIFY(m_Measurement.Temp != 0);
		QCOMPARE(m_Measurement.TimestampList.size(), 1ul);
		QVERIFY(m_Measurement.AveragingParms == m_AveragingParms);
		QCOMPARE(m_Measurement.TriggerParms.Source, m_Trigger.Source);
		QCOMPARE(m_Measurement.TriggerParms.Count, m_Trigger.Count);
		QCOMPARE(m_Measurement.TriggerParms.Period_s, PeriodOfImmediateTrigger(m_AveragingParms));
		QVERIFY(m_Measurement.OutputSelect == m_OutputSelect);
		QVERIFY(m_Measurement.SleepParm == m_SleepParm);
		QVERIFY(m_Measurement.RangeParms.Auto == m_RangeParms.Auto &&
				(m_RangeParms.Auto || m_Measurement.RangeParms.Range == m_RangeParms.Range));
		QVERIFY(m_Measurement.CommFormat == m_CommFormat);

        std::cout << "- Measured Immediate,1,Continuous: B = (" << m_Measurement.Bx[0] << ", " << m_Measurement.By[0] << ", " << m_Measurement.Bz[0] << ") [T], "
		"Temp = " << m_Measurement.Temp << ", Timestamp = " << m_Measurement.TimestampList[0] << ", " <<
        m_Measurement.Warnings.size() << " Warnings" << std::endl;
    }

	QCOMPARE(l_NotifyErrorListSpy.count(), 0);

	//	- Emit SetOperatingMode = Idle:
	//		- Should receive NotifyOperatingMode = Idle
	//		- Should not receive NotifyErrorList
	Manager.SetOperatingMode(kTHM1176Idle);

	l_NotifyOperatingModeSpy.wait(THM1176_MEASURE_TIME);
	QCOMPARE(l_NotifyOperatingModeSpy.count(), 1);
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176Idle);

	QCOMPARE(l_NotifyErrorListSpy.count(), 0);

} // THM1176IM_Test02_Measure::TestSetOperatingMode_TimedLong

//////////////////////////////////////////////////////////////////////////
/// \test   Test THM1176 Instrument Manager: Test setting SetOperatingMode to Measure Timed,Continuous:
///	- Emit SetOperatingMode = Reset:
///		- Should receive NotifyOperatingMode = Reset, Idle
///	- Set SetTriggerParms to Timed,0.1,1:
///		- Should not receive NotifyErrorList
///	- Emit SetOperatingMode = Measure,Continuous:
///		- Should receive NotifyOperatingMode = Measure,Continuous
///		- 10x: Should receive NotifyMeasurement length 1
///		- Should not receive fatal errors in NotifyErrorList
///	- Emit SetOperatingMode = Idle:
///		- Should receive NotifyOperatingMode = Idle
///		- Should not receive NotifyErrorList
void THM1176IM_Test02_Measure::TestSetOperatingMode_TimedContinuous(void)
{
	// Create  Signal Spies to retrieve measurement result, operating mode, and possible errors.
	QSignalSpy	l_NotifyMeasurementSpy(&Manager, SIGNAL(NotifyMeasurement(CMeasurement)));
	QSignalSpy	l_NotifyOperatingModeSpy(&Manager, SIGNAL(NotifyOperatingMode(eTHM1176OperatingMode)));
	QSignalSpy	l_NotifyErrorListSpy(&Manager, SIGNAL(NotifyErrorList(CErrorList)));

	//	- Emit SetOperatingMode = Reset:
	//		- Should receive NotifyOperatingMode = Reset, Idle
	Manager.SetOperatingMode(kTHM1176Reset);

	l_NotifyOperatingModeSpy.wait(THM1176_RESET_TIME);
	QVERIFY(l_NotifyOperatingModeSpy.count() > 0);
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176Reset);
	if (l_NotifyOperatingModeSpy.count() <= 0)
	{
		l_NotifyOperatingModeSpy.wait(THM1176_RESET_TIME);
		QCOMPARE(l_NotifyOperatingModeSpy.count(), 1);
	}
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176Idle);

	m_AveragingParms		= Manager.GetAveragingParms();
	m_Trigger				= Manager.GetTriggerParms();
	m_OutputSelect			= Manager.GetOutputSelect();
	m_SleepParm				= Manager.GetSleepParm();
	m_Units					= Manager.GetUnits();
	m_RangeParms			= Manager.GetRangeParms();
	m_CommFormat			= Manager.GetCommFormat();

    std::cout << "- Reset " << m_Identification.Model << ", S/N " << m_Identification.SerialNumber << std::endl;

	//	- Set SetTriggerParms to Timed,0.1,1:
	//		- Should not receive NotifyErrorList
	m_Trigger.Source	= kInputTrigSrcTimer;
	m_Trigger.Period_s	= 0.1;
	m_Trigger.Count		= 1;
	Manager.SetTriggerParms(m_Trigger);

	l_NotifyErrorListSpy.wait(THM1176_CHANGE_PARM_TIME);
	QCOMPARE(l_NotifyErrorListSpy.count(), 0);

	//	- Emit SetOperatingMode = Measure,Continuous:
	//		- Should receive NotifyOperatingMode = Measure,Continuous
	//		- 10x: Should receive NotifyMeasurement length 1
	//		- Should not receive NotifyErrorList
	Manager.SetOperatingMode(kTHM1176MeasureContinuously);

	l_NotifyOperatingModeSpy.wait(THM1176_MEASURE_TIME);
	QCOMPARE(l_NotifyOperatingModeSpy.count(), 1);
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176MeasureContinuously);

	for (int i = 0; i < 10; i++)
	{
		l_NotifyMeasurementSpy.wait(THM1176_MEASURE_TIME);
        QThread::currentThread()->msleep(100);

		QVERIFY(l_NotifyMeasurementSpy.count() > 0);
		m_Arguments = l_NotifyMeasurementSpy.takeFirst();
		m_Measurement = qvariant_cast<CMeasurement> (m_Arguments.at(0));
		QCOMPARE(m_Measurement.Bx.size(), 1ul);
		QCOMPARE(m_Measurement.By.size(), 1ul);
		QCOMPARE(m_Measurement.Bz.size(), 1ul);
        QCOMPARE(m_Measurement.Units, MTL::kT);
		QVERIFY(m_Measurement.Temp != 0);
		QCOMPARE(m_Measurement.TimestampList.size(), 1ul);
		QVERIFY(m_Measurement.AveragingParms == m_AveragingParms);
		QCOMPARE(m_Measurement.TriggerParms.Source, m_Trigger.Source);
		QCOMPARE(m_Measurement.TriggerParms.Count, m_Trigger.Count);
		QCOMPARE(m_Measurement.TriggerParms.Period_s, m_Trigger.Period_s);
		QVERIFY(m_Measurement.OutputSelect == m_OutputSelect);
		QVERIFY(m_Measurement.SleepParm == m_SleepParm);
		QVERIFY(m_Measurement.RangeParms.Auto == m_RangeParms.Auto &&
				(m_RangeParms.Auto || m_Measurement.RangeParms.Range == m_RangeParms.Range));
		QVERIFY(m_Measurement.CommFormat == m_CommFormat);

        std::cout << "- Measured Timed,0.1,1,Continuous: B = (" << m_Measurement.Bx[0] << ", " << m_Measurement.By[0] << ", " << m_Measurement.Bz[0] << ") [T], "
		"Temp = " << m_Measurement.Temp << ", Timestamp = " << m_Measurement.TimestampList[0] << ", " <<
        m_Measurement.Warnings.size() << " Warnings" << std::endl;
    }

	QCOMPARE(l_NotifyErrorListSpy.count(), 0);

	//	- Emit SetOperatingMode = Idle:
	//		- Should receive NotifyOperatingMode = Idle
	//		- Should not receive NotifyErrorList
	Manager.SetOperatingMode(kTHM1176Idle);

	l_NotifyOperatingModeSpy.wait(THM1176_MEASURE_TIME);
	QCOMPARE(l_NotifyOperatingModeSpy.count(), 1);
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176Idle);

	QCOMPARE(l_NotifyErrorListSpy.count(), 0);

} // THM1176IM_Test02_Measure::TestSetOperatingMode_TimedContinuous

//////////////////////////////////////////////////////////////////////////
/// \test   Test THM1176 Instrument Manager: Test setting SetOperatingMode to Measure Triggered,Continuous:
///	- Emit SetOperatingMode = Reset:
///		- Should receive NotifyOperatingMode = Reset, Idle
///	- Set SetTriggerParms to Bus,1:
///		- Should not receive NotifyErrorList
///	- Emit SetOperatingMode = Measure,Continuous:
///		- Should receive NotifyOperatingMode = Measure,Continuous
///	Send 10 triggers:
///		- 10x: Should receive NotifyMeasurement length 1
///		- Should not receive fatal errors in NotifyErrorList
///	- Emit SetOperatingMode = Idle:
///		- Should receive NotifyOperatingMode = Idle
///		- Should not receive NotifyErrorList
void THM1176IM_Test02_Measure::TestSetOperatingMode_TriggeredContinuous(void)
{
	// Create  Signal Spies to retrieve measurement result, operating mode, and possible errors.
	QSignalSpy	l_NotifyMeasurementSpy(&Manager, SIGNAL(NotifyMeasurement(CMeasurement)));
	QSignalSpy	l_NotifyOperatingModeSpy(&Manager, SIGNAL(NotifyOperatingMode(eTHM1176OperatingMode)));
	QSignalSpy	l_NotifyErrorListSpy(&Manager, SIGNAL(NotifyErrorList(CErrorList)));

	//	- Emit SetOperatingMode = Reset:
	//		- Should receive NotifyOperatingMode = Reset, Idle
	Manager.SetOperatingMode(kTHM1176Reset);

	l_NotifyOperatingModeSpy.wait(THM1176_RESET_TIME);
	QVERIFY(l_NotifyOperatingModeSpy.count() > 0);
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176Reset);
	if (l_NotifyOperatingModeSpy.count() <= 0)
	{
		l_NotifyOperatingModeSpy.wait(THM1176_RESET_TIME);
		QCOMPARE(l_NotifyOperatingModeSpy.count(), 1);
	}
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176Idle);

	m_AveragingParms		= Manager.GetAveragingParms();
	m_Trigger				= Manager.GetTriggerParms();
	m_OutputSelect			= Manager.GetOutputSelect();
	m_SleepParm				= Manager.GetSleepParm();
	m_Units					= Manager.GetUnits();
	m_RangeParms			= Manager.GetRangeParms();
	m_CommFormat			= Manager.GetCommFormat();

    std::cout << "- Reset " << m_Identification.Model << ", S/N " << m_Identification.SerialNumber << std::endl;

	//	- Set SetTriggerParms to Bus,1:
	//		- Should not receive NotifyErrorList
	m_Trigger.Source	= kInputTrigSrcBus;
	m_Trigger.Period_s	= 0.1;
	m_Trigger.Count		= 1;
	Manager.SetTriggerParms(m_Trigger);

	l_NotifyErrorListSpy.wait(THM1176_CHANGE_PARM_TIME);
	QCOMPARE(l_NotifyErrorListSpy.count(), 0);

	//	- Emit SetOperatingMode = Measure,Continuous:
	//		- Should receive NotifyOperatingMode = Measure,Continuous
	Manager.SetOperatingMode(kTHM1176MeasureContinuously);

	l_NotifyOperatingModeSpy.wait(THM1176_MEASURE_TIME);
	QCOMPARE(l_NotifyOperatingModeSpy.count(), 1);
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176MeasureContinuously);

	//	Send 10 triggers:
	//		- 10x: Should receive NotifyMeasurement length 1
	//		- Should not receive NotifyErrorList
    QThread::currentThread()->msleep(100);
    for (int i = 0; i < 10; i++)
	{
		Manager.SendTrigger();
        QThread::currentThread()->msleep(100);

        l_NotifyMeasurementSpy.wait(THM1176_MEASURE_TIME);
		QCOMPARE(l_NotifyMeasurementSpy.count(), 1);
		m_Arguments = l_NotifyMeasurementSpy.takeFirst();
		m_Measurement = qvariant_cast<CMeasurement> (m_Arguments.at(0));
		QCOMPARE(m_Measurement.Bx.size(), 1ul);
		QCOMPARE(m_Measurement.By.size(), 1ul);
		QCOMPARE(m_Measurement.Bz.size(), 1ul);
        QCOMPARE(m_Measurement.Units, MTL::kT);
		QVERIFY(m_Measurement.Temp != 0);
		QCOMPARE(m_Measurement.TimestampList.size(), 1ul);
		QVERIFY(m_Measurement.AveragingParms == m_AveragingParms);
		QCOMPARE(m_Measurement.TriggerParms.Source, m_Trigger.Source);
		QCOMPARE(m_Measurement.TriggerParms.Count, m_Trigger.Count);
		QCOMPARE(m_Measurement.TriggerParms.Period_s, 0.);
		QVERIFY(m_Measurement.OutputSelect == m_OutputSelect);
		QVERIFY(m_Measurement.SleepParm == m_SleepParm);
		QVERIFY(m_Measurement.RangeParms.Auto == m_RangeParms.Auto &&
				(m_RangeParms.Auto || m_Measurement.RangeParms.Range == m_RangeParms.Range));
		QVERIFY(m_Measurement.CommFormat == m_CommFormat);

        std::cout << "- Measured Triggered,1,Continuous: B = (" << m_Measurement.Bx[0] << ", " << m_Measurement.By[0] << ", " << m_Measurement.Bz[0] << ") [T], "
		"Temp = " << m_Measurement.Temp << ", Timestamp = " << m_Measurement.TimestampList[0] << ", " <<
        m_Measurement.Warnings.size() << " Warnings" << std::endl;

		QCOMPARE(l_NotifyErrorListSpy.count(), 0);
	}

	//	- Emit SetOperatingMode = Idle:
	//		- Should receive NotifyOperatingMode = Idle
	//		- Should not receive NotifyErrorList
	Manager.SetOperatingMode(kTHM1176Idle);

	l_NotifyOperatingModeSpy.wait(THM1176_MEASURE_TIME);
	QCOMPARE(l_NotifyOperatingModeSpy.count(), 1);
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176Idle);

	QCOMPARE(l_NotifyErrorListSpy.count(), 0);

} // THM1176IM_Test02_Measure::TestSetOperatingMode_TriggeredContinuous

//////////////////////////////////////////////////////////////////////////
/// \test   Test THM1176 Instrument Manager: Test setting SetOperatingMode to Calibrate Zero Offset:
///	- Emit SetOperatingMode = Calibrate Zero Offset with Override enabled:
///		- Should receive NotifyOperatingMode = Calibrate, Idle
///	- Emit SetOperatingMode = Calibrate Zero Offset without Override enabled,
///     if this model is not supposed to be calibrated, we should receive an error.
///	- Emit SetOperatingMode = Restore Zero Offset:
///		- Should receive NotifyOperatingMode = Restore, Idle
void THM1176IM_Test02_Measure::TestSetOperatingMode_CalibrateRestore(void)
{
	// Create  Signal Spies to retrieve operating mode and possible errors.
	QSignalSpy	l_NotifyOperatingModeSpy(&Manager, SIGNAL(NotifyOperatingMode(eTHM1176OperatingMode)));
	QSignalSpy	l_NotifyErrorListSpy(&Manager, SIGNAL(NotifyErrorList(CErrorList)));

    //	- Emit SetOperatingMode = Calibrate Zero Offset with Override enabled:
	//		- Should receive NotifyOperatingMode = Calibrate, Idle
    Manager.SetCalibrationOverride(true);
	Manager.SetOperatingMode(kTHM1176CalibrateZeroOffset);

	l_NotifyOperatingModeSpy.wait(THM1176_CALIBRATE_TIME);
	QVERIFY(l_NotifyOperatingModeSpy.count() > 0);
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176CalibrateZeroOffset);
	if (l_NotifyOperatingModeSpy.count() <= 0)
	{
		l_NotifyOperatingModeSpy.wait(THM1176_CALIBRATE_TIME);
		QCOMPARE(l_NotifyOperatingModeSpy.count(), 1);
	}
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176Idle);

	QCOMPARE(l_NotifyErrorListSpy.count(), 0);

    std::cout << "- Performed zero calibration " << m_Identification.Model << ", S/N " << m_Identification.SerialNumber << std::endl;

    ///	- Emit SetOperatingMode = Calibrate Zero Offset without Override enabled,
    ///     if this model is not supposed to be calibrated, we should receive an error.
    if (Manager.GetIdentification().Model == "TFM1186")
    {
        Manager.SetCalibrationOverride(false);
        Manager.SetOperatingMode(kTHM1176CalibrateZeroOffset);

        l_NotifyOperatingModeSpy.wait(THM1176_CALIBRATE_TIME);
        QVERIFY(l_NotifyOperatingModeSpy.count() > 0);
        m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
        m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
        QCOMPARE(m_OperatingMode, kTHM1176CalibrateZeroOffset);
        if (l_NotifyOperatingModeSpy.count() <= 0)
        {
            l_NotifyOperatingModeSpy.wait(THM1176_CALIBRATE_TIME);
            QCOMPARE(l_NotifyOperatingModeSpy.count(), 1);
        }
        m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
        m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
        QCOMPARE(m_OperatingMode, kTHM1176Idle);

        QCOMPARE(l_NotifyErrorListSpy.count(), 1);
        m_Arguments = l_NotifyErrorListSpy.takeFirst();
        m_LatestErrors = qvariant_cast<CErrorList>(m_Arguments.at(0));
        QCOMPARE(m_LatestErrors.size(), 1ul);

        std::cout << "- Trying to calibrate 'prohibited' model returned error: "
        << m_LatestErrors[0].Code << ", "
        << m_LatestErrors[0].Context << ": "
        << m_LatestErrors[0].Description << std::endl;
    }

    //	- Emit SetOperatingMode = Calibrate Zero Offset:
	//		- Should receive NotifyOperatingMode = Calibrate, Idle
	Manager.SetOperatingMode(kTHM1176RestoreZeroOffset);

	l_NotifyOperatingModeSpy.wait(THM1176_CALIBRATE_TIME);
	QVERIFY(l_NotifyOperatingModeSpy.count() > 0);
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176RestoreZeroOffset);
	if (l_NotifyOperatingModeSpy.count() <= 0)
	{
		l_NotifyOperatingModeSpy.wait(THM1176_CALIBRATE_TIME);
		QCOMPARE(l_NotifyOperatingModeSpy.count(), 1);
	}
	m_Arguments = l_NotifyOperatingModeSpy.takeFirst();
	m_OperatingMode = qvariant_cast<eTHM1176OperatingMode>(m_Arguments.at(0));
	QCOMPARE(m_OperatingMode, kTHM1176Idle);

	QCOMPARE(l_NotifyErrorListSpy.count(), 0);

    std::cout << "- Restored zero calibration " << m_Identification.Model << ", S/N " << m_Identification.SerialNumber << std::endl;
}

//////////////////////////////////////////////////////////////////////////
/// \test   Test THM1176 Instrument Manager utilities.
///	- Call GetImmediateMeasurementPeriod for averaging 1, 2, 3:
///		- Should be linear
///	- Call ConvertTimestamp for 0:
///		- Should get a date within the last 24 hours.
///	- Call ReadInformationDates:
///		- Should get two real dates
void THM1176IM_Test02_Measure::TestUtilities(void)
{
    bool l_Result;

    //	- Call GetImmediateMeasurementPeriod for averaging 1, 2, 3:
    //		- Should be linear.
    sAveraging<uParm> l_Avg;
    F64 l_Period1, l_Period2, l_Period3;
    l_Avg.NoPoints = 1;
    l_Result = Manager.GetImmediateMeasurementPeriod(l_Avg, l_Period1);
    Q_ASSERT(true == l_Result);
    l_Avg.NoPoints = 2;
    l_Result = Manager.GetImmediateMeasurementPeriod(l_Avg, l_Period2);
    Q_ASSERT(true == l_Result);
    l_Avg.NoPoints = 3;
    l_Result = Manager.GetImmediateMeasurementPeriod(l_Avg, l_Period3);
    Q_ASSERT(true == l_Result);
    QVERIFY(abs((l_Period2 - l_Period1) - (l_Period3 - l_Period2)) < 1E-8);

    //	- Call ConvertTimestamp for 0:
    //		- Should get a date within the last 24 hours.
    CAbsoluteTimestamp l_Timestamp;
    l_Result = Manager.ConvertTimestamp(0ul, l_Timestamp);
    Q_ASSERT(true == l_Result);
    QVERIFY(l_Timestamp.seconds() > (std::time(NULL) - 24l*60l*60l) &&
            l_Timestamp.seconds() < std::time(NULL));

    //	- Call ReadInformationDates:
    //		- Should get Manufacturing date since 2008, and calibration date within 3 years.
    QDateTime l_MfrDate, l_CalDate;
    l_Result = Manager.ReadInformationDates(l_MfrDate, l_CalDate);
    Q_ASSERT(true == l_Result);
    QVERIFY(2008 < l_MfrDate.date().year());
    QVERIFY((QDateTime::currentDateTime().date().year() - 3) < l_CalDate.date().year() &&
            QDateTime::currentDateTime().date().year() >= l_CalDate.date().year());
}

//----------------------------------------------------------------------//
//	main()																//
//----------------------------------------------------------------------//
QTEST_MAIN(THM1176IM_Test02_Measure)

#include "THM1176IM_Test02_Measure.moc"
