// 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 THM1176 API: MeasurementsGet, SetFormat

#include "gtest/gtest.h"
#include "THM1176TestUtilities.h"
#include <ctime>
#include <chrono>
#include <thread>

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

static const I32 THM1176_NO_MEASUREMENTS				(3);
static const U32 THM1176_AVG_COUNT						(100);
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 const U64 THM1176_TIME_PER_MEASUREMENT			(static_cast<U64>(THM1176_IMMEDIATE_TIME_PER_MEAS + THM1176_AVG_COUNT * THM1176_IMMEDIATE_TIME_PER_ACQ + 0.5));

/// \brief Test THM1176 API: MeasurementsGet, SetFormat
class CTHM1176MeasuresTest : public ::testing::Test
{
protected:
	static THM1176_TEST_RESOURCE_MANAGER_CLASS * pResourceManager;
	static CTHM1176Instrument<THM1176_TEST_INSTRUMENT_CLASS, THM1176_TEST_RESOURCE_MANAGER_CLASS> * pTHM1176;

	static void SetUpTestCase()
	{
		ASSERT_EQ(true, ConnectToTHM1176(pResourceManager, pTHM1176));
		ASSERT_NE(nullptr, pResourceManager);
		ASSERT_NE(nullptr, pTHM1176);
		ASSERT_EQ(true, pTHM1176->IsOpen());
		ASSERT_EQ(true, pTHM1176->Reset());
	}
	
	static void TearDownTestCase()
	{
		delete pTHM1176;
		pTHM1176 = nullptr;
		delete pResourceManager;
		pResourceManager = nullptr;
	}
	
	virtual void SetUp()
	{
		// Reset the instrument.
		ASSERT_NE(pTHM1176, nullptr);
		ASSERT_EQ(true, pTHM1176->Reset());
		
		// Set lowest range and enable averaging, so that PACKED,1 will hopefully work.
		sRange<sBoundedParm> l_RangeBounds;
		ASSERT_EQ(true, pTHM1176->ParmRangeGet(l_RangeBounds));
		sRange<uParm> l_Range;
		l_Range.Auto = false;
		l_Range.Range = l_RangeBounds.Range.Min;
		ASSERT_EQ(true, pTHM1176->ParmRangeSet(l_Range));
		
		sAveraging<sBoundedParm> l_AvgBounds;
		ASSERT_EQ(true, pTHM1176->ParmAveragingGet(l_AvgBounds));
		sAveraging<uParm> l_Avg;
		l_Avg.NoPoints = THM1176_AVG_COUNT;
		ASSERT_EQ(true, pTHM1176->ParmAveragingSet(l_Avg));
		
		// Acquire THM1176_NO_MEASUREMENTS measurements with immediate trigger.
		sInputTrigger<sBoundedParm> l_TrigBounds;
		ASSERT_EQ(true, pTHM1176->ParmTriggerInputGet(l_TrigBounds));
		sInputTrigger<uParm> l_Trig;
		l_Trig.Source	= kInputTrigSrcImmediate;
		l_Trig.Count		= THM1176_NO_MEASUREMENTS;
		ASSERT_EQ(true, pTHM1176->ParmTriggerInputSet(l_Trig));
		ASSERT_EQ(true, pTHM1176->Initiate());
	}
};
THM1176_TEST_RESOURCE_MANAGER_CLASS * CTHM1176MeasuresTest::pResourceManager = nullptr;
CTHM1176Instrument<THM1176_TEST_INSTRUMENT_CLASS, THM1176_TEST_RESOURCE_MANAGER_CLASS> * CTHM1176MeasuresTest::pTHM1176 = nullptr;

/// \test Test SetFormat method.
TEST_F(CTHM1176MeasuresTest, SetFormat)
{
	// Format should be ASCII by default.
	CSCPIBuffer l_Buffer;
	ASSERT_EQ(true, pTHM1176->Write("FORM?") && pTHM1176->Read(l_Buffer));
	EXPECT_EQ("ASCII\n", std::string(l_Buffer.begin(), l_Buffer.end()));
	
	// Test setting to INTEGER.
	ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatInteger));
	ASSERT_EQ(true, pTHM1176->Write("FORM?") && pTHM1176->Read(l_Buffer));
	EXPECT_EQ("INTEGER\n", std::string(l_Buffer.begin(), l_Buffer.end()));
	
	// Test setting back to ASCII.
	ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatAscii));
	ASSERT_EQ(true, pTHM1176->Write("FORM?") && pTHM1176->Read(l_Buffer));
	EXPECT_EQ("ASCII\n", std::string(l_Buffer.begin(), l_Buffer.end()));
	
	// Test setting to PACKED,2.
	ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatPacked2Byte));
	ASSERT_EQ(true, pTHM1176->Write("FORM?") && pTHM1176->Read(l_Buffer));
	EXPECT_EQ("PACKED,2\n", std::string(l_Buffer.begin(), l_Buffer.end()));
	
	// Test setting to PACKED,1.
	ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatPacked1Byte));
	ASSERT_EQ(true, pTHM1176->Write("FORM?") && pTHM1176->Read(l_Buffer));
	EXPECT_EQ("PACKED,1\n", std::string(l_Buffer.begin(), l_Buffer.end()));
}

/// \test Test GetFormat method.
TEST_F(CTHM1176MeasuresTest, GetFormat)
{
	eCommunicationFormat l_Format;

	// Format should be ASCII by default.
	ASSERT_EQ(true, pTHM1176->GetFormat(l_Format) && l_Format == kComFormatAscii);

	// Test setting to INTEGER.
	ASSERT_EQ(true, pTHM1176->Write("FORM INTEGER"));
	ASSERT_EQ(true, pTHM1176->GetFormat(l_Format) && l_Format == kComFormatInteger);

	// Test setting back to ASCII.
	ASSERT_EQ(true, pTHM1176->Write("FORM ASCII"));
	ASSERT_EQ(true, pTHM1176->GetFormat(l_Format) && l_Format == kComFormatAscii);

	// Test setting to PACKED,2.
	ASSERT_EQ(true, pTHM1176->Write("FORM PACKED,2"));
	ASSERT_EQ(true, pTHM1176->GetFormat(l_Format) && l_Format == kComFormatPacked2Byte);

	// Test setting to PACKED,1.
	ASSERT_EQ(true, pTHM1176->Write("FORM PACKED,1"));
	ASSERT_EQ(true, pTHM1176->GetFormat(l_Format) && l_Format == kComFormatPacked1Byte);
}

