#ifndef LTRK415API_H_
#define LTRK415API_H_

#include "ltr01api.h"

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

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


/** Размер строки с именем модуля в структуре #TLTRK415_MODULE_INFO */
#define LTRK415_NAME_SIZE               16
/** Размер строки с серийным номером модуля в структуре #TLTRK415_MODULE_INFO */
#define LTRK415_SERIAL_SIZE             24
/** Количество выходных каналов с управляемыми ключами */
#define LTRK415_OUT_CH_CNT              2
/** Количество выходных управляемых ключей для каждого выходного канала */
#define LTRK415_OUT_CH_SW_CNT           10
/** Размер циклического буфера для вывода состояния выходов в словах */
#define LTRK415_OUT_CH_CBUF_SIZE        512
/** Количество входных каналов для измерения параметров импульсов запросов */
#define LTRK415_IN_REQ_CH_CNT           2


/** Коды ошибок, специфичные для LTRK415. */
typedef enum {
    LTRK415_ERR_INVALID_SW_STATE        = -11110,  /**< Задано неверное состояние выходного ключа. */
    LTRK415_ERR_INVALID_CH_NUM          = -11111,  /**< Указан неверный номер канала */
    LTRK415_ERR_INVALID_CH_MSK          = -11112,  /**< Неверна задана группа каналов */
    LTRK415_ERR_INVALID_OUT_CH_SW_NUM   = -11113,  /**< Указан неверный номер выходного ключа порта */
    LTRK415_ERR_INVALID_OUT_CH_SRC      = -11114,  /**< Неверный код источника данных для канала */
    LTRK415_ERR_INSUF_OUT_BUF_SIZE      = -11115,  /**< Превышен максимальный размер буфера вывода */

} e_LTRK415_ERROR_CODES;

/** Состояния выходного ключа модуля */
typedef enum {
    LTRK415_OUT_SW_STATE_OFF            = 0,  /**< Отключен. */
    LTRK415_OUT_SW_STATE_ON             = 1,  /**< Прямое включение. */
    LTRK415_OUT_SW_STATE_ON_INV         = 2   /**< Обратное включение. */
} e_LTRK415_OUT_SW_STATE;

/** Источник данных для вывода */
typedef enum {
    LTRK415_CH_SRC_DIRECT               = 0, /**< Ручной однократный вывод через регистры.
                                                  Данные выводятся с помощью функций
                                                  LTRK415_SetOutSwState()
                                                  и/или LTRK415_SetOutChSwStates() */
    LTRK415_CH_SRC_CBUF                 = 1, /**< Циклический вывод из буфера.
                                                  Данные загружаются в буфер с помощью
                                                  LTRK415_LoadOutBuf(), после чего
                                                  выводятся из него по кругу по приходу
                                                  входных запросов */
} e_LTRK415_CH_SRC;

/** Номер канала обработанного слова измерения параметров запросов */
typedef enum {
    LTRK415_ACQ_CHNUM_CH1_REQ   = 1, /**< Канал 1, запросы */
    LTRK415_ACQ_CHNUM_CH2_REQ   = 2, /**< Канал 2, запросы */
    LTRK415_ACQ_CHNUM_CH1_PHASE = 3, /**< Канал 1, фаза */
    LTRK415_ACQ_CHNUM_CH2_PHASE = 4, /**< Канал 2, фаза */
}  e_LTRK415_ACQ_CHNUM;

typedef enum {
    LTRK415_ACQ_TYPE_REQ_PERIOD     = 1, /**< Период следования запросов */
    LTRK415_ACQ_TYPE_REQ1_WIDTH     = 2, /**< Длительность запроса 1 и соответствующего запроса D */
    LTRK415_ACQ_TYPE_REQ2_DELAY     = 3, /**< Задержка запроса 2 относительно запроса 1 */
    LTRK415_ACQ_TYPE_REQ2_WIDTH     = 4, /**< Длительность запроса 2 и соответствующего запроса D */
    LTRK415_ACQ_TYPE_PHASE_PERIOD   = 5, /**< Период следования запросов фазы M4 */
    LTRK415_ACQ_TYPE_PHASE_WIDTH    = 6, /**< Длительность запроса фаза M4 */
} e_LTRK415_ACQ_TYPE;

#pragma pack (4)

/** Информация о модуле */
typedef struct {
    CHAR        Name[LTRK415_NAME_SIZE];      /**< Название модуля (оканчивающаяся нулем ASCII-строка) */
    CHAR        Serial[LTRK415_SERIAL_SIZE];  /**< Серийный номер модуля (оканчивающаяся нулем ASCII-строка) */
    BYTE        VerPLD;                      /**< Версия прошивки PLD  */
    DWORD       Reserved[15];                 /**< Резерв */
} TLTRK415_MODULE_INFO;

