/*
    Данный пример демонстрирует измерение частоты с помощью модуля LTR51.
    По умолчанию идет работа с первым слотом первого крейта, но это можно изменить
        через параметры командной строки:
    ltr51_interval  slot crate_serial srvip
    где:
        slot         - номер слота (от 1 до 16)
        crate_serial - серийный номер крейта (если крейтов больше одного)
        srvip        - ip-адрес программы ltrd или LtrServer (если он запущен на другой машине)
    Параметры опциональны: можно указать только слот, слот и серийный номер крейта или все

    Данный пример использует факт, что в бибилотеках 1.30.0 и выше можно передать
    пустую строку в качестве имени TTF-файла для загурузки и будет взят
    файл из ресурса библиотеки (Windows) или по стандартному пути (Linux).

    Пример принимает данные от первых двух каналов и измеряет частоту сигнала.
    Устанавливаемое время AcqTime должно быть больше чем два периода входной частоты.

    Пользователь может изменить настройки на свои, поменяв заполнение полей
    структуры перед запуском сбора.

    Сбор идет до нажатия любой клавиши на Windows или  CTRL+C на Linux

    Сборка в VisualStudio:
    Для того чтобы собрать проект в Visual Studio, измените путь к заголовочным файлам
    (Проект (Project) -> Свойства (Properties) -> Свойства конфигурации (Configuration Properties)
    -> С/С++ -> Общие (General) -> Дополнительные каталоги включения (Additional Include Directories))
    на нужный в зависимаости от пути установки библиотек (ltr51api.h  и остальные заголовочные
    файлы должны находится в поддиректории ltr/include относительно указанного пути)
    и измените путь к .lib файлам на <путь установки библиотек>/lib/msvc
    (Проект (Project) -> Свойства (Properties) -> Свойства конфигурации (Configuration Properties) ->
    Компоновщик (Linker) -> Общие (General) -> Дополнительные каталоги библиотек (Additional Library Directories)).

    Внимание!: Если Вы собираете проект под Visual Studio и у Вас некорректно
    отображается вывод русских букв, то нужно изменить кодировку:
    выберите Файл (File) -> Дополнительные параметры сохранения (Advanced Save Options)...
    и в поле Кодировка (Encoding) выберите Юникод (UTF8, с сигнатурой)/Unicode (UTF-8 with signature)
    и сохраните изменения в файле. А также следует убедится, что в настройках
    консоли стоит шрифт с поддержкой русского языка (например Consolas).
*/

#include "ltr/include/ltr51api.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef _WIN32
#include <locale.h>
#include <conio.h>
#else
#include <signal.h>
#include <unistd.h>
#endif

/* путь к прошивке ПЛИС. Пустая строка => используем встроенную прошивку */
#define LTR51_TTF_FILE ""

typedef struct {
    int slot;
    const char *serial;
    DWORD addr;
} t_open_param;


static int f_out = 0;
#ifndef _WIN32
/* Обработчик сигнала завершения для Linux */
static void f_abort_handler(int sig) {
    f_out = 1;
}
#endif