/// \test Test MeasurementsGet method: simple variant.
TEST_F(CTHM1176MeasuresTest, MeasurementsGet)
{
	CFluxList l_Bx, l_By, l_Bz;
	eUnits l_Units;
	U16 l_Temperature;
	CTimestampList l_TimestampList;
	U64 l_TimestampInterval;
	CErrorList l_ErrorList;

	// NoMeasurements = 0.
	{
		// ASCII format.
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatAscii));
		ASSERT_EQ(false, pTHM1176->MeasurementsGet(0, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		{
			l_ErrorList = pTHM1176->CurrentErrorList();
			EXPECT_EQ(3, l_ErrorList.size());
			EXPECT_EQ(-222, l_ErrorList[0].Code);
			EXPECT_EQ(-222, l_ErrorList[1].Code);
			EXPECT_EQ(-222, l_ErrorList[2].Code);
		}
		EXPECT_EQ(0, l_Bx.size());
		EXPECT_EQ(0, l_By.size());
		EXPECT_EQ(0, l_Bz.size());
		EXPECT_EQ(0, l_Temperature);
		ASSERT_EQ(0, l_TimestampList.size());

		// Retrieve the data in INTEGER format.
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatInteger));
		ASSERT_EQ(false, pTHM1176->MeasurementsGet(0, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		{
			l_ErrorList = pTHM1176->CurrentErrorList();
			EXPECT_EQ(3, l_ErrorList.size());
			EXPECT_EQ(-222, l_ErrorList[0].Code);
			EXPECT_EQ(-222, l_ErrorList[1].Code);
			EXPECT_EQ(-222, l_ErrorList[2].Code);
		}
		EXPECT_EQ(0, l_Bx.size());
		EXPECT_EQ(0, l_By.size());
		EXPECT_EQ(0, l_Bz.size());
		EXPECT_EQ(0, l_Temperature);
		ASSERT_EQ(0, l_TimestampList.size());
		
		// Retrieve the data in PACKED,2 format.
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatPacked2Byte));
		ASSERT_EQ(false, pTHM1176->MeasurementsGet(0, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		{
			l_ErrorList = pTHM1176->CurrentErrorList();
			EXPECT_EQ(3, l_ErrorList.size());
			EXPECT_EQ(-222, l_ErrorList[0].Code);
			EXPECT_EQ(-222, l_ErrorList[1].Code);
			EXPECT_EQ(-222, l_ErrorList[2].Code);
		}
		EXPECT_EQ(0, l_Bx.size());
		EXPECT_EQ(0, l_By.size());
		EXPECT_EQ(0, l_Bz.size());
		EXPECT_EQ(0, l_Temperature);
		ASSERT_EQ(0, l_TimestampList.size());
		
		// Retrieve the data in PACKED,1 format.
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatPacked1Byte));
		ASSERT_EQ(false, pTHM1176->MeasurementsGet(0, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		{
			l_ErrorList = pTHM1176->CurrentErrorList();
			EXPECT_EQ(3, l_ErrorList.size());
			EXPECT_EQ(-222, l_ErrorList[0].Code);
			EXPECT_EQ(-222, l_ErrorList[1].Code);
			EXPECT_EQ(-222, l_ErrorList[2].Code);
		}
		EXPECT_EQ(0, l_Bx.size());
		EXPECT_EQ(0, l_By.size());
		EXPECT_EQ(0, l_Bz.size());
		EXPECT_EQ(0, l_Temperature);
		ASSERT_EQ(0, l_TimestampList.size());
	}
	
	// NoMeasurements = THM1176_NO_MEASUREMENTS.
	{
		// ASCII format.
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatAscii));
		ASSERT_EQ(true, pTHM1176->MeasurementsGet(THM1176_NO_MEASUREMENTS, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_Bx.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_By.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_Bz.size());
		EXPECT_LT(0, l_Temperature);
		ASSERT_EQ(THM1176_NO_MEASUREMENTS, l_TimestampList.size());
		for (int i = 0; i < THM1176_NO_MEASUREMENTS - 1; i++)
		{
			l_TimestampInterval = l_TimestampList[i+1] - l_TimestampList[i];
			EXPECT_EQ(l_TimestampInterval, THM1176_TIME_PER_MEASUREMENT);
		}
		
		// Retrieve the data in INTEGER format.
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatInteger));
		ASSERT_EQ(true, pTHM1176->MeasurementsGet(THM1176_NO_MEASUREMENTS, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_Bx.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_By.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_Bz.size());
		EXPECT_LT(0, l_Temperature);
		ASSERT_EQ(THM1176_NO_MEASUREMENTS, l_TimestampList.size());
		for (int i = 0; i < THM1176_NO_MEASUREMENTS - 1; i++)
		{
			l_TimestampInterval = l_TimestampList[i+1] - l_TimestampList[i];
			EXPECT_EQ(l_TimestampInterval, THM1176_TIME_PER_MEASUREMENT);
		}

		// Retrieve the data in PACKED,2 format.
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatPacked2Byte));
		ASSERT_EQ(true, pTHM1176->MeasurementsGet(THM1176_NO_MEASUREMENTS, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_Bx.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_By.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_Bz.size());
		EXPECT_LT(0, l_Temperature);
		ASSERT_EQ(THM1176_NO_MEASUREMENTS, l_TimestampList.size());
		for (int i = 0; i < THM1176_NO_MEASUREMENTS - 1; i++)
		{
			l_TimestampInterval = l_TimestampList[i+1] - l_TimestampList[i];
			EXPECT_EQ(l_TimestampInterval, THM1176_TIME_PER_MEASUREMENT);
		}

		// Retrieve the data in PACKED,1 format.
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatPacked1Byte));
		ASSERT_EQ(true, pTHM1176->MeasurementsGet(THM1176_NO_MEASUREMENTS, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_Bx.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_By.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_Bz.size());
		EXPECT_LT(0, l_Temperature);
		ASSERT_EQ(THM1176_NO_MEASUREMENTS, l_TimestampList.size());
		for (int i = 0; i < THM1176_NO_MEASUREMENTS - 1; i++)
		{
			l_TimestampInterval = l_TimestampList[i+1] - l_TimestampList[i];
			EXPECT_EQ(l_TimestampInterval, THM1176_TIME_PER_MEASUREMENT);
		}
	}
	
	// NoMeasurements = THM1176_NO_MEASUREMENTS-1.
	{
		// ASCII format.
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatAscii));
		ASSERT_EQ(true, pTHM1176->MeasurementsGet(THM1176_NO_MEASUREMENTS-1, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		EXPECT_EQ(THM1176_NO_MEASUREMENTS-1, l_Bx.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS-1, l_By.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS-1, l_Bz.size());
		EXPECT_LT(0, l_Temperature);
		ASSERT_EQ(THM1176_NO_MEASUREMENTS-1, l_TimestampList.size());
		for (int i = 0; i < THM1176_NO_MEASUREMENTS - 2; i++)
		{
			l_TimestampInterval = l_TimestampList[i+1] - l_TimestampList[i];
			EXPECT_EQ(l_TimestampInterval, THM1176_TIME_PER_MEASUREMENT);
		}

		// Retrieve the data in INTEGER format.
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatInteger));
		ASSERT_EQ(true, pTHM1176->MeasurementsGet(THM1176_NO_MEASUREMENTS-1, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		EXPECT_EQ(THM1176_NO_MEASUREMENTS-1, l_Bx.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS-1, l_By.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS-1, l_Bz.size());
		EXPECT_LT(0, l_Temperature);
		ASSERT_EQ(THM1176_NO_MEASUREMENTS-1, l_TimestampList.size());
		for (int i = 0; i < THM1176_NO_MEASUREMENTS - 2; i++)
		{
			l_TimestampInterval = l_TimestampList[i+1] - l_TimestampList[i];
			EXPECT_EQ(l_TimestampInterval, THM1176_TIME_PER_MEASUREMENT);
		}

		// Retrieve the data in PACKED,2 format.
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatPacked2Byte));
		ASSERT_EQ(true, pTHM1176->MeasurementsGet(THM1176_NO_MEASUREMENTS-1, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		EXPECT_EQ(THM1176_NO_MEASUREMENTS-1, l_Bx.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS-1, l_By.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS-1, l_Bz.size());
		EXPECT_LT(0, l_Temperature);
		ASSERT_EQ(THM1176_NO_MEASUREMENTS-1, l_TimestampList.size());
		for (int i = 0; i < THM1176_NO_MEASUREMENTS - 2; i++)
		{
			l_TimestampInterval = l_TimestampList[i+1] - l_TimestampList[i];
			EXPECT_EQ(l_TimestampInterval, THM1176_TIME_PER_MEASUREMENT);
		}

		// Retrieve the data in PACKED,1 format.
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatPacked1Byte));
		ASSERT_EQ(true, pTHM1176->MeasurementsGet(THM1176_NO_MEASUREMENTS-1, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		EXPECT_EQ(THM1176_NO_MEASUREMENTS-1, l_Bx.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS-1, l_By.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS-1, l_Bz.size());
		EXPECT_LT(0, l_Temperature);
		ASSERT_EQ(THM1176_NO_MEASUREMENTS-1, l_TimestampList.size());
		for (int i = 0; i < THM1176_NO_MEASUREMENTS - 2; i++)
		{
			l_TimestampInterval = l_TimestampList[i+1] - l_TimestampList[i];
			EXPECT_EQ(l_TimestampInterval, THM1176_TIME_PER_MEASUREMENT);
		}
	}
	// NoMeasurements = THM1176_NO_MEASUREMENTS+1.
	{
		// ASCII format.
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatAscii));
		ASSERT_EQ(false, pTHM1176->MeasurementsGet(THM1176_NO_MEASUREMENTS+1, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		{
			l_ErrorList = pTHM1176->CurrentErrorList();
			EXPECT_EQ(3, l_ErrorList.size());
			EXPECT_EQ(-222, l_ErrorList[0].Code);
			EXPECT_EQ(-222, l_ErrorList[1].Code);
			EXPECT_EQ(-222, l_ErrorList[2].Code);
		}
		EXPECT_EQ(0, l_Bx.size());
		EXPECT_EQ(0, l_By.size());
		EXPECT_EQ(0, l_Bz.size());
		EXPECT_EQ(0, l_Temperature);
		ASSERT_EQ(0, l_TimestampList.size());
		
		// Retrieve the data in INTEGER format.
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatInteger));
		ASSERT_EQ(false, pTHM1176->MeasurementsGet(THM1176_NO_MEASUREMENTS+1, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		{
			l_ErrorList = pTHM1176->CurrentErrorList();
			EXPECT_EQ(3, l_ErrorList.size());
			EXPECT_EQ(-222, l_ErrorList[0].Code);
			EXPECT_EQ(-222, l_ErrorList[1].Code);
			EXPECT_EQ(-222, l_ErrorList[2].Code);
		}
		EXPECT_EQ(0, l_Bx.size());
		EXPECT_EQ(0, l_By.size());
		EXPECT_EQ(0, l_Bz.size());
		EXPECT_EQ(0, l_Temperature);
		ASSERT_EQ(0, l_TimestampList.size());
		
		// Retrieve the data in PACKED,2 format.
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatPacked2Byte));
		ASSERT_EQ(false, pTHM1176->MeasurementsGet(THM1176_NO_MEASUREMENTS+1, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		{
			l_ErrorList = pTHM1176->CurrentErrorList();
			EXPECT_EQ(3, l_ErrorList.size());
			EXPECT_EQ(-222, l_ErrorList[0].Code);
			EXPECT_EQ(-222, l_ErrorList[1].Code);
			EXPECT_EQ(-222, l_ErrorList[2].Code);
		}
		EXPECT_EQ(0, l_Bx.size());
		EXPECT_EQ(0, l_By.size());
		EXPECT_EQ(0, l_Bz.size());
		EXPECT_EQ(0, l_Temperature);
		ASSERT_EQ(0, l_TimestampList.size());
		
		// Retrieve the data in PACKED,1 format.
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatPacked1Byte));
		ASSERT_EQ(false, pTHM1176->MeasurementsGet(THM1176_NO_MEASUREMENTS+1, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		{
			l_ErrorList = pTHM1176->CurrentErrorList();
			EXPECT_EQ(3, l_ErrorList.size());
			EXPECT_EQ(-222, l_ErrorList[0].Code);
			EXPECT_EQ(-222, l_ErrorList[1].Code);
			EXPECT_EQ(-222, l_ErrorList[2].Code);
		}
		EXPECT_EQ(0, l_Bx.size());
		EXPECT_EQ(0, l_By.size());
		EXPECT_EQ(0, l_Bz.size());
		EXPECT_EQ(0, l_Temperature);
		ASSERT_EQ(0, l_TimestampList.size());
	}
	// Try changing units.
	{
		CFluxList l_Bx1, l_By1, l_Bz1;
		
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatInteger));
		
		CUnitsList l_AllUnits;
		ASSERT_EQ(true, pTHM1176->GetAllUnits(l_AllUnits));
		ASSERT_LT(1, l_AllUnits.size());
		
		ASSERT_EQ(true, pTHM1176->ParmUnitsSet(l_AllUnits[0]));
		ASSERT_EQ(true, pTHM1176->MeasurementsGet(THM1176_NO_MEASUREMENTS, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_Bx.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_By.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_Bz.size());
		
		ASSERT_EQ(true, pTHM1176->ParmUnitsSet(l_AllUnits[1]));
		ASSERT_EQ(true, pTHM1176->MeasurementsGet(THM1176_NO_MEASUREMENTS, l_Bx1, l_By1, l_Bz1, l_Units, l_Temperature, l_TimestampList));
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_Bx1.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_By1.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_Bz1.size());
		
		U32 l_Divisor, l_Divisor1;
		ASSERT_EQ(true, pTHM1176->GetDivisor(l_AllUnits[0], l_Divisor));
		ASSERT_EQ(true, pTHM1176->GetDivisor(l_AllUnits[1], l_Divisor1));
		
		for (auto l_pBx = l_Bx.begin(), l_pBx1 = l_Bx1.begin();
			 l_pBx < l_Bx.end() && l_pBx1 < l_Bx1.end();
			 l_pBx++, l_pBx1++)
			EXPECT_FLOAT_EQ(*l_pBx * l_Divisor, *l_pBx1 * l_Divisor1);
		for (auto l_pBy = l_By.begin(), l_pBy1 = l_By1.begin();
			 l_pBy < l_By.end() && l_pBy1 < l_By1.end();
			 l_pBy++, l_pBy1++)
			EXPECT_FLOAT_EQ(*l_pBy * l_Divisor, *l_pBy1 * l_Divisor1);
		for (auto l_pBz = l_Bz.begin(), l_pBz1 = l_Bz1.begin();
			 l_pBz < l_Bz.end() && l_pBz1 < l_Bz1.end();
			 l_pBz++, l_pBz1++)
			EXPECT_FLOAT_EQ(*l_pBz * l_Divisor, *l_pBz1 * l_Divisor1);
	}
    // Try with UseCalibration off, in ASCII and Integer format.
    {
        CFluxList l_Bx1, l_By1, l_Bz1;

        l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
        ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatAscii));
        ASSERT_EQ(true, pTHM1176->ParmUseCalibrationSet(false));

        ASSERT_EQ(true, pTHM1176->MeasurementsGet(THM1176_NO_MEASUREMENTS, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
        EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_Bx.size());
        EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_By.size());
        EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_Bz.size());

        for (auto l_pBx = l_Bx.begin(); l_pBx < l_Bx.end(); l_pBx++)
            EXPECT_FLOAT_EQ(*l_pBx, std::round(*l_pBx));
        for (auto l_pBy = l_By.begin(); l_pBy < l_By.end(); l_pBy++)
            EXPECT_FLOAT_EQ(*l_pBy, std::round(*l_pBy));
        for (auto l_pBz = l_Bz.begin(); l_pBz < l_Bz.end(); l_pBz++)
            EXPECT_FLOAT_EQ(*l_pBz, std::round(*l_pBz));

        ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatInteger));
        ASSERT_EQ(true, pTHM1176->ParmUseCalibrationSet(false));

        ASSERT_EQ(true, pTHM1176->MeasurementsGet(THM1176_NO_MEASUREMENTS, l_Bx1, l_By1, l_Bz1, l_Units, l_Temperature, l_TimestampList));
        EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_Bx1.size());
        EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_By1.size());
        EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_Bz1.size());

        for (auto l_pBx = l_Bx.begin(), l_pBx1 = l_Bx1.begin();
             l_pBx < l_Bx.end() && l_pBx1 < l_Bx1.end();
             l_pBx++, l_pBx1++)
            EXPECT_FLOAT_EQ(*l_pBx, *l_pBx1);
        for (auto l_pBy = l_By.begin(), l_pBy1 = l_By1.begin();
             l_pBy < l_By.end() && l_pBy1 < l_By1.end();
             l_pBy++, l_pBy1++)
            EXPECT_FLOAT_EQ(*l_pBy, *l_pBy1);
        for (auto l_pBz = l_Bz.begin(), l_pBz1 = l_Bz1.begin();
             l_pBz < l_Bz.end() && l_pBz1 < l_Bz1.end();
             l_pBz++, l_pBz1++)
            EXPECT_FLOAT_EQ(*l_pBz, *l_pBz1);

        ASSERT_EQ(true, pTHM1176->ParmUseCalibrationSet(true));
    }
	// Continuous measurements.
	{
		// Set timed trigger with 10 ms period and 20 measurements.
		sInputTrigger<sBoundedParm> l_TrigBounds;
		ASSERT_EQ(true, pTHM1176->ParmTriggerInputGet(l_TrigBounds));
		sInputTrigger<uParm> l_Trig;
		l_Trig.Source	= kInputTrigSrcTimer;
		l_Trig.Count	= 20;
		l_Trig.Period_s	= 0.01;
		ASSERT_EQ(true, pTHM1176->ParmTriggerInputSet(l_Trig));
		
		// Initiate continuously.
		ASSERT_EQ(true, pTHM1176->Initiate(true));
		
		// Wait a little, to consistently cause overrun errors
		// (but this should be the only error!).
		std::this_thread::sleep_for(std::chrono::seconds(1));
		
		// Read the data in ASCII format (just to be consistent, not relevant for the test).
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatAscii));
		ASSERT_EQ(true, pTHM1176->MeasurementsGet(l_Trig.Count, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		EXPECT_EQ(l_Trig.Count, l_Bx.size());
		EXPECT_EQ(l_Trig.Count, l_By.size());
		EXPECT_EQ(l_Trig.Count, l_Bz.size());
		EXPECT_LT(0, l_Temperature);
		
		// Check the timestamp list.
		ASSERT_EQ(l_Trig.Count, l_TimestampList.size());
		for (int i = 0; i < l_Trig.Count - 1; i++)
		{
			l_TimestampInterval = l_TimestampList[i+1] - l_TimestampList[i];
			EXPECT_EQ(l_TimestampInterval, l_Trig.Period_s * 1E9);
		}
		
		// Wait a second, then do another fetch, this time retrieving the Measurement Conditions.
		std::this_thread::sleep_for(std::chrono::seconds(1));

		sMeasurementConditions l_MeasurementConditions;
		ASSERT_EQ(true, pTHM1176->MeasurementsGet(l_Trig.Count, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList, &l_MeasurementConditions));
		EXPECT_EQ(l_Trig.Count, l_Bx.size());
		EXPECT_EQ(l_Trig.Count, l_By.size());
		EXPECT_EQ(l_Trig.Count, l_Bz.size());
		EXPECT_LT(0, l_Temperature);
		
		// Check the timestamp list.
		ASSERT_EQ(l_Trig.Count, l_TimestampList.size());
		for (int i = 0; i < l_Trig.Count - 1; i++)
		{
			l_TimestampInterval = l_TimestampList[i+1] - l_TimestampList[i];
			EXPECT_EQ(l_TimestampInterval, l_Trig.Period_s * 1E9);
		}
		
		// Check the Measurement Conditions.
		EXPECT_EQ(l_MeasurementConditions.AveragingParms.NoPoints, THM1176_AVG_COUNT);
		EXPECT_EQ(l_MeasurementConditions.TriggerParms.Source, l_Trig.Source);
		EXPECT_EQ(l_MeasurementConditions.TriggerParms.Count, l_Trig.Count);
		EXPECT_EQ(l_MeasurementConditions.TriggerParms.Period_s, l_Trig.Period_s);
		EXPECT_EQ(l_MeasurementConditions.UseCalibration, true);
		EXPECT_LT(0, l_MeasurementConditions.Range);

		// Test the GetEstimatedPeriod() method.
		F64 l_Period;
		ASSERT_EQ(true, l_TimestampList.GetEstimatedPeriod(l_Period));
		EXPECT_DOUBLE_EQ(l_Period, l_Trig.Period_s * 1E9);
		
		// Check to make sure we got a Data Overrun error.
		l_ErrorList = pTHM1176->CurrentErrorList();
		EXPECT_EQ(1, l_ErrorList.size());
		EXPECT_EQ(204, l_ErrorList[0].Code);
	}
	// Bus Triggered measurements.
	{
		// Reset to have a clean slate.
		pTHM1176->Reset();

		// Set bus trigger.
		sInputTrigger<uParm> l_Trig;
		l_Trig.Source	= kInputTrigSrcBus;
		l_Trig.Count		= THM1176_NO_MEASUREMENTS;
		l_Trig.Period_s	= 0;
		ASSERT_EQ(true, pTHM1176->ParmTriggerInputSet(l_Trig));
		
		// Initiate.
		ASSERT_EQ(true, pTHM1176->Initiate(false));

		// Trigger at 1-second intervals.
		std::vector<std::chrono::time_point<std::chrono::high_resolution_clock>> l_TriggerTimes;
		for (int i = 0; i < THM1176_NO_MEASUREMENTS; i++)
		{
			ASSERT_EQ(true, pTHM1176->SendBusTrigger());
			
			// Save the current time.
			l_TriggerTimes.push_back (std::chrono::high_resolution_clock::now());

			// Print it out for debugging.
			std::time_t l_Now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
			char		l_DateTimeString[32];
			std::strftime(l_DateTimeString, 31, "%FT%T", std::localtime(&l_Now));
			std::cout << "Send trigger " << i << std::string(l_DateTimeString) << std::endl;

			// NOTE: We seem to be getting spurious 206 (Timer Overrun) errors here – firmware bug?
			//		To catch it, uncomment the assertion, below.
			U16 l_Status;
			ASSERT_EQ(true, pTHM1176->StatusGet(sStatusRegister(kStatusByte, kStatusEvent), l_Status));
			// ASSERT_EQ(0, l_Status);
			pTHM1176->ClearErrorList();
			
			std::this_thread::sleep_for(std::chrono::seconds(1));
		}
		
		// Read the data in ASCII format (just to be consistent, not relevant for the test).
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatAscii));
		ASSERT_EQ(true, pTHM1176->MeasurementsGet(THM1176_NO_MEASUREMENTS, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_Bx.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_By.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_Bz.size());
		EXPECT_LT(0, l_Temperature);
		
		// Pay particular attention to the timestamps.
		ASSERT_EQ(THM1176_NO_MEASUREMENTS, l_TimestampList.size());
		for (int i = 0; i < THM1176_NO_MEASUREMENTS - 1; i++)
		{
			l_TimestampInterval = l_TimestampList[i+1] - l_TimestampList[i];
			F64 l_ExpectedTimestampInterval = std::chrono::duration_cast<std::chrono::nanoseconds>(l_TriggerTimes[i+1] - l_TriggerTimes[i]).count();
			EXPECT_NEAR(static_cast<F64>(l_TimestampInterval), l_ExpectedTimestampInterval, 1E7);
		}
		
		// Convert the timestamps to absolute timestamps, and print them out.
		for (int i = 0; i < THM1176_NO_MEASUREMENTS; i++)
		{
			CAbsoluteTimestamp l_AbsolutTimestamp;
			ASSERT_EQ(true, pTHM1176->ConvertTimestamp(l_TimestampList[i], l_AbsolutTimestamp));
			std::cout << "Timestamp: " << l_AbsolutTimestamp << std::endl;
		}

		// We expect no errors.
		l_ErrorList = pTHM1176->CurrentErrorList();
		EXPECT_EQ(0, l_ErrorList.size());
	}
}