/** Информация о состоянии одного канала */
typedef struct {
    BYTE Sw[LTRK415_OUT_CH_SW_CNT]; /**< Состояние всех выходных ключей канала.
                                         Действительно только при ручном выводе через
                                         регистры (#LTRK415_CH_SRC_DIRECT).
                                         Каждый элемент массива определяет состояние ключа
                                         с соответствующим номером и может принимать одно из
                                         значений из перечисления #e_LTRK415_OUT_SW_STATE. */
    DWORD Reserved[7]; /**< Резерв */
} TLTRK415_CH_STATE;
/** Параметры состояния модуля */
typedef struct {
    TLTRK415_CH_STATE Ch[LTRK415_OUT_CH_CNT]; /**< Состояне каналов */
    BOOLEAN AcqActive; /**< Признак запущенного сбора измерений временных параметров запросов
                            со входных каналов. Изменяется библиотекой при вызовах LTRK415_StartAcq()
                            и LTRK415_StopAcq(). При запущенном сборе данных недопустимо изменять состояния
                            выходов или конфигурацию модуля */
    DWORD Reserved[15]; /**< Резерв */
} TLTRK415_STATE;


/** Настройки вывода одного канала */
typedef struct {
    BYTE Source;              /**< Признак, каким образом будут устанавливаться значения на выходах
                                   данного канала. Одно из значений из #e_LTRK415_CH_SRC. */
    BOOLEAN ActiveWithoutReq; /**< Если флаг установлен, то выставленные уровни на
                                   выходах будет активны все время даже при отсутствии запроса,
                                   иначе --- при отсутствии запроса будет установлено третье состояние */
    BOOLEAN InvertedData;     /**< Если флаг установлен, то при выводе данных инвертируется
                                   прямое и обратное включение. При выводе из буфера значение
                                   бита 1 при установленном поле соответствует обратному включению,
                                   если не установлен --- прямому. При прямом выводе, если
                                   данная поле установленно, то состоянию #LTRK415_OUT_SW_STATE_ON
                                   соответствует #LTRK415_OUT_SW_STATE_ON_INV и наоборот.*/

    DWORD Reserved[7]; /**< Резерв */
} TLTRK415_CH_CONFIG;

/** Настройки модуля, относящиеся к выводу */
typedef struct {
    TLTRK415_CH_CONFIG Ch[LTRK415_OUT_CH_CNT]; /**< настройки каналов вывода */
    DWORD Reserved[4]; /**< Резерв */
} TLTRK415_OUT_CONFIG;


/** Настройки модуля заполняются пользователем, после чего при вызове
    LTRK415_Configure() осуществляется передача их в модуль.
*/
typedef struct {
    TLTRK415_OUT_CONFIG Out; /**< Настройки вывода */
    DWORD Reserved[16]; /**< Резерв */
} TLTRK415_CONFIG;


/** Описатель модуля */
typedef struct {
    INT size;     /**< Размер структуры. Заполняется в LTRK415_Init(). */
    /** Структура, содержащая состояние соединения с сервером.
        Не используется напрямую пользователем. */
    TLTR Channel;
    /** Указатель на непрозрачную структуру с внутренними параметрами,
        используемыми исключительно библиотекой и недоступными для пользователя. */
    PVOID Internal;
    TLTRK415_CONFIG Cfg;
    /** Состояние модуля и рассчитанные параметры. Поля изменяются функциями
        библиотеки. Пользовательской программой могут использоваться
        только для чтения. */
    TLTRK415_STATE State;
    TLTRK415_MODULE_INFO ModuleInfo; /**< Информация о модуле */
} TLTRK415;

/** Информация о принятом измерении одного временного параметра по входному
 *  каналу */
typedef struct {
    BYTE ChNum; /**< Номер канала, которому принадлежит измерение.
                     Значение из #e_LTRK415_ACQ_CHNUM */
    BYTE Type;  /**< Тип измерения. Значение из #e_LTRK415_ACQ_TYPE */
    union {
        WORD Full; /**< Полное 16-битное значение счетчика (актуально для периода и задержки) */
        struct {
            BYTE d; /**< Значение 8-битного счетчика D (длительность дублирующго испульса для запросов 1 и 2) */
            BYTE p; /**< Значение 8-битного счетчика P (длительность основного испульса) */
        };
    } Cntr; /** Исходное значение счетчика из принятого слово */
    DWORD TimeNS; /**< Измеренное время, переведенное из значения счетчика в нс */
    DWORD TimeNS_D; /**< Измеренное время для дублирующего импульса D в нс
                         (актуально только для измерений #LTRK415_ACQ_TYPE_REQ1_WIDTH
                          и #LTRK415_ACQ_TYPE_REQ2_WIDTH). Если длительность больше
                          основного импульса, то возвращается значение 0xFFFFFFFF */
} TLTRK415_ACQ_DATA;


