#include "ltr/include/ltr12api.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 BLOCK_TIME 500
/* таймаут на ожидание данных при приеме (без учета времени преобразования) */
#define RECV_TOUT  4000
#define RECV_FREQ  400*1000

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


/* Разбор параметров командной строки. Если указано меньше, то используются
 * значения по умолчанию:
 * 1 параметр - номер слота (от 1 до 16)
 * 2 параметр - серийный номер крейта
 * 3 параметр - ip-адрес сервера */
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, "Неверный формат IP-адреса!!\n");
            err = -1;
        }

        for (i=0; (i < 4) && !err; i++) {
            if ((a[i]<0) || (a[i] > 255)) {
                fprintf(stderr, "Недействительный IP-адрес!!\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[]) {
    TLTR12 hltr12;
    INT  err;
    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
    /* для вывода русских букв в консоль для ОС Windows*/
    setlocale(LC_ALL, "");
#endif
    err = f_get_params(argc, argv, &par);

    if (!err) {
        /* инициализация дескриптора модуля */
        LTR12_Init(&hltr12);
        /* открытие канала связи с модулем, установленным в заданный слот */
        err = LTR12_Open(&hltr12, par.addr, LTRD_PORT_DEFAULT, par.serial, par.slot);
    }
    if (err != LTR_OK) {
        fprintf(stderr, "Не удалось установить связь с модулем. Ошибка %d (%s)\n",
                err, LTR12_GetErrorString(err));
    } else {
        BYTE ch_idx;
        /* Вывод информации о модуле */
        printf("Модуль открыт успешно! Информация о модуле: \n");
        printf("  Название модуля    = %s\n", hltr12.ModuleInfo.Name);
        printf("  Серийный номер     = %s\n", hltr12.ModuleInfo.Serial);
        printf("  Версия прошивки    = %d.%d\n", (hltr12.ModuleInfo.FirmwareVersion >> 8) & 0xFF,
                                                 hltr12.ModuleInfo.FirmwareVersion & 0xFF);
        printf("  Дата прошивки      = %s\n", hltr12.ModuleInfo.FirmwareDate);
        fflush(stdout);


        hltr12.Cfg.BgLChCnt = 1; /**< Дополнительный такт для измерения смещения нуля */
        hltr12.Cfg.LChCnt = 12;
        for (ch_idx = 0; ch_idx < hltr12.Cfg.LChCnt; ch_idx++) {
            LTR12_FillLChannel(&hltr12, ch_idx, ch_idx, LTR12_CH_MODE_COMM);
        }
        LTR12_FillAdcFreqParams(&hltr12, RECV_FREQ, NULL);


        err = LTR12_SetADC(&hltr12);
        if (err != LTR_OK) {
            fprintf(stderr, "Не удалось настройки модуля. Ошибка %d (%s)\n",
                    err, LTR12_GetErrorString(err));
        } else {
            fprintf(stderr, "Модуль сконфигурирован успешно!. Частота АЦП = %.2f\n",
                    hltr12.State.AdcFreq);
            fflush(stdout);
        }
    }

    if (err == LTR_OK) {
        err = LTR12_MeasAdcZeroOffset(&hltr12, 0);
        if (err != LTR_OK) {
            fprintf(stderr, "Ошибка измерения нуля. Ошибка %d (%s)\n",
                    err, LTR12_GetErrorString(err));
        } else {
            fprintf(stderr, "Успешно выполнено начальное измерение смещения нуля. Код смещения = %.3f\n",
                    hltr12.State.AdcZeroOffsetCode);
            fflush(stdout);
        }
    }


    if (err==LTR_OK) {
        DWORD recvd_blocks=0;
        DWORD block_ch_pts = (DWORD)(((hltr12.State.FrameFreq * BLOCK_TIME) + 999)/1000);
        DWORD recv_wrd_cnt = block_ch_pts * hltr12.State.FrameWordsCount;
        DWORD recv_data_cnt = block_ch_pts * hltr12.Cfg.LChCnt;

        DWORD  *rbuf = (DWORD*)malloc(recv_wrd_cnt*sizeof(rbuf[0]));
        double *data = (double *)malloc(recv_data_cnt*sizeof(data[0]));

        if ((rbuf==NULL) || (data==NULL)) {
            fprintf(stderr, "Ошибка выделения памяти!\n");
            err = LTR_ERROR_MEMORY_ALLOC;
        }


        /* Запуск сбора данных */
        err = LTR12_Start(&hltr12);
        if (err != LTR_OK) {
            fprintf(stderr, "Не удалось запустить сбор данных! Ошибка %d (%s)\n",
                    err, LTR12_GetErrorString(err));
        }

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

        /* ведем сбор данных до возникновения ошибки или до
         * запроса на завершение */
        while (!f_out && (err == LTR_OK)) {
            INT recvd;
            /* В таймауте учитываем время сбора запрашиваемого числа отсчетов */
            DWORD tout = RECV_TOUT + BLOCK_TIME;
            /* Прием данных от модуля.  */
            recvd = LTR12_Recv(&hltr12, rbuf, NULL, recv_wrd_cnt, tout);

            /* Значение меньше нуля соответствуют коду ошибки */
            if (recvd < 0) {
                err = recvd;
                fprintf(stderr, "Ошибка приема данных. Ошибка %d:%s\n",
                        err, LTR12_GetErrorString(err));
            } else if ((DWORD)recvd != recv_wrd_cnt) {
                fprintf(stderr, "Принято недостаточно данных. Запрашивали %d, приняли %d\n",
                        recv_wrd_cnt, recvd);
                err = LTR_ERROR_RECV_INSUFFICIENT_DATA;
            } else {
                err = LTR12_ProcessData(&hltr12, rbuf, data, &recvd,
                                         LTR12_PROC_FLAG_CALIBR
                                        | LTR12_PROC_FLAG_CONV_UNIT
                                        | LTR12_PROC_FLAG_ZERO_OFFS_COR
                                        | LTR12_PROC_FLAG_ZERO_OFFS_AUTORECALC);
                if (err != LTR_OK) {
                    fprintf(stderr, "Ошибка обработки данных. Ошибка %d:%s\n",
                            err, LTR12_GetErrorString(err));
                } else {
                    unsigned ch;
                    recvd_blocks++;
                    /* выводим по первому слову на канал */
                    printf("Блок %4d:", recvd_blocks);
                    for (ch = 0; ch < hltr12.Cfg.LChCnt; ch++) {
                        printf(" %9.3f", data[ch]);
                        if (ch != (hltr12.Cfg.LChCnt - 1))
                            printf(", ");
                    }
                    printf("\n");

                    fflush(stdout);
                }
            }

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

        if (hltr12.State.Run) {
            INT stop_err = LTR12_Stop(&hltr12);
            if (stop_err != LTR_OK) {
                fprintf(stderr, "Не удалось остановить сбор данных. Ошибка %d:%s\n",
                        stop_err, LTR12_GetErrorString(stop_err));
                if (err==LTR_OK)
                    err = stop_err;
            } else {
                printf("Сбор остановлен успешно.\n");
            }
        }



        free(rbuf);
        free(data);
    }

    if (LTR12_IsOpened(&hltr12) == LTR_OK) {
        /* закрытие канала связи с модулем */
        LTR12_Close(&hltr12);
    }
        
    return err;
}


