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

//////////////////////////////////////////////////////////////////////////
/// \file
/// \brief Type definitions for C++ API for Metrolab THM1176/TFM1186.

#pragma once

// Standard includes
#include <string>
#include <vector>
#include <cmath>
#include <ctime>

// Personal includes
#include "OSDefines.h"
#include "IEEE488InstrumentTypes.h"

namespace MTL
{
namespace Instrument
{
namespace THM1176Types
{

//----------------------------------------------------------------------//
//							Basic Types									//
//----------------------------------------------------------------------//
typedef F32					tFlux;	///< \brief Flux density value, as 32-bit floating-point number.

//----------------------------------------------------------------------//
//								Status									//
//----------------------------------------------------------------------//
/// \brief Enumeration of %SCPI status register sets.
enum eStatusRegisterSet
{
    kStatusByte = 0,					///< Status Byte.
    kStandardEventStatusRegister,		///< Standard Event Status Register.
    kStatusQuestionableStatusRegister,	///< Questionable Status Register.
    kStatusOperationStatusRegister		///< Operation Status Register.
};
/// \brief Enumeration of %SCPI status register types.
enum eStatusRegisterType
{
    kStatusEvent = 0,					///< Event register
    kStatusCondition,					///< Condition register
    kStatusEnable						///< Enable register
};
/// \brief Complete identification of a %SCPI status register.
struct sStatusRegister
{
    eStatusRegisterSet	Set		= kStatusByte;	///< %SCPI register set.
    eStatusRegisterType	Type	= kStatusEvent;	///< %SCPI register type.

public:
    /// \brief Constructor.
    /// \param[in] S	%SCPI register set.
    /// \param[in] T	%SCPI register type.
    sStatusRegister(eStatusRegisterSet S = { }, eStatusRegisterType T = { })
        : Set(S), Type(T)
    { }
};
/// \brief List of %SCPI status registers.
class RegisterList : public std::vector<sStatusRegister>
{
};
/// \brief List of values returned for several %SCPI status registers.
///
/// *Note:*
/// The original IEEE 488.2 status registers (Status Byte and Standard Event Status Register)
/// are actually 8-bit registers, whereas the %SCPI extensions (Questionable Status Register
/// and Operation Status Register) really are 16-bit registers.
/// For consistency, all registers are treated as 16-bit.
class StatusValues : public std::vector<U16>
{
};

/// \brief Union to access the Status Byte as integer or bit fields.
union uStatusByte
{
    /// \brief Access the Status Byte as unsigned integer.
    U16	RawSTB = 0;

    /// \brief Access the Status Byte as bit fields.
    struct sStatusByte
    {
        // Contains a 1-byte status summary. The THM1176 uses the following bits:
        U8		NA0_1	: 2;	///< Not Available
        U8		EAV		: 1;	///< Error Available in Error / Event Queue
        U8		QSB		: 1;	///< QUEStionable status summary bit
        U8		MAV		: 1;	///< Message Available
        U8		ESB		: 1;	///< Standard Event Status Register summary bit
        U8		RQS		: 1;	///< ReQuest for Service
        U8		OSB		: 1;	///< OPERation status summary bit
    } StatusByte;			///< Access the Status Byte as bit fields.
};
/// \brief Union to access the Standard Event Status Register as integer or bit fields.
union uStandardEvent
{
    /// \brief Access the Standard Event Status Register as unsigned integer.
    U16 RawSE = 0;

    /// \brief Access the Standard Event Status Register as bit fields.
    struct sStandardEvent
    {
        // Latches certain standardized events. The THM1176 uses the following bits:
        U8		OperationComplete		: 1;	///< *OPC has flagged operation complete
        U8		NA1						: 1;	///< Not Available
        U8		QueryError				: 1;	///< Error in preceding query
        U8		DeviceDependentError	: 1;	///< Errors specific to the THM1176, including internal errors
        U8		ExecutionError			: 1;	///< Error detected during command execution
        U8		CommandError			: 1;	///< Error in preceding command
        U8		NA6                     : 1;	///< Not Available
        U8		PowerOn					: 1;	///< THM1176 has been powered up
    } StandardEvent;						///< Access the Standard Event Status Register as bit fields.
};
/// \brief Union to access the Operation Status Register as integer or bit fields.
union uOPERation
{
    /// \brief Access the Operation Status Register as unsigned integer.
    U16 RawOPER = 0;