/// \test Test MeasurementsGet method: variant with sArbitraryMeasurements selection.
TEST_F(CTHM1176MeasuresTest, MeasurementsGetArbitrary)
{
	CFluxList l_Bx, l_By, l_Bz;
	eUnits l_Units;
	U16 l_Temperature;
	CTimestampList l_TimestampList;
	U64 l_TimestampInterval;
	CErrorList l_ErrorList;
	
	// NoMeasurements = 0, retrieve all.
	{
		sArbitraryMeasurements l_Select = { true, true, true, true, true, 0 };
		
		// ASCII format.
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatAscii));
		ASSERT_EQ(false, pTHM1176->MeasurementsGet(l_Select, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		{
			l_ErrorList = pTHM1176->CurrentErrorList();
			EXPECT_EQ(3, l_ErrorList.size());
			EXPECT_EQ(-222, l_ErrorList[0].Code);
			EXPECT_EQ(-222, l_ErrorList[1].Code);
			EXPECT_EQ(-222, l_ErrorList[2].Code);
		}
		EXPECT_EQ(0, l_Bx.size());
		EXPECT_EQ(0, l_By.size());
		EXPECT_EQ(0, l_Bz.size());
		EXPECT_EQ(0, l_Temperature);
		ASSERT_EQ(0, l_TimestampList.size());

		// Retrieve the data in INTEGER format.
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatInteger));
		ASSERT_EQ(false, pTHM1176->MeasurementsGet(l_Select, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		{
			l_ErrorList = pTHM1176->CurrentErrorList();
			EXPECT_EQ(3, l_ErrorList.size());
			EXPECT_EQ(-222, l_ErrorList[0].Code);
			EXPECT_EQ(-222, l_ErrorList[1].Code);
			EXPECT_EQ(-222, l_ErrorList[2].Code);
		}
		EXPECT_EQ(0, l_Bx.size());
		EXPECT_EQ(0, l_By.size());
		EXPECT_EQ(0, l_Bz.size());
		EXPECT_EQ(0, l_Temperature);
		ASSERT_EQ(0, l_TimestampList.size());

		// Retrieve the data in PACKED,2 format.
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatPacked2Byte));
		ASSERT_EQ(false, pTHM1176->MeasurementsGet(l_Select, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		{
			l_ErrorList = pTHM1176->CurrentErrorList();
			EXPECT_EQ(3, l_ErrorList.size());
			EXPECT_EQ(-222, l_ErrorList[0].Code);
			EXPECT_EQ(-222, l_ErrorList[1].Code);
			EXPECT_EQ(-222, l_ErrorList[2].Code);
		}
		EXPECT_EQ(0, l_Bx.size());
		EXPECT_EQ(0, l_By.size());
		EXPECT_EQ(0, l_Bz.size());
		EXPECT_EQ(0, l_Temperature);
		ASSERT_EQ(0, l_TimestampList.size());
		
		// Retrieve the data in PACKED,1 format.
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatPacked1Byte));
		ASSERT_EQ(false, pTHM1176->MeasurementsGet(l_Select, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		{
			l_ErrorList = pTHM1176->CurrentErrorList();
			EXPECT_EQ(3, l_ErrorList.size());
			EXPECT_EQ(-222, l_ErrorList[0].Code);
			EXPECT_EQ(-222, l_ErrorList[1].Code);
			EXPECT_EQ(-222, l_ErrorList[2].Code);
		}
		EXPECT_EQ(0, l_Bx.size());
		EXPECT_EQ(0, l_By.size());
		EXPECT_EQ(0, l_Bz.size());
		EXPECT_EQ(0, l_Temperature);
		ASSERT_EQ(0, l_TimestampList.size());
	}
	
	// NoMeasurements = THM1176_NO_MEASUREMENTS, retrieve first set.
	{
		sArbitraryMeasurements l_Select = { true, false, true, false, true, static_cast<U32>(THM1176_NO_MEASUREMENTS) };
		
		// ASCII format.
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatAscii));
		ASSERT_EQ(true, pTHM1176->MeasurementsGet(l_Select, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_Bx.size());
		EXPECT_EQ(0, l_By.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_Bz.size());
		EXPECT_EQ(0, l_Temperature);
		ASSERT_EQ(THM1176_NO_MEASUREMENTS, l_TimestampList.size());
		for (int i = 0; i < THM1176_NO_MEASUREMENTS - 1; i++)
		{
			l_TimestampInterval = l_TimestampList[i+1] - l_TimestampList[i];
			EXPECT_EQ(l_TimestampInterval, THM1176_TIME_PER_MEASUREMENT);
		}
		l_ErrorList = pTHM1176->CurrentErrorList();
		ASSERT_EQ(1, l_ErrorList.size());
		EXPECT_EQ(THM1176_NO_ANGLE_CORRECTION_CODE, l_ErrorList[0].Code);
		pTHM1176->ClearErrorList();

		// Retrieve the data in INTEGER format.
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatInteger));
		ASSERT_EQ(true, pTHM1176->MeasurementsGet(l_Select, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_Bx.size());
		EXPECT_EQ(0, l_By.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_Bz.size());
		EXPECT_EQ(0, l_Temperature);
		ASSERT_EQ(THM1176_NO_MEASUREMENTS, l_TimestampList.size());
		for (int i = 0; i < THM1176_NO_MEASUREMENTS - 1; i++)
		{
			l_TimestampInterval = l_TimestampList[i+1] - l_TimestampList[i];
			EXPECT_EQ(l_TimestampInterval, THM1176_TIME_PER_MEASUREMENT);
		}
		l_ErrorList = pTHM1176->CurrentErrorList();
		ASSERT_EQ(1, l_ErrorList.size());
		EXPECT_EQ(THM1176_NO_ANGLE_CORRECTION_CODE, l_ErrorList[0].Code);
		pTHM1176->ClearErrorList();

		// Retrieve the data in PACKED,2 format.
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatPacked2Byte));
		ASSERT_EQ(true, pTHM1176->MeasurementsGet(l_Select, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_Bx.size());
		EXPECT_EQ(0, l_By.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_Bz.size());
		EXPECT_EQ(0, l_Temperature);
		ASSERT_EQ(THM1176_NO_MEASUREMENTS, l_TimestampList.size());
		for (int i = 0; i < THM1176_NO_MEASUREMENTS - 1; i++)
		{
			l_TimestampInterval = l_TimestampList[i+1] - l_TimestampList[i];
			EXPECT_EQ(l_TimestampInterval, THM1176_TIME_PER_MEASUREMENT);
		}
		l_ErrorList = pTHM1176->CurrentErrorList();
		ASSERT_EQ(1, l_ErrorList.size());
		EXPECT_EQ(THM1176_NO_ANGLE_CORRECTION_CODE, l_ErrorList[0].Code);
		pTHM1176->ClearErrorList();

		// Retrieve the data in PACKED,1 format.
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatPacked1Byte));
		ASSERT_EQ(true, pTHM1176->MeasurementsGet(l_Select, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_Bx.size());
		EXPECT_EQ(0, l_By.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_Bz.size());
		EXPECT_EQ(0, l_Temperature);
		ASSERT_EQ(THM1176_NO_MEASUREMENTS, l_TimestampList.size());
		for (int i = 0; i < THM1176_NO_MEASUREMENTS - 1; i++)
		{
			l_TimestampInterval = l_TimestampList[i+1] - l_TimestampList[i];
			EXPECT_EQ(l_TimestampInterval, THM1176_TIME_PER_MEASUREMENT);
		}
		l_ErrorList = pTHM1176->CurrentErrorList();
		ASSERT_EQ(1, l_ErrorList.size());
		EXPECT_EQ(THM1176_NO_ANGLE_CORRECTION_CODE, l_ErrorList[0].Code);
		pTHM1176->ClearErrorList();
	}
	
	// NoMeasurements = THM1176_NO_MEASUREMENTS-1, retrieve second set.
	{
		sArbitraryMeasurements l_Select = { false, true, false, true, false, THM1176_NO_MEASUREMENTS-1 };
		
		// ASCII format.
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatAscii));
		ASSERT_EQ(true, pTHM1176->MeasurementsGet(l_Select, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		EXPECT_EQ(0, l_Bx.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS-1, l_By.size());
		EXPECT_EQ(0, l_Bz.size());
		EXPECT_LT(0, l_Temperature);
		ASSERT_EQ(0, l_TimestampList.size());
		l_ErrorList = pTHM1176->CurrentErrorList();
		ASSERT_EQ(1, l_ErrorList.size());
		EXPECT_EQ(THM1176_NO_ANGLE_CORRECTION_CODE, l_ErrorList[0].Code);
		pTHM1176->ClearErrorList();

		// Retrieve the data in INTEGER format.
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatInteger));
		ASSERT_EQ(true, pTHM1176->MeasurementsGet(l_Select, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		EXPECT_EQ(0, l_Bx.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS-1, l_By.size());
		EXPECT_EQ(0, l_Bz.size());
		EXPECT_LT(0, l_Temperature);
		ASSERT_EQ(0, l_TimestampList.size());
		l_ErrorList = pTHM1176->CurrentErrorList();
		ASSERT_EQ(1, l_ErrorList.size());
		EXPECT_EQ(THM1176_NO_ANGLE_CORRECTION_CODE, l_ErrorList[0].Code);
		pTHM1176->ClearErrorList();

		// Retrieve the data in PACKED,2 format.
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatPacked2Byte));
		ASSERT_EQ(true, pTHM1176->MeasurementsGet(l_Select, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		EXPECT_EQ(0, l_Bx.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS-1, l_By.size());
		EXPECT_EQ(0, l_Bz.size());
		EXPECT_LT(0, l_Temperature);
		ASSERT_EQ(0, l_TimestampList.size());
		l_ErrorList = pTHM1176->CurrentErrorList();
		ASSERT_EQ(1, l_ErrorList.size());
		EXPECT_EQ(THM1176_NO_ANGLE_CORRECTION_CODE, l_ErrorList[0].Code);
		pTHM1176->ClearErrorList();

		// Retrieve the data in PACKED,1 format.
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatPacked1Byte));
		ASSERT_EQ(true, pTHM1176->MeasurementsGet(l_Select, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		EXPECT_EQ(0, l_Bx.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS-1, l_By.size());
		EXPECT_EQ(0, l_Bz.size());
		EXPECT_LT(0, l_Temperature);
		ASSERT_EQ(0, l_TimestampList.size());
		l_ErrorList = pTHM1176->CurrentErrorList();
		ASSERT_EQ(1, l_ErrorList.size());
		EXPECT_EQ(THM1176_NO_ANGLE_CORRECTION_CODE, l_ErrorList[0].Code);
		pTHM1176->ClearErrorList();
	}
	// NoMeasurements = THM1176_NO_MEASUREMENTS+1, retrieve all.
	{
		sArbitraryMeasurements l_Select = { true, true, true, true, true, THM1176_NO_MEASUREMENTS+1 };
		
		// ASCII format.
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatAscii));
		ASSERT_EQ(false, pTHM1176->MeasurementsGet(l_Select, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		{
			l_ErrorList = pTHM1176->CurrentErrorList();
			EXPECT_EQ(3, l_ErrorList.size());
			EXPECT_EQ(-222, l_ErrorList[0].Code);
			EXPECT_EQ(-222, l_ErrorList[1].Code);
			EXPECT_EQ(-222, l_ErrorList[2].Code);
		}
		EXPECT_EQ(0, l_Bx.size());
		EXPECT_EQ(0, l_By.size());
		EXPECT_EQ(0, l_Bz.size());
		EXPECT_EQ(0, l_Temperature);
		ASSERT_EQ(0, l_TimestampList.size());
		
		// Retrieve the data in INTEGER format.
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatInteger));
		ASSERT_EQ(false, pTHM1176->MeasurementsGet(l_Select, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		{
			l_ErrorList = pTHM1176->CurrentErrorList();
			EXPECT_EQ(3, l_ErrorList.size());
			EXPECT_EQ(-222, l_ErrorList[0].Code);
			EXPECT_EQ(-222, l_ErrorList[1].Code);
			EXPECT_EQ(-222, l_ErrorList[2].Code);
		}
		EXPECT_EQ(0, l_Bx.size());
		EXPECT_EQ(0, l_By.size());
		EXPECT_EQ(0, l_Bz.size());
		EXPECT_EQ(0, l_Temperature);
		ASSERT_EQ(0, l_TimestampList.size());
		
		// Retrieve the data in PACKED,2 format.
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatPacked2Byte));
		ASSERT_EQ(false, pTHM1176->MeasurementsGet(l_Select, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		{
			l_ErrorList = pTHM1176->CurrentErrorList();
			EXPECT_EQ(3, l_ErrorList.size());
			EXPECT_EQ(-222, l_ErrorList[0].Code);
			EXPECT_EQ(-222, l_ErrorList[1].Code);
			EXPECT_EQ(-222, l_ErrorList[2].Code);
		}
		EXPECT_EQ(0, l_Bx.size());
		EXPECT_EQ(0, l_By.size());
		EXPECT_EQ(0, l_Bz.size());
		EXPECT_EQ(0, l_Temperature);
		ASSERT_EQ(0, l_TimestampList.size());
		
		// Retrieve the data in PACKED,1 format.
		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatPacked1Byte));
		ASSERT_EQ(false, pTHM1176->MeasurementsGet(l_Select, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		{
			l_ErrorList = pTHM1176->CurrentErrorList();
			EXPECT_EQ(3, l_ErrorList.size());
			EXPECT_EQ(-222, l_ErrorList[0].Code);
			EXPECT_EQ(-222, l_ErrorList[1].Code);
			EXPECT_EQ(-222, l_ErrorList[2].Code);
		}
		EXPECT_EQ(0, l_Bx.size());
		EXPECT_EQ(0, l_By.size());
		EXPECT_EQ(0, l_Bz.size());
		EXPECT_EQ(0, l_Temperature);
		ASSERT_EQ(0, l_TimestampList.size());
	}
	// Try changing units.
	{
		sArbitraryMeasurements l_Select = { true, true, true, false, false, static_cast<U32>(THM1176_NO_MEASUREMENTS) };
		CFluxList l_Bx1, l_By1, l_Bz1;

		l_Bx.clear(); l_By.clear(); l_Bz.clear(); l_Temperature = 0; l_TimestampList.clear();
		ASSERT_EQ(true, pTHM1176->SetFormat(kComFormatInteger));

		CUnitsList l_AllUnits;
		ASSERT_EQ(true, pTHM1176->GetAllUnits(l_AllUnits));
		ASSERT_LT(1, l_AllUnits.size());

		ASSERT_EQ(true, pTHM1176->ParmUnitsSet(l_AllUnits[0]));
		ASSERT_EQ(true, pTHM1176->MeasurementsGet(l_Select, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_Bx.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_By.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_Bz.size());
		
		ASSERT_EQ(true, pTHM1176->ParmUnitsSet(l_AllUnits[1]));
		ASSERT_EQ(true, pTHM1176->MeasurementsGet(l_Select, l_Bx1, l_By1, l_Bz1, l_Units, l_Temperature, l_TimestampList));
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_Bx1.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_By1.size());
		EXPECT_EQ(THM1176_NO_MEASUREMENTS, l_Bz1.size());
		
		U32 l_Divisor, l_Divisor1;
		ASSERT_EQ(true, pTHM1176->GetDivisor(l_AllUnits[0], l_Divisor));
		ASSERT_EQ(true, pTHM1176->GetDivisor(l_AllUnits[1], l_Divisor1));
		
		for (auto l_pBx = l_Bx.begin(), l_pBx1 = l_Bx1.begin();
			 l_pBx < l_Bx.end() && l_pBx1 < l_Bx1.end();
			 l_pBx++, l_pBx1++)
			EXPECT_FLOAT_EQ(*l_pBx * l_Divisor, *l_pBx1 * l_Divisor1);
		for (auto l_pBy = l_By.begin(), l_pBy1 = l_By1.begin();
			 l_pBy < l_By.end() && l_pBy1 < l_By1.end();
			 l_pBy++, l_pBy1++)
			EXPECT_FLOAT_EQ(*l_pBy * l_Divisor, *l_pBy1 * l_Divisor1);
		for (auto l_pBz = l_Bz.begin(), l_pBz1 = l_Bz1.begin();
			 l_pBz < l_Bz.end() && l_pBz1 < l_Bz1.end();
			 l_pBz++, l_pBz1++)
			EXPECT_FLOAT_EQ(*l_pBz * l_Divisor, *l_pBz1 * l_Divisor1);
	}
}