static int f_get_params(int argc, char** argv, t_open_param* par) {
    int err = 0;
    par->slot = LTR_CC_CHNUM_MODULE1;
    par->serial = "";
    par->addr = LTRD_ADDR_DEFAULT;


    if (argc > 1)
        par->slot = atoi(argv[1]);
    if (argc > 2)
        par->serial = argv[2];
    if (argc > 3) {
        int a[4],i;
        if (sscanf(argv[3], "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3])!=4) {
            fprintf(stderr, "Неверный формат адреса сервера!!\n");
            err = -1;
        }

        for (i=0; (i < 4) && !err; i++) {
            if ((a[i]<0) || (a[i] > 255)) {
                fprintf(stderr, "Неверный формат адреса сервера!!\n");
                err = -1;
            }
        }

        if (!err) {
            par->addr = (a[0] << 24) | (a[1]<<16) | (a[2]<<8) | a[3];
        }
    }
    return err;
}

int main(int argc, char** argv) {
    INT err = LTR_OK;
    TLTR51 hltr51;
    t_open_param par;
#ifndef _WIN32
    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    /* В ОС Linux устанавливаем свой обработчик на сигнал закрытия,
       чтобы завершить сбор корректно */
    sa.sa_handler = f_abort_handler;
    sigaction(SIGTERM, &sa, NULL);
    sigaction(SIGINT, &sa, NULL);
    sigaction(SIGABRT, &sa, NULL);
#endif


#ifdef _WIN32
    setlocale(LC_ALL, "");
#endif

    err = f_get_params(argc, argv, &par);
    if (!err) {
        LTR51_Init(&hltr51);
        err = LTR51_Open(&hltr51, par.addr, LTRD_PORT_DEFAULT, par.serial, par.slot,
                         LTR51_TTF_FILE);

        if (err!=LTR_OK) {
            fprintf(stderr, "Не могу открыть модуль. Ошибка %d (%s)\n",
                    err, LTR51_GetErrorString(err));
        } else {
            double HighThreshold, LowThreshold;
            printf("Модуль открыт успешно. Информация:\n Название модуля: %s\n Серийный номер: %s\n"
                   " Версия прошивки: %s\n Дата создания прошивки: %s\n Версия ПЛИС: %s\n",
                   hltr51.ModuleInfo.Name,
                   hltr51.ModuleInfo.Serial,
                   hltr51.ModuleInfo.FirmwareVersion,
                   hltr51.ModuleInfo.FirmwareDate,
                   hltr51.ModuleInfo.FPGA_Version
                   );
            fflush(stdout);

            /* время должно быть не меньше 2-х периодов частоты.
             * настройки FS и Base берем автоматически рассчитанные */
            hltr51.AcqTime = 1000;

            hltr51.LChQnt = 2;
            HighThreshold = 0.7;
            LowThreshold = 0.3;
            hltr51.LChTbl[0] = LTR51_CreateLChannel(1, &HighThreshold, &LowThreshold,
                                                    LTR51_THRESHOLD_RANGE_10V, LTR51_EDGE_MODE_RISE);
            hltr51.LChTbl[1] = LTR51_CreateLChannel(2, &HighThreshold, &LowThreshold,
                                                    LTR51_THRESHOLD_RANGE_10V, LTR51_EDGE_MODE_FALL);


            err = LTR51_Config(&hltr51);
            if (err!=LTR_OK) {
                fprintf(stderr, "Не удалось настроить модуль! Ошибка %d:%s\n",
                        err, LTR51_GetErrorString(err));
            } else {
                printf("Установлены следующие параметры:\n Частота дискретизации = %.3f Гц\n Счетчик BASE = %d\n Время счета = %d мс\n Количество периодов измерения = %d\n",
                       hltr51.Fs, hltr51.Base, hltr51.AcqTime, hltr51.TbaseQnt);
                fflush(stdout);
            }

            if (err==LTR_OK) {
                /* выделяем массивы под буферы данных */
                DWORD read_cnt = 2*LTR51_CHANNEL_CNT*hltr51.TbaseQnt;
                DWORD *rbuf = malloc(read_cnt*sizeof(rbuf[0]));
                double *freqs = malloc(hltr51.LChQnt*sizeof(double));
                if ((rbuf==NULL) || (freqs==NULL)) {
                    err = LTR_ERROR_MEMORY_ALLOC;
                    fprintf(stderr, "Ошибка выделения памяти!\n");
                } else {
                    /* Запускаем сбор данных */
                    err = LTR51_Start(&hltr51);
                    if (err!=LTR_OK) {
                        fprintf(stderr, "Не запустить сбор данных! Ошибка %d:%s\n",
                                err, LTR51_GetErrorString(err));
                    } else {
                        DWORD tout = LTR51_CalcTimeOut(&hltr51, hltr51.TbaseQnt);
                        DWORD block_num = 0;
                        INT stop_err;

                        printf("Сбор данных запущен успешно! Для останова нажмите %s\n",
#ifdef _WIN32
                           "любую клавишу"
#else
                           "CTRL+C"
#endif
                           );

                        /* выполняем сбор либо пока не произойдет ошибка, либо
                         * пока не будет запрос на завершение */
                        while ((err==LTR_OK) && !f_out) {
                            INT recvd = LTR51_Recv(&hltr51, rbuf, NULL, read_cnt, tout);
                            if (recvd<0) {
                                err = recvd;
                                fprintf(stderr, "Ошибка приема данных. Ошибка %d:%s\n",
                                        err, LTR51_GetErrorString(err));
                            } else if (recvd!=(INT)read_cnt) {
                                fprintf(stderr, "Принято недостаточно данных. Запрашивали %d, приняли %d\n",
                                        read_cnt, recvd);
                                err = LTR_ERROR_RECV_INSUFFICIENT_DATA;
                            } else {
                                /* в обрабатываемых данных используем только значения
                                 * рассчитанных частот. Пример использования
                                 * значений N и M см. в примере ltr51_interval */
                                err = LTR51_ProcessData(&hltr51, rbuf, NULL, freqs, (DWORD*)&recvd);
                                if (err!=LTR_OK){
                                    fprintf(stderr, "Ошибка обработки данных. Ошибка %d:%s\n",
                                            err, LTR51_GetErrorString(err));
                                } else {
                                    INT ch;
                                    printf("\nБлок %d:", block_num+1);
                                    for (ch=0; ch < hltr51.LChQnt; ch++) {
                                        printf("  Канал %2d: f=%.5f",
                                               ch+1, freqs[ch]);
                                    }
                                    fflush(stdout);
                                    block_num++;
                                }
                            }

#ifdef _WIN32
                            /* проверка нажатия клавиши для выхода */
                            if (err==LTR_OK) {
                                if (_kbhit())
                                    f_out = 1;
                            }
#endif
                        }



                        stop_err = LTR51_Stop(&hltr51);
                        if (stop_err!=LTR_OK) {
                            fprintf(stderr, "Ошибка останова сбора данных. Ошибка %d:%s\n",
                                    stop_err, LTR51_GetErrorString(stop_err));
                            if (err==LTR_OK)
                                err = stop_err;
                        } else {
                            printf("Сбор данных остановлен успешно!\n");
                        }
                    }
                }
                free(rbuf);
                free(freqs);
            }
        }

        LTR51_Close(&hltr51);
    }

    return err;
}