    /// \brief Access the Operation Status Register as bit fields.
    struct sOPERation
    {
        // Captures conditions which are part of the instrument's normal operation. The THM1176 uses the following bits:
        U16		CALibrating			: 1;	///< Measuring zero-offset
        U16		NA1                 : 1;	///< Not Available
        U16		RANGing				: 1;	///< Changing range
        U16		NA3                 : 1;	///< Not Available
        U16		MEASuring			: 1;	///< Measuring magnetic field strength
        U16		WaitingForTRIGger	: 1;	///< Waiting for trigger
        U16		NA6_15				: 10;	///< Not Available
    } OPERation;						///< Access the Operation Status Register as bit fields.
};
/// \brief Union to access the Questionable Status Register as integer or bit fields.
union uQUEStionable
{
    /// \brief Access the Questionable Status Register as unsigned integer.
    U16	RawQUES = 0;

    /// \brief Access the Questionable Status Register as bit fields.
    struct sQUEStionable
    {
        // Indicates conditions that may reduce the quality of the measurement. The THM1176 sets the following bits:
        U16		NA0_4				: 5;	///< Not Available
        U16		Frequency           : 1;	///< Acquisition buffer or the timed trigger has been overrun
        U16		NA6_8               : 3;	///< Not Available
        U16		Overrange			: 1;	///< Measurement was over-range
        U16		NA10_15				: 6;	///< Not Available
    } QUEStionable;						///< Access the Questionable Status Register as bit fields.
};

std::ostream &  operator<<(std::ostream & Stream, const eStatusRegisterSet & RegSet);               ///< Status register set stream output.
std::ostream &  operator<<(std::ostream & Stream, const eStatusRegisterType & RegType);             ///< Status register type stream output.
std::ostream &  operator<<(std::ostream & Stream, const sStatusRegister & RegDef);                  ///< Status register definition stream output.
std::ostream &  operator<<(std::ostream & Stream, const RegisterList & RegList);                    ///< Status register list stream output.
std::ostream &  operator<<(std::ostream & Stream, const StatusValues & StatusList);                 ///< Status value list stream output.
std::ostream &  operator<<(std::ostream & Stream, const uStatusByte & StatusByte);                  ///< Status byte stream output.
std::ostream &  operator<<(std::ostream & Stream, const uStandardEvent & StdEventReg);              ///< Standard event register stream output.
std::ostream &  operator<<(std::ostream & Stream, const uOPERation & OperReg);                      ///< OPERation register stream output.
std::ostream &  operator<<(std::ostream & Stream, const uQUEStionable & QuestReg);                  ///< QUEStionable register stream output.

//----------------------------------------------------------------------//
//								Flux									//
//----------------------------------------------------------------------//
/// \brief List of flux density values.
class CFluxList : public std::vector<tFlux>
{
};
std::ostream &  operator<<(std::ostream & Stream, const CFluxList & FluxList); ///< Flux list stream output.

//----------------------------------------------------------------------//
//								Units									//
//----------------------------------------------------------------------//
/// \brief Enumeration of possible measurement units.
///
/// *Note:*
/// Not all models support all measurement units.
enum eUnits
{
    kT,			///< Tesla
    kmT,		///< Milli-Tesla
    kuT,		///< Micro-Tesla
    knT,		///< Nano-Tesla
    kGauss,		///< Gauss
    kkGauss,	///< Kilo-Gauss
    kmGauss,	///< Milli-Gauss
    kMHzp		///< Equivalent proton NMR resonant frequency, in Mega-Hertz
};
/// \brief List of measurement units.
class CUnitsList : public std::vector<eUnits>
{
};
/// \brief List of divisors, one per measurement unit
///
/// *Note:*
/// Each model THM1176/TFM1186 has a "base unit" - the measurement units used
///	when returning the results in binary format.
/// The divisor is the factor that converts the base units to the desired units.
class CDivisorList : public std::vector<U32>
{
};
std::ostream &  operator<<(std::ostream & Stream, const eUnits & Units);                ///< Units stream output.
std::ostream &  operator<<(std::ostream & Stream, const CUnitsList & UnitsList);        ///< Units list stream output.
std::ostream &  operator<<(std::ostream & Stream, const CDivisorList & DivisorList);    ///< Divisor list stream output.

//----------------------------------------------------------------------//
//								Errors									//
//----------------------------------------------------------------------//
/// \brief Error returned by the instrument.
struct sError
{
    I32				Code;			///< Error code.
    std::string		Description;	///< Error description.
    std::string		Context;		///< %SCPI commands being executed at time of error.

public:
    /// \brief Constructor.
    /// \param[in] Code			Error code.
    /// \param[in] Description	Error description.
    /// \param[in] Context		%SCPI commands being executed at time of error.
    sError(I32 Code = 0, std::string Description = "", std::string Context = "")
        : Code(Code), Description(Description), Context(Context)
    { }
    bool operator==(sError other) const;	///< Equality operator.
    bool operator!=(sError other) const;	///< Inequality operator.
};
/// \brief List of errors returned by the instrument.
class CErrorList : public std::vector<sError>
{
};
std::ostream &  operator<<(std::ostream & Stream, const sError & Error);                ///< Error stream output.
std::ostream &  operator<<(std::ostream & Stream, const CErrorList & ErrorList);        ///< Error list stream output.

//----------------------------------------------------------------------//
//								Parameters								//
//----------------------------------------------------------------------//
//------------------------------------------//
// Generic
/// \brief Parameter template, with current/min/max/default values.
/// \tparam DataType Parameter's data type (e.g. I32 or F32).
template <class DataType>
struct sBoundedParm
{
    DataType	Val{};	///< Current value.
    DataType	Min{};	///< Lower bound.
    DataType	Max{};	///< Upper bound.
    DataType	Def{};	///< Default value.

public:
    /// \brief Constructor
    /// \param[in] Val	Current value.
    /// \param[in] Min	Lower bound.
    /// \param[in] Max	Upper bound.
    /// \param[in] Def	Default value.
    sBoundedParm(DataType Val = 0, DataType Min = 0, DataType Max = 0, DataType Def = 0)
        : Val(Val), Min(Min), Max(Max), Def(Def)
    { }
    void clear(void)
    {
        Val = { };
        Min = { };
        Max = { };
        Def = { };
    }									///< Clear the parameter to default values.
    bool operator==(sBoundedParm other) const
    {
        return (
                    Val	== other.Val &&
                    Min	== other.Min &&
                    Max	== other.Max &&
                    Def	== other.Def
                    );
    }									///< Equality operator.
    bool operator!=(sBoundedParm other) const
    {
        return (!operator==(other));
    }									///< Inequality operator.
    sBoundedParm & operator=(const DataType & scalar)
    {
        Val = scalar;
        Min = scalar;
        Max = scalar;
        Def = scalar;
        return *this;
    }									///< Set value, min, max and default to given value.
};

/// \brief Parameter template, with only current value.
/// \tparam DataType Parameter's data type.
template <class DataType>
using uParm = DataType;

/// \brief Sample parameter template.
/// \tparam ParmType Type of template: uParm or sBoundedParm.
///
/// The declaration would be sExample<uParm> or sExample<sBoundedParm>,
/// depening on whether we want only the current value or
/// the current/min/max/default values.
template <template<class> class ParmType>
struct sExample
{
    bool				ExampleState;	///< Example of a boolean element.
    ParmType<F64>		ExampleF64;		///< Example of an F64 element.
    ParmType<F32>		ExampleF32;		///< Example of an F32 element.
};

//------------------------------------------//
// Version
/// \brief Major and minor version numbers.
struct sVersion
{
    U8					Major	= 0;	///< Major version number.
    U8					Minor	= 0;	///< Minor version number.
    std::string         Name	= "";	///< Version name.

public:
    /// \brief Constructor.
    /// \param[in] Maj	Major version number.
    ///	\param[in] Min	Minor version number.
    sVersion(U8 Maj = 0, U8 Min = 0)
        : Major(Maj), Minor(Min)
    { }
    void clear(void);						///< Clear to default (zeroes).
    bool operator==(sVersion other) const;	///< Equality operator.
    bool operator!=(sVersion other) const;	///< Inequality operator.
};
std::ostream &  operator<<(std::ostream & Stream, const sVersion & Version);        ///< Version stream output.

//------------------------------------------//
// Instrument enum model
/// \brief Enumeration of instrument (THM1176-LF, THM1176-MF, ...) model
enum class eInstrModel {
    kTHM1176LF,
    kTHM1176MF,
    kTHM1176HF,
    kTHM1176HFC,
    kTFM1186,
    kUnknown
};

//------------------------------------------//
// Thm Revision
/// \brief THM1176 type A or B
enum eModelRevision { kA, kB };

//------------------------------------------//
// Identifier
/// \brief %Instrument's identification string - parsed version.
struct sIdentifier
{
    std::string			Manufacturer;		///< Manufacturer name ("Metrolab Technology SA")
    std::string			Model;				///< Model name (e.g. "THM1176-MF")
    U32					SerialNumber = 0;	///< Serial number.
    struct sVersion		ElectronicsVersion;	///< Version numbers of electronics.
    struct sVersion		ProbeVersion;		///< Version numbers of probe.
    struct sVersion		FirmwareVersion;	///< Version numbers of firmware.
    enum eModelRevision ModelRevision;      ///< Revision of Model.
    enum eInstrModel    InstrModel;         ///< Enumerator of instrument model.

public:
    /// \brief Constructor.
    /// \param[in] Mfr	Manufacturer name ("Metrolab Technology SA")
    /// \param[in] Mdl	Model name (e.g. "THM1176-MF")
    /// \param[in] SN	Serial number.
    /// \param[in] EVsn	Version numbers of electronics.
    /// \param[in] PVsn	Version numbers of probe.
    /// \param[in] FVsn	Version numbers of firmware.
    /// \param[in] ThmRev	Revision of THM model.
    /// \param[in] InstrMdl	Enumeration of instrument model.
    sIdentifier(std::string Mfr = "", std::string Mdl = "", U32 SN = 0, struct sVersion EVsn = { }, struct sVersion PVsn = { }, struct sVersion FVsn = { }, eModelRevision ThmRev = kA, eInstrModel InstrMdl= eInstrModel::kUnknown)
        : Manufacturer(Mfr), Model(Mdl), SerialNumber(SN), ElectronicsVersion(EVsn), ProbeVersion(PVsn), FirmwareVersion(FVsn), ModelRevision(ThmRev), InstrModel(InstrMdl)
    { }
    void clear(void);							///< Clear to default.
    bool operator==(sIdentifier other) const;	///< Equality oeprator.
    bool operator!=(sIdentifier other) const;	///< Inequality operator.
};
std::ostream &  operator<<(std::ostream & Stream, const sIdentifier & ID);          ///< Identifier stream output.

//------------------------------------------//
// Averaging
/// \brief Averaging parameter.
/// \tparam ParmType uParm for value only, or sBoundedParm for value/min/max/default
template <template<class> class ParmType>
struct sAveraging
{
    ParmType<U16>			NoPoints{};			///< Number of points in block average.

public:
    /// \brief Constructor.
    /// \param[in] NPts Number of points in block average.
    sAveraging(ParmType<U16> NPts = { })
        : NoPoints(NPts)
    { }
    void clear(void)
    {
        NoPoints = { };
    }											///< Clear to default (zero).
    bool operator==(sAveraging other) const
    {
        return (NoPoints == other.NoPoints);
    }											///< Equality operator.
    bool operator!=(sAveraging other) const
    {
        return (!operator==(other));
    }											///< Inequality operator.
};
std::ostream &  operator<<(std::ostream & Stream, const sAveraging<uParm> & AvgParm);        ///< Averaging parameters stream output.
std::ostream &  operator<<(std::ostream & Stream, const sAveraging<sBoundedParm> & AvgParm); ///< Averaging bounds stream output.

//------------------------------------------//
// Input Trigger
/// \brief Enumeration of possible trigger sources.
enum eInputTriggerSource
{
    kInputTrigSrcImmediate,	///< Immediate trigger: start measurement immediately after previous one completes.
    kInputTrigSrcTimer,		///< Timed trigger: start measurement at regular intervals.
    kInputTrigSrcBus		///< Bus trigger: start measurement upon USB trigger message.
};
/// \brief Input trigger parameter.
/// \tparam ParmType uParm for value only, or sBoundedParm for value/min/max/default
template <template<class> class ParmType>
struct sInputTrigger
{
    eInputTriggerSource		Source{ };		///< Trigger source.
    ParmType<F64>			Period_s{ };	///< Trigger period, for timed trigger.
    ParmType<U16>			Count{ };		///< Trigger count: take this many measurements before sending results.

public:
    /// \brief Constructor.
    /// \param[in] Src	Trigger source.
    /// \param[in] Per	Trigger period.
    /// \param[in] Cnt	Trigger count.
    sInputTrigger(eInputTriggerSource Src = { }, ParmType<F64> Per = { }, ParmType<U16> Cnt = { })
        : Source(Src), Period_s(Per), Count(Cnt)
    { }
    void clear(void)
    {
        Source		= { };
        Period_s	= { };
        Count		= { };
    }										///< Clear to default.
    bool operator==(sInputTrigger other) const
    {
        return (
                    Source		== other.Source &&
                    Period_s	== other.Period_s &&
                    Count		== other.Count
                    );
    }										///< Equality operator.
    bool operator!=(sInputTrigger other) const
    {
        return (!operator==(other));
    }										///< Inequality operator.
};
std::ostream &  operator<<(std::ostream & Stream, const eInputTriggerSource & TrgSrc);
std::ostream &  operator<<(std::ostream & Stream, const sInputTrigger<uParm> & TrigParm);        ///< Trigger parameters stream output.
std::ostream &  operator<<(std::ostream & Stream, const sInputTrigger<sBoundedParm> & TrigParm); ///< Trigger bounds stream output.

//------------------------------------------//
// Format
/// \brief Enumeration of possible formats for returned data.
enum eCommunicationFormat
{
    kComFormatAscii,		///< Human-legible text.
    kComFormatInteger,		///< Binary (32-bit integers)
    kComFormatPacked2Byte,	///< Binary packed: first field value as I32, remainder deltas as I16.
    kComFormatPacked1Byte	///< Binary packed: first field value as I32, remainder deltas as I8.
};
std::ostream &  operator<<(std::ostream & Stream, const eCommunicationFormat & CommFormat);     ///< Comm format stream output.

//------------------------------------------//
// Range
/// \brief Measurement range parameter.
template <template<class> class ParmType>
struct sRange
{
    bool					Auto{ };	///< Auto-ranging enabled.
    ParmType<tFlux>			Range{ };	///< Measurement range, if auto-ranging is not enabled.

public:
    /// \brief Constructor.
    /// \param[in] A	Auto-ranging enabled.
    /// \param[in] R	Measurement range, if auto-ranging is not enabled.
    sRange(bool A = { }, ParmType<tFlux> R = { })
        : Auto(A), Range(R)
    { }
    void clear(void)
    {
        Auto	= { };
        Range	= { };
    }										///< Clear to default values.
    bool operator==(sRange other) const
    {
        return (
                    Auto	== other.Auto &&
                    Range	== other.Range
                    );
    }										///< Equality operator.
    bool operator!=(sRange other) const
    {
        return (!operator==(other));
    }										///< Inequality operator.
};
std::ostream &  operator<<(std::ostream & Stream, const sRange<uParm> & RangeParm);        ///< Range parameters stream output.
std::ostream &  operator<<(std::ostream & Stream, const sRange<sBoundedParm> & RangeParm); ///< Range bounds stream output.

//------------------------------------------//
// Files
/// \brief Directory entry in the instrument's file system.
struct sFile
{
    size_t			Size	= 0;	///< File size, in bytes.
    std::string		Path;			///< File path.
    std::string		Type;			///< File type ("ASCII" or "BINARY").

public:
    /// \brief Constructor.
    /// \param[in] S	File size, in bytes.
    /// \param[in] P	File path.
    /// \param[in] T	File type ("ASCII" or "BINARY").
    sFile(size_t S = 0, std::string P = "", std::string T = "")
        : Size(S), Path(P), Type(T)
    { }
    void clear();							///< Clear to default values.
    bool operator==(sFile other) const;		///< Equality operator.
    bool operator!=(sFile other) const;		///< Inequality operator.
};
/// \brief List of directory entries.
typedef std::vector<sFile>		tFileList;

std::ostream &  operator<<(std::ostream & Stream, const sFile & FileInfo);                  ///< File info stream output.
std::ostream &  operator<<(std::ostream & Stream, const tFileList & FileList);              ///< File List stream output.

//----------------------------------------------------------------------//
//								Time stamp								//
//----------------------------------------------------------------------//
/// \brief Timestamp for a measurement.
///
/// *Note:*
/// Timestamps are returned from the instrument as the number of nanoseconds since the instrument booted,
/// with a timer resolution of 167 ns.
/// By adding the computer's UNIX Epoch timestamp of when the instrument booted (usually a number of seconds since 1970),
/// we obtain an absolute measurement timestamp, with a resolution of 167 ns.
/// This class represents such an absolute measurement timestamp as a structure, [ UNIX Epoch time, residual in nanoseconds ].
/// We can represent the instrument's timestamp as Ti = [ 0 s, X ns ], and the computer time as Tc = [ Y s, 0 ns ].
/// One can then compute the measurement timestamp as (Ti + Tc); the class automatically takes care of carry-overs from ns to s.
class CAbsoluteTimestamp
{
private:
    std::time_t				s	= 0;
    U64						ns	= 0;

public:
    static const U64		NS_PER_SEC		= 1000000000;					///< Class constant: number of ns per s.
    /// \brief Constructor.
    /// \param[in] Seconds		Number of seconds: UNIX Epoch time, or zero for instrument's nanosecond timestamp.
    /// \param[in] Nanoseconds	Number of nanoseconds; automatically normalized to [ seconds, residual nanoseconds ].
    CAbsoluteTimestamp(std::time_t Seconds = 0, U64 Nanoseconds = 0);
    CAbsoluteTimestamp &	operator= (const CAbsoluteTimestamp & Value);	///< Assignment operator.
    bool					operator==(CAbsoluteTimestamp other);			///< Equality operator.
    bool					operator!=(CAbsoluteTimestamp other);			///< Inequality operator.
    std::time_t				seconds(void) const;							///< Fetch the number of seconds.
    U64						nanoseconds(void) const;						///< Fetch the number of nanoseconds.
    void					clear(void);									///< Clear to default values (zeroes)
};

CAbsoluteTimestamp			operator+ (CAbsoluteTimestamp a, CAbsoluteTimestamp b);	///< Timestamp addition operator.
CAbsoluteTimestamp			operator- (CAbsoluteTimestamp a, CAbsoluteTimestamp b);	///< Timestamp subtraction operator.
std::ostream &				operator<<(std::ostream & Stream, const CAbsoluteTimestamp & Timestamp); ///< Timestamp stream output.

/// \brief List of timestamps.
class CTimestampList : public std::vector<U64>
{
public:
    /// \brief Estimate the measurement period from this timestamp list, by means of a least-squares fit.
    /// \param[out]	Period	The estimated measurement period, in seconds.
    ///
    /// *Note:*
    /// This is really useful only for bus-triggered data.
    /// Otherwise, we presumably know the trigger period from the trigger and averaging parameters.
    bool					GetEstimatedPeriod(F64 & Period);
};
std::ostream &				operator<<(std::ostream & Stream, const CTimestampList & TimestampList); ///< Timestamp list stream output.

//----------------------------------------------------------------------//
//								Measurements							//
//----------------------------------------------------------------------//
/// \brief Specify the measurement data to be returned.
struct sArbitraryMeasurements
{
    bool	Bx = false;				///< Return the flux density X-component.
    bool	By = false;				///< Return the flux density Y-component.
    bool	Bz = false;				///< Return the flux density Z-component.
    bool	Temperature = false;	///< Return the sensor temperature.
    bool	Timestamp = false;		///< Return the timestamp.
    U32		NoMeasurements = 0;		///< Return this number of measurements.

public:
    /// \brief Constructor.
    /// \param[in] Bx		Return the flux density X-component.
    /// \param[in] By		Return the flux density Y-component.
    /// \param[in] Bz		Return the flux density Z-component.
    /// \param[in] Temp		Return the sensor temperature.
    /// \param[in] Time		Return the timestamp.
    /// \param[in] NMeas	Return this number of measurements.
    sArbitraryMeasurements(bool Bx = false, bool By = false, bool Bz = false, bool Temp = false, bool Time = false, U32 NMeas = 0)
        : Bx(Bx), By(By), Bz(Bz), Temperature(Temp), Timestamp(Time), NoMeasurements(NMeas)
    { }
    void	clear();										///< Clear to default values.
    bool	operator==(sArbitraryMeasurements other) const;	///< Equality operator.
    bool	operator!=(sArbitraryMeasurements other) const;	///< Inequality operator.
};

/// \brief Summary of the parameters used to make a measurement.
struct sMeasurementConditions
{
    sAveraging<uParm>		AveragingParms;			///< Averaging parameters.
    sInputTrigger<uParm>	TriggerParms;			///< Trigger parameters.
    bool					UseCalibration = false;	///< Use calibration data.
    tFlux                   Range;                  ///< Current range setting

public:
    /// \brief Constructor.
    /// \param[in] AvgParms		Averaging parameters.
    /// \param[in] TrigParms	Trigger parameters.
    /// \param[in] UseCal		Use calibration data.
    /// \param[in] RangeIn		Current range setting.
    sMeasurementConditions(sAveraging<uParm> AvgParms = { }, sInputTrigger<uParm> TrigParms= { }, bool UseCal = false, tFlux RangeIn = 0.)
        : AveragingParms(AvgParms), TriggerParms(TrigParms), UseCalibration(UseCal), Range(RangeIn)
    { }
    void clear();											///< Clear to default values.
    bool operator==(sMeasurementConditions other) const;	///< Equality operator.
    bool operator!=(sMeasurementConditions other) const;	///< Inequality operator.
};

std::ostream &				operator<<(std::ostream & Stream, const sArbitraryMeasurements & MeasSpec); ///< Arbitrary measurement specification stream output.
std::ostream &				operator<<(std::ostream & Stream, const sMeasurementConditions & MeasCond); ///< Measurement conditions stream output.

} // namespace THM1176Types
} // namespace Instrument
} // namespace MTL
