
#include "ltr/include/ltr34api.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "ltimer.h"

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



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

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



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

/* Разбор параметров командной строки. Если указано меньше, то используются
 * значения по умолчанию:
 * 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;
}

static int is_valid_dig(char c) {
    return  ((c >= '0') && (c <= '9')) || (c == '.') || (c == '-');
}

static INT f_get_vals(double *vals, int *out) {
    static char tmp_str[2048];
    memset(tmp_str, 0, sizeof(tmp_str));

    printf("Введите новые значения или 'out' для выхода\n");
    fgets(tmp_str, sizeof(tmp_str), stdin);
    if (strlen(tmp_str) > 0) {
        if (strstr(tmp_str, "out")) {
            *out = 1;
        } else {
            int vals_cnt = 0;
            char *proc_ptr = tmp_str;

            while (*proc_ptr) {
                while ((*proc_ptr != 0) && !is_valid_dig(*proc_ptr)) {
                    proc_ptr++;
                }

                if (*proc_ptr != 0) {
                    float val;
                    const char *start_pt = proc_ptr;
                    while (is_valid_dig(*proc_ptr))
                        proc_ptr++;
                    *proc_ptr++ = 0;
                    sscanf(start_pt, "%f", &val);
                    if (vals_cnt < LTR34_DAC_CHANNEL_CNT)
                        vals[vals_cnt++] = (double)val;
                }
            }
        }
    }
    return LTR_OK;
}

static INT f_set_vals(TLTR34 *hnd, const double *vals) {
    DWORD snd_size = hnd->ChannelQnt;
    INT err=LTR_OK;
    unsigned ch;
    double data[LTR34_DAC_CHANNEL_CNT];
    DWORD  wrds[LTR34_DAC_CHANNEL_CNT];

    for (ch = 0; ch < hnd->ChannelQnt; ch++) {
        data[ch] = vals[ch];
    }
    err = LTR34_ProcessData(hnd, data, wrds, snd_size, TRUE);
    if (err!=LTR_OK) {
        fprintf(stderr, "Ошибка подготовки данных (%d) : %s!\n", err, LTR34_GetErrorString(err));
    }


    if (err == LTR_OK) {
        INT cur_sent = LTR34_Send(hnd, wrds, snd_size, 100);
        if (cur_sent < 0) {
            err = cur_sent;
            fprintf(stderr, "Ошибка передачи данных (%d) : %s!\n", err, LTR34_GetErrorString(err));
        } else if ((DWORD)cur_sent != snd_size) {
            fprintf(stderr, "Переданы не все слова. Передавали %d, передано %d!\n",
                    snd_size, cur_sent);
            err = LTR_ERROR_SEND_INSUFFICIENT_DATA;
        }
    }
    return err;
}



int main(int argc, char** argv) {
    INT err = LTR_OK;
    TLTR34 hltr34;
    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);

    LTR34_Init(&hltr34);

    err = LTR34_Open(&hltr34, par.addr, LTRD_PORT_DEFAULT, par.serial, par.slot);
    if (err != LTR_OK) {
        fprintf(stderr, "Не удалось установить соединение с модулем. Ошибка %d: %s\n",
                err, LTR34_GetErrorString(err));
    } else {
        int ch = 0;;
        double vals[LTR34_DAC_CHANNEL_CNT];

        printf("Модуль открыт успешно. Информация о модуле:\n  Название %s\n  Серийный %s\n  Версия ПЛИС %s\n  Максимальное число каналов - %d\n",
               hltr34.ModuleInfo.Name, hltr34.ModuleInfo.Serial, hltr34.ModuleInfo.FPGA_Version, hltr34.ModuleInfo.MaxChannelQnt);
        fflush(stdout);

        hltr34.ChannelQnt = hltr34.ModuleInfo.MaxChannelQnt;
        for (ch=0; ch < hltr34.ChannelQnt; ch++) {
            hltr34.LChTbl[ch] = LTR34_CreateLChannel(ch + 1, 0);
            vals[ch] = 0;
        }

        LTR34_FindDacFreqDivisor(500000, hltr34.ChannelQnt, &hltr34.FrequencyDivisor, NULL);
        hltr34.AcknowledgeType = LTR34_ACKTYPE_STATUS;
        hltr34.RingMode = FALSE;
        hltr34.UseClb = TRUE;
        hltr34.ExternalStart = FALSE;


        err = LTR34_Reset(&hltr34);
        if (err != LTR_OK) {
            fprintf(stderr, "Не удалось выполнить сброс модуля LTR34. Ошибка %d: %s\n",
                    err, LTR34_GetErrorString(err));
        } else {
            err = LTR34_Config(&hltr34);
            if (err != LTR_OK) {
                fprintf(stderr, "Не удалось сконфигурировать модуль LTR34. Ошибка %d: %s\n",
                        err, LTR34_GetErrorString(err));
            }
        }

        if (err == LTR_OK)
            err = f_get_vals(vals, &f_out);
        if ((err == LTR_OK) && !f_out)
            err = f_set_vals(&hltr34, vals);


        if ((err == LTR_OK) && !f_out) {
            /* запуск генерации */
            err = LTR34_DACStart(&hltr34);
            if (err != LTR_OK) {
                fprintf(stderr, "Не удалось запустить генерацию данных. Ошибка %d: %s\n",
                        err, LTR34_GetErrorString(err));
            }


            /* передаем данные в модуль постоянно до момента прихода
             * сигнала завершения генерации */
            while (!f_out && (err == LTR_OK)) {
                if (err == LTR_OK)
                    err = f_get_vals(vals, &f_out);
                if ((err == LTR_OK) && !f_out)
                    err = f_set_vals(&hltr34, vals);
            }

            if (hltr34.DACRunning) {
                INT stop_err;
                /* останов генерации данных */
                printf("Останавливаем генерацию...\n");
                fflush(stdout);
                stop_err = LTR34_DACStop(&hltr34);
                if (stop_err == LTR_OK) {
                    printf("Останов генерации завершен успешно!\n");
                    fflush(stdout);
                } else {
                    fprintf(stderr, "Не удалось остановить генерацию данных. Ошибка %d: %s\n",
                            stop_err, LTR34_GetErrorString(stop_err));
                    if (err == LTR_OK)
                        err = stop_err;
                }
            }
        }

        LTR34_Close(&hltr34);
    }
    return err;
}