#pragma pack ()

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

LTRK415API_DllExport(INT) LTRK415_Init(TLTRK415 *hnd);
LTRK415API_DllExport(INT) LTRK415_Open(TLTRK415 *hnd, DWORD net_addr, WORD net_port,
                                       const CHAR *csn, WORD slot);
LTRK415API_DllExport(INT) LTRK415_Close(TLTRK415 *hnd);
LTRK415API_DllExport(INT) LTRK415_IsOpened(TLTRK415 *hnd);



/***************************************************************************//**
   @brief Настройка модуля.

   Функция передает настройки, соответствующие значениям полей
   [структуры конфигурации](@ref TLTRK415::Cfg) описателя модуля, в модуль.
   Вызывается каждый раз при изменении настроек модуля для того, чтобы эти настройки
   вступили в силу.

   @param[in] hnd       Описатель модуля.
   @return              Код ошибки.
 ******************************************************************************/
LTRK415API_DllExport(INT) LTRK415_Configure(TLTRK415 *hnd);


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

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

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

   @param[in] hnd       Описатель модуля.
   @param[in] ch_num    Номер канала, которому принадлежит ключ. От 0 до #LTRK415_OUT_CH_CNT-1.
   @param[in] sw_num    Номер выходного ключа. От 0 до #LTRK415_OUT_CH_SW_CNT-1.
   @param[in] sw_state  Состояния ключа, которое необходимо установить.
                        Одно из значений перечисления #e_LTRK415_OUT_SW_STATE.
   @return              Код ошибки.
 ******************************************************************************/