/// \test Test that angle correction is not applied under the proper circumstances.
TEST_F(CTHM1176MeasuresTest, ApplyRotationMatrix)
{
	// Note 1: This test is most meaningful with a magnetic field.
	// Note 2: Initial testing compared results manually with LabVIEW THM1176 software (v 4.1).
	CFluxList l_Bx, l_By, l_Bz;
	eUnits l_Units;
	U16 l_Temperature = 0;
	CTimestampList l_TimestampList;
	CErrorList l_ErrorList;

	// Fetch Bx, By, Bz separately – cannot apply angle correction.
	CFluxList l_BxRaw, l_ByRaw, l_BzRaw;
	sArbitraryMeasurements l_Select;
	
	l_Select = { true, false, false, false, false, 1 };
	ASSERT_EQ(true, pTHM1176->MeasurementsGet(l_Select, l_BxRaw, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
	EXPECT_EQ(1, l_BxRaw.size());
	EXPECT_EQ(0, l_By.size());
	EXPECT_EQ(0, l_Bz.size());
	EXPECT_EQ(0, l_Temperature);
	ASSERT_EQ(0, l_TimestampList.size());
	l_ErrorList = pTHM1176->CurrentErrorList();
	ASSERT_EQ(1, l_ErrorList.size());
	EXPECT_EQ(THM1176_NO_ANGLE_CORRECTION_CODE, l_ErrorList[0].Code);
	pTHM1176->ClearErrorList();
	
	l_Select = { false, true, false, false, false, 1 };
	ASSERT_EQ(true, pTHM1176->MeasurementsGet(l_Select, l_Bx, l_ByRaw, l_Bz, l_Units, l_Temperature, l_TimestampList));
	EXPECT_EQ(0, l_Bx.size());
	EXPECT_EQ(1, l_ByRaw.size());
	EXPECT_EQ(0, l_Bz.size());
	EXPECT_EQ(0, l_Temperature);
	ASSERT_EQ(0, l_TimestampList.size());
	l_ErrorList = pTHM1176->CurrentErrorList();
	ASSERT_EQ(1, l_ErrorList.size());
	EXPECT_EQ(THM1176_NO_ANGLE_CORRECTION_CODE, l_ErrorList[0].Code);
	pTHM1176->ClearErrorList();

	l_Select = { false, false, true, false, false, 1 };
	ASSERT_EQ(true, pTHM1176->MeasurementsGet(l_Select, l_Bx, l_By, l_BzRaw, l_Units, l_Temperature, l_TimestampList));
	EXPECT_EQ(0, l_Bx.size());
	EXPECT_EQ(0, l_By.size());
	EXPECT_EQ(1, l_BzRaw.size());
	EXPECT_EQ(0, l_Temperature);
	ASSERT_EQ(0, l_TimestampList.size());
	l_ErrorList = pTHM1176->CurrentErrorList();
	ASSERT_EQ(1, l_ErrorList.size());
	EXPECT_EQ(THM1176_NO_ANGLE_CORRECTION_CODE, l_ErrorList[0].Code);
	pTHM1176->ClearErrorList();

	// Apply the rotation matrix.
	Matrix3f l_Matrix;
	ASSERT_EQ(true, pTHM1176->GetRotationMatrix(l_Matrix));
	Vector3f l_B;
	l_B << l_BxRaw[0], l_ByRaw[0], l_BzRaw[0];
	l_B = l_Matrix * l_B;

	// Fetch l_Bx, By, Bz all together – angle correction applied.
	l_Select = { true, true, true, false, false, 1 };
	ASSERT_EQ(true, pTHM1176->MeasurementsGet(1, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
	EXPECT_EQ(1, l_Bx.size());
	EXPECT_EQ(1, l_By.size());
	EXPECT_EQ(1, l_Bz.size());
	EXPECT_LT(0, l_Temperature);
	ASSERT_EQ(1, l_TimestampList.size());
	l_ErrorList = pTHM1176->CurrentErrorList();
	ASSERT_EQ(0, l_ErrorList.size());

	// Check the results.
	EXPECT_FLOAT_EQ(l_B(0), l_Bx[0]);
	EXPECT_FLOAT_EQ(l_B(1), l_By[0]);
	EXPECT_FLOAT_EQ(l_B(2), l_Bz[0]);
	
	// Make sure that we get a warning when Use Calibration is off.
	ASSERT_EQ(true, pTHM1176->ParmUseCalibrationSet(false));
	// NOTE: We seem to be getting spurious 206 (Timer Overrun) errors here – firmware bug?
	//		To catch it, uncomment the assertion, below.
	U16 l_Status = pTHM1176->Initiate();
	// ASSERT_EQ(true, l_Status);

	l_Select = { true, true, true, false, false, 1 };
	ASSERT_EQ(true, pTHM1176->MeasurementsGet(1, l_Bx, l_By, l_Bz, l_Units, l_Temperature, l_TimestampList));
	EXPECT_EQ(1, l_Bx.size());
	EXPECT_EQ(1, l_By.size());
	EXPECT_EQ(1, l_Bz.size());
	EXPECT_LT(0, l_Temperature);
	ASSERT_EQ(1, l_TimestampList.size());
	l_ErrorList = pTHM1176->CurrentErrorList();
	ASSERT_EQ(1, l_ErrorList.size());
	EXPECT_EQ(THM1176_NO_ANGLE_CORRECTION_CODE, l_ErrorList[0].Code);
	pTHM1176->ClearErrorList();
}

