#include "ltr/include/ltr114api.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 STREAM_RECV_FRAME_CNT  200
#define STREAM_RECV_TOUT  5000

/* признак необходимости завершить сбор данных */
static int f_out = 0;


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


#ifndef _WIN32
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;
    TLTR114 hltr114;
    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)
    {
        LTR114_Init(&hltr114);
        err = LTR114_Open(&hltr114, par.addr, LTRD_PORT_DEFAULT, par.serial, par.slot);
        if (err)
        {
            fprintf(stderr, "Не могу открыть модуль. Ошибка %d (%s)\n",
                    err, LTR114_GetErrorString(err));
        }
        else
        {
            printf("Модуль открыт успешно.\n");
            err = LTR114_GetConfig(&hltr114);
            if (err!=LTR_OK)
            {
                fprintf(stderr, "Не удалось прочитать конфигурацию модуля из Flash-памяти. Ошибка %d (%s)\n",
                        err, LTR114_GetErrorString(err));
            }
            else
            {
                printf("Информация о модуле:\n Название модуля: %s\n Серийный номер: %s\n"
                       " Версия прошивки AVR: %d.%d\n Версия прошивки PLD: %d\n",
                       hltr114.ModuleInfo.Name,
                       hltr114.ModuleInfo.Serial,
                       (hltr114.ModuleInfo.VerMCU >> 8) &0xFF,
                       hltr114.ModuleInfo.VerMCU & 0xFF,
                       hltr114.ModuleInfo.VerPLD);

                fflush(stdout);
            }

            hltr114.FreqDivider = 2; //частота дискретизации АЦП 4Кгц
            hltr114.LChQnt = 2; //2 логических канала
            //снимаем напряжение с первого канала, диапазон +/- 10 В
            hltr114.LChTbl[0] = LTR114_CreateLChannel(LTR114_MEASMODE_U, 0, LTR114_URANGE_10);
            //и с 16-го, диапазон +/- 0.4 В
            hltr114.LChTbl[1] = LTR114_CreateLChannel(LTR114_MEASMODE_U, 1, LTR114_URANGE_10);
            hltr114.SyncMode = LTR114_SYNCMODE_INTERNAL; //внутренняя синхронизация
            hltr114.Interval = 0; //без межкадрового интервала

            //передаем настройки модулю
            err = LTR114_SetADC(&hltr114);
            if (err!=LTR_OK)
            {
                fprintf(stderr, "Не удалось установить настройки АЦП. Ошибка %d (%s)\n",
                        err, LTR114_GetErrorString(err));
            }

            if (err==LTR_OK)
            {
                //производим начальную калибровку модуля
                err = LTR114_Calibrate(&hltr114);
                if (err != LTR_OK)
                {
                    fprintf(stderr, "Не удалось провести начальную калибровку. Ошибка %d (%s)\n",
                            err, LTR114_GetErrorString(err));
                }
                else
                {
                    printf("Начальная калибровка выполнена успешно!\n");
                }
            }

            if (err==LTR_OK)
            {
                INT size = STREAM_RECV_FRAME_CNT*hltr114.FrameLength;
                DWORD* recv_data = NULL;
                double* proc_data = NULL;
                //выделение памяти под принимаемые данные и обработанные данные
                recv_data = malloc(size*sizeof(DWORD));
                //в результируещем массиве будет LChQnt слов на кадр
                proc_data = (double*)malloc(STREAM_RECV_FRAME_CNT*hltr114.LChQnt*sizeof(double));

                if ((recv_data==NULL) || (proc_data==NULL))
                {
                    err = LTR_ERROR_MEMORY_ALLOC;
                    fprintf(stderr, "Ошибка выделения памяти!\n");
                }
                else
                {
                    err = LTR114_Start(&hltr114);
                    if (err!=LTR_OK)
                    {
                        fprintf(stderr, "Не удалось запустить сбор данных. Ошибка %d (%s)\n",
                                err, LTR114_GetErrorString(err));
                    }
                    else
                    {
                        printf("Сбор данных запущен. Для останова нажмите %s\n",
#ifdef _WIN32
                               "любую клавишу"
#else
                               "CTRL+C"
#endif
                               );

                    }

                    if (err==LTR_OK)
                    {
                        INT stop_err = LTR_OK;
                        INT block = 0;

                        while (!f_out && (err==LTR_OK))
                        {
                            INT recvd;
                            //обновляем size, так как в цикле он изменяется в process_data
                            size = STREAM_RECV_FRAME_CNT*hltr114.FrameLength;
                            recvd = LTR114_Recv(&hltr114, recv_data, NULL, size, STREAM_RECV_TOUT);
                            if (recvd<0)
                            {
                                err = recvd;
                                fprintf(stderr, "Ошибка приема данных. Ошибка %d:%s\n",
                                        err, LTR114_GetErrorString(err));
                            }
                            else if (recvd!=size)
                            {
                                fprintf(stderr, "Принято недостаточно данных. Запрашивали %d, приняли %d\n",
                                        size, recvd);
                                err = LTR_ERROR_RECV;
                            }
                            else
                            {
                                err = LTR114_ProcessData(&hltr114, recv_data, proc_data, &size,
                                                        LTR114_CORRECTION_MODE_INIT, LTR114_PROCF_VALUE);
                                if (err!=LTR_OK)
                                {
                                    fprintf(stderr, "Ошибка обработки данных. Ошибка %d:%s\n",
                                            err, LTR114_GetErrorString(err));
                                }
                                else
                                {
                                    INT ch;
                                    printf("Блок %d", block+1);
                                    for (ch=0; ch < hltr114.LChQnt; ch++)
                                    {
                                        printf(" ch[%d]=%.6f", ch+1, proc_data[ch]);
                                    }

                                    printf("\n");
                                    fflush(stdout);
                                    block++;
                                }
                            }

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


                        stop_err = LTR114_Stop(&hltr114);
                        if (stop_err==LTR_OK)
                        {
                            printf("Модуль остановлен успешно!\n");
                        }
                        else
                        {
                            fprintf(stderr, "Ошибка останова сбора данных. Ошибка %d:%s\n",
                                    stop_err, LTR114_GetErrorString(stop_err));
                            if (err==LTR_OK)
                                err = stop_err;
                        }
                    }

                    free(proc_data);
                    free(recv_data);
                }
            }

            LTR114_Close(&hltr114);
        }
    }

    return err;
}
