using System;
using ltrModulesNet;

/* Данный пример демонстрирует работу с модулем LTR51 из программы на языке C#.
 * Пример представляет собой консольную программу, которая устанавливает связь с модулем,
 * выводит информацию о модуле, устанавливает настройки и собирает заданное кол-во 
 * блоков данных, соответствующих по вермени установленному интервалу подсчета.
 * На каждый блок рассчитывается полученная частота сигнала и выводится ее значение.
 * 
 * Необходимо установить номер слота, в котором вставлен модуль (константа SLOT).
 * Настройки сбора задаются в коде при конфигурации модуля.
 */

namespace ltr51_freq
{
    class ltr51_freq
    {
        /* Номер слота в крейте, где вставлен модуль */
        const int SLOT = 2;
        /* Количество блоков, которые нужно принять и выйти */
        const int RECV_BLOCK_CNT = 500;

        static void Main(string[] args)
        {
            /* LTR51_Init() вызывается уже в конструкторе */
            ltr51api hltr51 = new ltr51api();
            /* отрываем модуль. Используем упрощенный вариант функции с указанием только слота.
             * (есть вариант как с только со слотом, так и с серийным крейта и слотом 
             *  + полный). Используем вариант функции без явного указания файла прошивки ПЛИС,
             *  который использует встроенный в .dll файл */
            _LTRNative.LTRERROR err = hltr51.Open(SLOT);
            if (err != _LTRNative.LTRERROR.OK)
            {
                Console.WriteLine("Не удалось открыть модуль. Ошибка {0}: {1}",
                                    err, ltr51api.GetErrorString(err));
            }
            else
            {
                /* выводим информацию из hltr51.ModuleInfo */
                Console.WriteLine("Информация о модуле: ");
                Console.WriteLine("  Название модуля        : {0}", hltr51.ModuleInfo.Name);
                Console.WriteLine("  Серийный номер         : {0}", hltr51.ModuleInfo.Serial);
                Console.WriteLine("  Версия прошивки        : {0}", hltr51.ModuleInfo.FirmwareVersion);
                Console.WriteLine("  Дата создания прошивки : {0}", hltr51.ModuleInfo.FirmwareDate);
                Console.WriteLine("  Версия прошивки ПЛИС   : {0}", hltr51.ModuleInfo.FPGA_Version);

                /* --------------- задание параметров работы модуля ------------ */
                 /* время должно быть не меньше 2-х периодов частоты.
                  * настройки FS и Base берем автоматически рассчитанные */
                 hltr51.AcqTime = 1000;
                 hltr51.LChQnt = 2;
                 
                double HighThreshold = 0.7;
                double LowThreshold = 0.3;
                /* для примера настраиваем первые два канала (первый мезанин).
                 * Первым параметром указываем номер заполняемого элемента в таблице (лог. канала) - считается от 0
                 * Вторым параметром - реально опрашиваемый канал - считается от 1
                 * ThresholdRange должен соответсвовать положению джампера на модуле */
                hltr51.FillLChannel(0, 1, HighThreshold, LowThreshold,
                                    ltr51api.ThresholdRange.Range_10V, ltr51api.EdgeMode.RISE);
                hltr51.FillLChannel(1, 2, HighThreshold, LowThreshold,
                                    ltr51api.ThresholdRange.Range_10V, ltr51api.EdgeMode.RISE);
    
                err = hltr51.Config();
                if (err != _LTRNative.LTRERROR.OK)
                    {
                        Console.WriteLine("Не удалось настроить модуль! Ошибка {0}: {1}",
                                        err, ltr51api.GetErrorString(err));     
                    } else 
                 {
                     Console.WriteLine("Установлены следующие параметры:");
                     Console.WriteLine("  Частота дискретизации         = {0} Гц", hltr51.Fs);
                     Console.WriteLine("  Счетчик BASE                  = {0}", hltr51.Base);
                     Console.WriteLine("  Время счета                   = {0} мс", hltr51.AcqTime);
                     Console.WriteLine("  Количество периодов измерения = {0}", hltr51.TbaseQnt);
                 }
            }


            if (err == _LTRNative.LTRERROR.OK)
            {
                /* всегда идет прием слов от всех каналов по два слова на канал.
                 * Для расчета частоты необходимо TbaseQnt кадров */
                uint recv_word_cnt = (uint)(2*ltr51api.LTR51_CHANNELS_CNT*hltr51.TbaseQnt);
                uint[] rbuf = new uint[recv_word_cnt];
                /* значение частоты рассчитывается по значению за один разрешенных канал на блок */
                double[] freqs = new double[hltr51.LChQnt];
                /* таймаут на прием расчитывается библиотечной функцией */
                uint tout = hltr51.CalcTimeOut(hltr51.TbaseQnt);

                /* запуск сбора данных */
                err = hltr51.Start();
                if (err != _LTRNative.LTRERROR.OK)
                {
                    Console.WriteLine("Не удалось запустить сбор данных. Ошибка {0}: {1}",
                         err, ltr51api.GetErrorString(err));
                }
                else
                {
                    _LTRNative.LTRERROR stop_err;
                    for (int i = 0; (i < RECV_BLOCK_CNT) &&
                            (err == _LTRNative.LTRERROR.OK); i++)
                    {
                        int rcv_cnt;
                        /* прием необработанных слов. есть варинант с tmark и без него для удобства */
                        rcv_cnt = hltr51.Recv(rbuf, (uint)rbuf.Length, tout);

                        /* значение меньше 0 => код ошибки */
                        if (rcv_cnt < 0)
                        {
                            err = (_LTRNative.LTRERROR)rcv_cnt;
                            Console.WriteLine("Ошибка приема данных. Ошибка {0}: {1}",
                                              err, ltr51api.GetErrorString(err));
                        }
                        else if (rcv_cnt != rbuf.Length)
                        {
                            err = _LTRNative.LTRERROR.ERROR_RECV_INSUFFICIENT_DATA;
                            Console.WriteLine("Приняли недостаточно данных: запрашивали {0}, приняли {1}",
                                              rbuf.Length, rcv_cnt);
                        }
                        else
                        {
                            /* ProcessData в LTR51 может расчитывать как частоту, так
                             * и значения N и M для каждого периода измерения.
                             * Для удобства введены 3 варианта ProcessData:
                             * c получением частоты, с получением N и M, и обоих значений.
                             * В данном случае используем первый. 
                             * Этот вариант принимает размер по значению, а не по ссылке,
                             * т.к. выходное значение size в нем не имеет смысла */
                            err = hltr51.ProcessData(rbuf, freqs, (uint)rcv_cnt);
                            if (err != _LTRNative.LTRERROR.OK)
                            {
                                Console.WriteLine("Ошибка обработки данных. Ошибка {0}: {1}",
                                                   err, ltr51api.GetErrorString(err));
                            }
                            else
                            {
                                /* при успешной обработке для примера выводим расчитанные значения частот */
                                Console.Write("Блок {0}.", i + 1);
                                for (int ch = 0; ch < hltr51.LChQnt; ch++)
                                {
                                    /* если все ок - выводим значение (для примера только первое) */
                                    Console.Write(" {1}", ch + 1, freqs[ch].ToString("F7"));
                                    if (ch == (hltr51.LChQnt - 1))
                                        Console.WriteLine("");
                                    else
                                        Console.Write(", ");
                                }
                            }
                        }
                    }

                    /* останавливаем сбор данных */
                    stop_err = hltr51.Stop();
                    if (stop_err != _LTRNative.LTRERROR.OK)
                    {
                        Console.WriteLine("Не удалось остановить сбор данных. Ошибка {0}: {1}",
                             stop_err, ltr51api.GetErrorString(stop_err));
                        if (err == _LTRNative.LTRERROR.OK)
                            err = stop_err;
                    }
                }
            }

            hltr51.Close();
        }
    }
}
