#ifndef LTRK511API_H_
#define LTRK511API_H_

#include "ltr01api.h"

#ifdef __cplusplus
extern "C" {                                 // only need to export C interface if
                                             // used by C++ source code
#endif

#ifdef _WIN32
    #ifdef LTRK511API_EXPORTS
      #define LTRK511API_DllExport(type) __declspec(dllexport) type APIENTRY
    #else
      #define LTRK511API_DllExport(type) __declspec(dllimport) type APIENTRY
    #endif
#elif defined __GNUC__
    #define LTRK511API_DllExport(type) __attribute__ ((visibility("default"))) type
#else
    #define LTRK511API_DllExport(type)  type
#endif

/** Размер строки с именем модуля в структуре #TLTRK511_MODULE_INFO */
#define LTRK511_NAME_SIZE               16
/** Размер строки с серийным номером модуля в структуре #TLTRK511_MODULE_INFO */
#define LTRK511_SERIAL_SIZE             24

/** Количество выходных управляемых ключей в модуле */
#define LTRK511_OUT_SW_CNT              32
/** Количество выходов реле в модуле (в максимальной комплектации) */
#define LTRK511_RELAY_CNT               2

/** Максимальное значение величины, выставляемой на ЦАП */
#define LTRK511_DAC_VALUE_MAX           100
/** Максимальный код ЦАП */
#define LTRK511_DAC_CODE_MAX            0x0FFF


/** Коды ошибок, специфичные для LTRK511. */
typedef enum {
    LTRK511_ERR_INVALID_SW_STATE        = -11100,  /**< Задано неверное состояние выходного ключа. */
    LTRK511_ERR_INVALID_SW_NUM          = -11101,  /**< Указан неверный номер выходного ключа */
    LTRK511_ERR_INVALID_RELAY_NUM       = -11102,  /**< Указан неверный номер реле */
} e_LTRK511_ERROR_CODES;

/** Состояния выходного ключа модуля */
typedef enum {
    LTRK511_OUT_SW_STATE_OPEN           = 0,  /**< Все отключено. Выход в состоянии обрыв. */
    LTRK511_OUT_SW_STATE_EXT_SIG        = 1,  /**< На выход подан внешний сигнал с соответствующего входа на разъеме. */
    LTRK511_OUT_SW_STATE_INT_DIV        = 2   /**< На выход подан сигнал с внутреннего делителя. */
} e_LTRK511_OUT_SW_STATE;

/** Тип микросхемы реле, установленной на модуле */
typedef enum {
    LTRK511_OUT_SW_TYPE_ADG444 = 1, /**< ADG444 */
    LTRK511_OUT_SW_TYPE_ADG453 = 2  /**< ADG453 */
} e_LTRK511_OUT_SW_TYPES;

/** Флаги, использующиеся при выводе значения на ЦАП */
typedef enum {
    LTRK511_DAC_FLAG_VALUE   = 0x0001, /**< Указывает, что значение задает величину в диапазоне от 0 до #LTRK511_DAC_VALUE_MAX.
                                              Если не указан, то значение задано в кодах ЦАП. */
    LTRK511_DAC_FLAG_CALIBR  = 0x0002, /**< Применение калибровочных коэффициентов к заданному значению. */
} e_LTRK511_DAC_FLAGS;

/** Флаги, указывающие, какие опциональные возможности поддерживаются модулем */
typedef enum {
    LTRK511_INFO_FLAG_SUPPORT_DAC       = (0x1UL << 0) /**< Признак наличия ЦАП для данной модификации модуля */
} e_LTRK511_INFO_FLAGS;

#pragma pack (4)


/** @brief Калибровочные коэффициенты

    Структура, хранящая калибровочные коэффициенты для ЦАП. */
typedef struct {
    float   Offset; /**< Код смещения. */
    float   Scale;  /**< Коэффициент шкалы. */
} TLTRK511_CBR_COEF;


/** Информация о модуле */
typedef struct {
    CHAR        Name[LTRK511_NAME_SIZE];      /**< Название модуля (оканчивающаяся нулем ASCII-строка). */
    CHAR        Serial[LTRK511_SERIAL_SIZE];  /**< Серийный номер модуля (оканчивающаяся нулем ASCII-строка). */
    BYTE        VerPLD;                       /**< Версия прошивки PLD.  */
    BYTE        Modification;                 /**< Модификация модуля (0 - LTRK511, 1 - LTRK511-01, 2 - LTRK511-02). */
    WORD        Flags;                        /**< Флаги из #e_LTRK511_INFO_FLAGS,
                                                   описывающие поддерживаемые опциональные
                                                   возможности модуля. */
    BYTE        OutSwCnt;                     /**< Количество каналов реле */
    BYTE        OutSwType;                    /**< Тип микросхемы реле */
    BYTE        RelayCnt;                     /**< Количество реле в модуле */
    TLTRK511_CBR_COEF DacCbrCoefs;            /**< Калибровочные коэффициенты ЦАП. */
    DWORD       Reserved[10];                 /**< Резерв. */
} TLTRK511_MODULE_INFO;

/** Состояние выхода ЦАП */
typedef struct {
    double Data; /**< Значение для вывода на ЦАП в кодах или величинах, в зависимости от флагов. */
    WORD Flags;  /**< Набор флагов из #e_LTRK511_DAC_FLAGS, определяющих получение результирующего
                     кода ЦАП по заданному значению. */
    WORD ResCode; /**< Результирующий код ЦАП, который был записан. */
    DWORD Reserved[3]; /**< Резерв. */
} TLTRK511_DAC_STATE;

/** Структура описывает состояние всех выходных каналов модуля */
typedef struct {
    BYTE Sw[LTRK511_OUT_SW_CNT]; /**< Состояние всех выходных ключей.
                                      Каждый элемент массива определяет состояние ключа
                                      с соответствующим номером и может принимать одно из
                                      значений из перечисления #e_LTRK511_OUT_SW_STATE. */
    DWORD RelayStates;  /**< Состояние выходов реле. Каждому реле соответствует свой бит
                             в данном слове. Используются только младшие #LTRK511_RELAY_CNT
                             бит. */
    TLTRK511_DAC_STATE Dac; /**< Состояние выхода ЦАП */
    DWORD Reserved[4]; /**< Резерв */
} TLTRK511_OUT_STATE;



/** Параметры состояния модуля */
typedef struct {
    TLTRK511_OUT_STATE  Out; /**< Состояния всех выходных каналов модуля.
                                  Обновляется при успешном выполнении функций вывода. */
    DWORD Reserved[4];       /**< Резерв */
} TLTRK511_STATE;



/** Описатель модуля */
typedef struct {
    INT size;     /**< Размер структуры. Заполняется в LTRK511_Init(). */
    /** Структура, содержащая состояние соединения с сервером.
        Не используется напрямую пользователем. */
    TLTR Channel;
    /** Указатель на непрозрачную структуру с внутренними параметрами,
        используемыми исключительно библиотекой и недоступными для пользователя. */
    PVOID Internal;
    DWORD Reserved[16]; /**< Резерв */
    /** Состояние модуля и рассчитанные параметры. Поля изменяются функциями
        библиотеки. Пользовательской программой могут использоваться
        только для чтения. */
    TLTRK511_STATE State;
    TLTRK511_MODULE_INFO ModuleInfo; /**< Информация о модуле */
} TLTRK511;

#pragma pack ()

/*============================================================================*/

LTRK511API_DllExport(INT) LTRK511_Init(TLTRK511 *hnd);
LTRK511API_DllExport(INT) LTRK511_Open(TLTRK511 *hnd, DWORD net_addr, WORD net_port,
                                       const CHAR *csn, WORD slot);
LTRK511API_DllExport(INT) LTRK511_Close(TLTRK511 *hnd);
LTRK511API_DllExport(INT) LTRK511_IsOpened(TLTRK511 *hnd);

/***************************************************************************//**
   @brief Установка состояний всех выходов модуля.

   Функция позволяет установить состояние всех выходов модуля одним вызовом.
   Требуемые состояния задаются структурой #TLTRK511_OUT_STATE.
   Поля @fieldref{TLTRK511_DAC_STATE,ResCode} в структуре состояния ЦАП не имеет
   значения.
   При успешном выводе обновляются значения состояния выходов в описателе модуля,
   а исходная структура, передаваемая в параметре, не изменяется.

   @param[in] hnd       Описатель модуля.
   @param[in] state     Состояния всех выходов модуля, которые необходимо
                        выставить.
   @param[in] flags     Флаги. Резерв. Должен передаваться 0.
   @return              Код ошибки.
 ******************************************************************************/
LTRK511API_DllExport(INT) LTRK511_SetModuleOutState(
        TLTRK511 *hnd, const TLTRK511_OUT_STATE *state, DWORD flags);


/***************************************************************************//**
   @brief Установка состояная заданного ключа.

   Функция позволяет отдельно установить состояние заданного выходного ключа.

   При успешном выводе обновляется значение состояния этого ключа в описателе
   модуля.

   @param[in] hnd       Описатель модуля.
   @param[in] sw_num    Номер выходного ключа. От 0 до #LTRK511_OUT_SW_CNT-1.
   @param[in] state     Состояния ключа, которое необходимо установить.
                        Одно из значений перечисления #e_LTRK511_OUT_SW_STATE.
   @return              Код ошибки.
 ******************************************************************************/
LTRK511API_DllExport(INT) LTRK511_SetOutSwState(TLTRK511 *hnd, DWORD sw_num, BYTE state);

/***************************************************************************//**
   @brief Установка значения ЦАП.

   Функция позволяет отдельно установить значение на ЦАП модуля.

   При успешном выводе обновляется значение состояния ЦАП в описателе
   модуля.

   @param[in] hnd       Описатель модуля.
   @param[in] data      Значение для вывода на ЦАП в кодах или величинах, в зависимости
                        от флагов.
   @param[in] flags     Набор флагов из #e_LTRK511_DAC_FLAGS.
   @return              Код ошибки.
 ******************************************************************************/
LTRK511API_DllExport(INT) LTRK511_SetDAC(TLTRK511 *hnd, double data, WORD flags);

/***************************************************************************//**
   @brief Установка состояний выходов реле.

   Функция устанавливает состояние всех #LTRK511_RELAY_CNT выходов реле модуля.
   Каждому реле соответствует один бит в записываемом слове, начиная с младшего.
   Если он установлен в 1, то реле включено, иначе - выключено.

   @param[in] hnd       Описатель модуля.
   @param[in] states    Слово с состоянием выходов реле.
                        Действительны только младшие #LTRK511_RELAY_CNT бит.
   @return              Код ошибки.
 ******************************************************************************/
LTRK511API_DllExport(INT) LTRK511_SetRelayStates(TLTRK511 *hnd, DWORD states);

/***************************************************************************//**
   @brief Установка состояния выхода реле.

   Функция устанавливает состояние одного указанного выхода реле.

   @param[in] hnd       Описатель модуля.
   @param[in] relay_num Номер реле от 0 до #LTRK511_RELAY_CNT-1.
   @param[in] state     Состояние реле (0 - выкл., 1 - вкл.).
   @return              Код ошибки.
 ******************************************************************************/
LTRK511API_DllExport(INT) LTRK511_SetRelayState(TLTRK511 *hnd, DWORD relay_num, BOOLEAN state);


LTRK511API_DllExport(INT) LTRK511_CalcDacCode(const TLTRK511_CBR_COEF *dac_cbr, double data, DWORD flags, WORD *res_code);

/***************************************************************************//**
   @brief Получение сообщения об ошибке.

   Функция возвращает строку, соответствующую переданному коду ошибки, в кодировке
   CP1251 для Windows или UTF-8 для Linux. Функция может обработать как ошибки
   из LTRK511API, так и общие коды ошибок из ltrapi.

   @param[in] err       Код ошибки
   @return              Указатель на строку, содержащую сообщение об ошибке.
 ******************************************************************************/
LTRK511API_DllExport(LPCSTR) LTRK511_GetErrorString(INT err);


#ifdef __cplusplus
}                                          // only need to export C interface if
                                           // used by C++ source code
#endif

#endif                      /* #ifndef LTRK511API_H_ */
