#include "ltr/include/ltr27api.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



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;
}

static int check_out(void) {
#ifdef _WIN32
    if (_kbhit())
        f_out = 1;
#endif
    return f_out;
}


int main(int argc, char** argv) {
    INT err = 0, stop_err = 0;
    TLTR27 ltr27;
    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 == LTR_OK) {
        LTR27_Init(&ltr27);
        /* устанавливаем соединение с модулем находящемся в первом слоте крейта.
           для сетевого адреса, сетевого порта ltr-сервера и серийного номера
           крейта используем значения по умолчанию */
        err = LTR27_Open(&ltr27, par.addr, LTRD_PORT_DEFAULT, par.serial, par.slot);
        if (err == LTR_OK) {
            printf("Модуль открыт успешно!\n");
            if (ltr27.ModuleInfo.Module.VerPLDIsValid) {
                printf("    Версия PLD:    : %d\n", ltr27.ModuleInfo.Module.VerPLD);
            }
        } else {
             fprintf(stderr, "Не удалось открыть модуль. Ошибка %d (%s)\n",
                                    err, LTR27_GetErrorString(err));
        }
    }

    if(err == LTR_OK) {
        /* получаем конфигурацию модуля:
           тип установленных мезонинов и параметры сбора данных АЦП */
        err = LTR27_GetConfig(&ltr27);
        if (err != LTR_OK) {
            fprintf(stderr, "Не удалось прочитать конфигурацию. Ошибка %d (%s)\n",
                            err, LTR27_GetErrorString(err));
        }



        if(err == LTR_OK) {
            err = LTR27_GetDescription(&ltr27,  LTR27_ALL_DESCRIPTION);
            if (err!=LTR_OK) {
                fprintf(stderr, "Не удалось прочитать описатель модуля и меззанинов. Ошибка %d (%s)\n",
                                err, LTR27_GetErrorString(err));
            }
        }

        if(err == LTR_OK) {
            INT mez_idx;

            printf("Прочитана информация о модуле :\n");
            printf("    Название       : %s\n", ltr27.ModuleInfo.Module.DeviceName);
            printf("    Серийный номер : %s\n", ltr27.ModuleInfo.Module.SerialNumber);
            if(ltr27.ModuleInfo.Cpu.Active) {
                printf("   Информация о процессоре :\n");
                printf("     Название        : %s\n",      ltr27.ModuleInfo.Cpu.Name);
                printf("     Частота клока   : %.1f Hz\n", ltr27.ModuleInfo.Cpu.ClockRate);
                printf("     Версия прошивки : %d.%d.%d.%d\n",
                       (ltr27.ModuleInfo.Cpu.FirmwareVersion>>24) & 0xFF,
                       (ltr27.ModuleInfo.Cpu.FirmwareVersion>>16) & 0xFF,
                       (ltr27.ModuleInfo.Cpu.FirmwareVersion>>8) & 0xFF,
                       ltr27.ModuleInfo.Cpu.FirmwareVersion & 0xFF);
                printf("     Комментарий     : %s\n",      ltr27.ModuleInfo.Cpu.Comment);
            } else {
                printf("  Не найдено действительное описание процессора!!!\n");
            }

            for (mez_idx = 0; mez_idx < LTR27_MEZZANINE_CNT; ++mez_idx) {
                if(ltr27.ModuleInfo.Mezzanine[mez_idx].Active) {
                    INT ceof_idx;
                    printf("    Информация о мезонине в слоте %d :\n", mez_idx+1);

                    printf("      Название        : %s\n", ltr27.ModuleInfo.Mezzanine[mez_idx].Name);
                    printf("      Серийный номер  : %s\n", ltr27.ModuleInfo.Mezzanine[mez_idx].SerialNumber);
                    printf("      Ревизия         : %d\n", (int)ltr27.ModuleInfo.Mezzanine[mez_idx].Revision);
                    for(ceof_idx = 0; ceof_idx < LTR27_MEZZANINE_CBR_COEF_CNT; ++ceof_idx) {
                        printf("      Калибр. коэф. %d : %.3f\n", ceof_idx, ltr27.ModuleInfo.Mezzanine[mez_idx].Calibration[ceof_idx]);
                    }
                }
            }

            fflush(stdout);
        }


        while ((err == LTR_OK) && !check_out()) {
            /* считываем описание модуля */
            err = LTR27_GetDescription(&ltr27,  LTR27_ALL_DESCRIPTION);
            if (err != LTR_OK) {
                fprintf(stdout, "Не удалось прочитать описание модуля или мезанинов. Ошибка %d (%s)\n",
                                err, LTR27_GetErrorString(err));
                fprintf(stderr, "Не удалось прочитать описание модуля или мезанинов. Ошибка %d (%s)\n",
                                err, LTR27_GetErrorString(err));
            } else {
                fprintf(stderr, ".");
                fprintf(stdout, ".");
                fflush(stdout);
            }
        }
        LTR27_Close(&ltr27);
    }
    return err;
}