LTRK415API_DllExport(INT) LTRK415_SetOutSwState(TLTRK415 *hnd, BYTE ch_num, BYTE sw_num, BYTE sw_state);

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

   Функция позволяет установить состояние всех ключей выбранного канала одновременно
   при настроенном прямом выводе через регистры (#LTRK415_CH_SRC_DIRECT).

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

   @param[in] hnd       Описатель модуля.
   @param[in] ch_num    Номер канала, состояния ключей которого должны быть обновлены.
                        От 0 до #LTRK415_OUT_CH_CNT-1.
   @param[in] sw_num    Номер выходного ключа. От 0 до -1.
   @param[in] sw_states Массив из #LTRK415_OUT_CH_SW_CNT элементов с требуемыми
                        состояниями ключей. Каждый элемент может принимать
                        одно из значений перечисления #e_LTRK415_OUT_SW_STATE.
   @return              Код ошибки.
 ******************************************************************************/
LTRK415API_DllExport(INT) LTRK415_SetOutChSwStates(TLTRK415 *hnd, BYTE ch_num, const BYTE *sw_states);


/***************************************************************************//**
   @brief Загрузка значений циклического буфера на вывод.

   Функция позволяет загрузить буфер значений для последующего циклического вывода
   по внешним запросам по кругу. Используется при настроенном выводе из циклического
   буфера (#LTRK415_CH_SRC_CBUF) для соответствующего канала.

   Каждого слово, загружаемое в буфер, состоит из 16 бит, из которых значащие только
   #LTRK415_OUT_CH_SW_CNT младших. Каждый бит соответствует состоянию выхода с тем же
   номером. Нулевое значение бита соответствуют выключенному состоянию, единичное ---
   прямому или обратному включенному состоянию (в зависимости от настройки
   #TLTRK415_CH_CONFIG::InvertedData).

   Общее количество слов - от 1 до #LTRK415_OUT_CH_CBUF_SIZE.
   Для каждого канала используется свой независимый буфер, который загружается отдельно
   своими данными и может иметь свой размер выводимых данных.

   Весь буфер должен быть загружен за один вызов. Повторный вызов функции приводит
   к замене текущих данных буфера на новые.

   @param[in] hnd       Описатель модуля.
   @param[in] ch_num    Номер канала, буфер циклических данных которого будет загружен.
   @param[in] data      Массив из size 16-битных слов, представляющих собой состояния выходов,
                        который должен быть загружен в буфер на вывод.
   @param[in] size      Количество слов в буфере data для загрузки в модуль. Может
                        быть от 1 до #LTRK415_OUT_CH_CBUF_SIZE.
   @return              Код ошибки.
 ******************************************************************************/
LTRK415API_DllExport(INT) LTRK415_LoadOutBuf(TLTRK415 *hnd, BYTE ch_num, const WORD *data, WORD size);


/***************************************************************************//**
    @brief Запуск приема измерений временных параметров сигналов на входах.

    После вызова данной функции модуль начинает передавать данные в ПК со значенями
    измерений выделенных импульсов запросов, которые в дальнейшем необходимо
    принимать с помощью LTRK415_Recv() и обрабатывать с помощью LTRK415_ProcessData().
    После запуска передачи измерений недопустимо посылать модулю другие управляющие команды,
    кроме останова передачи измерений с помощью LTRK415_StopAcq().

    @param[in] hnd       Описатель модуля.
    #param[in] ch_msk    Маска каналов для которых разрешается прием измерений.
                         Каждому каналу соответствует один бит слова. Хотя бы один бит
                         должен быть установлен.
   @return              Код ошибки.
 ******************************************************************************/
LTRK415API_DllExport(INT) LTRK415_StartAcq(TLTRK415 *hnd, BYTE ch_msk);
/***************************************************************************//**
    @brief Останов приема измерений временных параметров сигналов на входах.

    При вызове данной функции запрещается выдача модулем измерений, разрешенная
    с помощью LTRK415_StartAcq(), а также происходит полная очистка буфера измерений.

    После вызова данной функции можно выполнять изменение конфигурации модуля или
    изменение выводимых данных.

    @param[in] hnd       Описатель модуля.
    @return              Код ошибки.
 ******************************************************************************/
LTRK415API_DllExport(INT) LTRK415_StopAcq(TLTRK415 *hnd);

/***************************************************************************//**
   @brief Прием данных от модуля

   Функция принимает запрашиваемое число слов от модуля. Возвращаемые слова
   находятся в специальном формате, который включает в себя служебную информацию.

   Для обработки принятых слов и получения значений измерений используется функция
   LTRK415_ProcessData().

   Функция возвращает управление либо когда примет запрошенное количество слов,
   либо по истечению таймаута. При этом реально принятое количество слов можно
   узнать по возвращенному значению.

   @param[in]  hnd      Описатель модуля.
   @param[out] data     Массив, в который будут сохранены принятые слова. Должен
                        быть размером на size 32-битных слов.
   @param[out] tmark    Указатель на массив размером на size 32-битных слов,
                        в который будут сохранены значения счетчиков синхрометок,
                        соответствующие принятым данным. Генерация меток
                        настраивается для крейта или специального модуля отдельно.
                        Синхрометки подробнее описаны в разделе "Синхрометки"
                        @docref_ltrapi{руководства для библиотеки ltrapi}.
                        Если синхрометки не используются, то можно передать
                        в качестве параметра нулевой указатель.
   @param[in]  size     Запрашиваемое количество 32-битных слов на прием.
   @param[in]  timeout  Таймаут на выполнение операции в миллисекундах. Если в течение
                        заданного времени не будет принято запрашиваемое количество
                        слов, то функция все равно вернет управление, возвратив
                        в качестве результата реально принятое количество слов
   @return              Значение меньше нуля соответствует коду ошибки. Значение
                        больше или равное нулю соответствует количеству реально
                        принятых и сохраненных в массив data слов.
*******************************************************************************/
LTRK415API_DllExport(INT) LTRK415_Recv(TLTRK415 *hnd, DWORD *data, DWORD *tstamp, DWORD size, DWORD timeout);

/***************************************************************************//**
    @brief Обработка принятых данных

    Функция посзволяет на основе слов, принятых с помощью LTRK415_Recv(), получить
    информацию о номере канала, типе измерения и значении измерения.

    На каждое слово функция возвращает структуру типа #TLTRK415_ACQ_DATA,
    в которой содержится вся инфомрация из исходного принятого слова.


    @param[in] hnd       Описатель модуля.
    @param[in] src_data  Массив из size 32-битных слов, принятых с помощью LTRK415_Recv().
    @param[out] dst_data Массив из size структур типа #TLTRK415_ACQ_DATA, в котором будет
                         сохранен результат обработки.
    @param[in]  size     Размер массива для обработки.
    @return              Код ошибки.
 ******************************************************************************/
LTRK415API_DllExport(INT) LTRK415_ProcessData(TLTRK415 *hnd, const DWORD *src_data, TLTRK415_ACQ_DATA *dst_data, DWORD size);

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

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

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


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

#endif                      /* #ifndef LTR11API_H_ */
