/************************************************************************************************
 *  Copyright DEWETRON GmbH 2014-2025                                                           *
 *                                                                                              *
 *   This is the public interface file for DMD file reader library.                             *
 *   Revision: 1.0                                                                              *
 ************************************************************************************************/

/**
 * @file dmd_reader_api_interface.h
 * @author DEWETRON GmbH.
 * @date 19 Nov 2014
 * @brief File containing the public DMD file reader interface
 *
 * SUPPORTED FEATURES:
 *  - Read raw data: Analog, Counter, Digital, FFT,...
 *  - Read reduced data (statistical data that is optionally stored during slow monitoring)
 *  - Read meta data: file header, markers, basic channel parameters
 *
 * NOT SUPPORTED FEATURES RIGHT NOW:
 *  - video channel data read
 */

#ifndef _DEWETRON_DMD_READER_API_INTERFACE_
#define _DEWETRON_DMD_READER_API_INTERFACE_

#if !defined(BUILD_X86) && !defined(BUILD_X64)
    #error Please define BUILD_X86 or BUILD_X64 to select the build architecture
#endif

#ifdef __cplusplus
extern "C" {
#endif

// ------------------------------------------------------------------------------------------------
//  1. INTERFACE VERSION
// ------------------------------------------------------------------------------------------------

/**
 * @brief Definition of the public interface version.
 *
 * The public interface version maybe different to the linked reader api dll version.
 * @note In order to validate interface compatibility use DMDReader_Initialize.
 */
#define DMDREADER_INTERFACE_VERSION_MAJOR 1
#define DMDREADER_INTERFACE_VERSION_MINOR 3

// ------------------------------------------------------------------------------------------------
//  2. BASIC DATA TYPES
// ------------------------------------------------------------------------------------------------

#ifdef _MSC_VER
    #define DMDREADER_EXPORT __stdcall
    typedef unsigned char       DMDReader_uint8;          // Unsigned  8 bit quantity
    typedef signed   char       DMDReader_sint8;          // Signed    8 bit quantity
    typedef unsigned short      DMDReader_uint16;         // Unsigned 16 bit quantity
    typedef signed   short      DMDReader_sint16;         // Signed   16 bit quantity
    typedef unsigned int        DMDReader_uint32;         // Unsigned 32 bit quantity
    typedef signed   int        DMDReader_sint32;         // Signed   32 bit quantity
    typedef unsigned __int64    DMDReader_uint64;         // Unsigned 64 bit quantity
    typedef signed   __int64    DMDReader_sint64;         // Signed   64 bit quantity
#endif  // _MSC_VER
#if defined(__MINGW32__) || defined(__CYGWIN32__) || defined(__GNUC__) || defined(__CLANG__)
    #define DMDREADER_EXPORT
    typedef unsigned char       DMDReader_uint8;          // Unsigned  8 bit quantity
    typedef signed   char       DMDReader_sint8;          // Signed    8 bit quantity
    typedef unsigned short      DMDReader_uint16;         // Unsigned 16 bit quantity
    typedef signed   short      DMDReader_sint16;         // Signed   16 bit quantity
    typedef unsigned int        DMDReader_uint32;         // Unsigned 32 bit quantity
    typedef signed   int        DMDReader_sint32;         // Signed   32 bit quantity
    typedef unsigned long long  DMDReader_uint64;         // Unsigned 64 bit quantity
    typedef signed   long long  DMDReader_sint64;         // Signed   64 bit quantity
#endif  // __MINGW32__ || __CYGWIN32__ || __GNUC__

enum
{
    DMDReader_False = 0,
    DMDReader_True = 1
};
typedef DMDReader_sint32 DMDReader_bool;

typedef DMDReader_uint64                            DMDReader_SampleIndex;
typedef DMDReader_uint64                            DMDReader_SampleCount;
typedef DMDReader_uint32                            DMDReader_SampleDimension;
typedef DMDReader_SampleDimension*                  DMDReader_P_SampleDimension;

/// All DMDReader_STRING values contain UTF-8 encoded unicode characters
/// Strings are managed by the library and freed as soon as the file handle is closed.
typedef const char*                                 DMDReader_STRING;

static const char DMD_READER_DEMO_FILE[]            = "DMD_DEMO_FILE";

// ------------------------------------------------------------------------------------------------
//  3. GLOBAL TYPES
// ------------------------------------------------------------------------------------------------

/**
 * @brief Internal handle types managed within the dynamic library.
 *
 * Those handles are used as keys for the calls of the dynamic library interface functions.
 * @note User must not free/allocate those handles, as these are managed within the dynamic library!
 */
typedef void* DMDReader_FileHandle;
typedef void* DMDReader_ChannelHandle;

/**
 * @brief Specification of all the possible error codes returned by the dmd reader api interface.
 *
 * Specification of all the possible error codes returned by the dmd reader api interface.
 * DMDReader_NoError indicates the ok case, where as all other codes denote the error that occurred.
 */
typedef enum
{
    DMDReader_NoError                             = 0,

    DMDReader_FileDoesNotExist                    = -5001,
    DMDReader_FileInvalid                         = -5002,
    DMDReader_InternalError                       = -5003,
    DMDReader_InvalidArgument                     = -5004,
    DMDReader_InvalidFileHandle                   = -5005,
    DMDReader_InvalidChannelHandle                = -5006,
    DMDReader_InvalidMemorySize                   = -5007,
    DMDReader_MaximumNumberOfDataValuesExceeded   = -5008,
    DMDReader_ChannelDataTypeMismatch             = -5009,
    DMDReader_InvalidMarkerHandle                 = -5010,
    DMDReader_OutOfMemory                         = -5011,
    DMDReader_IncompatibleVersion                 = -5012,
    DMDReader_APINotInitialized                   = -5013,
    DMDReader_InputBufferTooSmall                 = -5014,

    DMDReader_ErrorEnd                            = -8000
} DMDReader_ErrorCode_Enum;
typedef DMDReader_sint32 DMDReader_ErrorCode;

/**
 * @brief Specification of all possible sample types of the channel data.
 *
 * Specification of all available sample types of the channel sample values.
 */
typedef enum
{
    DMDReader_SAMPLETYPE_INVALID = 0,
    DMDReader_SAMPLETYPE_DOUBLE,
    DMDReader_SAMPLETYPE_REDUCED,
    DMDReader_SAMPLETYPE_SINT32,
    DMDReader_SAMPLETYPE_DOUBLE_VECTOR = 100,
    DMDReader_SAMPLETYPE_COMPLEX_VECTOR,
} DMDReader_SampleType_Enum;
typedef DMDReader_sint32 DMDReader_SampleType;

/**
 * @brief Specification of all possible channel types.
 *
 * Specification of all available channel types.
 */
typedef enum
{
    DMDReader_CHANNELTYPE_ALL_CHANNELS = 0, /**< Used reference all channels*/
    DMDReader_CHANNELTYPE_OTHER_CHANNEL = 0, /**< Used for channels that do not fit any other type */
    DMDReader_CHANNELTYPE_ANALOG_CHANNEL,
    DMDReader_CHANNELTYPE_COUNTER_CHANNEL,
    DMDReader_CHANNELTYPE_DIGITAL_CHANNEL,
} DMDReader_ChannelType_Enum;
typedef DMDReader_sint32 DMDReader_ChannelType;

/**
 * @brief Specification of all possible marker event sources.
 *
 * The marker event source defines the trigger source.
 */
typedef enum
{
    DMDReader_MARKEREVENT_SOURCE_TRIGGER = 0,
    DMDReader_MARKEREVENT_SOURCE_APPLICATION,
    DMDReader_MARKEREVENT_SOURCE_MANUAL,
    DMDReader_MARKEREVENT_SOURCE_EXTERNAL,
    DMDReader_MARKEREVENT_SOURCE_SYNC,
    DMDReader_MARKEREVENT_SOURCE_TOPOLOGY
} DMDReader_MarkerEvent_Source_Enum;
typedef DMDReader_sint32 DMDReader_MarkerEvent_Source;

/**
 * @brief Specification of all possible marker event types.
 *
 * Specification of all possible marker event types.
 */
typedef enum
{
    DMDReader_MARKEREVENT_TYPE_MARKER = 0,
    DMDReader_MARKEREVENT_TYPE_START,
    DMDReader_MARKEREVENT_TYPE_STOP,
    DMDReader_MARKEREVENT_TYPE_NODE_RECORDING_STOP,
    DMDReader_MARKEREVENT_TYPE_PRETIME_START,
    DMDReader_MARKEREVENT_TYPE_POSTTIME_STOP,
    DMDReader_MARKEREVENT_TYPE_SYNC_SIGNAL_LOST,
    DMDReader_MARKEREVENT_TYPE_SYNC_TIME_ERROR,
    DMDReader_MARKEREVENT_TYPE_SYNC_SYNC_LOST,
    DMDReader_MARKEREVENT_TYPE_SYNC_SYNC_ERROR,
    DMDReader_MARKEREVENT_TYPE_SYNC_RESYNCED,
    DMDReader_MARKEREVENT_TYPE_TOPOLOGY_NODE_FOUND,
    DMDReader_MARKEREVENT_TYPE_TOPOLOGY_NODE_LOST,
    DMDReader_MARKEREVENT_TYPE_ALARM,
    DMDReader_MARKEREVENT_TYPE_ALARM_ACK,
    DMDReader_MARKEREVENT_TYPE_EVENT,
    DMDReader_MARKEREVENT_TYPE_SPLIT_START,
    DMDReader_MARKEREVENT_TYPE_SPLIT_STOP,
    DMDReader_MARKEREVENT_TYPE_DATA_DELAY_NORMAL,
    DMDReader_MARKEREVENT_TYPE_DATA_DELAY_WARNING,
    DMDReader_MARKEREVENT_TYPE_DATA_DELAY_ERROR,
} DMDReader_MarkerEvent_Type_Enum;
typedef DMDReader_sint32 DMDReader_MarkerEvent_Type;

/**
 * @brief Specification of the channel array.
 *
 * Specification of the channel array, which has to be allocated by the caller beforehand a subsequent call to read the channels. e.g. GetChannels
 */

typedef DMDReader_ChannelHandle* DMDReader_P_ChannelHandle;
// ------------------------------------------------------------------------------------------------
//  4. TYPEDEFS SAMPLE TYPES: SINGLE VALUE
// ------------------------------------------------------------------------------------------------

typedef double DMDReader_SAMPLEVALUE_SCALED;
typedef DMDReader_SAMPLEVALUE_SCALED* DMDReader_P_SAMPLEVALUE_SCALED;

/**
 * @brief Defines the data type for single complex value.
 *
 * This type is used for the sample values for complex data.
 */
typedef struct
{
    double real;
    double imag;
} DMDReader_SAMPLEVALUE_COMPLEX, *DMDReader_P_SAMPLEVALUE_COMPLEX;

/**
 * @brief Defines the data type for single reduced sample value.
 *
 * This type is used for the sample values for the reduced data.
 */
typedef struct
{
    double min;
    double max;
    double avg;
    double rms;
} DMDReader_SAMPLEVALUE_REDUCED, *DMDReader_P_SAMPLEVALUE_REDUCED;

/**
 * @brief Specifies the timestamp data type for seconds.
 *
 * Specifies the timestamp data type for seconds.
 */
typedef double DMDReader_TIMESTAMP_SECONDS;
typedef DMDReader_TIMESTAMP_SECONDS* DMDReader_P_TIMESTAMP_SECONDS;

/**
 * @brief Specifies the Timestamp Format.
 *
 * Specifies the Timestamp Format.
 */
typedef struct
{
    DMDReader_sint32 year;      /**< The year */
    DMDReader_sint32 yearDay;   /**< The day of the year*/
    double timeOfDay;           /**< Representing the number of seconds after midnight (local time; subtract timeOffset to get UTC time)*/
    DMDReader_sint32 timeOffset;/**< Representing the offset (in minutes) between UTC and the local time when the measurement started (for recordings in CET: +60) */
    DMDReader_bool valid;       /**< True, if time is available */
} DMDReader_TIMESTAMP_UTC;

// ------------------------------------------------------------------------------------------------
//  5. TYPEDEFS SAMPLE TYPES: VALUE + TIMESTAMP PAIRS
// ------------------------------------------------------------------------------------------------

/**
 * @brief Specifies the tuple scaled sample value and timestamp in seconds.
 *
 * Specifies the tuple scaled sample value and timestamp in seconds.
 */
typedef struct
{
    DMDReader_SAMPLEVALUE_SCALED     value;
    DMDReader_TIMESTAMP_SECONDS      timestamp;
} DMDReader_SCALEDSAMPLE_TIMESTAMP, *DMDReader_P_SCALEDSAMPLE_TIMESTAMP;

/**
 * @brief Specifies the tuple reduced sample value and timestamp in seconds.
 *
 * Specifies the tuple reduced sample value and timestamp in seconds.
 */
typedef struct
{
    DMDReader_SAMPLEVALUE_REDUCED    value;
    DMDReader_TIMESTAMP_SECONDS      timestamp;
} DMDReader_REDUCEDSAMPLE_TIMESTAMP, *DMDReader_P_REDUCEDSAMPLE_TIMESTAMP;

/**
 * @brief Specifies the tuple integer data value and timestamp in seconds.
 *
 * Specifies the tuple integer data value and timestamp in seconds. The integer data value is used for digital sample values.
 * @note here we would have some padding of the struct
 */
typedef struct
{
    DMDReader_sint32 value;
    DMDReader_sint32 _padding0;
    DMDReader_TIMESTAMP_SECONDS timestamp;
} DMDReader_DIGITALSAMPLE_TIMESTAMP, *DMDReader_P_DIGITALSAMPLE_TIMESTAMP;

// ------------------------------------------------------------------------------------------------
//  7. TYPEDEFS DMD FILE META DATA
// ------------------------------------------------------------------------------------------------

/**
 * @brief Specifies a single header field in the dmd file.
 *
 * Header information is returned as name value pairs
 */
typedef struct
{
    DMDReader_STRING name;
    DMDReader_STRING value;
} DMDReader_HEADERFIELD, *DMDReader_P_HEADERFIELD;

/**
 * @brief Specifies the channel information.
 *
 * Specifies the channel information.
 */
typedef struct
{
    double sampleRate;                                  /**< Sample rate [Hz] */
    DMDReader_ChannelType channelType;                  /**< Channel Type */
#ifdef BUILD_X64
    DMDReader_uint32 _padding0;
#endif
    DMDReader_STRING name;                              /**< Name of the channel */
    DMDReader_STRING unit;                              /**< Physical unit of the channel sample data */
    DMDReader_STRING description;                       /**< Description of the channel */
    DMDReader_TIMESTAMP_SECONDS measurementDuration;    /**< Measurement duration of the channel's sample data [seconds] */
    DMDReader_SAMPLEVALUE_SCALED rangeMin;              /**< Minimum range of the channel's sample data. Specified in the physical unit of the channel */
    DMDReader_SAMPLEVALUE_SCALED rangeMax;              /**< Maximum range of the channel's sample data. Specified in the physical unit of the channel */
} DMDReader_CHANNELINFORMATION, *DMDReader_P_CHANNELINFORMATION;

/**
 * @brief Specifies the marker event data.
 *
 * Specifies the marker event data.
 */
typedef struct
{
    DMDReader_MarkerEvent_Source source;
    DMDReader_MarkerEvent_Type type;
    DMDReader_TIMESTAMP_SECONDS time;
    DMDReader_STRING text;
#ifdef BUILD_X86
    DMDReader_uint32 _padding0;
#endif
} DMDReader_MARKEREVENT, *DMDReader_P_MARKEREVENT;

/**
 * @brief Specifies a single sweep of data.
 *
 * For synchronous data the sampleFrequency is set to samples per second and a single sweep only contains equidistant samples.
 *   The timestamp of the first sample is startTime and each index from firstSample to lastSample references an individual sample in this case.
 * For asynchronous data the sampleFrequency is set 0.0 and the *Sample & *Time fields reference the range of the sweep but not necessarily individual samples.
 *   Respecting the numValidSamples and nextSample parameters of GetSamples* functions is essential to read async data correctly.
 */
typedef struct
{
    DMDReader_SampleIndex firstSample;
    DMDReader_SampleIndex lastSample;
    DMDReader_TIMESTAMP_SECONDS startTime;
    DMDReader_TIMESTAMP_SECONDS endTime;
    double sampleFrequency;
} DMDReader_SWEEP, *DMDReader_P_SWEEP;

// ------------------------------------------------------------------------------------------------
//  8. READER LIBRARY PUBLIC INTERFACE FUNCTIONS
// ------------------------------------------------------------------------------------------------

/**
 * @brief Returns the interface version of the loaded dmd reader api dynamic library.
 *
 * The interface version of the linked dynamic load library may be different to the public interface version.
 * The version returned is different to the build version of the dynamic link library, as this version describes the interface version.
 *
 * @param[out]  interfaceVersionMajor       major version of the dynamic library interface
 * @param[out]  interfaceVersionMinor       minor version of the dynamic library interface
 * @return DMDReader_NoError in case ok. Otherwise error code for the error description.
 */
typedef DMDReader_ErrorCode (DMDREADER_EXPORT *FP_DMDReader_GetVersion) (DMDReader_uint32* interfaceVersionMajor, DMDReader_uint32* interfaceVersionMinor);

/**
 * @brief Initializes the dmd reader library.
 *
 * The interface version of the linked dynamic load library may be different to the public interface version.
 * The version returned is different to the build version of the dynamic link library, as this version describes the interface version.
 *
 * @param       interfaceVersionMajor       major version of the public interface version in use
 * @param       interfaceVersionMinor       minor version of the public interface version in use
 * @return DMDReader_NoError in case ok. Otherwise error code for the error description.
 */
typedef DMDReader_ErrorCode (DMDREADER_EXPORT *FP_DMDReader_Initialize) (DMDReader_uint32 interfaceVersionMajor, DMDReader_uint32 interfaceVersionMinor);

/**
 * @brief Destroys the dmd reader library and all associated global variables.
 *
 * @return DMDReader_NoError in case ok. Otherwise error code for the error description.
 */
typedef DMDReader_ErrorCode (DMDREADER_EXPORT *FP_DMDReader_Dispose) ();

/**
 * @brief Opens a dmd file.
 *
 * @param       fullFilename    Either provide full filename incl. path or for demo usage DMD_READER_DEMO_FILE; UTF-8 encoding
 * @param[out]  file            handle of the opened file
 * @return DMDReader_NoError in case ok. Otherwise error code for the error description.
 *         DMDReader_FileInvalid is returned if the file is not a valid DMD file.
 */
typedef DMDReader_ErrorCode (DMDREADER_EXPORT *FP_DMDReader_OpenFile) (const char* fullFilename, DMDReader_FileHandle* file);

/**
 * @brief Closes an open dmd file.
 *
 * Close the dmd file and frees all library-managed resources (handles for channels, strings ...) for this dmd file.
 *
 * @param       file            has to be a valid file handle
 * @return DMDReader_NoError in case ok. Otherwise error code for the error description.
 */
typedef DMDReader_ErrorCode (DMDREADER_EXPORT *FP_DMDReader_CloseFile) (DMDReader_FileHandle* file);

/**
 * @brief Get the number of channels within a dmd file.
 *
 * @param       file            handle of an open dmd file
 * @param       type            specific channel type (use DMDReader_CHANNELTYPE_ALL_CHANNELS to count all available channels)
 * @param[out]  numChannels     within the dmd file
 * @return DMDReader_NoError in case ok. Otherwise error code for the error description.
 */
typedef DMDReader_ErrorCode (DMDREADER_EXPORT *FP_DMDReader_GetNumChannels) (DMDReader_FileHandle file, DMDReader_ChannelType type, DMDReader_uint64* numChannels);

/**
 * @brief Get the channels for a specific channel type
 *
 * @param       file            valid file handle
 * @param       type            specific channel type (use DMDReader_CHANNELTYPE_ALL_CHANNELS to get all channels)
 * @param       firstChannel    index of the first channel to return
 * @param       maxChannels     maximum number of channels that will be returned. channelList must be large enough to hold as many items
 * @param[out]  channelList     only channels for the specific type are returned
 * @param[out]  numChannels     number of valid channels that were returned in channelList
 * @return DMDReader_NoError in case ok. Otherwise error code for the error description
 */
typedef DMDReader_ErrorCode (DMDREADER_EXPORT *FP_DMDReader_GetChannels) (DMDReader_FileHandle file, DMDReader_ChannelType type, DMDReader_uint64 firstChannel, DMDReader_uint64 maxChannels, DMDReader_P_ChannelHandle channelList, DMDReader_uint64* numChannels);

/**
 * @brief Get the sample type for a specific channel
 * DMDReader_GetVectorSampleType should be used instead of DMDReader_GetSampleType in order to get information for scalar and vector channels.
 * Vector channels will return INVALID if this version of the function is used.
 *
 * @param       channel             valid channel handle
 * @param[out]  dataSampleType      (can return INVALID if no data available)
 * @param[out]  reducedSampleType   (can return INVALID if no data available)
 * @return DMDReader_NoError in case ok. Otherwise error code for the error description.
 */
typedef DMDReader_ErrorCode (DMDREADER_EXPORT *FP_DMDReader_GetSampleType) (DMDReader_ChannelHandle channel, DMDReader_SampleType* dataSampleType, DMDReader_SampleType* reducedSampleType);

/**
 * @brief Get the sample type for a specific vector channel
 * In case of a scalar channel, the maxSampleDimension will be 1
 *
 * @param       channel             valid channel handle
 * @param[out]  dataSampleType      (can return INVALID if no data available)
 * @param[out]  reducedSampleType   (can return INVALID if no data available)
 * @param[out]  maxSampleDimension  (can return 0 if no data available)
 * @return DMDReader_NoError in case ok. Otherwise error code for the error description.
 */
typedef DMDReader_ErrorCode(DMDREADER_EXPORT *FP_DMDReader_GetVectorSampleType) (DMDReader_ChannelHandle channel, DMDReader_SampleType* dataSampleType, DMDReader_SampleType* reducedSampleType, DMDReader_SampleDimension* maxSampleDimension);

/**
 * @brief Get the channel information (meta data) for a specific channel
 *
 * @param       channel     valid channel handle
 * @param[out]  info        channel information is written to this structure
 * @return DMDReader_NoError in case ok. Otherwise error code for the error description.
 */
typedef DMDReader_ErrorCode (DMDREADER_EXPORT *FP_DMDReader_GetChannelInformation) (DMDReader_ChannelHandle channel, DMDReader_P_CHANNELINFORMATION info);

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 8a. READ SAMPLE VALUES INTO AN ARRAY
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/**
 * The following functions are used to read sample data from a single channel
 * DMDReader_GetSamplesWithTS_ functions write the data into an array of structures containing both the samples value and its timestamp.
 * DMDReader_GetSamplesAndTS_ functions write into separate arrays for values and timestamps. One of the arrays may be NULL to read only one type of data.
 *
 * The remainder of the function name indicates the format used to store sample values and timestamps.
 * Supported sample formats vary depending on channel type.
 *
 * All functions take parameters from the set below:
 * @param       channel             valid channel handle
 * @param       firstSample         index of first requested sample index (including)
 * @param       maxSamples          number of elements in the values array and therefore the maximum number of samples to read
 * @param[out]  values              read tuple (value, timestamp) array
 * @param[out]  samples             scaled value for each sample is stored in this array; may be NULL if sample values are not wanted
 * @param[out]  timestamps          timestamp of each sample in seconds is stored here; may be NULL if timestamps are not wanted
 * @param[out]  numValidSamples     The number of valid samples that was written to the output arrays. Always equal or less than maxSamples.
 *                                  The first numValidSamples entries of both samples[]/timestamps[] or samples[] will contain valid data.
 * @param[out]  nextSample          index of the sample just beyond the last sample that was returned by the function.
 *                                  This value can reference an invalid sample if it is larger than lastSample of the corresponding sweep
 *                                  Use this as firstSample parameter on the next call to get the next block of samples
 *                                  Rationale: for some channel types (async channels) there may not be a sample at each sample index
 *                                             Using nextValidSample while iterating (as long as nextValidSample<=sweep.lastSample) over all channel data
 *                                             makes sure that only non-overlapping blocks are returned
 * @return DMDReader_NoError in case ok. Otherwise error code for the error description.
 */

/**
 * This function should be used to read raw sample data of DMDReader_SAMPLETYPE_DOUBLE channels.
 */
typedef DMDReader_ErrorCode (DMDREADER_EXPORT *FP_DMDReader_GetSamplesWithTS_ScaledValue_Seconds) (DMDReader_ChannelHandle channel, DMDReader_SampleIndex firstSample, DMDReader_SampleCount maxSamples,
                                                                                                   DMDReader_P_SCALEDSAMPLE_TIMESTAMP values, DMDReader_SampleCount* numValidSamples, DMDReader_SampleIndex* nextSample);

/**
 * This function should be used to read raw data channel value data of DMDReader_SAMPLETYPE_DOUBLE channels.
 */
typedef DMDReader_ErrorCode (DMDREADER_EXPORT *FP_DMDReader_GetSamplesAndTS_ScaledValue_Seconds) (DMDReader_ChannelHandle channel, DMDReader_SampleIndex firstSample, DMDReader_SampleCount maxSamples,
                                                                                                  DMDReader_SAMPLEVALUE_SCALED* samples, DMDReader_TIMESTAMP_SECONDS* timestamps, DMDReader_SampleCount* numValidSamples, DMDReader_SampleIndex* nextSample);

/**
 * This function should be used to read reduced channel value data.
 */
typedef DMDReader_ErrorCode (DMDREADER_EXPORT *FP_DMDReader_GetSamplesWithTS_ReducedValue_Seconds) (DMDReader_ChannelHandle channel, DMDReader_SampleIndex firstSample, DMDReader_SampleCount maxSamples,
                                                                                                    DMDReader_P_REDUCEDSAMPLE_TIMESTAMP values, DMDReader_SampleCount* numValidSamples, DMDReader_SampleIndex* nextSample);

/**
 * This function should be used to read reduced channel value data.
 */
typedef DMDReader_ErrorCode (DMDREADER_EXPORT *FP_DMDReader_GetSamplesAndTS_ReducedValue_Seconds) (DMDReader_ChannelHandle channel, DMDReader_SampleIndex firstSample, DMDReader_SampleCount maxSamples,
                                                                                                    DMDReader_SAMPLEVALUE_REDUCED* samples, DMDReader_TIMESTAMP_SECONDS* timestamps, DMDReader_SampleCount* numValidSamples, DMDReader_SampleIndex* nextSample);

/**
 * This function should be used to read samples of DIGITAL channels.
 */
typedef DMDReader_ErrorCode (DMDREADER_EXPORT *FP_DMDReader_GetSamplesWithTS_DigitalValue_Seconds) (DMDReader_ChannelHandle channel, DMDReader_SampleIndex firstSample, DMDReader_SampleCount maxSamples,
                                                                                                    DMDReader_P_DIGITALSAMPLE_TIMESTAMP values, DMDReader_SampleCount* numValidSamples, DMDReader_SampleIndex* nextSample);

/**
 * This function should be used to read samples of DIGITAL channels.
 */
typedef DMDReader_ErrorCode (DMDREADER_EXPORT *FP_DMDReader_GetSamplesAndTS_DigitalValue_Seconds) (DMDReader_ChannelHandle channel, DMDReader_SampleIndex firstSample, DMDReader_SampleCount maxSamples,
                                                                                                   DMDReader_sint32* samples, DMDReader_TIMESTAMP_SECONDS* timestamps, DMDReader_SampleCount* numValidSamples, DMDReader_SampleIndex* nextSample);

/**
* The following functions are used to read sample data from a single vector channel
* DMDReader_GetSamplesAndTS_?Vector_Seconds writes into separate arrays for values, timestamps and actual value dimension. Unused arrays may be NULL to read only desired types of data.
*
* Supported sample formats are double and complex vectors.
*
* All functions take parameters from the set below:
* @param        channel             valid channel handle
* @param        firstSample         index of first requested sample index (including)
* @param        maxSamples          number of elements in the values array and therefore the maximum number of samples to read
* @param        maxSampleDimension  maximum allocated space for each sample vector. Can be smaller/larger than the value reported by DMDReader_GetVectorSampleType
* @param[out]   samples             row-major 2D matrix with [maxSamples x maxSampleDimension] double/complex values; may be NULL if sample values are not wanted
* @param[out]   timestamps          timestamp of each sample in seconds is stored here; may be NULL if timestamps are not wanted
* @param[out]   sampleDimensions    number of dimensions for each sample 0 <= sampleDimensions[n] <= maxSampleDimension; may be NULL if sample dimensions are not wanted
* @param[out]   numValidSamples     The number of valid samples that was written to the output arrays. Always equal or less than maxSamples.
*                                   The first numValidSamples entries of both samples[]/timestamps[] or samples[] will contain valid data.
* @param[out]   nextSample          index of the sample just beyond the last sample that was returned by the function.
*                                   This value can reference an invalid sample if it is larger than lastSample of the corresponding sweep
*                                   Use this as firstSample parameter on the next call to get the next block of samples
*                                   Rationale: for some channel types (async channels) there may not be a sample at each sample index
*                                              Using nextValidSample while iterating (as long as nextValidSample<=sweep.lastSample) over all channel data
*                                              makes sure that only non-overlapping blocks are returned
* @return DMDReader_NoError in case ok. Otherwise error code for the error description.
*/
/**
 * This function should be used to read a vector of samples of DMDReader_SAMPLETYPE_DOUBLE_VECTOR channels.
 */
typedef DMDReader_ErrorCode (DMDREADER_EXPORT *FP_DMDReader_GetSamplesAndTS_ScalarVector_Seconds) (DMDReader_ChannelHandle channel, DMDReader_SampleIndex firstSample, DMDReader_SampleCount maxSamples,
                                                                                                   DMDReader_SampleDimension maxSampleDimension, DMDReader_SAMPLEVALUE_SCALED* samples,
                                                                                                   DMDReader_P_TIMESTAMP_SECONDS timestamps, DMDReader_P_SampleDimension sampleDimensions,
                                                                                                   DMDReader_SampleCount* numValidSamples, DMDReader_SampleIndex* nextSample);

/**
 * This function should be used to read a vector of samples of DMDReader_SAMPLETYPE_COMPLEX_VECTOR channels.
 */
typedef DMDReader_ErrorCode (DMDREADER_EXPORT *FP_DMDReader_GetSamplesAndTS_ComplexVector_Seconds) (DMDReader_ChannelHandle channel, DMDReader_SampleIndex firstSample, DMDReader_SampleCount maxSamples,
                                                                                                    DMDReader_SampleDimension maxSampleDimension, DMDReader_SAMPLEVALUE_COMPLEX* samples,
                                                                                                    DMDReader_P_TIMESTAMP_SECONDS timestamps, DMDReader_P_SampleDimension sampleDimensions,
                                                                                                    DMDReader_SampleCount* numValidSamples, DMDReader_SampleIndex* nextSample);

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 8b. READ FILE META DATA
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/**
 * @brief Returns the number of name-value-pairs with acquisition meta-data that are stored in the dmd file.
 *
 * @param       file        valid file handle
 * @param[out]  numFields   number of header fields in the current file
 * @return DMDReader_NoError if successful, otherwise an error code indicating what went wrong.
 */
typedef DMDReader_ErrorCode(DMDREADER_EXPORT *FP_DMDReader_GetNumHeaderFields) (DMDReader_FileHandle file, DMDReader_uint64* numFields);

/**
* @brief Returns a subset of name-value-pairs contained in the dmd file.
*
* @param        file        valid file handle
* @param        firstField  index of the first item that should be stored in fields
* @param        maxFields   maximum number of items that can be stored
* @param[out]   fields      array with all read header fields
* @param[out]   numFields   number of valid items stored in fields
* @return DMDReader_NoError if successful, otherwise an error code indicating what went wrong.
*/
typedef DMDReader_ErrorCode(DMDREADER_EXPORT *FP_DMDReader_GetHeaderFields) (DMDReader_FileHandle file, DMDReader_uint64 firstField, DMDReader_uint64 maxFields, DMDReader_P_HEADERFIELD fields, DMDReader_uint64* numFields);

/**
* @brief Returns the value of a specific header field if the identifier is known.
*
* @param        file        valid file handle
* @param        name        identifier of the requested value
* @param[out]   value       the value stored under the given name
* @return DMDReader_NoError if successful, otherwise an error code indicating what went wrong.
*/
typedef DMDReader_ErrorCode(DMDREADER_EXPORT *FP_DMDReader_GetHeaderField) (DMDReader_FileHandle file, DMDReader_STRING name, DMDReader_STRING* value);


/**
 * @brief Get the measurement start time in the UTC format of the dmd file.
 * If requesting the local time (utc=FALSE) this returns the local time at the measurement site when the measurement was started.
 *
 * @param       file        valid file handle
 * @param[out]  timestamp   measurement start time will be stored here
 * @param       utc         if set to true the function returns the utc time, if false it returns local time and the utc time offset.
 * @return DMDReader_NoError in case ok. Otherwise error code for the error description.
 */
typedef DMDReader_ErrorCode (DMDREADER_EXPORT *FP_DMDReader_GetMeasurementStartTime) (DMDReader_FileHandle file, DMDReader_TIMESTAMP_UTC* timestamp, DMDReader_bool utc);

/**
 * @brief Get the number of markers within the dmd file
 *
 * @param       file        valid file handle
 * @param[out]  numMarkers  number of markers
 * @return DMDReader_NoError in case ok. Otherwise error code for the error description.
 */
typedef DMDReader_ErrorCode (DMDREADER_EXPORT *FP_DMDReader_GetNumMarkers) (DMDReader_FileHandle file, DMDReader_uint64* numMarkers);

/**
 * @brief Get the markers of the dmd file
 *
 * Get the markers of the dmd file. The markers array has to be allocated of the caller and has to be the size of DMDReader_GetNumMarkers.
 *
 * @param       file            valid file handle
 * @param       firstMarker     index of the first item that should be stored in markers
 * @param       maxMarkers      maximum number of markers that can be stored
 * @param[out]  markers         array with all read markers
 * @param[out]  numMarkers      number of valid items stored in markers
 * @return DMDReader_NoError in case ok. Otherwise error code for the error description.
 */
typedef DMDReader_ErrorCode (DMDREADER_EXPORT *FP_DMDReader_GetMarkers) (DMDReader_FileHandle file, DMDReader_uint64 firstMarker, DMDReader_uint64 maxMarkers, DMDReader_P_MARKEREVENT markers, DMDReader_uint64* numMarkers);

/**
 * @brief Get the number of raw data sweeps for this channel
 * A channel that was recorded without interruption from measurement start until the end would have a single sweep with matching properties.
 *
 * @param       channel     valid channel handle
 * @param[out]  numSweeps   number of sweeps
 */
typedef DMDReader_ErrorCode (DMDREADER_EXPORT *FP_DMDReader_GetNumDataSweeps) (DMDReader_ChannelHandle channel, DMDReader_uint64* numSweeps);

/**
 * @brief Get raw data sweeps for the selected channel
 * One sweep entry is filled for each range of samples that occurred continuously with a constant frequency.
 * If the reported frequency is 0 the distance between samples varies and must be explicitly read
 *
 * @param       channel     valid channel handle
 * @param       firstSweep  index of the first sweep that should be read
 * @param       maxSweeps   maximum numbers of sweeps that can be read (=number of entries in sweeps)
 * @param[out]  sweeps      array where sweep information will be stored
 * @param[out]  numSweeps   number valid items stored in sweeps
 */
typedef DMDReader_ErrorCode (DMDREADER_EXPORT *FP_DMDReader_GetDataSweeps) (DMDReader_ChannelHandle channel, DMDReader_uint64 firstSweep, DMDReader_uint64 maxSweeps, DMDReader_P_SWEEP sweeps, DMDReader_uint64* numSweeps);

/**
 * @brief Get the number of reduced data sweeps for this channel
 * A channel for which statistical data was recorded without interruption from measurement start until the end would have a single sweep with matching properties.
 *
 * @param       channel     valid channel handle
 * @param[out]  numSweeps   number of sweeps of reduced samples
 */
typedef DMDReader_ErrorCode (DMDREADER_EXPORT *FP_DMDReader_GetNumReducedSweeps) (DMDReader_ChannelHandle channel, DMDReader_uint64* numSweeps);

/**
 * @brief Get reduced data sweeps for the selected channel
 *
 * @param       channel     valid channel handle
 * @param       firstSweep  index of the first sweep that should be read
 * @param       maxSweeps   maximum numbers of sweeps that can be read (=number of entries in sweeps)
 * @param[out]  sweeps      array where sweep information will be stored
 * @param[out]  numSweeps   number valid items stored in sweeps
 */
typedef DMDReader_ErrorCode (DMDREADER_EXPORT *FP_DMDReader_GetReducedSweeps) (DMDReader_ChannelHandle channel, DMDReader_uint64 firstSweep, DMDReader_uint64 maxSweeps, DMDReader_P_SWEEP sweeps, DMDReader_uint64* numSweeps);

/**
* @brief Returns the configuration xml of specified file
* @version 1.2
*
* @param        file        valid file handle
* @param[out]   value       the xml content
* @return DMDReader_NoError if successful, otherwise an error code indicating what went wrong.
*
* Reading channel topology:
*   XPath to root of the topology: /MeasurementConfig/SystemSetup/MeasurementTree
*     This subtree contains information about the system structure, the physical location of channels and synchronization options, among other things.
*     Since this is a very flexible structure we will only document some important elements:
*       <MeasurementNode> a local or OxyNet node
*       <Enclosure> a physical unit that can contain for example channels, devices and sync connectors
*       <Device> a measurement device, for example a TRION board
*       <Channel> a physical connector of any type and some basic visual and identification properties.
*         Actual details (type, configuration,...) can be found using the channel properties below.
*         IMPORTANT: the topology uses hexadecimal ChannelIDs, which have to be converted to decimal format for use in the channel list!
*
* Reading channel properties:
*   XPath to Channel: /MeasurementConfig/Channels/Channel[@id='12345']
*     relative path to channel config: ./MeasurementChain/<asterisk>/ChannelConfig (replace astrisk with *!)
*       This provides a list of ChannelConfig elements, that contain the channels properties
*       The properties have a name (often prefixed for uniqueness) and a (typed) value.
*       The meaning should usually be self explanatory based on the name, but the next section will describe some frequently used ones.
*
*       Later properties of the same channel with same name overwrite the previous value.
*       Therefore only the most recent value should be used in normal circumstances.
*
*       Some noteable properties:
*         Unit              the unit used to report measurement on the channel
*         Range             the span of measurement value that can be expected
*         Neon/Name         the name of the channel
*         Neon/DomainUrl    a suffix that can be appended to make channel name unique
*         Neon/LongName     the combination of the two properties above
*         Neon/Comment      can be used to describe the purpose of the channel
*         Neon/Active       indicate if the channel is used in the measurement
*         Scaling           XML description on how transform the raw measured value to the physical amount
*
*/
typedef DMDReader_ErrorCode(DMDREADER_EXPORT* FP_DMDReader_GetConfigurationXML) (DMDReader_FileHandle file, DMDReader_STRING* xml);

/**
 * @brief Returns global configuration strings of the DMD reader (e.g. build information)
 * @version 1.3
 *
 * @param        name        Name of the config item (case-insensitive). See below for supported names
 * @param[out]   value       the value of the config item, the memory is managed by DMD reader and valid as long as the DLL is loaded
 *
 * Supported names for global config items are:
 *     InterfaceVersion      the version of the DMD Reader DLL interface (e.g. "1.3")
 *     ReaderVersion         the version of the DMD Reader DLL (e.g. "7.3.0")
 *     BuildDate             the date when the DMD Reader DLL was build (e.g. "2024-01-31 16:30")
 *     BuildRevision         the hash code of the source revision (e.g. "b1234567890a")
 *
 */
typedef DMDReader_ErrorCode(DMDREADER_EXPORT* FP_DMDReader_GetGlobalConfigItem) (DMDReader_STRING name, DMDReader_STRING* value);

#ifdef __cplusplus
}
#endif

#endif // #define _DEWETRON_DMD_READER_API_INTERFACE_
